fix(gateway): auto-lowercase agent name in Register Agent dialog - #1
Closed
abeldantas wants to merge 21 commits into
Closed
fix(gateway): auto-lowercase agent name in Register Agent dialog#1abeldantas wants to merge 21 commits into
abeldantas wants to merge 21 commits into
Conversation
…ADME (sandbox-quantum#303) * Show Switch working in a chat app, with room for one recording per app * Add the Slack recording * Replace the overview diagram * Add the Mattermost recording * Use the cropped overview diagram
) * Update CLAUDE.md module layout and doc references to match the tree The module layout listed directories that do not exist and missed some that do, and the reference section said the synced docs/official documentation does not exist. * Remove tasks from the standalone feature lists CHOO-1418 removed the task protocol from the skills, but the codex README and the configure skills still list it as working, which can confuse agents. * Rename the generated docs index to TOC.md to fix a case collision The repo tracked both INDEX.md and index.md. On macOS and Windows these are the same path, so one of them wins, the docs/README.md link opens the wrong file, and git status is never clean. The sync script now writes TOC.md. * Fix stale references in the codex docs, CONTRIBUTING and console/AGENTS.md Small stale bits: a comparison with a Claude connector mechanism that no longer exists, mcp_servers where the file says mcpServers, an outdated docs row and a dead anchor in CONTRIBUTING, and connector paths in console/AGENTS.md that resolve from the wrong directory. * Add Mattermost to the architecture section's platform lists The architecture section names four platforms but the README supports five. Added Mattermost to the transport list and the image alt text. The diagram PNG still shows four icons. * Add release and CI badges to the readme
…4) (sandbox-quantum#304) Dismissing the "Setting up Switch" checklist wrote the setting straight over IPC instead of going through the settings mutation. The panel renders from the cached `onboarding` setting and nothing broadcasts a settings change back to the renderer, so the write persisted but the cache kept saying `showChecklist: true` — the ✕ looked dead until the next launch. Route the dismissal through the same mutation the Settings toggle uses, so the cache is updated optimistically and invalidated. This also drops the `if (!onboarding) return` guard, which silently did nothing when the setting had not loaded; the mutation merges from the cache itself. The existing tests mount the presentational panel with a stub `onDismiss`, so they never touched the wiring. Add a test that mounts the hook and asserts the cached setting flips, which fails against the old call.
…10 (sandbox-quantum#305) switch-console 0.31.0 → 0.31.1 (patch): - fix(console): the setup checklist's ✕ now actually dismisses it (sandbox-quantum#304) Connector plugins patched so the sandbox-quantum#302 configure-skill correction re-downloads: switch-connector 0.9.8 → 0.9.9, switch-connector-codex 0.3.9 → 0.3.10. The standalone feature list no longer claims the task protocol works (removed in CHOO-1418); codex skill also fixes an mcp_servers → mcpServers reference. opencode untouched (0.1.5). No switch-core release: the doc-sync PR (sandbox-quantum#295) only touched a Teams README and a test under core/, no shipping code — bundle pin stays at 0.21.0. agent-runtime (0.3.2) and sidecar (1.9.4) unchanged. Contracts stay 1/1. artifacts.yaml + generated modules regenerated; artifacts-check passes. Authored all changelog entries (every [Unreleased] was empty). Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…er (sandbox-quantum#307) * fix(agent-runtime): exit when the host does, instead of running forever The runtime intended to shut down with its host — `transport.onclose` stopped the stream, the heartbeat and the lease renewal, then exited. It never fired. The MCP SDK's stdio transport binds only 'data' and 'error' on stdin, so `onclose` is reached only by an orderly `close()`, never by a host that was killed, crashed or force-quit. That exit path was dead code in exactly the case it existed for. Nothing else stopped the process either: the hook listener's TCP server held the event loop open, the 2s heartbeat and lease timers kept running against a Switch that was gone, and `uncaughtException` swallowed the resulting EPIPE once `serving` was true rather than letting it escalate. Measured on one developer machine: 486 processes, 3.5 GB resident, ~198% CPU, 242 stale loopback listeners, across five runtime versions, the oldest 18 days. The two longest-lived had grown to 470 MB and 367 MB — consistent with writes queueing against a stderr pipe whose reader is gone but which was never closed. Four independent triggers now, because each covers a case the others miss: stdin 'end'/'close' for a dropped pipe, the termination signals for an orderly kill, a stdout/stderr 'error' for a peer that is gone but not closed, and a ppid watchdog as the backstop — reparenting is the one signal that survives every way a host can vanish, and SESSION_PPID was already recorded for the session directory. Any one of them would have prevented all 486. The hook listener is also unref'd, so the stdin reader is what holds the loop open: alive now means a host is attached rather than a port is bound. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * feat(agent-runtime): clear up runtimes that already outlived their host The shutdown fix stops new orphans. It does nothing about the ones already running: every published version up to 0.3.2 lacks it, and those processes sit there until the machine reboots — 486 of them, 3.5 GB, on the machine that prompted this. A new runtime now clears them out on its way up, which reaches a user through the connector pin without waiting for an app release. The signal is the process tree, not anything on disk. When the host dies its `npm exec` wrapper is reparented to init while the runtime carries on pointing at a wrapper that is alive but orphaned — so "is the parent dead?" is the wrong question, and would have missed both of the worst offenders (15765 was very much alive; only its parent was gone). Reaching init without passing through a live host is the right one, and it needs no port file, no session directory and no hook. The match is anchored on argv[0] rather than a substring of the command line. A substring test also matches any shell that merely mentions the package — installing it, grepping for it — and an orphaned one of those would have been killed. An early draft did exactly that; the cases are pinned in the tests. The reaper excludes its own chain outright rather than relying on the walk to spare it. The walk does spare it, since a freshly spawned runtime has a live host by construction, but a reaper that can reach itself is one bad predicate away from killing the session it serves. Stale session directories go too — pure litter from runtimes that were killed outright and never ran `unpublishPort`, 8071 of them here. Verified end to end against a real orphan built the way the bug builds one (host killed with its stdin held open by a third party, so the runtime never sees EOF): a fresh runtime reported `reaping 2 runtime process(es) whose host is gone` and `removing 8016 stale session director(ies)`, and left itself running. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
agent-runtime 0.3.2 → 0.3.3 (patch): - fix(sandbox-quantum#307): the runtime exits when its host does instead of running forever. Its onclose-based shutdown never fired for a killed/crashed/force-quit host, and the hook listener + heartbeat/lease timers kept the process alive, leaving stale processes and loopback listeners accumulating. Shutdown is now driven by four independent triggers (stdin end/close, termination signals, stdout/stderr write error, parent-pid watchdog). Phase 1 of a two-phase runtime release: this publishes 0.3.3 to npm via the switch-agent-runtime-v0.3.3 tag. The connector runtime pins (claude/codex .mcp.json, opencode opencode.json, SWITCH_AGENT_RUNTIME_PIN), the plugin versions, and the sidecar are DELIBERATELY left at their current versions — a pin must never name a version npm does not have yet. Phase 2 (re-pin + plugin/sidecar bumps) follows once 0.3.3 is live, on request. artifacts.yaml + generated modules regenerated; artifacts-check passes. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…-quantum#310) Phase 2 of the agent-runtime 0.3.3 release (0.3.3 is live on npm). Moves every runtime pin from 0.3.2 → 0.3.3 and bumps each consumer so the host-exit fix (sandbox-quantum#307) reaches users: - Runtime pin → 0.3.3 in all four places: claude & codex .mcp.json, opencode opencode.json, and SWITCH_AGENT_RUNTIME_PIN in console distribution.ts (the embedded opencode config derives from that constant, so it follows). - Plugin versions bumped so installs re-download: switch-connector 0.9.9 → 0.9.10, switch-connector-codex 0.3.10 → 0.3.11, switch-connector-opencode 0.1.5 → 0.1.6. - sidecar 1.9.4 → 1.9.5 (runs the new runtime; major stays 1, wire unchanged). claude/codex reach users on next marketplace Update; opencode + sidecar ride the next Switch Console release. artifacts.yaml + generated modules regenerated; artifacts-check passes; pins agree with each other (runtime-pin/connector-assets tests green). Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
) * feat(console): reap orphaned agent runtimes at boot The runtime learned to exit when its host dies, and to clear up predecessors on startup. Both reach a machine only through the connector pin, which moves when a user updates a marketplace plugin — so a user who never revisits Settings → Agents keeps their backlog indefinitely. This path reaches them when they update the app instead. The two populations do not overlap as much as they look: someone who updates the app but not the connector is reached only from here, and someone running Codex standalone with no Switch Console is reached only by the runtime. Neither alone covers the fleet. The predicate is imported from the runtime package, not reimplemented. Two copies of "is this runtime abandoned?" is a failure mode this repo already knows — where they disagree, one of them kills a live session — so `reapOrphanedRuntimes` moved to the package's public surface and both callers share it. It now returns what it did rather than taking a log callback. There were two callers with two ideas of a log line: the runtime writes prose to stderr, the app wants an enumerated event, and threading either through the sweep was the wrong shape. Runs unawaited after the RPC router is up and before session relaunch, so an abandoned runtime is gone before its replacement starts, without the window waiting on a full process scan. Verified against real orphans rather than mocks, twice: reaped: 4, removedSessionDirs: 3 — four genuine orphans, all gone reaped: 0 — with a healthy session running, its runtime, its wrapper and its session directory all untouched The second matters more than the first. Killing a live session would be far worse than leaving an orphan, and it is the case no unit test can fully stand in for. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * feat(console): bring installed Switch connectors up to date once A connector's pinned runtime version only moves when a user goes looking for it in Settings → Agents. Someone who never does keeps whatever they first installed, across every release — which is how an install ends up several runtime versions behind without anything being broken enough to notice. This is a one-shot catch-up, deliberately not a standing auto-updater. It latches a generation marker on success and does nothing on every later launch; the Update button stays the normal path. Bumping CATCH_UP_GENERATION — a deliberate edit, not a release — is what makes it run again. What it will not do: - install a connector that is not installed. Which agents have one is the user's decision, and this is a version catch-up, not an installer. - latch when the marketplace could not be refreshed. `updateAvailable` is false both for "no update" and "could not look", and spending the single shot on an answer that never arrived is the one way a one-shot fails silently. - retry forever. Three attempts, then it stops, because "runs every launch" is precisely what this is not. Runs unawaited before session relaunch, so a session started on the old pin picks the new one up next launch rather than holding up this one. Verified locally against a real gap. First launch: connector_catch_up_updated claude 0.9.8 -> 0.9.10 connector_catch_up_updated opencode 0.1.5 -> 0.1.6 connector_catch_up_complete updated: 2 Second launch on the same install: no catch-up activity, no marketplace call, nothing logged — latched. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
switch-console 0.31.1 → 0.31.2 (patch, per request — contains sandbox-quantum#309): - reap orphaned agent runtimes at boot (sandbox-quantum#309) - one-shot catch-up to bring already-installed connectors up to date once (sandbox-quantum#309) Also ships the console-side Phase 2 rollout already on main: the bundled sidecar (1.9.5) and OpenCode connector (0.1.6) now run agent-runtime 0.3.3. Bundle pin stays at core 0.21.0 (no core release). Runtime version drift from sandbox-quantum#309 (runtime source changed but package.json still 0.3.3, matching npm) is deliberately left for the next runtime release — no user-facing runtime behaviour changed. artifacts.yaml + generated modules regenerated; artifacts-check passes. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…CHOO-2455) The New agent dialog greys out "Add agent" whenever the form is not ready but doesn't tell people why. This fixes that.
The previous commit keyed the tooltip on !runHostReady, which is true both while the readiness probe is still in flight and when the host is known to be missing setup. A blocked host got "Waiting for ... to be ready", telling the user to wait for something that never resolves. Branch on hostReadiness.checking and hostReadiness.blocked instead, and point the blocked case at the HostReadinessNotice that names what is missing. Also runs the file through oxfmt, which the previous commit skipped and which is what failed CI.
…disabled-reason Tell the user why "Add agent" is disabled, on hover over the button (CHOO-2455)
…ion-bump-rule Stop hand-bumping versions per commit; leave it to the release agent
The name input now lowercases as the user types, so "MyAgent" becomes "myagent" without a server-side validation error. Genuinely invalid characters are still caught by the backend.
There was a problem hiding this comment.
🔵 Needs a closer look
The PR bundles multiple unrelated functional areas (gateway UI, runtime process management, release/versioning, docs) under a narrow title/description, increasing review and regression risk.
Pull request overview
This PR combines a small gateway UX change (auto-lowercasing agent names during registration) with a broader set of console/runtime lifecycle fixes, connector pin/version updates, documentation sync output changes, and release metadata updates across the repo.
Changes:
- Gateway: normalize Register Agent “Name” input to lowercase as the user types.
- Console/runtime: add orphaned-runtime reaping + shutdown triggers so
switch-agent-runtimedoesn’t outlive its host; add connector catch-up at boot; bump related artifact versions/pins. - Docs/meta: rename docs index output to
TOC.md, update README/docs pointers and various release/version tracking files.
File summaries
| File | Description |
|---|---|
| signatures/version1/cla.json | Adds additional CLA signature entries. |
| scripts/sync_docs.py | Writes docs table-of-contents to docs/official/TOC.md during sync. |
| README.md | Updates top-level marketing copy, badges, images, and embeds demo recordings. |
| gateway/src/pages/agents/RegisterAgentDialog.tsx | Lowercases agent name input on change. |
| docs/README.md | Updates docs pointer from INDEX.md to TOC.md. |
| docs/official/TOC.md | Adds generated documentation table-of-contents file. |
| core/tests/switch_core/bridges/collaboration/test_slack_adapter.py | Adds test ensuring typed !command mentions are normalized. |
| core/switch_core/bridges/collaboration/slack/adapter.py | Normalizes typed-command args via translate_inbound. |
| core/switch_core/artifacts.py | Bumps tracked artifact versions (console/runtime/sidecar/connectors). |
| CONTRIBUTING.md | Updates README anchor and clarifies docs/ directory meaning. |
| console/packages/switch-agent-runtime/src/reap.ts | Adds orphaned runtime/session-dir reaper implementation. |
| console/packages/switch-agent-runtime/src/reap.test.ts | Unit tests for runtime reaper predicates and directory sweeping. |
| console/packages/switch-agent-runtime/src/index.ts | Exports reaper utilities from the runtime package. |
| console/packages/switch-agent-runtime/src/bin.ts | Adds robust shutdown triggers and runs reaper after MCP handshake; unrefs hook listener server. |
| console/packages/switch-agent-runtime/src/bin.shutdown.test.ts | Tests/shims asserting shutdown triggers remain present and effective. |
| console/packages/switch-agent-runtime/src/artifacts.ts | Updates runtime-side artifact version constants. |
| console/packages/switch-agent-runtime/package.json | Bumps runtime package version to 0.3.3. |
| console/packages/shared/src/artifacts.ts | Updates shared artifact version constants. |
| console/packages/plugins/src/distribution.ts | Updates runtime pin used for marketplace/plugin distribution. |
| console/apps/switch-console-desktop/src/renderer/tests/browser/onboarding-checklist-dismiss.test.tsx | Adds renderer test ensuring checklist dismissal updates cached settings and persists. |
| console/apps/switch-console-desktop/src/renderer/features/onboarding/use-onboarding-checklist.ts | Routes dismissal through settings mutation (react-query) instead of direct IPC call. |
| console/apps/switch-console-desktop/src/renderer/features/locations/components/add-agent-modal/add-agent-modal.tsx | Adds tooltip explaining why “Add agent” is disabled. |
| console/apps/switch-console-desktop/src/main/index.ts | Runs orphaned-runtime reap and connector catch-up at boot (best-effort, unawaited). |
| console/apps/switch-console-desktop/src/main/core/switch-setup/catch-up-connectors.ts | Implements one-shot connector catch-up with generation+attempt latching. |
| console/apps/switch-console-desktop/src/main/core/switch-setup/catch-up-connectors.test.ts | Tests catch-up behavior, latching, and retry limits. |
| console/apps/switch-console-desktop/src/main/core/agent-runtime/reap-orphaned-runtimes.ts | Main-process wrapper calling runtime reaper and logging outcomes. |
| console/apps/switch-console-desktop/src/main/core/agent-runtime/reap-orphaned-runtimes.test.ts | Tests main-process reap wrapper behavior and logging. |
| console/apps/switch-console-desktop/package.json | Bumps desktop app version to 0.31.2. |
| console/AGENTS.md | Fixes connector file paths to be relative to console/. |
| connectors/opencode-plugin/package.json | Bumps OpenCode connector version to 0.1.6. |
| connectors/opencode-plugin/opencode.json | Updates runtime pin to @sandboxaq/switch-agent-runtime@0.3.3. |
| connectors/codex-plugin/skills/configure/SKILL.md | Fixes mcpServers naming and adjusts stated feature support text. |
| connectors/codex-plugin/README.md | Updates wording around env var forwarding and feature list. |
| connectors/codex-plugin/.mcp.json | Updates runtime pin to 0.3.3. |
| connectors/codex-plugin/.codex-plugin/plugin.json | Bumps Codex connector version to 0.3.11. |
| connectors/claude-code-plugin/skills/configure/SKILL.md | Adjusts stated feature support text. |
| connectors/claude-code-plugin/.mcp.json | Updates runtime pin to 0.3.3. |
| connectors/claude-code-plugin/.claude-plugin/plugin.json | Bumps Claude Code connector version to 0.9.10. |
| CLAUDE.md | Updates repo guidance text and documentation section. |
| CHANGELOG.md | Adds entries for 0.31.2, runtime 0.3.3, sidecar 1.9.5, connector bumps, etc. |
| artifacts.yaml | Updates declared artifact versions to match bumped packages/connectors. |
Review details
- Files reviewed: 40/43 changed files
- Comments generated: 2
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Comment on lines
339
to
343
| <TextField | ||
| label="Name" | ||
| value={name} | ||
| onChange={(e) => setName(e.target.value)} | ||
| onChange={(e) => setName(e.target.value.toLowerCase())} | ||
| fullWidth |
Comment on lines
260
to
+262
| rel = page[len(SOURCE_PREFIX) :] or "index" | ||
| lines.append(f"- [{rel}]({rel}.md) — <{published_url(page)}>") | ||
| (dest / "INDEX.md").write_text("\n".join(lines).rstrip() + "\n", encoding="utf-8") | ||
| (dest / "TOC.md").write_text("\n".join(lines).rstrip() + "\n", encoding="utf-8") |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Test plan
!,#) — server still rejects them