feat: unify CLI and web run lifecycle#232
Conversation
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 151a52f329
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| useEffect(() => { | ||
| setStreamConnected(subscription.status === 'pending'); | ||
| }, [subscription.status]); | ||
| if (activeRun) { | ||
| ensureRunSubscription(activeRun); | ||
| } | ||
| }, [activeRun, ensureRunSubscription]); |
There was a problem hiding this comment.
Validate active run address before subscribing
When the user switches from a session that still has an active run to another session, runControl.activeRun still contains the previous session's run for the render before its reset effect applies. This effect then calls ensureRunSubscription with the new workspaceId/sessionId but the old runId, so the new session subscribes to a non-existent run and starts the reconnect/error path on the wrong session. Include the run address in the tracked value or clear/validate the active run against the selected session before subscribing.
Useful? React with 👍 / 👎.
What changed
ConversationRunService, including active-run recovery and stable public result projectionWhy
Heddle already executed prompts, continuation, direct shell, and compaction through the public run service, but its own CLI and web clients still consumed a separate non-replayable session event path. That meant the experience inside Heddle differed from the lifecycle SDK users build against and could lose or duplicate activity across reconnects.
This change makes Heddle dogfood the same accepted identity, ordered replay, terminal, cancellation, and approval semantics exposed by the SDK while keeping the daemon/control-plane boundary intact.
Contract impact
controlPlane.sessionEventsnow carries lifecycle/discovery, queue, approval, and durable-session signals rather than conversation activities.controlPlane.sessionRunEvents({ sessionId, runId, afterSequence }).controlPlane.sessionRunStatenow includesactiveRun.Validation
yarn test— 109 unit files / 626 tests; 29 integration files / 285 testsyarn typecheckyarn lintyarn buildyarn verify:tui-behavioryarn test:browser-integration— 7 Playwright tests, including active-run recovery/replay after browser reload