cmux-next: optional Agent integrations helper in Settings

Merged
TE
16d ago
+3940-31

Stacked on manaflow-ai/cmux#21813 (hook status reports conflicts); review that first. This PR's diff against feat-cmux-next includes it until it lands.

Settings > Agents gets an optional Agent integrations card for the coding-agent hooks that let cmux show when an agent is working, waiting or done. It lists each provider's hook state and offers Install, Repair or Remove, with the CLI command to copy as a fallback.

It stays out of the way: the card is collapsed, reads nothing until opened, and changes nothing without a click. A deep link (focus=agents.integrations) opens it.

What it does

  • Status comes from the bundled CLI, cmux --json agent hook status. It's read once when the card opens and again on Refresh.
  • Install (state absent) and Repair (partial) run cmux --json agent hook install <id>. Remove (installed or partial) runs agent hook uninstall <id>. Status is read again after each one. A refusal from the CLI shows on that row in the CLI's own words.
  • Blocked (conflict, added in #21813) means a file cmux didn't create, a symlink, or a non-file is in the way. The row offers no Install. It says what's there, shows the path, and gives cmux agent hook install <id> to copy once the file is moved. Can't read (unavailable) says to check permissions. The host refuses Install over either state too, not just the page.
  • No CLI in the build: the card says so and still shows the command.

The install logic lives only in the Rust CLI (cmux-tui-hooks). Swift (SettingsAgentIntegrations) runs the CLI with ProcessRunner, parses the result, and keeps the row list. It accepts only provider ids the last status listed.

One limit: the app runs the CLI with the app's own environment. A CLAUDE_CONFIG_DIR or CODEX_HOME set only in a shell profile isn't seen, so the card targets the default paths. Each row shows its path so this is visible, and the copyable command is the fallback.

Files

  • New target CmuxNextAgentIntegrations: SettingsAgentIntegrations.swift (+ +Process.swift, split out because CmuxNextDaemon and CmuxNextSettings both export a JSONValue). It is a PageProvider; the App passes it the bundled CLI's location. It lives outside CmuxNextApp because the App target may not grow (check-app-size.sh).
  • SettingsPageProvider routes cmux.settings.integrations.state|run to it, and PageFactory wires it. The provider's nil-host guards now share one helper, so CmuxNextApp ends with fewer source lines than the base.
  • SettingsPageLayout.Card.agentIntegrations sits in the Agents trail. The exported settings-schema.json and its source stamp were updated to match (defaults_guard.py check-stamp passes).
  • React: components/AgentIntegrations.tsx, plus ops, store, mock and gallery variants (agents-integrations, agents-integrations-no-cli).
  • 22 settingsWindow.agentIntegrations.* strings, translated into all 21 catalog locales.

Verification

  • Red first (343228a4577): bun test src/pages/settings/agentIntegrations.test.tsx at the test-only commit gave 0 pass, 4 fail.
  • After merging feat-cmux-next (c5a1f900ec0c, merge c9ed6ee1d5e) and trimming two lines of filler copy (2813f171d96): bun test src/pages/settings src/gallery gave 132 pass at c9ed6ee1d5e, and the card, description-length and strings tests passed again at 2813f171d96.
  • Green (4101d5ae05b): bun test src/pages/settings src/gallery gave 131 pass, including the 60-character description-line check in every locale. bun run typecheck, bun run lint, vp fmt --check and scripts/lint-ios-package-conventions.sh are clean. scripts/localization_catalog.py check reports no errors for the new keys.
  • Swift, on fleet minis via cmux-ci run: red on 343228a4577 (cannot find 'SettingsAgentIntegrations' in scope). Green on a6e702fb47d: package-test-lane.sh suite Packages/macOS/CmuxNext SettingsAgentIntegrationsTests gave 5 tests in 1 suite passed. Two test-only fixups landed in between: an import CmuxNextPages, and moving the fake CLI off the main actor.
  • Not verified: a native tagged build. cmux-ci build cmux can't provision the dev backend from huge-blue (no route to cmux-dev-backend-1), so no tagged app was built or dogfooded. The screenshots below are the React Settings page from the webviews gallery build (agents-integrations* variants against the mock host), rendered in headless Chromium. They are not the native app. The full CmuxNext package build and suites run in this PR's CI.

Screenshots

Collapsed (the default):

agent integrations collapsed

Opened, light and dark: installed, needs repair, blocked by a file cmux didn't create, and not installed:

agent integrations open light

agent integrations open dark

A build without the CLI:

agent integrations no cli

Localization audit

There are 22 new keys in CmuxNextSettingsWindow/Localizable.xcstrings, translated into all 21 locales the catalog carries (the 9 required macOS locales among them), and regenerated into generated/strings.json. Every line is 60 characters or fewer in every locale. There's no bare English in the changed TSX or Swift. The CLI's English detail and refusal text is shown as-is, as other Settings cards do with daemon text.

Changelog

  • Added: An optional Agent integrations card in Settings > Agents that installs, repairs or removes coding-agent hooks and explains when a file cmux didn't create is in the way.

No capture: the card is part of the webview Settings page. The gallery advisory run captures it (agents-integrations, agents-integrations-no-cli). The Swift side is a page provider with no native UI of its own.

🤖 Generated with Claude Code

Agent session: cosmic-gray