mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-10-02 13:39:41 +02:00
feat(tui): offer r to resume a session whose pane has died
Refusing the attach stopped the freeze but told the user to throw the session away (`x` to close, `n` for new), which loses the conversation. tmux's own dead-pane screen already says what to do instead: `claude --resume "<name>"`. The Error card now offers `r` when the row can actually be resumed (claude, with a conversation id and a working directory), and the footer says so. One press resumes into a fresh pane and attaches to it, so a dead end becomes recovery. ⚠️ Three things keep this from becoming the resume runaway that once spawned 35 sessions in 40 seconds. The offer holds a session ID, not a row, and is re-resolved from the model when the key is pressed: a row captured when the card opened is stale by then. It disarms BEFORE anything async, so a second `r` cannot start a second resume. And it routes through resumeSelected(), which owns the `resuming` flag and ends in attachToSession() rather than the group dispatch. ⚠️ The `r` branch has to run BEFORE the generic dismiss, because a message overlay is dismissed by ANY key: without that ordering the offer is consumed as "some key was pressed" and the card merely closes. `help` keeps the any-key behaviour, so the two modes no longer share a case. Verified end to end against a genuinely dead claude pane: card, footer, one press, one new session, and F12 back to the dashboard.
This commit is contained in:
@@ -460,6 +460,16 @@ describe('buildListLines', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('the dead-row resume offer', () => {
|
||||
it('advertises r on the message footer only while an offer is armed', () => {
|
||||
const base = { server: true } as const;
|
||||
expect(footerKeysFor('message', GLYPHS, { ...base, resumeOffer: true })).toEqual(['r resume', 'esc dismiss']);
|
||||
// Without an offer the card is a plain notice, and a footer promising `r`
|
||||
// would be advertising a key that does nothing.
|
||||
expect(footerKeysFor('message', GLYPHS, base)).toEqual(['esc dismiss']);
|
||||
});
|
||||
});
|
||||
|
||||
describe('the one-key way out', () => {
|
||||
it('names a single key with no modifier at all', () => {
|
||||
// The whole point: three beta rounds died on a chord that had to be typed
|
||||
|
||||
Reference in New Issue
Block a user