Repository navigation
Show agent update outcomes automatically - #21480
Conversation
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configuration
You can disable this status message by setting the Use the checkbox below for a quick retry:
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
This comment has been minimized.
This comment has been minimized.
|
cmux status (one comment, edited in place; each line is updated by the job that owns it) Review App of this head (app.zip, kept 1 day)
Not verified: macOS jobs did not run: compile and app tests were skipped on CI passes on Written by web and size checks: green
|
|
Agents: |
ba609d8 to
bd9ff6b
Compare
548883b to
79df51c
Compare
Bugbot needs on-demand usage enabledBugbot uses usage-based billing for this team and requires on-demand usage to be enabled. A team admin can enable on-demand usage in the Cursor dashboard. |
bd9ff6b to
ad73e4c
Compare
|
Visual preview of 2e328ff: in the maintainers' private review feed. |
|
Bead |
Replays #21398's change onto current feat-cmux-next as one commit. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Replays #21401's change onto current feat-cmux-next as one commit. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Replays #21402's change onto current feat-cmux-next as one commit. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Replays #21414's change onto current feat-cmux-next as one commit. Keeps the crash ratchet flat: poisoned locks are recovered instead of unwrapped (only a held job lock is busy), and the job status parses its decimal strings with radix: 10. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Replays #21429's change onto current feat-cmux-next as one commit, written without growing CmuxNextApp's source lines (size cap). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Replays #21436's change onto current feat-cmux-next as one commit. ControlRequest takes callerApp in its init so CmuxNextApp's source lines don't grow (size cap). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Replays #21447's change onto current feat-cmux-next as one commit, together with its follow-up fix. Settings and the palette run agent updates on their captured owner route instead of typing a health argv into a focused pane. The update owner prepares only npm and native installations, and refuses a family when any of its rows is another channel or already current, so both surfaces submit only those families and Settings shows Update only for rows whose channel the owner runs. A start the owner refuses (agent_cli_job.*, answered before it journals a creation) leaves no "unknown" job that blocks that CLI. One family's failure does not stop the rest of a batch; the batch reports every failure. A lost reply still keeps its unknown job, since the terminal may exist. Update, Update all and turning Update Automatically on still need a gesture or a confirmed user, as #21439 requires. The update action, its owner route and the health-row reader live in a new CmuxNextAgentUpdates module, leaving thin app glue in CmuxNextApp. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Replays #21469's change onto current feat-cmux-next as one commit, on top of the owner-channel fix, with these changes so a retained intent always has a way out: - A start the owner refuses before journaling (agent_cli_job.*) settles its intent, in a batch and on Resume, instead of leaving a Resume that is refused again. - Any terminal exit settles, including one whose outcome is unknown, and a failed creation state settles on recovery. - A person may dismiss an unstarted (not_found, prepared) or indeterminate intent from Settings; dismissing stops nothing. Pending stays fenced. Resume and Dismiss need a gesture, like Update. - The Rust ledger gains agent-cli-intents-settle, which deletes rows. Recording drops rows older than seven days and keeps the newest 256 per actor instead of failing at a cap. Recovery, the ledger port and the owner route live in the CmuxNextAgentUpdates module; the app keeps only its daemon glue. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Replays #21439's change onto current feat-cmux-next as one commit. Turning Update Automatically on now needs a gesture or native confirmation too, since acpmux runs the update after its next check (review finding); SettingsHarnesses is compacted so CmuxNextApp's source lines don't grow (size cap). The health read defaults to the named AcpmuxEnvironment.harnessHealth rather than an async closure literal (crash ratchet). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Replays #21480's change onto current feat-cmux-next as one commit, on top of the rebuilt #21469. Settings, palette and recovered jobs follow their retained terminals. terminal-registry-changed events from the captured control connection only trigger a bounded read of the original receipt; they never dispatch work or imply completion. Completed batches stop observing. AgentCLIUpdateActions+Observation.swift lives in the CmuxNextAgentUpdates module beside the rest of the action, and the owner route captures the event stamp there. As in #21469, any exit, including one with an unknown outcome, settles its intent in the ledger. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ad73e4c to
23441cc
Compare
Replays #21487's change onto current feat-cmux-next as one commit, on top of the rebuilt #21480. A host reinstalled behind the same link socket is a replacement owner: the reach diff replaces its session when the paired installation changes, not only when the route does. A closed session is retired, so callbacks that still hold it cannot connect or wake it again. ServerMachineSession.close() is written on one line, like disconnect(), so CmuxNextApp gains no source lines. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts: # Packages/macOS/CmuxNext/Package.swift
Bugbot needs on-demand usage enabledBugbot uses usage-based billing for this team and requires on-demand usage to be enabled. A team admin can enable on-demand usage in the Cursor dashboard. |
|
|
||
| /** Creation and unknown outcomes cannot authorize a second update. */ | ||
| export function updateUnsettled(state: HarnessesState | null | undefined, id: string): boolean { | ||
| return (state?.jobs ?? []).some((job) => job.profiles.includes(id) && job.state !== "exited"); |
There was a problem hiding this comment.
Remote jobs block local updates
updateState includes jobs from every current machine, but updateUnsettled checks only the profile ID. Starting a remote Codex update from the palette therefore disables the local Codex Update button and removes it from Update All. Filter jobs by the Settings machine before using them to disable controls.
| ], | ||
| "packages": [] | ||
| }, | ||
| "CmuxNextFloating": { |
There was a problem hiding this comment.
Declared targets disappear from graph
The updated ci-target-graph.json removes six Files and Screenshots targets that Package.swift still declares. The generator includes every declared target, so ci-target-graph.py --check will reject this file and the generated-files job will fail. Regenerate the graph from the current package without dropping those targets.
# Conflicts: # Packages/macOS/CmuxNext/Package.swift
Bugbot needs on-demand usage enabledBugbot uses usage-based billing for this team and requires on-demand usage to be enabled. A team admin can enable on-demand usage in the Cursor dashboard. |
| job["state"] = "exited"; intent.jobs[index] = .object(job) | ||
| await settle(key, in: nil) |
There was a problem hiding this comment.
Closing allows overlapping installers
Closing an update terminal marks its job as exited and deletes its ledger row before the updater has stopped. Rust publishes the close before queuing host termination, and the host gives the process time to exit before killing it. A new Update click can therefore start another installer against the same installation while the first still runs.
Keep the family blocked until the host confirms termination.
| "id" : "palette.mobileConnect", | ||
| "main_menu" : "window", | ||
| "mcp" : "offered", | ||
| "main_menu" : null, |
There was a problem hiding this comment.
The changed export sets palette.mobileConnect.main_menu to null, but CloudActionCatalog still declares .window. ActionSurfaceExport copies that field directly, and exportIsFresh compares the complete generated file. The freshness check will fail.
Regenerate the action exports from the current source.
- Packages/macOS/CmuxNext/ci-target-graph.json Autofix-Run: https://github.com/manaflow-ai/cmux/actions/runs/39366869850
|
This PR keeps conflicting on the Your branch will conflict there one more time when you merge the base. To resolve it:
The cmux-next |
|
owner: 01a15bbf-a30f-7992-abba-3e3ca6f5adc1 |
Base 67eea14 now carries #21469 (agent update recovery) in its rebuilt form, so every conflict takes base's side and only this PR's automatic observation is re-applied on top: - observeRetained keeps base's owner(of:) rule (same machine and session after a reconnect) and calls the shared observe(_:route:). - owner(of:) restarts observation on the replacement route when it swaps in a re-capture (the PR did this in recovery before). - observe(_:route:) keeps base's unknown-outcome field and the closed-tab (terminalGone) settle path. - Generated files (ci-target-graph, action surfaces, catalogs) take base. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15bbf-a30f-7992-abba-3e3ca6f5adc1&host=cosmic-gray
Only the base autofix writes it; generated drift refused the hand edit. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15bbf-a30f-7992-abba-3e3ca6f5adc1&host=cosmic-gray
#21480 (this PR's stacked parent) was brought current with feat-cmux-next, which now carries the landed #21447 and #21469. Merging its head keeps the agent-update chain exactly as #21480 resolved it; this PR's own change stays the server install replacement on top. Conflicts: Package.swift, Localizable.xcstrings and the generated plans/cmux-next/action-surfaces.json and actions.md were base drift on both sides; took #21480's newer side. plans/cmux-next/coordination/server.md kept both sides' Active streams lines. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15bd3-b49c-7d53-bea7-64f63a046a36&host=cosmic-gray
No conflicts. With #21447 and #21469 landed and #21480 merged in, this PR's diff against base is #21480's live-outcome observation plus the server install replacement (ServerReachPlan.diff compares installID, a closed ServerMachineSession is retired, and their tests). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15bd3-b49c-7d53-bea7-64f63a046a36&host=cosmic-gray
|
|
|
Fleet Swift suites (CmuxNext, 4 shards) on 9fea696. The next head, 4f1ae63, only reverts ci-target-graph.json and has the same Swift. Result: 1090 passed, 25 failed.
PR CI reds on 4f1ae63 are base reds:
|
* acpmux: require version evidence for already-current updates Replays #21398's change onto current feat-cmux-next as one commit. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * agents: refresh inventory versions without probing or updating Replays #21401's change onto current feat-cmux-next as one commit. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * agents: connect explicit version refresh to the selected owner Replays #21402's change onto current feat-cmux-next as one commit. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Add owner update terminal jobs with durable replay Replays #21414's change onto current feat-cmux-next as one commit. Keeps the crash ratchet flat: poisoned locks are recovered instead of unwrapped (only a held job lock is busy), and the job status parses its decimal strings with radix: 10. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Preserve app mutation keys through shared action runs Replays #21429's change onto current feat-cmux-next as one commit, written without growing CmuxNextApp's source lines (size cap). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Preserve app callers through the shared action registry Replays #21436's change onto current feat-cmux-next as one commit. ControlRequest takes callerApp in its init so CmuxNextApp's source lines don't grow (size cap). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Share agent CLI update UI across Settings and actions Replays #21447's change onto current feat-cmux-next as one commit, together with its follow-up fix. Settings and the palette run agent updates on their captured owner route instead of typing a health argv into a focused pane. The update owner prepares only npm and native installations, and refuses a family when any of its rows is another channel or already current, so both surfaces submit only those families and Settings shows Update only for rows whose channel the owner runs. A start the owner refuses (agent_cli_job.*, answered before it journals a creation) leaves no "unknown" job that blocks that CLI. One family's failure does not stop the rest of a batch; the batch reports every failure. A lost reply still keeps its unknown job, since the terminal may exist. Update, Update all and turning Update Automatically on still need a gesture or a confirmed user, as #21439 requires. The update action, its owner route and the health-row reader live in a new CmuxNextAgentUpdates module, leaving thin app glue in CmuxNextApp. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Recover agent updates across app restarts Replays #21469's change onto current feat-cmux-next as one commit, on top of the owner-channel fix, with these changes so a retained intent always has a way out: - A start the owner refuses before journaling (agent_cli_job.*) settles its intent, in a batch and on Resume, instead of leaving a Resume that is refused again. - Any terminal exit settles, including one whose outcome is unknown, and a failed creation state settles on recovery. - A person may dismiss an unstarted (not_found, prepared) or indeterminate intent from Settings; dismissing stops nothing. Pending stays fenced. Resume and Dismiss need a gesture, like Update. - The Rust ledger gains agent-cli-intents-settle, which deletes rows. Recording drops rows older than seven days and keeps the newest 256 per actor instead of failing at a cap. Recovery, the ledger port and the owner route live in the CmuxNextAgentUpdates module; the app keeps only its daemon glue. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Require trusted page context for Settings agent updates Replays #21439's change onto current feat-cmux-next as one commit. Turning Update Automatically on now needs a gesture or native confirmation too, since acpmux runs the update after its next check (review finding); SettingsHarnesses is compacted so CmuxNextApp's source lines don't grow (size cap). The health read defaults to the named AcpmuxEnvironment.harnessHealth rather than an async closure literal (crash ratchet). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Show agent update outcomes automatically Replays #21480's change onto current feat-cmux-next as one commit, on top of the rebuilt #21469. Settings, palette and recovered jobs follow their retained terminals. terminal-registry-changed events from the captured control connection only trigger a bounded read of the original receipt; they never dispatch work or imply completion. Completed batches stop observing. AgentCLIUpdateActions+Observation.swift lives in the CmuxNextAgentUpdates module beside the rest of the action, and the owner route captures the event stamp there. As in #21469, any exit, including one with an unknown outcome, settles its intent in the ledger. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Retire obsolete sessions when a paired server is reinstalled Replays #21487's change onto current feat-cmux-next as one commit, on top of the rebuilt #21480. A host reinstalled behind the same link socket is a replacement owner: the reach diff replaces its session when the paired installation changes, not only when the route does. A closed session is retired, so callbacks that still hold it cannot connect or wake it again. ServerMachineSession.close() is written on one line, like disconnect(), so CmuxNextApp gains no source lines. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Let every retained agent update end Review follow-ups on #21469, so a retained intent always has a way out. - A closed update terminal settles its job. terminal.wait_exit answers terminal.closed, then selector.not_found for the tombstoned terminal; both mean the process ended. A missing session or connection still keeps it. - Ledger reads apply the seven-day age bound, not only recording, which a blocked family never reaches. - A row from a session no route can reach (a reinstalled server) no longer blocks the current session's update; it waits out the age bound. Rows of the same session, or of a session recovery reattached, still block. - A failed record clears the batch's jobs, since nothing started. - A creation still pending ten minutes after a recovery first saw it may be dismissed. - agent_cli_job.busy no longer settles: the owner may be running that key. - A test covers adding recorded_at to a ledger created without it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * chore(next): PR autofix at 0aae74c - regenerated plans/cmux-next/action-surfaces.json - regenerated schemas/defaults/cmux-next.json - vp fmt webviews/src/agent-session/acpmux/replyHref.ts - vp fmt webviews/src/pages/markdown/links.ts - vp fmt webviews/test/markdown-cmux-app-links.test.ts Autofix-Run: https://github.com/manaflow-ai/cmux/actions/runs/39208575467 * Keep other sessions' agent update rows blocking A row from a session recovery cannot reach blocks the CLI on that machine again. "No current route" cannot tell a dead session from a second live server on the same machine that may still be running the updater, so unblocking it could start two global installs at once. The ledger's seven-day read bound retires true orphans. Also notes at the closed-terminal settle that Rust answers terminal.closed before it queues the runtime signal, so the updater may still be dying in its close grace. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * chore(next): PR autofix at 953137a - vp fmt webviews/src/pages/markdown/README.md - cargo fmt in cmux-tui Autofix-Run: https://github.com/manaflow-ai/cmux/actions/runs/39217229319 * Bind the Settings update scope with withValueInTask TaskLocal.withValue frees its marker with the task allocator even when no task is current (cx-bpcj); the crash-class gate bans it. Use the shared withValueInTask helper, as ActionRunScope does. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * chore(next): PR autofix at 45adaef - regenerated plans/cmux-next/action-surfaces.json - regenerated web/data/cmux-shortcuts.generated.json - regenerated cmux-tui/crates/cmux-app-host/generated/cmux-app.d.ts - regenerated schemas/defaults/cmux-next.json Autofix-Run: https://github.com/manaflow-ai/cmux/actions/runs/39219479749 * chore(next): PR autofix at a51fde3 - regenerated plans/cmux-next/action-surfaces.json - regenerated web/data/cmux-shortcuts.generated.json - regenerated cmux-tui/crates/cmux-app-host/generated/cmux-app.d.ts - regenerated schemas/defaults/cmux-next.json Autofix-Run: https://github.com/manaflow-ai/cmux/actions/runs/39219476854 * chore(next): PR autofix at 226720e - regenerated plans/cmux-next/action-surfaces.json - regenerated web/data/cmux-shortcuts.generated.json - regenerated cmux-tui/crates/cmux-app-host/generated/cmux-app.d.ts - regenerated schemas/defaults/cmux-next.json Autofix-Run: https://github.com/manaflow-ai/cmux/actions/runs/39219477423 * chore(next): PR autofix at 1ee01b5 - regenerated plans/cmux-next/action-surfaces.json - regenerated web/data/cmux-shortcuts.generated.json - regenerated cmux-tui/crates/cmux-app-host/generated/cmux-app.d.ts - regenerated schemas/defaults/cmux-next.json Autofix-Run: https://github.com/manaflow-ai/cmux/actions/runs/39219477932 * Translate the agent update intent argument into every locale check-l10n flagged argument.agent.harness.intent as missing 12 of the 21 locales. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * cmux-tui: drop the std::sync qualification the base's clippy fix removed (unused_qualifications) * chore(next): PR autofix at 52aaa2c - Packages/macOS/CmuxNext/ci-target-graph.json - plans/cmux-next/action-surfaces.json - plans/cmux-next/actions.md Autofix-Run: https://github.com/manaflow-ai/cmux/actions/runs/39360940433 * chore(next): PR autofix at cac5e24 - Packages/macOS/CmuxNext/ci-target-graph.json - plans/cmux-next/action-surfaces.json - plans/cmux-next/actions.md Autofix-Run: https://github.com/manaflow-ai/cmux/actions/runs/39361101859 * chore(next): PR autofix at a746f81 - Packages/macOS/CmuxNext/ci-target-graph.json Autofix-Run: https://github.com/manaflow-ai/cmux/actions/runs/39364024850 * chore(next): PR autofix at d86b10d - Packages/macOS/CmuxNext/ci-target-graph.json Autofix-Run: https://github.com/manaflow-ai/cmux/actions/runs/39366869850 * chore(next): PR autofix at 6714366 - Packages/macOS/CmuxNext/ci-target-graph.json Autofix-Run: https://github.com/manaflow-ai/cmux/actions/runs/39366896424 * Leave ci-target-graph.json to the base autofix Only the base autofix writes it; generated drift refused the hand edit. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15bbf-a30f-7992-abba-3e3ca6f5adc1&host=cosmic-gray --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: cmux-autofix[bot] <cmux-autofix[bot]@users.noreply.github.com>
…e passed (#22947) * test(ci): a hand merge of a Swift PR must wait for its Release compile #22835, #21480 and #21487 were merged with gh pr merge while their Release compile was still pending (2026-10-21). Red: no guard exists. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15bf1-fdac-78a0-ac2e-a3aef81402c7&host=cosmic-gray * ci(next): refuse a hand merge of a Swift PR before its Release compile passed A Claude Code PreToolUse hook refuses gh pr merge (with or without --auto) and gh api .../pulls/N/merge for a feat-cmux-next PR that changes Swift, headers, module maps, Xcode projects or package manifests while its head's cmux-next Release compile (Xcode 26) is queued, running, not yet created while cmux-next routes, or finished red or cancelled. A compile the router skipped does not apply. next-autoland waits for the same compile (leo-workspace #662). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15bf1-fdac-78a0-ac2e-a3aef81402c7&host=cosmic-gray --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
|
Shipped in:
|
|
Shipped in:
|
…new connection (#23219) Pins owner(of:)'s reconnect path from #21480: after the connection epoch advances, the next state read re-captures the same owner and restarts the follow task on the new connection, whose events deliver the outcome with no refresh; repeated state reads with no reconnect never subscribe again. Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15bbf-a30f-7992-abba-3e3ca6f5adc1&host=cosmic-gray Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Agent update outcomes now show up in Settings and the palette on their own, including for restored jobs. You no longer have to press Refresh. The app listens for terminal changes on the original owner's control connection and then reads that owner's retained receipts. A reconnect, a withdrawn policy or a detached owner stops the listening. A signal can never start an update or count as success; only a bounded read of the original receipt sets an outcome.
#21469 (recovery across restarts) has merged, so this PR is now just the observation layer on top of feat-cmux-next:
AgentCLIUpdateActions+Observation.swift:follow(_:),observe(_:route:)andterminalChanges(...). The terminal-change stream comes from the captured source/serial only.Route.changesis captured inRoute.capture. Explicit refresh and the follow task both use the sameobserve(_:route:). That function keeps base's unknown-outcome field and its closed-tab (terminalGone) settle path.owner(of:)swaps in a re-captured route after a reconnect, it restarts observation on the new route.rememberrestarts it when a batch gains a receipt.terminal-registry-changedoutlives snapshots, collapses to the newest event per source/serial in the event inbox, and is delivered through side events.Merge note (adopted 2026-10-20): base rebuilt #21469 after this branch forked from it. Every conflict takes base's side, and only the observation commit (23441cc) and its later fixes are re-applied on top.
Changelog
Fixed: Agent update outcomes appear without pressing Refresh.
Observed / Not run
scripts/cmux-next/prepush-gate.py(no new violations) andscripts/web-lint.sh. Fleet Swift suites (CmuxNext, 4 shards) on the head: see the comment below.Agent session: cosmic-gray
🤖 Generated with Claude Code