mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-10-09 08:59:40 +02:00
fix(tiles): Attach reads the response envelope; an exited agent gets no Attach
Found live: the attach and shell routes report a refusal in the envelope of
a 200 ({success: false}), and Attach read only res.ok, so a refused attach
remounted the tile as if it had worked. It now reads the envelope.
The refusal in question: an agent that exited in a live pane (paneExit, e.g.
a shell ended with `exit 3`) still has the pane's tmux client running, so
both routes refuse to start anything ("Session already has a running
process"), and the single view has no restart for it either. Its tile now
shows the exit with a pointer to Close session instead of an Attach button
that cannot work. A session with no PTY attached, or one whose socket closed
because it exited (4009), still gets Attach.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -63,10 +63,20 @@ describe('when the overlay shows', () => {
|
||||
expect(visible('s-a')).toBe(false);
|
||||
});
|
||||
|
||||
it('an agent that exited in a live pane', () => {
|
||||
gridWith((app) => (app.sessions.get('s-c').paneExit = { status: 2 }));
|
||||
it('an agent that exited in a live pane: the reason, and no Attach (the server cannot restart it in place)', async () => {
|
||||
const app = gridWith((a) => (a.sessions.get('s-c').paneExit = { status: 2 }));
|
||||
expect(visible('s-c')).toBe(true);
|
||||
expect(textOf('s-c')).toBe('The agent exited (2)');
|
||||
expect(attachButton('s-c').hidden).toBe(true);
|
||||
expect(overlayOf('s-c')!.children[2].hidden).toBe(false);
|
||||
expect(await app.attachTileSession('s-c')).toBe(false);
|
||||
expect(fetchSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('a session with no PTY gets the button, not the close hint', () => {
|
||||
gridWith((app) => (app.sessions.get('s-b').pid = null));
|
||||
expect(attachButton('s-b').hidden).toBe(false);
|
||||
expect(overlayOf('s-b')!.children[2].hidden).toBe(true);
|
||||
});
|
||||
|
||||
it('a socket closed because the session exited (4009) keeps the tile and shows it', () => {
|
||||
@@ -133,6 +143,15 @@ describe('Attach', () => {
|
||||
await first;
|
||||
});
|
||||
|
||||
it('a refusal in the envelope of a 200 is a failure, not a success', async () => {
|
||||
const app = gridWith((a) => (a.sessions.get('s-b').pid = null));
|
||||
fetchSpy.mockImplementation(async () => ({ ok: true, json: async () => ({ success: false, error: 'busy' }) }));
|
||||
expect(await app.attachTileSession('s-b')).toBe(false);
|
||||
expect(app.showToast).toHaveBeenCalledWith('Could not attach the session', 'error');
|
||||
expect(tilesFor('s-b')).toHaveLength(1);
|
||||
expect(visible('s-b')).toBe(true);
|
||||
});
|
||||
|
||||
it('a failed attach keeps the overlay and says so', async () => {
|
||||
const app = gridWith((a) => (a.sessions.get('s-b').pid = null));
|
||||
fetchSpy.mockImplementation(async () => ({ ok: false, json: async () => ({}) }));
|
||||
|
||||
Reference in New Issue
Block a user