Merge pull request #466 from irisitymichaelgrundberg/feat/pane-exit-reporting

feat(tmux): report that a pane's agent has exited (#446, part 1)
This commit is contained in:
Codeman maintainer
2026-09-23 11:32:02 +02:00
15 changed files with 1799 additions and 33 deletions
+23
View File
@@ -1371,6 +1371,19 @@ describe('session-routes', () => {
expect(body.success).toBe(false);
});
// Ark0N/Codeman#446: starting a command in the pane retracts `paneExit`, and
// the pane-exit watcher cannot write that retraction for us — its next tick
// finds the field already cleared, reports no change and persists nothing.
// Broadcasting without persisting leaves state.json saying the agent exited.
it('persists the session, not just broadcasts it', async () => {
const res = await harness.app.inject({
method: 'POST',
url: `/api/sessions/${harness.ctx._sessionId}/interactive`,
});
expect(res.statusCode).toBe(200);
expect(harness.ctx.persistSessionState).toHaveBeenCalledWith(harness.ctx._session);
});
it('returns error if session is busy', async () => {
harness.ctx._session.isBusy.mockReturnValue(true);
const res = await harness.app.inject({
@@ -1447,6 +1460,16 @@ describe('session-routes', () => {
expect(harness.ctx.setupSessionListeners).toHaveBeenCalledWith(harness.ctx._session);
});
// Same reason as /interactive above (Ark0N/Codeman#446).
it('persists the session, not just broadcasts it', async () => {
const res = await harness.app.inject({
method: 'POST',
url: `/api/sessions/${harness.ctx._sessionId}/shell`,
});
expect(res.statusCode).toBe(200);
expect(harness.ctx.persistSessionState).toHaveBeenCalledWith(harness.ctx._session);
});
it('returns error if session is busy', async () => {
harness.ctx._session.isBusy.mockReturnValue(true);
const res = await harness.app.inject({