[stack 5/8] fix(coding-agent): repair queued and archived session lifecycle - #1162
[stack 5/8] fix(coding-agent): repair queued and archived session lifecycle#1162sethkarten wants to merge 7 commits into
Conversation
| lifecycle: "resident", | ||
| env: this.options.sendClientEnv ? collectDaemonClientEnv() : undefined, | ||
| }); | ||
| if ( |
There was a problem hiding this comment.
🟡 Medium agent-connection/daemon-agent-connection.ts:839
reviveArchivedSession creates a resident daemon session via the create request, and if dispose() or a concurrent session switch occurs while that request is in flight, the function throws "Archived-session revival was superseded" without detaching or otherwise cleaning up the newly created resident session. The daemon keeps that resident worker running indefinitely with no owner.
The guard at line 840 checks disposed/disposing/activeSessionId/attachedSessionFile after create already succeeded, so when the condition is true it discards summary and throws instead of detaching the new session. Consider detaching (or completing) targetActiveSessionId in that branch before throwing.
🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @packages/coding-agent/src/modes/agent-connection/daemon-agent-connection.ts around line 839:
`reviveArchivedSession` creates a resident daemon session via the `create` request, and if `dispose()` or a concurrent session switch occurs while that request is in flight, the function throws `"Archived-session revival was superseded"` without detaching or otherwise cleaning up the newly created resident session. The daemon keeps that resident worker running indefinitely with no owner.
The guard at line 840 checks `disposed`/`disposing`/`activeSessionId`/`attachedSessionFile` *after* `create` already succeeded, so when the condition is true it discards `summary` and throws instead of detaching the new session. Consider detaching (or completing) `targetActiveSessionId` in that branch before throwing.
91643f5 to
bf5e9fa
Compare
| options?: AgentConnectionPromptOptions, | ||
| ): Promise<void> { | ||
| const pendingRevival = this.revival; | ||
| if (pendingRevival) await pendingRevival.promise.catch(() => undefined); |
There was a problem hiding this comment.
🟡 Medium agent-connection/daemon-agent-connection.ts:752
promptWithAdmissionCancellation awaits a pending revival before checking options.signal, so a concurrent prompt whose signal is already aborted (or aborts during a slow revival) hangs until the unrelated revival finishes instead of promptly rejecting with AgentConnectionPromptAdmissionError. Check the signal before awaiting the pending revival so aborted prompts reject immediately.
🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @packages/coding-agent/src/modes/agent-connection/daemon-agent-connection.ts around line 752:
`promptWithAdmissionCancellation` awaits a pending revival before checking `options.signal`, so a concurrent prompt whose signal is already aborted (or aborts during a slow revival) hangs until the unrelated revival finishes instead of promptly rejecting with `AgentConnectionPromptAdmissionError`. Check the signal before awaiting the pending revival so aborted prompts reject immediately.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit bf5e9fa. Configure here.
|
|
||
| private async _prompt(text: string, options?: InternalPromptOptions): Promise<void> { | ||
| if (!this.isStreaming) { | ||
| this._sessionInputPumpSuspended = false; |
There was a problem hiding this comment.
Injected prompts hang under update-restart
High Severity
_promptInjectedMessage can admit an immediately eligible turn while update_restart suspension keeps the input pump stopped, then await delivered/completed. Cancelled RLM children that fall back to this path during abortForUpdateRestart never finish, so their finally cleanup and usage flush do not run.
Additional Locations (2)
Reviewed by Cursor Bugbot for commit bf5e9fa. Configure here.
| } | ||
| const targetActiveSessionId = summary.activeSessionId ?? summary.id; | ||
| await this.reattachSession(sourceActiveSessionId, targetActiveSessionId); | ||
| this.terminalCloseEmitted = false; |
There was a problem hiding this comment.
Superseded revival leaves resident worker
Medium Severity
reviveArchivedSession can successfully create a resident worker and then throw as superseded when the connection is disposing, without stopping or detaching that worker. dispose also does not cancel or await an in-flight revival, so the revived session can remain running unattached.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit bf5e9fa. Configure here.


Stack 5/8 — fix(coding-agent): repair queued and archived session lifecycle
Base:
stack/external-04-daemon-foundationsReview order: merge only after the preceding stack layer is accepted. This PR is not intended to merge independently out of order.
Stack navigation
Summary
Validation
npm run check; final clean-environment lifecycle suites 189/189.Provenance
upstream/mainusing issue reports and PR descriptions/comments only.Linked-item disposition
Fixed on merge
%%bashsubprocesses running forever: forceAbort resolves the tool call after 1s but never reaches the cell's grandchildren #849 — Esc/interrupt leaves%%bashsubprocesses running forever: forceAbort resolves the tool call after 1s but never reaches the cell's grandchildrenIndependently superseded pull requests
Partially addressed — remains open
Reviewer notes
main, to avoid cumulative duplicate diffs.