agent pane: Pause and Resume a Cloud chat's machine from the chat menu

TE
7d ago
+544-10

A chat on one of the account's Cloud machines now has Pause Machine and Resume Machine in its chat menu, wired to the machine's own pause and resume.

Leo, 2026-10-28: "whatever's convenient for cloud, like that can be productionized, operationalized, we ought to just put out there". The Cloud state-of-affairs issue (cmuxterm-hq#4755), quoting Leo: "we want to get a lot of good stuff wrt the pausing and resuming and how it integrates with acpmux + the gui chat". Its gap list says "A manual or billing pause can cut a live turn without warning." This PR is the chat-menu half of the pause/resume work. The banner half, a paused machine's chat reading "paused" with Resume instead of "offline", is the companion PR.

What changed

  • Webview (webviews/src/agent-session/acpmux/cloudMachineMenu.ts, wired in App.tsx's chat menu):
    • A Cloud chat whose peer is one of the account's machines (matched by name, any case, as the app matches a peer to a Cloud machine) gets one row before the tools group:
      • Pause Machine while the machine is ready;
      • Stop and Pause Machine while the chat's turn runs, which sends chat.cancel first;
      • Resume Machine while the machine is paused;
      • nothing while it starts or has failed.
    • Stopping the turn first means the turn ends as stopped, on the chat and on its hand-off (cmux#26864 reports it), instead of freezing mid-call while the machine sleeps.
    • A stop request returns before the turn stops. So Stop and Pause waits for the chat's turn to end, for at most 10 s (STOP_WAIT_MS), and pauses nothing if the turn still runs then or the stop was refused.
    • The app runs pause and resume in the background. After each pick, the account's list is read at 0, 1, 2, 4 and 8 s (ACTION_READS_MS), after any read already in flight, and the reads stop once the machine's stage moves. The list is also read when a Cloud chat shows.
  • Timers:
    • The stop wait's timeout is cleared when the turn ends, and otherwise ends by itself after 10 s.
    • The post-pick reads end at the stage change or after the fifth read (15 s).
    • Nothing else repeats.
  • Swift (CmuxNextAgentPane/AgentPaneCloudMachineRequest.swift, CmuxNextApp/Cloud/AgentPaneCloudMachines+App.swift):
    • The pane bridge gains cloudMachine.pause {id}. Like Open and Resume, it takes one user gesture.
    • The app runs it as its own cloudPauseMachine action, only on a machine of the loaded list whose status is running.
  • Gating: behind Labs > Preview features (labs.previewFeatures, off by default), the same gate as the account's Cloud machines in the composer's machine list. So it is off for everyone until Preview is on.
  • UI rules: the rows are ordinary chat-menu rows. The menu opens on the click with no fade-in, and the menu's own trigger keeps its lit state while open (ChatHeaderTools, unchanged). There is no new working indicator.

Visual evidence

Gallery: agent-pane.header-tools/menu-open, agent-pane.header-tools/menu-cloud-machine-running, agent-pane.header-tools/menu-cloud-machine-working, agent-pane.header-tools/menu-cloud-machine-paused

No capture: the Swift side adds only a bridge request and an app action, no native view; the visible change is the webview chat menu row, shown in the gallery before/after.

Risk: low.

  • The feature is off by default (Preview).
  • A new bridge method is refused unless the person clicked and the machine is in the loaded list and running.
  • The chat menu gains at most one row.

Tests

  • Webview: test/agent-pane-cloud-machine-menu.test.ts covers:
    • name matching;
    • Pause, and Stop and Pause, including that the stop comes first and that a turn which hasn't stopped isn't paused;
    • the stop wait ends when the turn ends, or after its timeout;
    • the post-pick reads stop when the stage moves, and after the last wait;
    • Resume never stops a turn;
    • no row while starting, failed or not the account's;
    • a refused pick still reads the list again.
  • Gallery: agent-pane.header-tools gains menu-cloud-machine-running, -working and -paused.
  • Swift: AgentPaneCloudMachineRequestTests decodes cloudMachine.pause, refuses ids outside the contract, and checks that Pause takes one gesture.

Agent session: agent session

🤖 Generated with Claude Code