next: cmux://agent links open the agent session, input focused

Merged
TE
16d ago
+1072-126

Summary

Agent commits, PRs and leases now carry a link back to the session that made them (manaflow-ai/cmuxterm-hq#2555, tool in cmuxterm-hq#2556). This PR lets cmux NEXT open that link. cmux://agent/<harness>/<session>?host=<machine>&name=<callsign> is one more DeepLink target. It goes through the same link.open path as every other link: the OS URL handler, the palette, cmux link open and MCP.

  • Opening it reveals the tab this app already shows that session in. That's either the agent chat tab that adopted harness:session, or a terminal whose agent hooks reported that session id. The terminals come from the machines this app is connected to.
  • It never creates a tab, resumes or launches a harness, connects to a host, or types anything. So the link is an address, not a credential: you reach a session only if your app could already reach it. host and name are display hints only, kept when they're 1โ€“64 char tokens, and they play no part in resolution.
  • When the user opens it, the tab is revealed with .raise, so the revealed session's input has the keyboard: the agent chat page's composer claims focus when its window takes focus (composerFocus.ts), and a terminal's surface takes it on selection. Talking to the agent is then one keystroke away. A background open (Cmd held, or automation) uses .bringForward, the same intent every other link target uses.
  • Debug Settings โ†’ "Agent links" (links.agentLinks, in AgentPaneTunables), on by default. Off refuses these links with a localized message.
  • plans/cmux-next/links.json, the Markdown page's link matcher and agent chat replies (replyHref.ts) all know the new host. Dots-only sessions and hints are refused, matching the web fallback (#22088).
  • CmuxNextApp doesn't grow (check-app-size). The candidate walk lives in CmuxNextDaemon (WorkspaceModel.agentHarnessSessions), and three unused App lines were removed (a logger, runningCount, an import os).

Unknown sessions get the existing "gone" refusal. A card for sessions on machines this app isn't connected to comes later.

Testing

  • Tests/CmuxNextActionsTests/DeepLinkAgentTests.swift: parse/format round trip; rejection of 1 or 3 segments, bad tokens, fragments and other schemes; malformed hints dropped; existing link kinds unchanged; tab matching (adopted chat first, harness mismatch skipped, unknown harness matched on session); and the daemon's harnessSessions tuples. The red commits 385d9134 and 7ed47659 come before the implementation.
  • LinkExportTests covers the new kind in links.json.
  • Tests/CmuxNextAppTests/TypeAheadQueueTests.swift (red commit a12fbf6f first): an earlier size trim dropped TypeAheadQueue.Wire.startedNs, so queued keys never expired. It's restored, and the test checks that text older than 2 s is dropped.
  • Review fixes at 76e48e08 (red commits da30996c and 6f383dcc first): an exited terminal and a disconnected machine's terminals are no candidates (WorkspaceAgentSessionsTests, DaemonStore.reachableAgentHarnessSessions), and a chat tab that switched away from the outside chat it adopted no longer answers for it (AgentTabHarnessOnCreateTests.switchingChatsReleasesTheAdoption). Swift tests for red and green: dispatched cmux-next.yml on next-batch/leo-agent-provenance-red (run 39358338412) and next-batch/leo-agent-provenance (run 39358342365); results added below when they finish.
    • Nothing was compiled locally (no heavy Swift builds on this Mac), so CI's CmuxNext lanes are the first compile and run. Focus relies on the existing revealTab(.raise) path and isn't dogfooded yet.

Proof

Not UI: link routing and parsing only; no layout or visual change. The one visible effect is that cmux://agent/... links in Markdown and agent replies draw as links, like the existing cmux://session/... links.

Review: PASS at 2de43467 (correctness-first reviewer subagent, read-only). It confirmed the startedNs restore matches cmux-focus-core and that the new test fails without it; no AgentFocus references remain; the overload labels are unambiguous; the size check passes (83246 = base). Its note about real machine names in examples is fixed in 0825459b (test strings and the links.json example only).

Changelog

Added: cmux://agent links open the agent session they name, with its input focused, when this Mac can already reach it

๐Ÿค– Generated with Claude Code