squadrant 0.10.0 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../packages/shared/src/config.ts","../packages/shared/src/effort.ts","../packages/shared/dist/types/runtime.js","../packages/shared/src/types/control.ts","../packages/shared/dist/types/projection.js","../packages/shared/dist/types/workspaces.js","../packages/shared/src/lib/cmux-config.ts","../packages/shared/src/lib/cmux-bin.ts","../packages/shared/src/lib/cmux-probe.ts","../packages/shared/src/lib/cmux-autoconfig.ts","../packages/shared/src/lib/compat-manifest.ts","../packages/shared/src/lib/config-drift.ts","../packages/shared/src/lib/config-version.ts","../packages/shared/src/lib/git-worktree.ts","../packages/shared/src/lib/resolve-text-input.ts","../packages/shared/src/lib/runtime-sync.ts","../packages/shared/src/lib/tool-compat.ts","../packages/shared/src/lib/canonical-source.ts","../packages/shared/src/lib/daily-logs.ts","../packages/shared/src/lib/vault-layout.ts","../packages/shared/src/index.ts","../packages/core/src/state-machine.ts","../packages/core/src/watchdog.ts","../packages/core/src/daemon.ts","../packages/core/src/mailbox.ts","../packages/core/src/protocol.ts","../packages/core/src/liveness.ts","../packages/core/src/store.ts","../packages/core/src/snapshot.ts","../packages/core/src/launchd.ts","../packages/core/src/crew-pane-reader.ts","../packages/core/dist/interfaces.js","../packages/core/src/gate.ts","../packages/core/src/daemon/context.ts","../packages/core/src/daemon/attach.ts","../packages/core/src/daemon/interactive-probe.ts","../packages/core/src/daemon/probes.ts","../packages/core/src/delivery/defer-delivery.ts","../packages/core/src/delivery/captain-delivery.ts","../packages/core/src/daemon/delivery.ts","../packages/core/src/daemon/gates.ts","../packages/core/src/daemon/server.ts","../packages/core/src/daemon/snapshot-gather.ts","../packages/core/src/daemon/start.ts","../packages/core/src/session-freshness.ts","../packages/core/src/crew-protocol.ts","../packages/core/src/crew-lifecycle.ts","../packages/core/src/telegram/auth.ts","../packages/core/src/telegram/commands.ts","../packages/core/src/telegram/ensure-captain.ts","../packages/core/src/telegram/format.ts","../packages/core/src/telegram/state.ts","../packages/core/src/telegram/client.ts","../packages/core/src/telegram/bridge.ts","../packages/core/src/telegram/setup.ts","../packages/core/src/telegram/index.ts","../packages/core/src/index.ts","../packages/workspaces/src/runtimes/cmux.ts","../packages/workspaces/src/runtimes/registry.ts","../packages/workspaces/src/runtimes/index.ts","../packages/workspaces/src/notifiers/cmux.ts","../packages/workspaces/src/notifiers/registry.ts","../packages/workspaces/src/notifiers/index.ts","../packages/workspaces/src/workspaces/obsidian.ts","../packages/workspaces/src/workspaces/registry.ts","../packages/workspaces/src/workspaces/index.ts","../packages/workspaces/src/cmux/events-bridge.ts","../packages/workspaces/src/cmux/daemon-cmux.ts","../packages/workspaces/src/crew-pane.ts","../packages/workspaces/src/index.ts","../packages/agents/src/drivers/claude.ts","../packages/agents/src/drivers/codex.ts","../packages/agents/src/drivers/gemini.ts","../packages/agents/src/drivers/opencode.ts","../packages/agents/src/drivers/types.ts","../packages/agents/src/drivers/registry.ts","../packages/agents/src/drivers/launch-cmd.ts","../packages/agents/src/drivers/index.ts","../packages/agents/src/projection/cursor.ts","../packages/agents/src/projection/marker.ts","../packages/agents/src/projection/codex.ts","../packages/agents/src/projection/gemini.ts","../packages/agents/src/projection/opencode.ts","../packages/agents/src/projection/registry.ts","../packages/agents/src/projection/index.ts","../packages/agents/src/codex/app-server-client.ts","../packages/agents/src/codex/config.ts","../packages/agents/src/codex/normalize.ts","../packages/agents/src/codex/driver.ts","../packages/agents/src/opencode/sse-bridge.ts","../packages/agents/src/interactive/claude.ts","../packages/agents/src/interactive/pane-classifier.ts","../packages/agents/src/interactive/registry.ts","../packages/agents/dist/interactive/types.js","../packages/agents/src/headless/types.ts","../packages/agents/src/headless/claude.ts","../packages/agents/src/headless/opencode.ts","../packages/agents/src/headless/codex.ts","../packages/agents/src/headless/registry.ts","../packages/agents/src/headless-launcher.ts","../packages/agents/src/index.ts","../packages/cli/src/index.ts","../packages/cli/src/commands/doctor.ts","../packages/cli/src/commands/health-view.ts","../packages/cli/src/commands/init.ts","../packages/cli/src/commands/projects.ts","../packages/cli/src/commands/status.ts","../packages/cli/src/commands/command.ts","../packages/cli/src/commands/crew.ts","../packages/cli/src/control/crew-routing.ts","../packages/cli/src/commands/crew-control.ts","../packages/cli/src/commands/crew-output.ts","../packages/cli/src/commands/crew-attach.ts","../packages/cli/src/commands/crew-chat.ts","../packages/cli/src/lib/per-crew-settings.ts","../packages/cli/src/commands/side.ts","../packages/cli/src/commands/dashboard.ts","../packages/web/src/read-status.ts","../packages/web/src/render.ts","../packages/web/src/sync-hub.ts","../packages/web/src/web-server.ts","../packages/web/src/snapshot-merge.ts","../packages/web/src/probes.ts","../packages/web/src/web-render.ts","../packages/cli/src/commands/launch.ts","../packages/cli/src/commands/shutdown.ts","../packages/cli/src/commands/feedback.ts","../packages/cli/src/commands/standup.ts","../packages/cli/src/commands/retro.ts","../packages/cli/src/commands/runtime.ts","../packages/cli/src/commands/workspace.ts","../packages/cli/src/commands/notify.ts","../packages/cli/src/commands/projection.ts","../packages/cli/src/commands/codex-chat-smoke.ts","../packages/cli/src/commands/config.ts","../packages/cli/src/commands/heal.ts","../packages/cli/src/commands/group.ts","../packages/cli/src/commands/cmux.ts","../packages/cli/src/commands/effort.ts","../packages/cli/src/commands/telegram.ts"],"sourcesContent":["// src/config.ts\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport os from \"node:os\";\nimport chalk from \"chalk\";\n\nexport interface ProjectConfig {\n path: string;\n captainName: string;\n spokeVault: string;\n host: string;\n group?: string;\n groupRole?: string;\n runtime?: string;\n workspace?: string;\n /** #246: when false, `squadrant group dispatch` rejects delegations to this\n * project. Defaults to true when absent. */\n acceptDelegations?: boolean;\n}\n\nexport interface PermissionConfig {\n command: string; // permission mode for the command session\n captain: string; // permission mode for captain sessions\n crew?: string; // permission mode for crew sessions (default: acceptEdits)\n // Flexible role->mode map so future roles don't need a type change.\n [role: string]: string | undefined;\n}\n\nexport type ModelAlias = \"opus\" | \"sonnet\" | \"haiku\";\n\nexport interface CrewRoutingRule {\n tier: string;\n match: string;\n agent: string;\n model?: string;\n}\n\nexport interface CrewRoutingConfig {\n rules: CrewRoutingRule[];\n}\n\nexport interface TelegramConfig {\n botToken?: string; // falls back to env TELEGRAM_BOT_TOKEN at read time\n supergroupId: number; // forum supergroup hosting per-project topics\n chats: number[]; // chat_id allowlist (inbound honored only from these)\n users?: number[]; // user-id allowlist for CONTROL actions (#321); empty ⇒ control disabled\n remoteControl?: boolean; // opt-in master switch for auto-launch + general commands (default false)\n pollMs?: number; // getUpdates long-poll cadence (default 1000)\n}\n\nexport interface ModelRoutingConfig {\n command: ModelAlias;\n captain: ModelAlias;\n crew: ModelAlias;\n exploration: ModelAlias;\n review: ModelAlias;\n}\n\nexport interface AgentEntry {\n cli: string;\n driver: string;\n}\n\nexport interface RoleAssignment {\n agent: string;\n model?: string;\n}\n\nexport type RoleConfig = Partial<Record<\"command\" | \"captain\" | \"crew\" | \"exploration\" | \"side\", RoleAssignment>>;\n\nexport interface SquadrantConfig {\n /** Package version that last reconciled this config. Absent on legacy/fresh configs. */\n _squadrantVersion?: string;\n commandName: string;\n hubVault: string;\n projects: Record<string, ProjectConfig>;\n agents?: Record<string, AgentEntry>;\n runtime?: string;\n workspace?: string;\n notifier?: string;\n /** Optional Telegram bridge config. Absent ⇒ the bridge is never constructed\n * (zero behavior change). See docs/superpowers/specs/2026-06-22-telegram-integration-v1-design.md. */\n telegram?: TelegramConfig;\n projection?: {\n targets?: string[];\n };\n delivery?: {\n /** Max consecutive defers before force-delivering a message (~1s poll cadence). Default: 300 (~5min). */\n maxDeferDeliveries?: number;\n /** Consecutive stable-content polls before probing early to avoid a stall (#302). Default: 3 (~3s). */\n stableProbePolls?: number;\n };\n defaults: {\n maxCrew: number;\n worktreeDir: string;\n teammateMode: string;\n permissions: PermissionConfig;\n models?: ModelRoutingConfig;\n roles?: RoleConfig;\n /** #225 hard crew task-timeout ceiling (ms). Default: 8h. */\n taskTimeoutMs?: number;\n /** #275 rule-based crew routing: keyword rules map task text to {agent, model}. Optional — absent = fall through to defaults.roles.crew. */\n crewRouting?: CrewRoutingConfig;\n /** B1: consume cmux's native event stream for crew turn-end (idle) detection\n * alongside the scrape fallback. Default true; set false for scrape-only. */\n cmuxEventsBridge?: boolean;\n /**\n * Audit C2 — agent hibernation (reclaim idle-crew RAM). INTENTIONALLY OFF and\n * INERT: cmux 0.64.16's `cmux agent-hibernation <on|off>` is GLOBAL (app-wide,\n * no per-session/per-workspace scope), so enabling it would also hibernate the\n * CAPTAIN — which must stay responsive for daemon-direct delivery —\n * breaking orchestration. We do NOT call `agent-hibernation on`\n * anywhere; this flag is a documented decision record + a forward hook for when\n * cmux gains crew-only scoping. Until then leave false.\n * See docs/research/2026-06-16-cmux-events-stream.md (C2 finding).\n */\n cmuxAgentHibernation?: boolean;\n /** #317 global crew tokenomics dial. Absent ⇒ \"balance\" (today's behavior).\n * Biases the captain toward stronger (\"max\") or cheaper (\"low\") crew models. */\n effort?: \"max\" | \"balance\" | \"low\";\n };\n metrics: {\n enabled: boolean;\n path: string;\n };\n}\n\nconst CONFIG_DIR = path.join(os.homedir(), \".config\", \"squadrant\");\nexport const DEFAULT_CONFIG_PATH = path.join(CONFIG_DIR, \"config.json\");\n\nexport function getDefaultConfig(): SquadrantConfig {\n return {\n commandName: \"\\u{1F3DB}\\u{FE0F} command\",\n hubVault: path.join(os.homedir(), \"squadrant-hub\"),\n projects: {},\n agents: {\n claude: { cli: \"claude\", driver: \"claude\" },\n },\n defaults: {\n maxCrew: 5,\n worktreeDir: \".worktrees\",\n teammateMode: \"in-process\",\n permissions: {\n command: \"auto\",\n captain: \"auto\",\n crew: \"auto\",\n },\n models: {\n command: \"opus\",\n captain: \"opus\",\n crew: \"opus\",\n exploration: \"haiku\",\n review: \"opus\",\n },\n roles: {\n command: { agent: \"claude\", model: \"opus\" },\n captain: { agent: \"claude\", model: \"opus\" },\n crew: { agent: \"claude\", model: \"opus\" },\n exploration: { agent: \"claude\", model: \"haiku\" },\n side: { agent: \"claude\", model: \"opus\" },\n },\n taskTimeoutMs: 8 * 60 * 60 * 1000,\n cmuxEventsBridge: true,\n // Audit C2: OFF by design — cmux hibernation is global-only and would\n // hibernate the captain. See the field doc above.\n cmuxAgentHibernation: false,\n crewRouting: {\n rules: [\n { tier: \"extreme\", match: \"redesign|architect|rewrite|from scratch|deep reasoning\", agent: \"claude\", model: \"opus\" },\n { tier: \"hard\", match: \"refactor|migrate|implement|feature|daemon|control-plane\", agent: \"claude\", model: \"sonnet\" },\n { tier: \"mobile\", match: \"mobile|ios|swift|android|kotlin|react native\", agent: \"codex\" },\n { tier: \"daily\", match: \"typo|rename|bump|docs|comment|lint|format\", agent: \"opencode\" },\n ],\n },\n },\n metrics: {\n enabled: true,\n path: path.join(CONFIG_DIR, \"metrics.json\"),\n },\n };\n}\n\nexport function loadConfig(configPath = DEFAULT_CONFIG_PATH): SquadrantConfig {\n try {\n const raw = fs.readFileSync(configPath, \"utf-8\");\n const config = JSON.parse(raw) as SquadrantConfig;\n\n // Backward compat: migrate models → roles if roles not set\n if (config.defaults.models && !config.defaults.roles) {\n const m = config.defaults.models;\n config.defaults.roles = {\n command: { agent: \"claude\", model: m.command },\n captain: { agent: \"claude\", model: m.captain },\n crew: { agent: \"claude\", model: m.crew },\n exploration: { agent: \"claude\", model: m.exploration },\n };\n }\n\n // Ensure agents has at least claude\n if (!config.agents) {\n config.agents = { claude: { cli: \"claude\", driver: \"claude\" } };\n }\n\n // #286: backfill crewRouting for configs written before routing existed\n if (!config.defaults.crewRouting) {\n config.defaults.crewRouting = getDefaultConfig().defaults.crewRouting;\n saveConfig(config, configPath);\n console.error(\n chalk.cyan(\n \"⬆ squadrant upgrade: added default crew routing rules to your config (leveled routing now active). \" +\n \"Edit defaults.crewRouting in ~/.config/squadrant/config.json or use the squadrant:add-pick-crew-rule skill.\",\n ),\n );\n }\n\n return config;\n } catch {\n return getDefaultConfig();\n }\n}\n\nexport function saveConfig(\n config: SquadrantConfig,\n configPath = DEFAULT_CONFIG_PATH,\n): void {\n const dir = path.dirname(configPath);\n fs.mkdirSync(dir, { recursive: true });\n fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + \"\\n\");\n}\n\nexport function resolveHome(p: string): string {\n return p.startsWith(\"~\") ? p.replace(\"~\", os.homedir()) : p;\n}\n","import type { SquadrantConfig } from \"./config.js\";\n\nexport type Effort = \"max\" | \"balance\" | \"low\";\n\nexport function resolveEffort(config: SquadrantConfig): Effort {\n return config.defaults.effort ?? \"balance\";\n}\n","export {};\n//# sourceMappingURL=runtime.js.map","// src/control/types.ts\nexport type Provider = \"claude\" | \"opencode\" | \"codex\" | \"gemini\";\nexport type Mode = \"headless\" | \"interactive\";\n\nexport type TaskState =\n | \"submitted\"\n | \"working\"\n | \"blocked\"\n | \"done\"\n | \"failed\"\n | \"stalled\"\n | \"awaiting-input\"\n | \"cancelled\";\n\nexport interface DispatchAttempt {\n attemptId: string;\n startedAt: number;\n pid?: number;\n resumeRef?: string; // opaque, hashed-treated, NEVER parsed (orca #1148)\n lastHeartbeatAt: number;\n error?: string;\n exitCode?: number;\n circuitBroken?: boolean;\n}\n\nexport interface Gate {\n gateId: string;\n taskId: string;\n kind: \"input\" | \"approval\";\n question: string;\n state: \"pending\" | \"resolved\" | \"timeout\";\n createdAt: number;\n resolvedBy?: string;\n resolution?: unknown;\n}\n\nexport interface TaskRecord {\n id: string;\n /** Human-readable crew name (e.g. the `--name` arg to `squadrant crew spawn`).\n * Optional for backward-compat with records written before this field\n * existed; relay/daemon fall back to the short id when absent. */\n name?: string;\n project: string;\n provider: Provider;\n mode: Mode;\n state: TaskState;\n task: string; // the dispatched instruction\n sessionId?: string; // provider session id for resume (blocked→reply)\n cwd?: string; // working dir for the spawned headless child (project/worktree); unset → daemon cwd\n pid?: number; // headless child pid (daemon-owned)\n question?: string; // populated when state === \"blocked\"\n error?: string; // populated when state === \"failed\"\n exitCode?: number;\n resultRef?: string; // filesystem path to captured output/artifact\n parseWarning?: boolean; // headless exit 0 but unparseable result\n createdAt: number; // epoch ms\n lastHeartbeat: number; // epoch ms\n lastEvent: string; // last event type applied\n heartbeatBudgetMs: number; // per-task stall threshold\n /** Append-only dispatch attempt history. Current attempt = at(-1). */\n attempts: DispatchAttempt[];\n /** Interactive-codex HITL slice (spec §4.9). */\n gates?: Gate[];\n /** Codex AskForApproval policy forwarded to startThread (interactive only).\n * When set to \"untrusted\", codex requests approval for tool/shell calls,\n * exercising the gate-promotion flow end-to-end. */\n approvalPolicy?: string;\n /** Role-priming content forwarded to startThread's developerInstructions\n * (interactive only). Parity with claude's --append-system-prompt-file:\n * injects crew rules / Karpathy discipline before the first user turn. */\n roleInstructions?: string;\n /** TCP port of an interactive opencode crew's embedded HTTP server\n * (`opencode --port <N>`). The daemon's SSE bridge subscribes to\n * http://127.0.0.1:<serverPort>/event for reliable turn-end detection. */\n serverPort?: number;\n /** #246: cross-project intra-group delegation — set to the origin project's\n * name when this task was dispatched by a sibling captain. When the task\n * settles, the daemon fans the outcome back to originProject's mailbox. */\n originProject?: string;\n /** #354: the tool call currently in flight, if any. Set when a PreToolUse\n * liveness signal arrives (cmux events-bridge carries the tool name); cleared\n * the moment its PostToolUse / next turn boundary arrives. A `working` crew\n * whose pendingTool has been outstanding past TOOL_STALL_BUDGET_MS is treated\n * as hung-on-a-tool (CREW STALLED warn) — distinct from a quiet thinking turn\n * (no pendingTool → CREW QUIET). Auto-clears: the next PostToolUse recovers\n * the record to `working` (state-machine + recoverStall). */\n pendingTool?: { name: string; since: number };\n}\n\nexport type ControlEvent =\n | { type: \"task.started\"; id: string; pid?: number; sessionId?: string }\n | { type: \"task.progress\"; id: string; note?: string; tool?: string }\n | { type: \"heartbeat\"; id: string }\n | { type: \"task.blocked\"; id: string; reason: string; question: string }\n | { type: \"task.done\"; id: string; resultRef: string; message?: string; parseWarning?: boolean }\n | { type: \"task.failed\"; id: string; error: string; exitCode?: number }\n | { type: \"task.session\"; id: string; resumeRef: string }\n | { type: \"task.turn.started\"; id: string; turnId: string }\n | { type: \"task.turn.completed\"; id: string; turnId: string }\n | { type: \"task.delta\"; id: string; turnId: string; chunk: string }\n | { type: \"task.input.requested\"; id: string; requestId: number; question: string }\n | { type: \"task.approval.requested\"; id: string; requestId: number; question: string; kind: string }\n | { type: \"task.reattached\"; id: string }\n // Reopen: the only event allowed to revive a terminal task. Emitted by\n // `squadrant crew send` when the target crew's daemon task is in a terminal\n // state, allowing the next `signal done` to be a real transition.\n | { type: \"task.reopened\"; id: string }\n // Synthetic events: emitted by the daemon (watchdog / reconcile) purely as\n // notify payloads. They are never sent over the wire and the reducer treats\n // them as no-ops; the watchdog has already updated state directly.\n // #354: `tool`/`elapsedMs` are set when the stall is a hung interactive tool\n // call (PreToolUse with no matching PostToolUse past TOOL_STALL_BUDGET_MS),\n // letting the notifier render \"still running {tool} ~{N}min\" instead of the\n // generic headless \"no heartbeat\" message.\n | { type: \"task.stalled\"; id: string; heartbeatBudgetMs: number; tool?: string; elapsedMs?: number }\n // task.idle is the interactive analogue of task.stalled: the watchdog has\n // already moved an idle interactive task to 'awaiting-input', and this carries\n // the accurate (non-alarming) notify payload to the captain.\n | { type: \"task.idle\"; id: string; heartbeatBudgetMs: number }\n // #354: a `working` interactive crew that has been quiet past its heartbeat\n // budget with NO tool in flight — alive but deep-thinking (no hook fires\n // during pure model thinking). Notify-only (reducer no-op): the crew stays\n // `working`, NOT awaiting-input. Real CREW IDLE still comes only from the Stop\n // hook (a genuine turn-end). `quietMs` = how long it has been silent.\n | { type: \"task.quiet\"; id: string; quietMs: number }\n // #225: emitted by the sweep when a task's wall-clock age exceeds the ceiling.\n // Notify-only (detect-first, #77); reducer is a no-op.\n | { type: \"task.timeout\"; id: string; taskTimeoutMs: number }\n | { type: \"task.reconcile-failed\"; id: string; reason: string }\n // Emitted by runCrewClose before closing the pane; transitions a non-terminal\n // task to the absorbing 'cancelled' state. Silent: captain initiated the close\n // so no CREW CANCELLED push is fired (not in ATTENTION_STATES).\n | { type: \"task.cancelled\"; id: string; reason?: string }\n // #139: a claude crew's SessionEnd hook fired — the session is GONE. Unlike\n // the other turn-boundary hooks (PostToolUse/SubagentStop = liveness), a dead\n // session must NOT resume 'working' (nothing heartbeats → false CREW STALLED\n // ~budget later). Terminalizes the record to the absorbing 'cancelled' state.\n // Silent (not in ATTENTION_STATES), like task.cancelled.\n | { type: \"task.session.ended\"; id: string };\n\n// 'stalled' is intentionally excluded — recoverable by the watchdog.\n// 'cancelled' is terminal and silent (captain-initiated close).\nexport const TERMINAL_STATES: ReadonlySet<TaskState> = new Set([\n \"done\",\n \"failed\",\n \"cancelled\",\n]);\n","export {};\n//# sourceMappingURL=projection.js.map","export {};\n//# sourceMappingURL=workspaces.js.map","// src/lib/cmux-config.ts\n//\n// #348 (part of #332): comment-preserving JSONC merge for the cmux control\n// socket auth mode. Writes ONLY `automation.socketControlMode = \"automation\"`\n// into ~/.config/cmux/cmux.json so the launchd squadrant daemon (NOT a cmux\n// descendant) may connect to the cmux control socket for daemon-direct delivery.\n//\n// See docs/specs/2026-06-16-cmux-socket-auth-daemon-direct-design.md §2–§4.1.\n//\n// We use jsonc-parser (modify + applyEdits) rather than JSON.parse/stringify so\n// every existing comment and key in the user's cmux.json survives — cmux itself\n// preserves comments and we must not clobber them.\nimport { existsSync, readFileSync, writeFileSync, mkdirSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { dirname, join } from \"node:path\";\nimport { parse, modify, applyEdits } from \"jsonc-parser\";\n\n/** Canonical cmux config path. cmux watches this file live (§3.2). */\nexport function defaultCmuxConfigPath(): string {\n return join(homedir(), \".config\", \"cmux\", \"cmux.json\");\n}\n\nexport const SOCKET_CONTROL_MODE_PATH = [\"automation\", \"socketControlMode\"] as const;\nexport const AUTOMATION_MODE = \"automation\";\n\nexport interface EnsureSocketAutomationResult {\n /** Absolute path written/inspected. */\n path: string;\n /** True when the file was written this call. */\n changed: boolean;\n /** True when socketControlMode was ALREADY \"automation\" (no write needed). */\n alreadySet: boolean;\n}\n\n// Minimal squadrant-managed template used only when cmux.json does not yet exist\n// (clean install before cmux has created its own template). It is a strict\n// subset of cmux's schema, so cmux merges its full template keys on next launch\n// without conflict.\nconst MINIMAL_TEMPLATE = [\n `{`,\n ` // [squadrant] file-managed: allow the launchd squadrant daemon to reach the cmux`,\n ` // control socket for daemon-direct notification delivery (#348/#332).`,\n ` \"automation\": {`,\n ` \"socketControlMode\": \"${AUTOMATION_MODE}\"`,\n ` }`,\n `}`,\n ``,\n].join(\"\\n\");\n\n/**\n * Ensure `automation.socketControlMode = \"automation\"` in the cmux config.\n *\n * Idempotent: a no-op (changed=false) when already set. Comment- and\n * formatting-preserving when adding/overwriting an existing file. Creates a\n * minimal squadrant-managed file when none exists.\n */\nexport function ensureSocketAutomation(\n opts: { path?: string } = {},\n): EnsureSocketAutomationResult {\n const path = opts.path ?? defaultCmuxConfigPath();\n\n if (!existsSync(path)) {\n mkdirSync(dirname(path), { recursive: true });\n writeFileSync(path, MINIMAL_TEMPLATE);\n return { path, changed: true, alreadySet: false };\n }\n\n const text = readFileSync(path, \"utf-8\");\n const current = parse(text)?.automation?.socketControlMode;\n if (current === AUTOMATION_MODE) {\n return { path, changed: false, alreadySet: true };\n }\n\n const edits = modify(text, [...SOCKET_CONTROL_MODE_PATH], AUTOMATION_MODE, {\n formattingOptions: { insertSpaces: true, tabSize: 2 },\n });\n writeFileSync(path, applyEdits(text, edits));\n return { path, changed: true, alreadySet: false };\n}\n","import { execFileSync } from \"node:child_process\";\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\n\nlet _cached: string | undefined;\n\nfunction resolveBin(): string {\n // 1. Env var override\n const envBin = process.env.SQUADRANT_CMUX_BIN;\n if (envBin && existsSync(envBin)) return envBin;\n\n // 2. Optional cmuxBin field in config.json\n try {\n const configPath = join(homedir(), \".config\", \"squadrant\", \"config.json\");\n if (existsSync(configPath)) {\n const cfg = JSON.parse(readFileSync(configPath, \"utf-8\"));\n const cfgBin: unknown = cfg.cmuxBin;\n if (typeof cfgBin === \"string\" && existsSync(cfgBin)) return cfgBin;\n }\n } catch { /* config read is best-effort */ }\n\n // 3. PATH lookup\n try {\n const which = execFileSync(\"which\", [\"cmux\"], { encoding: \"utf-8\" }).trim();\n if (which && existsSync(which)) return which;\n } catch { /* not on PATH */ }\n\n // 4. Fallback (backward compat for macOS .app install)\n return \"/Applications/cmux.app/Contents/Resources/bin/cmux\";\n}\n\nexport function resolveCmuxBin(): string {\n return _cached ??= resolveBin();\n}\n\nexport function resetCmuxBinCache(): void {\n _cached = undefined;\n}\n","// src/lib/cmux-probe.ts\n//\n// #348 (part of #332): the hybrid gate. Answer \"can a NON-cmux process reach the\n// cmux control socket right now?\" — i.e. is daemon-direct delivery viable?\n//\n// See docs/specs/2026-06-16-cmux-socket-auth-daemon-direct-design.md §4.2.\n//\n// FAITHFULNESS: cmuxOnly mode checks the connecting process's parent chain and\n// rejects anything not descended from the cmux app. Prior research was\n// CONTAMINATED because it ran inside a cmux pane and kept cmux ancestry even\n// under `env -i`. A faithful probe MUST run from a process reparented to launchd\n// (PPID ⇒ 1). We achieve that with a launcher→worker double-fork: the launcher\n// exits immediately, orphaning the worker, which waits until process.ppid === 1\n// before touching the socket.\nimport { spawn } from \"node:child_process\";\nimport { mkdtempSync, rmSync, existsSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { tmpdir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { resolveCmuxBin } from \"./cmux-bin.js\";\n\nexport type ProbeVerdict = \"reachable\" | \"denied\" | \"unknown\";\n\nexport interface ProbeRawResult {\n ok: boolean;\n stderr?: string;\n}\n\n// cmux's parentage rejection message (and generic socket permission errors).\nconst DENIED_RE = /access denied|only processes started inside cmux|permission denied/i;\n\n/**\n * Pure. Map a raw probe result to a verdict.\n * - ok ⇒ reachable (daemon-direct viable)\n * - access-denied stderr ⇒ denied (socket still cmuxOnly — restart needed)\n * - anything else ⇒ unknown (fail soft → stay on relay)\n */\nexport function classifyProbe(r: ProbeRawResult): ProbeVerdict {\n if (r.ok) return \"reachable\";\n if (r.stderr && DENIED_RE.test(r.stderr)) return \"denied\";\n return \"unknown\";\n}\n\nexport interface ProbeOpts {\n /** Injectable runner (tests). Default = orphan-escape spawn of a cmux read. */\n run?: () => Promise<ProbeRawResult>;\n /** Overall budget for the orphan probe (default 8s). */\n timeoutMs?: number;\n}\n\n/**\n * Probe whether a non-cmux process can reach the cmux control socket. Never\n * throws — a failed/timed-out probe degrades to \"unknown\" so the caller stays on\n * the zero-setup relay.\n */\nexport async function probeCmuxDaemonDirect(opts: ProbeOpts = {}): Promise<ProbeVerdict> {\n const run = opts.run ?? (() => orphanProbe(opts.timeoutMs ?? 8000));\n try {\n return classifyProbe(await run());\n } catch {\n return \"unknown\";\n }\n}\n\n// The worker script, run via `node`. Two modes in one file:\n// launch: spawn the worker detached, then exit → worker is orphaned to launchd\n// work: wait until PPID===1 (no cmux ancestor), run the cmux read, write JSON\n// argv: [node, script, mode, resultFile, cmuxBin]\nconst WORKER_SRC = `\nimport { spawn, execFileSync } from \"node:child_process\";\nimport { writeFileSync } from \"node:fs\";\nconst [mode, resultFile, cmuxBin] = process.argv.slice(2);\nif (mode === \"launch\") {\n const child = spawn(process.execPath, [process.argv[1], \"work\", resultFile, cmuxBin], {\n detached: true, stdio: \"ignore\",\n });\n child.unref();\n process.exit(0);\n}\n// work mode: wait to be reparented to launchd (PPID 1), then probe.\nconst deadline = Date.now() + 3000;\nwhile (process.ppid !== 1 && Date.now() < deadline) {\n const until = Date.now() + 25;\n while (Date.now() < until) { /* tiny busy wait — no timers in a dying orphan */ }\n}\nlet result;\nif (process.ppid !== 1) {\n result = { ok: false, stderr: \"orphan-timeout\" };\n} else {\n try {\n execFileSync(cmuxBin, [\"workspace\", \"list\", \"--json\"], {\n encoding: \"utf-8\", timeout: 10000, env: { ...process.env, CMUX_QUIET: \"1\" },\n });\n result = { ok: true };\n } catch (e) {\n const stderr = (e && (e.stderr?.toString?.() || e.message)) || \"probe failed\";\n result = { ok: false, stderr };\n }\n}\nwriteFileSync(resultFile, JSON.stringify(result));\n`;\n\n// Default runner: double-fork to a launchd-reparented worker, poll its result.\nasync function orphanProbe(timeoutMs: number): Promise<ProbeRawResult> {\n const dir = mkdtempSync(join(tmpdir(), \"cmux-probe-\"));\n const scriptFile = join(dir, \"probe-worker.mjs\");\n const resultFile = join(dir, \"result.json\");\n writeFileSync(scriptFile, WORKER_SRC);\n\n try {\n const launcher = spawn(\n process.execPath,\n [scriptFile, \"launch\", resultFile, resolveCmuxBin()],\n { detached: true, stdio: \"ignore\" },\n );\n launcher.unref();\n\n const deadline = Date.now() + timeoutMs;\n while (Date.now() < deadline) {\n if (existsSync(resultFile)) {\n try {\n return JSON.parse(readFileSync(resultFile, \"utf-8\")) as ProbeRawResult;\n } catch {\n // partial write — fall through and retry\n }\n }\n await sleep(100);\n }\n return { ok: false, stderr: \"probe-timeout\" };\n } finally {\n rmSync(dir, { recursive: true, force: true });\n }\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((r) => setTimeout(r, ms));\n}\n","// src/lib/cmux-autoconfig.ts\n//\n// #348 (part of #332): orchestrator for cmux socket auto-config. Ties together\n// the comment-preserving config write, the non-cmux probe, and a SEMI-AUTOMATIC,\n// one-time restart prompt.\n//\n// See docs/specs/2026-06-16-cmux-socket-auth-daemon-direct-design.md §4.3–§4.4.\n//\n// This module decides WHAT to surface (configChanged / verdict / one-time\n// prompt); it does not print or log. The caller — the `squadrant cmux autoconfig`\n// CLI or the daemon-start re-check — renders the result. squadrant NEVER restarts\n// cmux for the user (that disrupts live sessions); we write config and prompt.\nimport { existsSync, readFileSync, writeFileSync, mkdirSync, rmSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { dirname, join } from \"node:path\";\nimport { ensureSocketAutomation } from \"./cmux-config.js\";\nimport { probeCmuxDaemonDirect, type ProbeVerdict } from \"./cmux-probe.js\";\n\n/** One-time prompt marker, alongside the daemon state. */\nexport function defaultStatePath(): string {\n return join(homedir(), \".config\", \"squadrant\", \"state\", \"cmux-autoconfig.json\");\n}\n\nexport interface AutoConfigResult {\n /** Path of the cmux config inspected/written. */\n configPath: string;\n /** True when the cmux config was written this run. */\n configChanged: boolean;\n /** True when socketControlMode was already \"automation\". */\n configAlreadySet: boolean;\n /** Live socket reachability from a non-cmux process. */\n verdict: ProbeVerdict;\n /** Config is in place but the live socket still rejects (cmux restart needed). */\n needsRestart: boolean;\n /** The one-time restart prompt fired this run (false on repeats — no nag). */\n promptedThisRun: boolean;\n}\n\nexport interface AutoConfigOpts {\n configPath?: string;\n statePath?: string;\n /** Injectable for tests. Default = ensureSocketAutomation. */\n ensureConfig?: typeof ensureSocketAutomation;\n /** Injectable for tests. Default = the real orphan probe. */\n probe?: () => Promise<ProbeVerdict>;\n}\n\ninterface PromptState {\n promptedRestart?: boolean;\n}\n\nfunction readState(path: string): PromptState {\n try {\n return JSON.parse(readFileSync(path, \"utf-8\")) as PromptState;\n } catch {\n return {};\n }\n}\n\n/**\n * Idempotent: write the cmux automation config (if needed), probe the live\n * socket, and fire a one-time restart prompt when the socket still rejects.\n *\n * Safe to call on every daemon start — it recovers the \"cmux not running at\n * first write\" edge case (§3.4): the value is already file-managed, so the next\n * start re-probes and daemon-direct activates once cmux is (re)launched.\n */\nexport async function ensureCmuxAutoConfig(opts: AutoConfigOpts = {}): Promise<AutoConfigResult> {\n const statePath = opts.statePath ?? defaultStatePath();\n const ensureConfig = opts.ensureConfig ?? ensureSocketAutomation;\n const probe = opts.probe ?? probeCmuxDaemonDirect;\n\n const cfg = ensureConfig({ path: opts.configPath });\n const verdict = await probe();\n const needsRestart = verdict === \"denied\";\n\n let promptedThisRun = false;\n if (needsRestart) {\n const already = readState(statePath).promptedRestart === true;\n if (!already) {\n mkdirSync(dirname(statePath), { recursive: true });\n writeFileSync(statePath, JSON.stringify({ promptedRestart: true }));\n promptedThisRun = true;\n }\n } else if (verdict === \"reachable\") {\n // Reset the marker so a future regression (e.g. cmux config wiped) re-prompts.\n if (existsSync(statePath)) rmSync(statePath, { force: true });\n }\n\n return {\n configPath: cfg.path,\n configChanged: cfg.changed,\n configAlreadySet: cfg.alreadySet,\n verdict,\n needsRestart,\n promptedThisRun,\n };\n}\n","export type ToolEntry = { min?: string; lastVerified?: string };\n\nexport const compatManifest = {\n tools: {\n cmux: { min: \"0.64.0\", lastVerified: \"0.64.16\" } satisfies ToolEntry,\n claude: { min: \"2.1.32\" } satisfies ToolEntry,\n node: { min: \"18.0.0\", lastVerified: \"24.6.0\" } satisfies ToolEntry,\n // presence-checked; no floor enforced yet\n codex: { lastVerified: \"0.139.0\" } satisfies ToolEntry,\n gemini: { lastVerified: \"0.38.2\" } satisfies ToolEntry,\n opencode: { lastVerified: \"1.17.4\" } satisfies ToolEntry,\n },\n} as const;\n","import type { SquadrantConfig } from \"../config.js\";\n\nexport type DriftKind = \"missing\" | \"deprecated\" | \"changed-default\" | \"invalid\";\nexport type DriftSeverity = \"info\" | \"advisory\" | \"warn\";\n\nexport interface DriftItem {\n path: string;\n kind: DriftKind;\n severity: DriftSeverity;\n current?: unknown;\n suggested?: unknown;\n note?: string;\n}\n\nexport const SAFE_KINDS: DriftKind[] = [\"missing\", \"deprecated\"];\n\nconst MANAGED_PATHS: string[] = [\n \"defaults.maxCrew\",\n \"defaults.worktreeDir\",\n \"defaults.teammateMode\",\n \"defaults.permissions.*\",\n \"defaults.roles.*\",\n \"agents.*\",\n \"workspace\",\n \"notifier\",\n \"runtime\",\n];\n\nconst KNOWN_DEPRECATED: Array<{ path: string; when?: (u: SquadrantConfig) => boolean; note: string }> = [\n {\n path: \"defaults.models\",\n when: (u) => u.defaults?.roles !== undefined,\n note: \"superseded by defaults.roles\",\n },\n];\n\nconst KNOWN_DEFAULT_HISTORY: Array<{ path: string; oldDefaults: unknown[] }> = [\n { path: \"defaults.roles.crew.model\", oldDefaults: [\"sonnet\"] },\n { path: \"defaults.roles.captain.model\", oldDefaults: [\"sonnet\"] },\n];\n\nconst KNOWN_DRIVERS = new Set([\"claude\", \"codex\", \"gemini\", \"opencode\"]);\n\nfunction getPath(obj: unknown, dotted: string): unknown {\n return dotted.split(\".\").reduce<unknown>((acc, k) => (acc && typeof acc === \"object\" ? (acc as Record<string, unknown>)[k] : undefined), obj);\n}\n\nfunction hasPath(obj: unknown, dotted: string): boolean {\n const parts = dotted.split(\".\");\n let cur: unknown = obj;\n for (const k of parts) {\n if (!cur || typeof cur !== \"object\" || !(k in (cur as Record<string, unknown>))) return false;\n cur = (cur as Record<string, unknown>)[k];\n }\n return true;\n}\n\nfunction expandManaged(managed: string, def: SquadrantConfig): string[] {\n if (!managed.endsWith(\".*\")) return [managed];\n const parent = managed.slice(0, -2);\n const node = getPath(def, parent);\n if (!node || typeof node !== \"object\") return [];\n return Object.keys(node as Record<string, unknown>).map((k) => `${parent}.${k}`);\n}\n\nexport function detectDrift(user: SquadrantConfig, def: SquadrantConfig): DriftItem[] {\n const items: DriftItem[] = [];\n\n for (const managed of MANAGED_PATHS) {\n for (const leaf of expandManaged(managed, def)) {\n const inDefault = hasPath(def, leaf);\n if (inDefault && !hasPath(user, leaf)) {\n items.push({ path: leaf, kind: \"missing\", severity: \"info\", suggested: getPath(def, leaf) });\n }\n }\n }\n\n for (const dep of KNOWN_DEPRECATED) {\n if (hasPath(user, dep.path) && (dep.when ? dep.when(user) : true)) {\n items.push({ path: dep.path, kind: \"deprecated\", severity: \"info\", current: getPath(user, dep.path), note: dep.note });\n }\n }\n\n for (const hist of KNOWN_DEFAULT_HISTORY) {\n if (!hasPath(user, hist.path) || !hasPath(def, hist.path)) continue;\n const cur = getPath(user, hist.path);\n const nowDefault = getPath(def, hist.path);\n if (cur !== nowDefault && hist.oldDefaults.includes(cur)) {\n items.push({\n path: hist.path,\n kind: \"changed-default\",\n severity: \"advisory\",\n current: cur,\n suggested: nowDefault,\n note: `default changed from ${JSON.stringify(cur)} to ${JSON.stringify(nowDefault)}`,\n });\n }\n }\n\n const agents = (user.agents ?? {}) as Record<string, { driver?: string }>;\n for (const [name, entry] of Object.entries(agents)) {\n if (entry?.driver && !KNOWN_DRIVERS.has(entry.driver)) {\n items.push({\n path: `agents.${name}.driver`,\n kind: \"invalid\",\n severity: \"warn\",\n current: entry.driver,\n note: `unknown driver '${entry.driver}'; known: ${[...KNOWN_DRIVERS].join(\", \")}`,\n });\n }\n }\n const roles = (user.defaults?.roles ?? {}) as Record<string, { agent?: string }>;\n for (const [role, asn] of Object.entries(roles)) {\n if (asn?.agent && !(asn.agent in agents)) {\n items.push({\n path: `defaults.roles.${role}.agent`,\n kind: \"invalid\",\n severity: \"warn\",\n current: asn.agent,\n note: `references agent '${asn.agent}' which is not defined in agents`,\n });\n }\n }\n\n return items;\n}\n\nfunction setPath(obj: Record<string, unknown>, dotted: string, value: unknown): void {\n const parts = dotted.split(\".\");\n let cur = obj;\n for (let i = 0; i < parts.length - 1; i++) {\n const k = parts[i];\n if (typeof cur[k] !== \"object\" || cur[k] === null) cur[k] = {};\n cur = cur[k] as Record<string, unknown>;\n }\n cur[parts[parts.length - 1]] = value;\n}\n\nfunction deletePath(obj: Record<string, unknown>, dotted: string): void {\n const parts = dotted.split(\".\");\n let cur: Record<string, unknown> | undefined = obj;\n for (let i = 0; i < parts.length - 1; i++) {\n cur = cur[parts[i]] as Record<string, unknown> | undefined;\n if (!cur || typeof cur !== \"object\") return;\n }\n delete cur[parts[parts.length - 1]];\n}\n\nexport function applySafeFixes(\n user: SquadrantConfig,\n items: DriftItem[],\n _def: SquadrantConfig,\n): { config: SquadrantConfig; applied: string[] } {\n const config = JSON.parse(JSON.stringify(user)) as SquadrantConfig;\n const applied: string[] = [];\n const root = config as unknown as Record<string, unknown>;\n for (const item of items) {\n if (!SAFE_KINDS.includes(item.kind)) continue;\n if (item.kind === \"missing\") setPath(root, item.path, item.suggested);\n else if (item.kind === \"deprecated\") deletePath(root, item.path);\n applied.push(item.path);\n }\n return { config, applied };\n}\n","import type { SquadrantConfig } from \"../config.js\";\n\nexport function readStamp(config: SquadrantConfig): string | null {\n return config._squadrantVersion ?? null;\n}\n\nexport function needsCheck(config: SquadrantConfig, pkgVersion: string): boolean {\n return readStamp(config) !== pkgVersion;\n}\n\nexport function withStamp(config: SquadrantConfig, pkgVersion: string): SquadrantConfig {\n return { ...config, _squadrantVersion: pkgVersion };\n}\n","// src/lib/git-worktree.ts\n//\n// Per-crew git worktree isolation (#216). A FEATURE crew (spawned with\n// `--worktree`) runs in its own worktree + branch so it can switch HEAD without\n// dragging the captain's checkout. Small/one-off crews keep running on the\n// shared root checkout (unchanged default). The side-effecting `git worktree`\n// calls live here so crew.ts stays mockable and surgical — same seam pattern as\n// per-crew-settings.ts.\n//\n// Builds and the daemon still run from the MAIN checkout's `dist`; worktrees\n// edit source only (issue #216 caveat).\nimport { execFileSync } from \"node:child_process\";\nimport path from \"node:path\";\n\nexport interface WorktreeSpec {\n /** The project's root checkout (also the shared `.git` owner). */\n repoRoot: string;\n /** Config.defaults.worktreeDir, resolved relative to repoRoot (e.g. \".worktrees\"). */\n worktreeDir: string;\n project: string;\n /** Crew name (e.g. \"crew-1\" or a --name value). */\n name: string;\n /** Branch to base the new crew branch on (GitFlow: \"develop\"). */\n base: string;\n}\n\n/** Deterministic worktree path: <repoRoot>/<worktreeDir>/<project>-<name>. */\nexport function worktreePath(repoRoot: string, worktreeDir: string, project: string, name: string): string {\n return path.resolve(repoRoot, worktreeDir, `${project}-${name}`);\n}\n\n/** Crew branch name for a worktree crew. */\nexport function crewBranch(name: string): string {\n return `crew/${name}`;\n}\n\n// #359: derive the branch a new worktree should be based on. Reads origin/HEAD\n// so main-based repos work without a hand-created `develop`. Falls back to\n// `fallback` (default \"develop\") when origin/HEAD is unset.\nexport function resolveWorktreeBase(repoRoot: string, fallback = \"develop\"): string {\n try {\n const ref = execFileSync(\n \"git\",\n [\"-C\", repoRoot, \"symbolic-ref\", \"refs/remotes/origin/HEAD\"],\n { stdio: [\"ignore\", \"pipe\", \"ignore\"] },\n ).toString().trim();\n const m = ref.match(/^refs\\/remotes\\/origin\\/(.+)$/);\n if (m) return m[1];\n } catch {\n return fallback;\n }\n return fallback;\n}\n\n/**\n * Create the crew's worktree + branch and return its absolute path.\n * Fails loud (throws) if git refuses — e.g. the base branch is missing or the\n * branch/path already exists. The caller's name-uniqueness check already\n * prevents live duplicates; a re-spawned-after-close name can collide on the\n * existing branch (rare — pick a new --name).\n */\nexport function addWorktree(spec: WorktreeSpec): string {\n const wt = worktreePath(spec.repoRoot, spec.worktreeDir, spec.project, spec.name);\n execFileSync(\n \"git\",\n [\"-C\", spec.repoRoot, \"worktree\", \"add\", wt, \"-b\", crewBranch(spec.name), spec.base],\n { stdio: \"pipe\" },\n );\n return wt;\n}\n\n/**\n * Remove a crew's worktree (auto-clean on close). Tries a plain remove first;\n * a dirty/locked worktree makes git refuse, so we retry with --force. The\n * branch is left intact so the crew's commits survive the close.\n */\nexport function removeWorktree(repoRoot: string, wtPath: string): void {\n try {\n execFileSync(\"git\", [\"-C\", repoRoot, \"worktree\", \"remove\", wtPath], { stdio: \"pipe\" });\n } catch {\n execFileSync(\"git\", [\"-C\", repoRoot, \"worktree\", \"remove\", \"--force\", wtPath], { stdio: \"pipe\" });\n }\n}\n","import fs from \"node:fs\";\n\nasync function readAllStdin(): Promise<string> {\n const chunks: Buffer[] = [];\n for await (const chunk of process.stdin) {\n chunks.push(Buffer.from(chunk));\n }\n return Buffer.concat(chunks).toString(\"utf-8\");\n}\n\nfunction flagName(label: string): string {\n return label === \"task\" ? \"--task-file\" : \"--message-file\";\n}\n\nexport interface ResolveTextInputOpts {\n positional?: string;\n filePath?: string;\n label: string;\n}\n\nexport interface ResolveTextInputDeps {\n readFile?: (path: string) => string;\n readStdin?: () => Promise<string>;\n}\n\nexport async function resolveTextInput(\n opts: ResolveTextInputOpts,\n deps?: ResolveTextInputDeps,\n): Promise<string> {\n const readFile = deps?.readFile ?? ((p: string) => fs.readFileSync(p, \"utf8\"));\n const readStdin = deps?.readStdin ?? readAllStdin;\n\n if (opts.filePath) {\n if (opts.filePath === \"-\") {\n return readStdin();\n }\n try {\n return readFile(opts.filePath);\n } catch (e) {\n const err = e as NodeJS.ErrnoException;\n const flag = flagName(opts.label);\n if (err.code === \"ENOENT\") {\n throw new Error(`${flag} '${opts.filePath}': file not found`);\n }\n throw new Error(`${flag} '${opts.filePath}': ${err.message}`);\n }\n }\n\n if (opts.positional === undefined) {\n throw new Error(\n `No ${opts.label} provided. Provide a positional argument or use ${flagName(opts.label)}.`,\n );\n }\n\n return opts.positional;\n}\n","import fs from \"node:fs\";\nimport path from \"node:path\";\n\n/**\n * Copy `src` → `dest` only if `dest` is missing or its bytes differ. Content\n * comparison (not size+mtime) makes this both correct — a same-size edit is\n * always detected — and idempotent: an unchanged file is never rewritten, so\n * there is no mtime churn across runs. Managed files are small; reading them\n * per invocation is sub-millisecond. Returns true if a copy happened.\n */\nfunction copyIfDifferent(src: string, dest: string): boolean {\n if (fs.existsSync(dest)) {\n if (fs.readFileSync(src).equals(fs.readFileSync(dest))) return false;\n }\n fs.copyFileSync(src, dest);\n return true;\n}\n\n/**\n * Mirror `src` into `dest`: recursively copy new/changed files AND prune any\n * dest entry that no longer exists in src. Idempotent — unchanged files are\n * left untouched. After this returns, `dest` is a structural copy of `src`.\n * Caller is responsible for only pointing this at source-managed trees — it\n * WILL delete dest entries absent from src.\n */\nexport function mirrorDir(src: string, dest: string): void {\n fs.mkdirSync(dest, { recursive: true });\n\n const srcEntries = fs.readdirSync(src, { withFileTypes: true });\n const srcNames = new Set(srcEntries.map((e) => e.name));\n\n for (const entry of srcEntries) {\n const srcPath = path.join(src, entry.name);\n const destPath = path.join(dest, entry.name);\n if (entry.isDirectory()) {\n mirrorDir(srcPath, destPath);\n } else {\n copyIfDifferent(srcPath, destPath);\n }\n }\n\n for (const entry of fs.readdirSync(dest, { withFileTypes: true })) {\n if (!srcNames.has(entry.name)) {\n fs.rmSync(path.join(dest, entry.name), { recursive: true, force: true });\n }\n }\n}\n\n/**\n * Copy the top-level (non-recursive) files of `src` matching `match` into a\n * flat `dest`, prune dest entries no longer in the matched set, and apply\n * `chmod` to freshly copied files when given. Idempotent — unchanged files\n * are left untouched. For runtime dirs whose source is a differently-named,\n * mixed directory (templates ← templates/, scripts).\n */\nexport function mirrorFlat(\n src: string,\n dest: string,\n match: RegExp,\n chmod?: number,\n): void {\n fs.mkdirSync(dest, { recursive: true });\n\n const matched = fs\n .readdirSync(src, { withFileTypes: true })\n .filter((e) => e.isFile() && match.test(e.name))\n .map((e) => e.name);\n const matchedSet = new Set(matched);\n\n for (const name of matched) {\n const destPath = path.join(dest, name);\n const copied = copyIfDifferent(path.join(src, name), destPath);\n if (copied && chmod !== undefined) fs.chmodSync(destPath, chmod);\n }\n\n for (const entry of fs.readdirSync(dest, { withFileTypes: true })) {\n if (!matchedSet.has(entry.name)) {\n fs.rmSync(path.join(dest, entry.name), { recursive: true, force: true });\n }\n }\n}\n\n/**\n * A source-managed runtime dir. `name` is the dir under the runtime root;\n * `srcRel` is its source dir relative to the package root (note: the\n * runtime `templates/` is sourced from `templates/`).\n */\nexport type ManagedTarget =\n | { name: string; srcRel: string; mode: \"tree\" }\n | {\n name: string;\n srcRel: string;\n mode: \"flat\";\n match: RegExp;\n chmod?: number;\n };\n\nexport const MANAGED_TARGETS: ManagedTarget[] = [\n { name: \"plugin\", srcRel: \"plugin\", mode: \"tree\" },\n { name: \"scripts\", srcRel: \"scripts\", mode: \"flat\", match: /\\.sh$/, chmod: 0o755 },\n {\n name: \"templates\",\n srcRel: \"templates\",\n mode: \"flat\",\n match: /\\.(claude\\.md|generic\\.md|opencode\\.md|CLAUDE\\.md)$/,\n },\n];\n\nexport interface EnsureRuntimeSyncedOptions {\n /** Package root containing the source dirs (`plugin/`, `templates/`, …). */\n sourceRoot: string;\n /** Runtime root, normally ~/.config/squadrant. */\n runtimeRoot: string;\n /** Override the managed-target list (defaults to MANAGED_TARGETS). */\n targets?: ManagedTarget[];\n}\n\n/**\n * Self-heal the runtime copy of source-managed dirs. Every invocation\n * mirrors each managed target (mirrorDir for tree, mirrorFlat for flat) —\n * idempotent copy-if-different + prune, so the runtime is always reconciled\n * to source. There is no cached state: nothing can claim \"synced\" while the\n * dest is actually wrong. Only ever touches the runtime dirs named in the\n * target list — never user/runtime state. Never throws — a sync failure\n * degrades to a stderr warning so the CLI stays usable.\n */\nexport function ensureRuntimeSynced(opts: EnsureRuntimeSyncedOptions): void {\n const targets = opts.targets ?? MANAGED_TARGETS;\n\n for (const t of targets) {\n const srcDir = path.join(opts.sourceRoot, t.srcRel);\n try {\n if (!fs.existsSync(srcDir)) continue;\n const destDir = path.join(opts.runtimeRoot, t.name);\n if (t.mode === \"tree\") {\n mirrorDir(srcDir, destDir);\n } else {\n mirrorFlat(srcDir, destDir, t.match, t.chmod);\n }\n } catch (err) {\n process.stderr.write(\n `squadrant: runtime sync skipped for ${t.name}: ${(err as Error).message}\\n`,\n );\n }\n }\n}\n","type SemVer = [number, number, number];\n\nfunction parseSemVer(v: string): SemVer | null {\n const m = v.match(/(\\d+)\\.(\\d+)\\.(\\d+)/);\n if (!m) return null;\n return [parseInt(m[1], 10), parseInt(m[2], 10), parseInt(m[3], 10)];\n}\n\nfunction cmpSemVer(a: SemVer, b: SemVer): number {\n for (let i = 0; i < 3; i++) {\n if (a[i] !== b[i]) return a[i] - b[i];\n }\n return 0;\n}\n\n/**\n * Compare an installed tool version against the compat manifest entry.\n * Returns a warning string when the version is below min or above lastVerified,\n * or null when the version is in-range or unparseable (non-blocking).\n * `min` is optional — entries without a floor are only drift-checked against lastVerified.\n */\nexport function checkToolCompat(\n name: string,\n rawVersion: string,\n entry: { min?: string; lastVerified?: string },\n): string | null {\n const installed = parseSemVer(rawVersion);\n if (!installed) return null;\n\n const min = entry.min ? parseSemVer(entry.min) : null;\n if (min && cmpSemVer(installed, min) < 0) {\n return `${name} ${rawVersion} < min ${entry.min} — upgrade to ${entry.min}+`;\n }\n\n if (entry.lastVerified) {\n const lastVerified = parseSemVer(entry.lastVerified);\n if (lastVerified && cmpSemVer(installed, lastVerified) > 0) {\n return `${name} ${rawVersion} > last-verified ${entry.lastVerified} — re-run compat audit`;\n }\n }\n\n return null;\n}\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport type { WorkspaceDriver } from \"../types/workspaces.js\";\nimport type { ProjectionSource } from \"../types/projection.js\";\n\ninterface SkillFrontmatter {\n name: string;\n description: string;\n}\n\nfunction parseSkill(raw: string): { frontmatter: SkillFrontmatter; body: string } | null {\n const match = raw.match(/^---\\n([\\s\\S]*?)\\n---\\n?([\\s\\S]*)$/);\n if (!match) return null;\n const [, fmBlock, body] = match;\n const fm: Partial<SkillFrontmatter> = {};\n for (const line of fmBlock.split(\"\\n\")) {\n const kv = line.match(/^(\\w+):\\s*(.+)$/);\n if (kv) (fm as Record<string, string>)[kv[1]] = kv[2].trim();\n }\n if (!fm.name || !fm.description) return null;\n return { frontmatter: fm as SkillFrontmatter, body: body.trim() };\n}\n\nasync function readSkills(\n driver: WorkspaceDriver,\n skillsDir: string,\n): Promise<ProjectionSource[\"skills\"]> {\n if (!(await driver.exists(skillsDir))) return [];\n const names = await driver.list(skillsDir);\n const skills: ProjectionSource[\"skills\"] = [];\n for (const name of names) {\n const skillPath = `${skillsDir}/${name}/SKILL.md`;\n if (!(await driver.exists(skillPath))) continue;\n const raw = await driver.read(skillPath);\n const parsed = parseSkill(raw);\n if (!parsed) continue;\n skills.push({\n name: parsed.frontmatter.name,\n description: parsed.frontmatter.description,\n content: parsed.body,\n });\n }\n skills.sort((a, b) => a.name.localeCompare(b.name));\n return skills;\n}\n\nexport interface UserSourceOptions {\n pkgRoot?: string;\n readFile?: (p: string) => string;\n}\n\nconst ROLE_TEMPLATES: ReadonlyArray<{ file: string; heading: string }> = [\n { file: \"captain.generic.md\", heading: \"## Captain Role\" },\n { file: \"crew.generic.md\", heading: \"## Crew Role\" },\n];\n\nfunction readRoleTemplates(opts: UserSourceOptions): string {\n if (!opts.pkgRoot) return \"\";\n const reader = opts.readFile ?? ((p: string) => fs.readFileSync(p, \"utf-8\"));\n const sections: string[] = [];\n for (const { file, heading } of ROLE_TEMPLATES) {\n const full = path.join(opts.pkgRoot, \"templates\", file);\n let body = \"\";\n try { body = reader(full); } catch { continue; }\n sections.push(`${heading}\\n\\n${body.trim()}`);\n }\n return sections.join(\"\\n\\n\");\n}\n\nexport async function readUserLevelSource(\n driver: WorkspaceDriver,\n opts: UserSourceOptions = {},\n): Promise<ProjectionSource> {\n const skills = await readSkills(driver, \"plugin/skills\");\n const instructions = readRoleTemplates(opts);\n return { instructions, skills };\n}\n\n// `driver` must be rooted at the project directory itself (createObsidianDriver\n// with root: proj.path). Reading via a driver rooted at process.cwd() — as the\n// projection command previously did — made the sandbox guard reject every\n// managed project living outside the squadrant repo, silently skipping them.\nexport async function readProjectLevelSource(\n driver: WorkspaceDriver,\n): Promise<ProjectionSource | null> {\n if (!(await driver.exists(\"AGENTS.md\"))) return null;\n const instructions = await driver.read(\"AGENTS.md\");\n const skills = await readSkills(driver, \"plugin/skills\");\n return { instructions, skills };\n}\n","import { execSync } from \"node:child_process\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport matter from \"gray-matter\";\nimport { resolveHome } from \"../config.js\";\nimport type { WorkspaceDriver } from \"../types/workspaces.js\";\n\nexport function iso(d: Date): string {\n return d.toISOString().slice(0, 10);\n}\n\nexport function daysAgo(n: number): Date {\n const d = new Date();\n d.setDate(d.getDate() - n);\n return d;\n}\n\nexport function enumerateDays(from: Date, to: Date): string[] {\n const out: string[] = [];\n const cur = new Date(from);\n cur.setHours(0, 0, 0, 0);\n const end = new Date(to);\n end.setHours(0, 0, 0, 0);\n while (cur <= end) {\n out.push(iso(cur));\n cur.setDate(cur.getDate() + 1);\n }\n return out;\n}\n\nexport interface DailyLog {\n content: string;\n blockers: string[];\n}\n\nexport async function readDailyLog(\n workspace: WorkspaceDriver,\n dateStr: string,\n): Promise<DailyLog | null> {\n const relPath = `daily-logs/${dateStr}.md`;\n if (!(await workspace.exists(relPath))) return null;\n\n const raw = await workspace.read(relPath);\n const { content } = matter(raw);\n\n const blockers: string[] = [];\n const blockerMatch = content.match(/## Blocked\\n([\\s\\S]*?)(?=\\n##|$)/);\n if (blockerMatch) {\n const lines = blockerMatch[1].trim().split(\"\\n\");\n for (const line of lines) {\n const trimmed = line.replace(/^[-*]\\s*/, \"\").trim();\n if (trimmed && trimmed !== \"(none)\" && trimmed !== \"None\") {\n blockers.push(trimmed);\n }\n }\n }\n return { content, blockers };\n}\n\nexport function parseSection(content: string, section: string): string[] {\n const match = content.match(new RegExp(`## ${section}\\\\n([\\\\s\\\\S]*?)(?=\\\\n##|$)`));\n if (!match) return [];\n return match[1]\n .trim()\n .split(\"\\n\")\n .map((l) => l.replace(/^[-*]\\s*/, \"\").trim())\n .filter((l) => l && l !== \"(none)\" && l !== \"None\");\n}\n\nexport function getGitCommits(projectPath: string, dateStr: string): string[] {\n return getGitCommitsInRange(projectPath, `${dateStr} 00:00:00`, `${dateStr} 23:59:59`);\n}\n\nexport function getGitCommitsInRange(projectPath: string, since: string, until?: string): string[] {\n const resolved = resolveHome(projectPath);\n if (!fs.existsSync(path.join(resolved, \".git\"))) return [];\n\n const untilArg = until ? ` --until=\"${until}\"` : \"\";\n try {\n const output = execSync(\n `git -C \"${resolved}\" log --since=\"${since}\"${untilArg} --oneline --no-merges 2>/dev/null`,\n { encoding: \"utf-8\", timeout: 5000 },\n ).trim();\n if (!output) return [];\n return output.split(\"\\n\").map((l) => l.trim()).filter(Boolean);\n } catch {\n return [];\n }\n}\n\nexport function getMergedPRsInRange(projectPath: string, since: string, until?: string): string[] {\n const resolved = resolveHome(projectPath);\n if (!fs.existsSync(path.join(resolved, \".git\"))) return [];\n\n const untilArg = until ? ` --until=\"${until}\"` : \"\";\n try {\n const output = execSync(\n `git -C \"${resolved}\" log --merges --since=\"${since}\"${untilArg} --pretty=format:%s 2>/dev/null`,\n { encoding: \"utf-8\", timeout: 5000 },\n ).trim();\n if (!output) return [];\n return output.split(\"\\n\").map((l) => l.trim()).filter(Boolean);\n } catch {\n return [];\n }\n}\n","import type { WorkspaceDriver } from \"../types/workspaces.js\";\n\nexport const SPOKE_SUBDIRS = [\n \"crew\",\n \"learnings\",\n \"daily-logs\",\n \"skills\",\n \"meta\",\n \"templates\",\n \"wiki\",\n \"wiki/pages\",\n];\n\nexport async function ensureSpokeLayout(workspace: WorkspaceDriver): Promise<void> {\n for (const sub of SPOKE_SUBDIRS) {\n await workspace.mkdir(sub);\n }\n}\n","// @squadrant/shared — pure types + leaf utilities + config.\nexport * from \"./config.js\";\nexport * from \"./effort.js\";\nexport * from \"./types/runtime.js\";\nexport * from \"./types/control.js\";\nexport * from \"./types/projection.js\";\nexport * from \"./types/workspaces.js\";\nexport * from \"./lib/cmux-autoconfig.js\";\nexport * from \"./lib/cmux-bin.js\";\nexport * from \"./lib/cmux-config.js\";\nexport * from \"./lib/cmux-probe.js\";\nexport * from \"./lib/compat-manifest.js\";\nexport * from \"./lib/config-drift.js\";\nexport * from \"./lib/config-version.js\";\nexport * from \"./lib/git-worktree.js\";\nexport * from \"./lib/resolve-text-input.js\";\nexport * from \"./lib/runtime-sync.js\";\nexport * from \"./lib/tool-compat.js\";\nexport * from \"./lib/canonical-source.js\";\nexport * from \"./lib/daily-logs.js\";\nexport * from \"./lib/vault-layout.js\";\n","// src/control/state-machine.ts\nimport type { ControlEvent, TaskRecord, DispatchAttempt } from \"@squadrant/shared\";\nimport { TERMINAL_STATES } from \"@squadrant/shared\";\n\n/**\n * Pure helper: merges `patch` into the last attempt and updates lastHeartbeatAt.\n * Returns a new TaskRecord; never mutates the input.\n */\nfunction stampAttempt(\n rec: TaskRecord,\n patch: Partial<DispatchAttempt>,\n now: number,\n): TaskRecord {\n const attempts = rec.attempts.slice();\n const last = attempts.at(-1) ?? { attemptId: \"a0\", startedAt: now, lastHeartbeatAt: now };\n attempts[attempts.length === 0 ? 0 : attempts.length - 1] = { ...last, ...patch, lastHeartbeatAt: now };\n if (attempts.length === 0) attempts.push(last);\n return { ...rec, attempts };\n}\n\n/**\n * #354: compute the next pendingTool marker for a task.progress liveness signal.\n * A PreToolUse (carried from the cmux events-bridge, with the tool name) opens a\n * tool-in-flight window; a PostToolUse or a new UserPromptSubmit closes it. Other\n * liveness notes (subagentstop / notification) leave the marker untouched — they\n * do not bound a tool call. The note strings match the two feeds: the events-bridge\n * emits the raw cmux hook name (\"agent.hook.PreToolUse\"); the claude hook bridge\n * emits the lower-cased event (\"posttooluse\").\n */\nfunction nextPendingTool(\n current: TaskRecord[\"pendingTool\"],\n ev: Extract<ControlEvent, { type: \"task.progress\" }>,\n now: number,\n): TaskRecord[\"pendingTool\"] {\n if (ev.note === \"agent.hook.PreToolUse\") return { name: ev.tool ?? \"tool\", since: now };\n if (ev.note === \"posttooluse\" || ev.note === \"agent.hook.UserPromptSubmit\") return undefined;\n return current;\n}\n\n/**\n * Pure transition. `now` is injected (epoch ms) so callers control time.\n * Returns a new record; never mutates the input.\n */\nexport function reduce(rec: TaskRecord, ev: ControlEvent, now: number): TaskRecord {\n // task.reopened is the ONE event allowed to escape a terminal state.\n // From ANY state (done/failed/stalled/awaiting-input/working) → working.\n // Clears question and error so the revived task looks fresh.\n if (ev.type === \"task.reopened\") {\n return { ...rec, state: \"working\", question: undefined, error: undefined, lastHeartbeat: now, lastEvent: ev.type };\n }\n\n // Terminal states are absorbing: ignore any late/duplicate event idempotently.\n if (TERMINAL_STATES.has(rec.state)) return rec;\n\n const base = { ...rec, lastHeartbeat: now, lastEvent: ev.type };\n\n switch (ev.type) {\n case \"task.started\":\n return {\n ...stampAttempt(base, { pid: ev.pid }, now),\n state: \"working\",\n pid: ev.pid ?? rec.pid,\n sessionId: ev.sessionId ?? rec.sessionId,\n question: undefined, // resuming after a blocked→reply clears the question\n pendingTool: undefined, // #354: a new turn closes any prior tool window\n };\n case \"task.progress\": {\n // task.progress is a real-activity signal (stdout chunk for headless,\n // PreToolUse/PostToolUse/SubagentStop hook for interactive). Stamp the\n // attempt so lastHeartbeatAt stays current and the watchdog stall-check\n // (#89) can key off it without false-stalling long-running headless tasks.\n // #354: also track the in-flight tool (PreToolUse opens, PostToolUse closes)\n // so a hung tool call is distinguishable from a quiet thinking turn.\n // From blocked: liveness only — do not auto-unblock (explicit reply required).\n // From awaiting-input OR stalled: resume to working — the next real activity\n // (e.g. the matching PostToolUse) auto-clears a hung-tool warn instantly.\n const pendingTool = nextPendingTool(rec.pendingTool, ev, now);\n if (rec.state === \"blocked\") return { ...rec, lastHeartbeat: now, lastEvent: ev.type, pendingTool };\n const b = { ...base, pendingTool };\n if (rec.state === \"awaiting-input\" || rec.state === \"stalled\") return { ...stampAttempt(b, {}, now), state: \"working\" };\n return stampAttempt(b, {}, now);\n }\n case \"heartbeat\":\n // Raw liveness ping — intentionally does NOT stamp the attempt so a late\n // heartbeat from a dead dispatch cannot mask stalls on the new one (#89).\n // From awaiting-input: resume to working (mirrors task.progress).\n if (rec.state === \"blocked\") return { ...rec, lastHeartbeat: now, lastEvent: ev.type };\n if (rec.state === \"awaiting-input\") return { ...base, state: \"working\" };\n return base;\n case \"task.blocked\":\n // ev.reason is protocol/logging-only and intentionally not persisted;\n // only `question` is stored on the record.\n // Idempotency (#174): the explicit `squadrant crew signal blocked` fires\n // BEFORE the turn ends; the auto-detect Stop hook may then re-emit\n // task.blocked on an already-blocked task. Treat a repeat block as a\n // no-op so the FIRST (explicit) question wins and no duplicate CREW\n // BLOCKED fires. Terminal states are already absorbed above.\n if (rec.state === \"blocked\") return { ...rec, lastHeartbeat: now, lastEvent: ev.type };\n return { ...base, state: \"blocked\", question: ev.question, pendingTool: undefined };\n case \"task.done\":\n return { ...base, state: \"done\", resultRef: ev.resultRef, parseWarning: ev.parseWarning };\n case \"task.failed\":\n return { ...base, state: \"failed\", error: ev.error, exitCode: ev.exitCode };\n case \"task.cancelled\":\n return { ...base, state: \"cancelled\" };\n case \"task.session.ended\":\n // #139: the claude crew session ended (SessionEnd hook). The process is\n // gone, so terminalize instead of resuming 'working'. Reuses the silent\n // 'cancelled' state — no alarming push, just a clean terminal record.\n return { ...base, state: \"cancelled\" };\n case \"task.session\":\n return stampAttempt(base, { resumeRef: ev.resumeRef }, now);\n case \"task.turn.started\":\n return { ...stampAttempt(base, {}, now), state: \"working\", pendingTool: undefined };\n case \"task.turn.completed\":\n // Anti-#2576 invariant: TurnCompleted is liveness, NEVER completion. Spec §4.8.\n // A turn ending while blocked must NOT unblock — only the captain's answer\n // (task.started via `crew send`) clears blocked. Mirrors task.progress: the\n // opencode SSE bridge emits task.turn.completed right after an explicit\n // `signal blocked`, and that trailing turn-end must not drop the question.\n if (rec.state === \"blocked\") return { ...rec, lastHeartbeat: now, lastEvent: ev.type };\n return { ...stampAttempt(base, {}, now), state: \"awaiting-input\", pendingTool: undefined };\n case \"task.delta\":\n return stampAttempt(base, {}, now); // heartbeat-only\n case \"task.input.requested\":\n case \"task.approval.requested\":\n return { ...stampAttempt(base, {}, now), state: \"blocked\", question: ev.question, pendingTool: undefined };\n case \"task.reattached\":\n return stampAttempt(base, {}, now);\n case \"task.stalled\":\n case \"task.idle\":\n case \"task.quiet\":\n case \"task.timeout\":\n case \"task.reconcile-failed\":\n // Synthetic notify-only events; the daemon has already updated state\n // directly via the watchdog/reconcile paths (task.quiet carries no state\n // change at all — the crew stays `working`). Reducer is a no-op.\n return rec;\n default:\n // #87: unknown/future event type from the wire — safe no-op.\n // The socket boundary (handle()) validates known types before calling\n // reduce; this default is a deep-defense fallback so reduce() can\n // never return undefined regardless of how it is called.\n return rec;\n }\n}\n","// src/control/watchdog.ts\nimport type { TaskRecord } from \"@squadrant/shared\";\n\n/**\n * #354: how long an interactive tool call may be in flight before it is treated\n * as hung. Deliberately generous (much larger than the 5-min heartbeat budget)\n * so a legitimately long tool — a multi-minute test suite, a big build, a slow\n * git/network op — does NOT trip it: those are real, recoverable work, and the\n * matching PostToolUse auto-clears the warn the instant it returns. Only a tool\n * that produces no result for this long is suspicious enough to surface as\n * \"possibly hung\". Default 10 min; tune via evaluateStall's `toolStallMs`.\n */\nexport const TOOL_STALL_BUDGET_MS = 10 * 60 * 1000;\n\n/**\n * Pure. Returns a stalled-transitioned record if a `working` task is genuinely\n * stuck at time `now` (epoch ms), else null. No I/O, no clock. #354 splits the\n * old single wall-clock timeout by what we can actually prove:\n *\n * - headless → 'stalled' once quiet past the heartbeat budget. A batch child\n * that stops emitting stdout is stuck; there is no captain turn to await.\n * - interactive WITH a tool in flight (pendingTool) → 'stalled' once that tool\n * has been outstanding past `toolStallMs`. A PreToolUse with no matching\n * PostToolUse is a hung tool call (we know which tool). Recoverable: the next\n * PostToolUse recovers it to `working` (state-machine / recoverStall).\n * - interactive with NO tool in flight → null. A quiet thinking turn is alive,\n * not stalled and NOT awaiting-input (the turn never ended — real CREW IDLE\n * comes only from the Stop hook). The daemon sweep surfaces this as a\n * distinct, non-alarming CREW QUIET notify instead (#354), keeping the crew\n * `working`. This replaces the old wall-clock → 'awaiting-input' flip, which\n * mislabeled deep-thinking crews as \"awaiting your input\".\n *\n * This function never produces `failed` or `awaiting-input` directly.\n */\nexport function evaluateStall(\n rec: TaskRecord,\n now: number,\n toolStallMs: number = TOOL_STALL_BUDGET_MS,\n): TaskRecord | null {\n if (rec.state !== \"working\") return null;\n if (rec.mode === \"interactive\") {\n // Only a hung tool call is a stall for an interactive crew; a quiet thinking\n // turn (no pendingTool) is alive and handled by the sweep's CREW QUIET path.\n if (!rec.pendingTool) return null;\n if (now - rec.pendingTool.since <= toolStallMs) return null;\n return { ...rec, state: \"stalled\", lastEvent: \"watchdog.tool-stall\" };\n }\n // headless: key off the latest attempt's lastHeartbeatAt so a stale event from\n // a dead prior attempt cannot refresh the liveness clock of the new dispatch (#89).\n const liveness = rec.attempts.at(-1)?.lastHeartbeatAt ?? rec.lastHeartbeat;\n if (now - liveness <= rec.heartbeatBudgetMs) return null;\n return { ...rec, state: \"stalled\", lastEvent: \"watchdog.stall\" };\n}\n\n/**\n * Pure. A stalled task that receives liveness returns to working.\n *\n * WARNING: this does NOT check heartbeat freshness — it returns a recovered\n * record for ANY stalled task. Callers MUST guard with\n * `now - rec.lastHeartbeat <= rec.heartbeatBudgetMs` before applying the\n * result, or a permanently-stale task will be falsely revived.\n */\nexport function recoverStall(rec: TaskRecord, now: number): TaskRecord | null {\n if (rec.state !== \"stalled\") return null;\n // #354: clear any hung-tool marker on recovery so a recovered crew never\n // carries a stale pendingTool into its next quiet window.\n return { ...rec, state: \"working\", lastHeartbeat: now, lastEvent: \"watchdog.recover\", pendingTool: undefined };\n}\n","// src/control/daemon.ts\nimport type { Store } from \"./store.js\";\nimport type { ControlEvent, TaskRecord, TaskState } from \"@squadrant/shared\";\nimport { TERMINAL_STATES } from \"@squadrant/shared\";\nimport { reduce } from \"./state-machine.js\";\nimport { evaluateStall, recoverStall } from \"./watchdog.js\";\nexport interface DaemonDeps {\n store: Store;\n now: () => number;\n /** Injected in Task 14; resumes a blocked session. Optional until then. */\n deliverReply?: (rec: TaskRecord, message: string) => Promise<void>;\n /** Defaults to a real process.kill(pid,0) check at the call site (Task 17). */\n isPidAlive?: (pid: number) => boolean;\n /**\n * #139 backstop: the interactive analogue of isPidAlive. Resolves whether an\n * interactive crew's backing cmux surface (pane/tab) still exists. Three-valued\n * so a transient cmux outage never false-reaps a live crew:\n * - \"alive\" → the crew's pane is present; keep watching.\n * - \"gone\" → cmux answered AND the pane is provably absent → terminalize.\n * - \"unknown\" → could not determine (cmux down, no captain, error) → do nothing.\n * Defaults to always-\"unknown\" (never reaps) when not wired — pure unit tests\n * and any non-cmux deployment are unaffected.\n */\n isSurfaceAlive?: (rec: TaskRecord) => Promise<\"alive\" | \"gone\" | \"unknown\">;\n /** Wired in squadrantd to runHeadless; absent in pure unit tests. */\n launchHeadless?: (rec: TaskRecord) => Promise<void>;\n /**\n * #259: true when a launchHeadless call for this task ID is currently in\n * flight (process spawned but no pid yet). reconcile() skips these so a\n * crash-restart re-run does NOT mark an actively-launching task as failed\n * and re-dispatch it, multiplying orphaned headless processes.\n * Defaults to () => false when not wired (pure unit tests, non-headless modes).\n */\n isHeadlessInFlight?: (id: string) => boolean;\n /**\n * Forward hook for the deferred interactive-wiring spec. While absent,\n * interactive dispatch fails LOUD (red-team #4) instead of silently\n * black-holing in `submitted` forever.\n */\n launchInteractive?: (rec: TaskRecord) => Promise<void>;\n /**\n * Wired in squadrantd to codexDriver.answer(). Delivers the captain's gate\n * resolution payload back to the interactive session (spec §4.9).\n */\n resolveInteractiveGate?: (taskId: string, payload: unknown) => Promise<void> | void;\n /**\n * Push notification hook (#109, refactored under mailbox-injector spec).\n * Called on every state transition into {done, blocked, failed, stalled}.\n * Implementations append to the mailbox; errors are caught + swallowed here\n * so an unhealthy notifier never breaks the event-ingest path.\n */\n notify?: (args: {\n project: string;\n message: string;\n record: TaskRecord;\n event: ControlEvent;\n }) => Promise<void> | void;\n /**\n * #225 hard crew task-timeout: wall-clock ceiling in ms. When a non-terminal\n * task's age (now - createdAt) exceeds this, the sweep fires a CREW TIMEOUT\n * escalation via the notify hook. Defaults to DEFAULT_TASK_TIMEOUT_MS (8h).\n * Distinct from the per-task heartbeat budget (stall detection).\n */\n taskTimeoutMs?: number;\n}\n\n// #225 hard crew task-timeout: default wall-clock ceiling (8h). A crew can\n// heartbeat continuously yet be stuck on one task — the stall watchdog won't\n// catch it. This ceiling does. Configurable via DaemonDeps.taskTimeoutMs.\nexport const DEFAULT_TASK_TIMEOUT_MS = 8 * 60 * 60 * 1000;\n\n// #378: GC TTL for terminal records (done/failed/cancelled). Records older\n// than this are pruned from the store during sweep().\nexport const TERMINAL_RECORD_TTL_MS = 7 * 24 * 60 * 60 * 1000;\n\n// 'awaiting-input' is an attention state: entering it (idle watchdog OR a\n// Stop-hook turn boundary) fires exactly one accurate CREW IDLE push. The\n// firePush prev===next guard keeps it from re-firing while the task sits idle.\nconst ATTENTION_STATES: ReadonlySet<TaskState> = new Set([\"done\", \"blocked\", \"failed\", \"stalled\", \"awaiting-input\"]);\n\n// #139: non-terminal, post-launch states an interactive crew can be sitting in\n// while its session has actually died. Any of these with a provably-gone surface\n// is a zombie → reap to 'cancelled'. 'submitted' is excluded: it is pre-launch\n// (no surface yet), so reaping it would race the spawn.\nconst REAPABLE_SURFACE_STATES: ReadonlySet<TaskState> = new Set([\"working\", \"stalled\", \"awaiting-input\", \"blocked\"]);\n\n// #210: CREW IDLE (awaiting-input) is debounced — suppressed when the turn-end\n// lands within this window of the captain's own last turn to the crew (a\n// `crew send`/reply emits task.started). This silences the rapid\n// send→respond→turn-end churn of an active back-and-forth while still\n// delivering a genuine self-idle (turn-end / idle-watchdog long after the\n// captain last engaged). Only awaiting-input is debounced; every other\n// attention state always delivers.\nexport const IDLE_DEBOUNCE_MS = 12_000;\n\nfunction shortId(id: string): string {\n return id.slice(0, 8);\n}\n\n/**\n * Build a disambiguated notification tag for a task record. Always appends\n * the short id so reused crew names are distinguishable across distinct ids.\n * Named: [provider/name · shortId] Unnamed: [provider/shortId]\n */\nexport function crewTag(r: TaskRecord): string {\n const suffix = shortId(r.id);\n if (r.name != null) {\n return `[${r.provider}/${r.name} · ${suffix}]`;\n }\n return `[${r.provider}/${suffix}]`;\n}\n\nfunction formatMessage(rec: TaskRecord, event?: ControlEvent): string | null {\n const tag = crewTag(rec);\n switch (rec.state) {\n case \"done\": {\n // Prefer the crew's own done message (`signal done --message`), carried on\n // the task.done event — this is what captains relied on under the old\n // relay formatter and must not regress (#214 unification). The task\n // snippet is the documented fallback when no message was provided.\n const doneMsg = event?.type === \"task.done\" ? event.message : undefined;\n const body =\n doneMsg != null && doneMsg.trim().length > 0\n ? doneMsg.split(/\\r?\\n/)[0].trim().slice(0, 200)\n : ((rec.task ?? \"\").split(/\\r?\\n/)[0]?.trim().slice(0, 120) ?? \"\");\n return `CREW DONE ${tag}: ${body}`;\n }\n case \"blocked\":\n return `CREW BLOCKED ${tag}: ${(rec.question ?? \"(no question)\").trim()}`;\n case \"failed\":\n return `CREW FAILED ${tag}: ${(rec.error ?? \"(no error)\").trim()}`;\n case \"stalled\": {\n // #354: a hung interactive tool call reads differently from a headless\n // heartbeat stall — name the tool and how long it has been outstanding,\n // and frame it as \"possibly hung\" (recoverable, auto-clears on the tool's\n // PostToolUse), NOT a death notice.\n if (event?.type === \"task.stalled\" && event.tool) {\n const mins = event.elapsedMs != null ? Math.max(1, Math.round(event.elapsedMs / 60000)) : null;\n return `CREW STALLED ${tag}: still running ${event.tool}${mins != null ? ` ~${mins}min` : \"\"} — possibly hung (no result yet).`;\n }\n return `CREW STALLED ${tag}: no heartbeat in ${rec.heartbeatBudgetMs}ms`;\n }\n case \"awaiting-input\":\n return `CREW IDLE ${tag}: turn ended / awaiting your input — review and reply or close.`;\n default:\n return null;\n }\n}\n\n/** #246: cross-project delegation report-back message. Called when a task\n * with originProject settles to a terminal state. Returns a captain-facing\n * one-liner delivered verbatim to the origin project's captain. */\nfunction formatDelegationReport(rec: TaskRecord, originProject: string, targetProject: string): string | null {\n const shortTask = (rec.task ?? \"\").split(/\\r?\\n/)[0]?.trim().slice(0, 120) ?? \"\";\n switch (rec.state) {\n case \"done\":\n return `✅ Cross-project task → ${targetProject}: done — ${shortTask}`;\n case \"blocked\":\n return `⛔ Cross-project task → ${targetProject}: blocked — ${(rec.question ?? \"(no question)\").trim()}`;\n case \"failed\":\n return `⛔ Cross-project task → ${targetProject}: failed — ${(rec.error ?? \"(no error)\").trim()}`;\n case \"stalled\":\n return `⚠️ Cross-project task → ${targetProject}: stalled (no heartbeat in ${rec.heartbeatBudgetMs}ms)`;\n default:\n return null;\n }\n}\n\nfunction firePush(\n deps: DaemonDeps,\n project: string,\n prev: TaskState,\n next: TaskRecord,\n event: ControlEvent,\n lastCaptainTurnAt?: number,\n): void {\n if (!deps.notify) return;\n if (prev === next.state) return;\n if (!ATTENTION_STATES.has(next.state)) return;\n // #210 idle debounce: a turn-end (awaiting-input) within IDLE_DEBOUNCE_MS of\n // the captain's last turn is part of an active back-and-forth — suppress the\n // CREW IDLE. All other attention states are never debounced.\n if (\n next.state === \"awaiting-input\" &&\n lastCaptainTurnAt != null &&\n deps.now() - lastCaptainTurnAt <= IDLE_DEBOUNCE_MS\n ) {\n return;\n }\n const message = formatMessage(next, event);\n if (!message) return;\n // Fire-and-forget; swallow errors so the daemon never trips on a flaky\n // notifier. Sync throws and async rejections both land here.\n try {\n const r = deps.notify({ project, message, record: next, event });\n if (r && typeof (r as Promise<void>).catch === \"function\") {\n (r as Promise<void>).catch(() => {});\n }\n } catch {\n // intentionally swallowed\n }\n // #246: cross-project delegation report-back. When a delegated task settles\n // (done/blocked/failed/stalled/cancelled), fan the outcome back to the origin\n // project's mailbox so A's relay wakes A's captain (dispatch-and-yield, never\n // poll). 'awaiting-input' is excluded — the origin doesn't need a noise push\n // every time the target crew ends a turn.\n const reportState = next.state === \"done\" || next.state === \"blocked\" || next.state === \"failed\" || next.state === \"stalled\" || next.state === \"cancelled\";\n if (next.originProject && next.originProject !== project && reportState) {\n const originMsg = formatDelegationReport(next, next.originProject, project);\n if (originMsg && deps.notify) {\n try {\n const r = deps.notify({ project: next.originProject, message: originMsg, record: next, event });\n if (r && typeof (r as Promise<void>).catch === \"function\") (r as Promise<void>).catch(() => {});\n } catch { /* swallowed */ }\n }\n }\n}\n\ntype Req =\n | { kind: \"dispatch\"; record: TaskRecord }\n | { kind: \"event\"; project: string; event: ControlEvent }\n | { kind: \"status\"; project: string; id: string }\n | { kind: \"list\"; project: string }\n | { kind: \"reply\"; project: string; id: string; message: string }\n | { kind: \"gate-resolve\"; project: string; gateId: string; resolvedBy: string; payload: unknown }\n | { kind: \"purge\"; project: string; id: string; force?: boolean };\n\n// #87: exhaustive set of known ControlEvent types for socket-boundary validation.\n// Any event.type arriving from the wire that is not in this set is rejected with\n// a clean structured error before it can reach reduce() or the store.\nconst KNOWN_EVENT_TYPES: ReadonlySet<string> = new Set([\n \"task.started\", \"task.progress\", \"heartbeat\",\n \"task.blocked\", \"task.done\", \"task.failed\",\n \"task.session\", \"task.turn.started\", \"task.turn.completed\",\n \"task.delta\", \"task.input.requested\", \"task.approval.requested\",\n \"task.reattached\", \"task.reopened\",\n \"task.stalled\", \"task.idle\", \"task.quiet\", \"task.timeout\", \"task.reconcile-failed\",\n \"task.cancelled\", \"task.session.ended\",\n]);\n\nexport function createDaemon(deps: DaemonDeps) {\n const { store, now } = deps;\n // #210: per-task timestamp of the captain's most recent turn (a `crew send`/\n // reply/answer emits task.started). Used to debounce CREW IDLE during an\n // active back-and-forth. Bounded by the live task set; never read after a\n // task terminates (terminal states don't transition to awaiting-input).\n const lastCaptainTurnAt = new Map<string, number>();\n // #354: per-task debounce for CREW QUIET. Keyed to the liveness timestamp of\n // the quiet episode so exactly one QUIET fires per episode; when the crew shows\n // activity again, liveness advances and a later quiet episode re-notifies.\n const quietNotifiedAt = new Map<string, number>();\n return {\n async handle(req: Req): Promise<TaskRecord | TaskRecord[]> {\n switch (req.kind) {\n case \"dispatch\": {\n store.put(req.record);\n // #246: cross-project delegation — notify B's mailbox so B's relay\n // wakes B's captain with the request. Skip auto-launch; B's captain\n // decides how to execute (typically spawns a crew).\n if (req.record.originProject) {\n const origin = req.record.originProject;\n const msg = `📨 Cross-project task from ${origin}: ${req.record.task}`;\n if (deps.notify) {\n try {\n const r = deps.notify({ project: req.record.project, message: msg, record: req.record, event: { type: \"task.started\", id: req.record.id } });\n if (r && typeof (r as Promise<void>).catch === \"function\") (r as Promise<void>).catch(() => {});\n } catch { /* swallowed — flaky notifier must not break dispatch */ }\n }\n return req.record;\n }\n if (req.record.mode === \"headless\" && deps.launchHeadless) {\n deps.launchHeadless(req.record).catch((e: unknown) => {\n const error = e instanceof Error ? e.message : String(e);\n store.put({ ...req.record, state: \"failed\", lastEvent: \"launch-error\", error });\n });\n return req.record;\n }\n if (req.record.mode === \"interactive\" && deps.launchInteractive) {\n deps.launchInteractive(req.record).catch((e: unknown) => {\n const error = e instanceof Error ? e.message : String(e);\n store.put({ ...req.record, state: \"failed\", lastEvent: \"launch-error\", error });\n });\n return req.record;\n }\n // No launcher for this mode → fail LOUD, never silently park in\n // `submitted` (red-team #4). Interactive launcher is the deferred\n // interactive-wiring spec; until then, say so explicitly.\n const failed: TaskRecord = {\n ...req.record,\n state: \"failed\",\n lastEvent: \"no-launcher\",\n error:\n req.record.mode === \"interactive\"\n ? \"interactive mode is not yet implemented (deferred interactive-wiring spec); use --mode headless\"\n : `no launcher available for mode '${req.record.mode}'`,\n };\n store.put(failed);\n return failed;\n }\n case \"event\": {\n // #87: validate event.type at the socket boundary before touching state.\n if (!KNOWN_EVENT_TYPES.has((req.event as any).type)) {\n throw new Error(`unknown event type '${(req.event as any).type}' — not a valid ControlEvent`);\n }\n const cur = store.get(req.project, req.event.id);\n if (!cur) throw new Error(`unknown task ${req.event.id}`);\n // A captain turn (crew send/reply) arrives as task.started → record it\n // so a quick trailing turn-end is debounced (#210).\n if (req.event.type === \"task.started\") lastCaptainTurnAt.set(req.event.id, now());\n // #227: gate SessionEnd behind surface-liveness — only terminalize\n // when the surface is provably GONE. Prevents a nested/spurious\n // SessionEnd from false-cancelling a live crew while preserving the\n // #139 dead-crew behavior. \"unknown\" never cancels (transient cmux\n // outage), identical to the sweep reaper's semantics.\n if (req.event.type === \"task.session.ended\" && !TERMINAL_STATES.has(cur.state)) {\n const liveness = deps.isSurfaceAlive ? await deps.isSurfaceAlive(cur) : \"unknown\";\n if (liveness !== \"gone\") return cur; // alive/unknown: no-op, keep current state\n }\n const next = reduce(cur, req.event, now());\n if (next !== cur) {\n store.put(next); // skip redundant write on terminal no-ops\n firePush(deps, req.project, cur.state, next, req.event, lastCaptainTurnAt.get(next.id));\n }\n return next;\n }\n case \"status\": {\n const r = store.get(req.project, req.id);\n if (!r) throw new Error(`unknown task ${req.id}`);\n return r;\n }\n case \"list\":\n return store.list(req.project);\n case \"reply\": {\n const r = store.get(req.project, req.id);\n if (!r) throw new Error(`unknown task ${req.id}`);\n if (r.state !== \"blocked\") throw new Error(`task ${req.id} is not blocked (state=${r.state})`);\n // The captain's answer is a turn to the crew (#210 debounce key).\n lastCaptainTurnAt.set(r.id, now());\n const next = reduce(r, { type: \"task.started\", id: r.id }, now());\n store.put(next); // persist the transition before delivering (durable first)\n if (deps.deliverReply) await deps.deliverReply(r, req.message);\n return next;\n }\n case \"gate-resolve\": {\n // Find the task that owns this gate.\n const owning = deps.store.listAll().find((r) => r.gates?.some((g) => g.gateId === req.gateId));\n if (!owning || !owning.gates) throw new Error(`gate ${req.gateId} not found`);\n const updatedGates = owning.gates.map((g) =>\n g.gateId === req.gateId\n ? { ...g, state: \"resolved\" as const, resolvedBy: req.resolvedBy, resolution: req.payload }\n : g,\n );\n deps.store.put({ ...owning, gates: updatedGates });\n // Driver answers via the saved requestId (it tracks it per-task internally).\n if (deps.resolveInteractiveGate) await deps.resolveInteractiveGate(owning.id, req.payload);\n return { ...owning, gates: updatedGates };\n }\n case \"purge\": {\n const r = store.get(req.project, req.id);\n if (!r) throw new Error(`unknown task ${req.id}`);\n if (!TERMINAL_STATES.has(r.state) && !req.force) {\n throw new Error(`task ${req.id} is not terminal (state=${r.state}); use --force to purge anyway`);\n }\n store.delete(req.project, req.id);\n return r;\n }\n default: { const _exhaustive: never = req; throw new Error(`unhandled request kind`); }\n }\n },\n async sweep(): Promise<void> {\n const t = now();\n const surfaceAlive = deps.isSurfaceAlive ?? (async () => \"unknown\" as const);\n for (const r of store.listAll()) {\n // #378: GC terminal records whose last heartbeat is older than the TTL.\n if (TERMINAL_STATES.has(r.state) && t - r.lastHeartbeat > TERMINAL_RECORD_TTL_MS) {\n store.delete(r.project, r.id);\n continue;\n }\n // #225 root-fix: terminate non-terminal tasks that exceeded the wall-clock\n // ceiling. Terminalization is the persistent dedup — a daemon restart sees\n // the cancelled record and the TERMINAL_STATES gate above blocks re-fire.\n // The volatile firedTimeout Set is removed; terminal state replaces it.\n if (!TERMINAL_STATES.has(r.state)) {\n const ceiling = deps.taskTimeoutMs ?? DEFAULT_TASK_TIMEOUT_MS;\n if (t - r.createdAt > ceiling) {\n const prevState = r.state; // capture BEFORE terminalization (shown in message)\n const tag = crewTag(r);\n const hrs = Math.round(ceiling / 3_600_000);\n const msg = `CREW TIMEOUT ${tag}: wall-clock exceeded ${hrs}h (id: ${r.id}, state: ${prevState})`;\n const synthEvent: ControlEvent = { type: \"task.timeout\", id: r.id, taskTimeoutMs: ceiling };\n // Terminalize first — persisted to store so any future daemon instance\n // sees a terminal record and skips it (flood-proof across restarts).\n store.put({ ...r, state: \"cancelled\", lastEvent: \"sweep.task-timeout\" });\n if (deps.notify) {\n try {\n const p = deps.notify({ project: r.project, message: msg, record: r, event: synthEvent });\n if (p && typeof (p as Promise<void>).catch === \"function\") {\n (p as Promise<void>).catch(() => {});\n }\n } catch {\n // swallowed — a flaky notifier must never trip the sweep\n }\n }\n continue; // #378: skip remaining sweep body — stale `r` must not clobber just-written terminal state\n }\n }\n // #139 backstop: reap interactive records whose backing surface is\n // PROVABLY gone (crew session died with no terminal signal — opencode has\n // no SessionEnd hook, and a hard kill can drop claude's). This is\n // liveness-based reaping, NOT a shorter timeout: the 24h heartbeat budget\n // is untouched, so a legitimately-idle LIVE crew is never reaped (its\n // surface answers \"alive\" and falls through to evaluateStall → CREW IDLE).\n // \"unknown\" (cmux down) never reaps. cancelled is silent (not in\n // ATTENTION_STATES) — no false CREW STALLED re-emitted.\n if (r.mode === \"interactive\" && REAPABLE_SURFACE_STATES.has(r.state)) {\n const liveness = await surfaceAlive(r);\n if (liveness === \"gone\") {\n store.put({ ...r, state: \"cancelled\", lastEvent: \"sweep.surface-gone\" });\n continue;\n }\n }\n // #354: evaluateStall now only stalls a HEADLESS heartbeat timeout or a\n // hung INTERACTIVE tool call (PreToolUse with no PostToolUse past the\n // tool-stall budget). A quiet interactive thinking turn no longer stalls\n // here — it is surfaced as CREW QUIET below, keeping the crew `working`.\n const idle = evaluateStall(r, t);\n if (idle) {\n store.put(idle);\n // The synth event only carries the notify payload; the reducer treats\n // it as a no-op (state already updated above). A hung-tool stall carries\n // the tool name + elapsed so the notifier renders the accurate message.\n const synthEvent: ControlEvent = idle.pendingTool\n ? { type: \"task.stalled\", id: r.id, heartbeatBudgetMs: r.heartbeatBudgetMs, tool: idle.pendingTool.name, elapsedMs: t - idle.pendingTool.since }\n : { type: \"task.stalled\", id: r.id, heartbeatBudgetMs: r.heartbeatBudgetMs };\n firePush(deps, r.project, r.state, idle, synthEvent, lastCaptainTurnAt.get(r.id));\n continue;\n }\n // #354 CREW QUIET: a `working` interactive crew quiet past its heartbeat\n // budget with NO tool in flight is alive but deep-thinking (no hook fires\n // during pure model thinking). Surface a distinct, non-alarming nudge —\n // NOT 'awaiting-input' (the turn never ended; real CREW IDLE comes only\n // from the Stop hook). State stays `working`; notify once per episode.\n if (r.mode === \"interactive\" && r.state === \"working\" && !r.pendingTool) {\n const liveness = r.attempts.at(-1)?.lastHeartbeatAt ?? r.lastHeartbeat;\n const quiet = t - liveness;\n if (quiet > r.heartbeatBudgetMs) {\n if (deps.notify && quietNotifiedAt.get(r.id) !== liveness) {\n quietNotifiedAt.set(r.id, liveness);\n const tag = crewTag(r);\n const mins = Math.max(1, Math.round(quiet / 60000));\n const message = `CREW QUIET ${tag}: working ~${mins}min with no tool activity — likely deep thinking (no reply expected yet).`;\n const synthEvent: ControlEvent = { type: \"task.quiet\", id: r.id, quietMs: quiet };\n try {\n const p = deps.notify({ project: r.project, message, record: r, event: synthEvent });\n if (p && typeof (p as Promise<void>).catch === \"function\") (p as Promise<void>).catch(() => {});\n } catch { /* swallowed — a flaky notifier must never trip the sweep */ }\n }\n continue;\n }\n }\n // Activity resumed (or never went quiet) → drop any QUIET debounce marker\n // so the next genuine quiet episode notifies again, and avoid map growth.\n if (quietNotifiedAt.has(r.id)) quietNotifiedAt.delete(r.id);\n const recovered = recoverStall(r, t);\n // recoverStall does NOT check heartbeat freshness — guard per its contract\n if (recovered && t - r.lastHeartbeat <= r.heartbeatBudgetMs) store.put(recovered);\n }\n },\n async reconcile(): Promise<void> {\n const alive = deps.isPidAlive ?? (() => true);\n const surfaceAlive = deps.isSurfaceAlive ?? (async () => \"unknown\" as const);\n for (const r of store.listAll()) {\n if (r.state !== \"working\" && r.state !== \"submitted\") continue;\n if (r.mode === \"headless\") {\n if (r.pid != null && alive(r.pid)) continue; // still running, keep watching\n if (deps.isHeadlessInFlight?.(r.id)) continue; // #259: launch in-flight, pid not yet set\n const failed: TaskRecord = {\n ...r, state: \"failed\", lastEvent: \"reconcile\",\n error: \"orphaned by daemon restart; exit unobserved (conservative fail)\",\n };\n store.put(failed);\n const synthEvent: ControlEvent = {\n type: \"task.failed\",\n id: r.id,\n error: failed.error ?? \"reconcile\",\n };\n firePush(deps, r.project, r.state, failed, synthEvent, lastCaptainTurnAt.get(r.id));\n } else {\n // #139: an interactive crew's cmux pane SURVIVES a daemon bounce, so a\n // live crew must stay 'working' for the reattach loop to re-subscribe\n // it. The old unconditional → 'stalled' both false-stalled live crews\n // AND fired CREW STALLED on every restart. Reap ONLY when the surface\n // is provably gone; alive/unknown stay working (sweep re-checks later).\n const liveness = await surfaceAlive(r);\n if (liveness === \"gone\") {\n store.put({ ...r, state: \"cancelled\", lastEvent: \"reconcile.surface-gone\" });\n // silent — the crew is gone; no alarming push (consistent with close).\n }\n }\n }\n },\n };\n}\n","import { promises as fs } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { randomUUID } from \"node:crypto\";\nimport type { TaskRecord, ControlEvent } from \"@squadrant/shared\";\n\nexport interface MailboxEntry {\n seq: number;\n ts: string;\n /** Absent on external (captain.message) entries — they have no task. */\n taskId?: string;\n /** Optional human-readable name carried from TaskRecord. Absent on legacy\n * records — readers must fall back to shortId(taskId). */\n name?: string;\n /** \"captain.message\" is an external (non-ControlEvent) message injected for the\n * captain — e.g. an inbound Telegram reply. */\n kind: ControlEvent[\"type\"] | \"captain.message\";\n /** Absent on external entries — no originating agent provider. */\n provider?: TaskRecord[\"provider\"];\n /** Absent/free-form on external entries. */\n payload?: Record<string, unknown>;\n /** Daemon-rendered captain-facing message (unified-formatter, #214/#210).\n * The daemon's formatMessage is the single source of truth; the relay\n * delivers this verbatim and skips entries where it is null/empty.\n * `null` on entries the daemon chose not to surface (and legacy records). */\n message?: string | null;\n}\n\ninterface AppendOpts {\n stateRoot: string;\n project: string;\n taskRecord: TaskRecord;\n event: ControlEvent;\n /** Captain-facing message rendered by the daemon (daemon.ts formatMessage). */\n message?: string | null;\n}\n\nfunction inboxDir(stateRoot: string): string {\n return join(stateRoot, \"inbox\");\n}\n\nfunction logPath(stateRoot: string, project: string): string {\n return join(inboxDir(stateRoot), `${project}.log`);\n}\n\nfunction extractPayload(event: ControlEvent): Record<string, unknown> {\n const { type: _type, id: _id, ...payload } = event as Record<string, unknown> & { type: string; id: string };\n return payload;\n}\n\nasync function listRotatedOldestFirst(stateRoot: string, project: string): Promise<string[]> {\n const dir = inboxDir(stateRoot);\n let entries: string[];\n try { entries = await fs.readdir(dir); }\n catch { return []; }\n const prefix = `${project}.log.`;\n return entries\n .filter((e) => e.startsWith(prefix) && /^\\d+$/.test(e.slice(prefix.length)))\n .map((e) => ({ name: e, n: Number(e.slice(prefix.length)) }))\n .sort((a, b) => b.n - a.n) // .3 first (oldest), .1 last (newest rotated)\n .map((e) => join(dir, e.name));\n}\n\nasync function readMaxSeqFromFile(file: string): Promise<number> {\n try {\n const buf = await fs.readFile(file, \"utf-8\");\n if (!buf.trim()) return 0;\n const lines = buf.trim().split(\"\\n\");\n for (let i = lines.length - 1; i >= 0; i--) {\n try {\n const obj = JSON.parse(lines[i]) as MailboxEntry;\n return obj.seq;\n } catch { continue; }\n }\n return 0;\n } catch (e) {\n if ((e as NodeJS.ErrnoException).code === \"ENOENT\") return 0;\n throw e;\n }\n}\n\nasync function readMaxSeq(stateRoot: string, project: string): Promise<number> {\n let max = 0;\n const files = [\n logPath(stateRoot, project),\n ...(await listRotatedOldestFirst(stateRoot, project)),\n ];\n for (const file of files) {\n const seq = await readMaxSeqFromFile(file);\n if (seq > max) max = seq;\n }\n return max;\n}\n\n// Per-project serial mutex. Node's event loop is single-threaded but async\n// readFile + writeFile can interleave; chaining all appends for the same\n// project through a single in-process Promise serializes them.\n//\n// For cross-process serialization (multi-daemon scenarios, e.g. launchctl\n// restart races), an OS-level flock would be needed on `<project>.log`.\n// Today squadrant runs a single daemon instance; the in-process mutex covers\n// the realistic concurrency model. flock can be added later if multi-process\n// access becomes a requirement.\nconst projectLocks = new Map<string, Promise<unknown>>();\n\nfunction withProjectLock<T>(project: string, fn: () => Promise<T>): Promise<T> {\n const prev = projectLocks.get(project) ?? Promise.resolve();\n const next = prev.catch(() => undefined).then(fn);\n // Store a tail that does not reject so the chain never breaks on caller failure\n projectLocks.set(project, next.catch(() => undefined));\n return next;\n}\n\n/** Assign a monotonic seq under the per-project lock and append the built entry. */\nfunction appendEntry(\n stateRoot: string,\n project: string,\n build: (seq: number) => MailboxEntry,\n): Promise<number> {\n return withProjectLock(project, async () => {\n const dir = inboxDir(stateRoot);\n await fs.mkdir(dir, { recursive: true });\n const file = logPath(stateRoot, project);\n const lastSeq = await readMaxSeq(stateRoot, project);\n const seq = lastSeq + 1;\n const entry = build(seq);\n await fs.appendFile(file, JSON.stringify(entry) + \"\\n\", { encoding: \"utf-8\" });\n return seq;\n });\n}\n\nexport async function appendToMailbox(opts: AppendOpts): Promise<number> {\n return appendEntry(opts.stateRoot, opts.project, (seq) => ({\n seq,\n ts: new Date().toISOString(),\n taskId: opts.taskRecord.id,\n ...(opts.taskRecord.name !== undefined ? { name: opts.taskRecord.name } : {}),\n kind: opts.event.type,\n provider: opts.taskRecord.provider,\n payload: extractPayload(opts.event),\n message: opts.message ?? null,\n }));\n}\n\n/**\n * Append an external message destined for the captain pane (#65 Telegram inbound).\n * `text` is the already-rendered captain-facing message; it is delivered verbatim\n * by the #332 delivery loop (deliverable() returns it, defer-protected). The entry\n * carries no taskId/provider — it is not tied to a crew task.\n */\nexport async function appendCaptainMessage(opts: {\n stateRoot: string;\n project: string;\n text: string;\n source: \"telegram\";\n}): Promise<void> {\n await appendEntry(opts.stateRoot, opts.project, (seq) => ({\n seq,\n ts: new Date().toISOString(),\n kind: \"captain.message\",\n payload: { source: opts.source },\n message: opts.text,\n }));\n}\n\nfunction cursorPath(stateRoot: string, project: string, subscriber: string): string {\n return join(inboxDir(stateRoot), `${project}.${subscriber}.cursor`);\n}\n\ninterface CursorOpts {\n stateRoot: string;\n project: string;\n subscriber: string;\n}\n\nexport interface CursorState {\n lastAckedSeq: number;\n subscriber: string;\n updatedAt: string;\n}\n\nexport async function readCursor(opts: CursorOpts): Promise<CursorState | null> {\n let buf: string;\n try {\n buf = await fs.readFile(cursorPath(opts.stateRoot, opts.project, opts.subscriber), \"utf-8\");\n } catch (e) {\n if ((e as NodeJS.ErrnoException).code === \"ENOENT\") return null;\n throw e;\n }\n // A 0-byte or corrupt cursor (e.g. an interrupted write) must be treated the\n // same as a missing one — return null so the caller starts fresh from seq 0\n // rather than crashing the relay boot / delivery loop (#332 storm BUG 1).\n if (!buf.trim()) return null;\n try {\n return JSON.parse(buf) as CursorState;\n } catch {\n return null;\n }\n}\n\nexport async function writeCursor(opts: CursorOpts & { lastAckedSeq: number }): Promise<void> {\n await fs.mkdir(inboxDir(opts.stateRoot), { recursive: true });\n const dest = cursorPath(opts.stateRoot, opts.project, opts.subscriber);\n // Unique tmp per call so overlapping writes never share a tmp path. A shared\n // `dest + \".tmp\"` let one rename consume the tmp the other expected → ENOENT\n // on rename, leaving a 0-byte/corrupt cursor (#332 storm BUG 2).\n const tmp = `${dest}.${process.pid}.${randomUUID()}.tmp`;\n const data: CursorState = {\n lastAckedSeq: opts.lastAckedSeq,\n subscriber: opts.subscriber,\n updatedAt: new Date().toISOString(),\n };\n const handle = await fs.open(tmp, \"w\");\n try {\n await handle.writeFile(JSON.stringify(data), { encoding: \"utf-8\" });\n await handle.sync();\n } finally {\n await handle.close();\n }\n try {\n await fs.rename(tmp, dest);\n } catch (e) {\n // Best-effort cleanup so a failed rename doesn't leave the unique tmp behind.\n await fs.unlink(tmp).catch(() => {});\n throw e;\n }\n}\n\ninterface ReadFromCursorOpts {\n stateRoot: string;\n project: string;\n fromSeq: number;\n}\n\nexport async function* readFromCursor(opts: ReadFromCursorOpts): AsyncIterable<MailboxEntry> {\n // Order: oldest rotated first (.3 → .2 → .1), then current.\n const rotated = await listRotatedOldestFirst(opts.stateRoot, opts.project);\n const files = [...rotated, logPath(opts.stateRoot, opts.project)];\n for (const file of files) {\n let buf: string;\n try {\n buf = await fs.readFile(file, \"utf-8\");\n } catch (e) {\n if ((e as NodeJS.ErrnoException).code === \"ENOENT\") continue;\n throw e;\n }\n for (const line of buf.split(\"\\n\")) {\n if (!line.trim()) continue;\n let entry: MailboxEntry;\n try {\n entry = JSON.parse(line) as MailboxEntry;\n } catch {\n continue;\n }\n if (entry.seq >= opts.fromSeq) yield entry;\n }\n }\n}\n\n/** Read-only Tier 2 observability stats for one project's mailbox (#44 dashboard). */\nexport interface MailboxStats {\n /** Highest seq across the current log + rotated segments (0 when empty). */\n maxSeq: number;\n /** Size in bytes of the current (un-rotated) log file. */\n sizeBytes: number;\n /** Age of the oldest entry in the current log (0 when empty/missing). */\n oldestEntryAgeMs: number;\n /** Number of rotated segments on disk (<project>.log.1, .2, …). */\n rotationCount: number;\n}\n\n/**\n * Read-only stats for the dashboard's Tier 2 data-plane view. Never mutates;\n * tolerates a missing inbox (returns zeros). The daemon gathers this and passes\n * it to the pure snapshot assembler.\n */\nexport async function mailboxStats(stateRoot: string, project: string): Promise<MailboxStats> {\n const file = logPath(stateRoot, project);\n let sizeBytes = 0;\n try { sizeBytes = (await fs.stat(file)).size; }\n catch (e) { if ((e as NodeJS.ErrnoException).code !== \"ENOENT\") throw e; }\n const rotated = await listRotatedOldestFirst(stateRoot, project);\n return {\n maxSeq: await readMaxSeq(stateRoot, project),\n sizeBytes,\n oldestEntryAgeMs: await oldestEntryAgeMs(file),\n rotationCount: rotated.length,\n };\n}\n\ninterface RotateOpts {\n stateRoot: string;\n project: string;\n maxBytes: number;\n maxAgeMs: number;\n keepCount: number;\n}\n\nexport interface RotateResult {\n rotated: boolean;\n from?: string;\n to?: string;\n}\n\nasync function oldestEntryAgeMs(file: string): Promise<number> {\n try {\n const buf = await fs.readFile(file, \"utf-8\");\n const firstLine = buf.split(\"\\n\").find((l) => l.trim());\n if (!firstLine) return 0;\n const entry = JSON.parse(firstLine) as MailboxEntry;\n return Date.now() - new Date(entry.ts).getTime();\n } catch {\n return 0;\n }\n}\n\nexport async function rotateIfNeeded(opts: RotateOpts): Promise<RotateResult> {\n return withProjectLock(opts.project, async () => {\n const file = logPath(opts.stateRoot, opts.project);\n let size = 0;\n try { size = (await fs.stat(file)).size; }\n catch (e) {\n if ((e as NodeJS.ErrnoException).code === \"ENOENT\") return { rotated: false };\n throw e;\n }\n const age = await oldestEntryAgeMs(file);\n if (size < opts.maxBytes && age < opts.maxAgeMs) return { rotated: false };\n\n // Shift existing .N files down (.N → .N+1), deleting anything beyond keepCount.\n // Process highest N first so we don't clobber.\n // Find the existing max N.\n const existing = await listRotatedOldestFirst(opts.stateRoot, opts.project);\n // existing is sorted by N desc (oldest first). Extract numbers.\n const nums = existing.map((p) => Number(p.slice(p.lastIndexOf(\".\") + 1))).sort((a, b) => b - a);\n for (const n of nums) {\n const src = `${file}.${n}`;\n const dst = `${file}.${n + 1}`;\n if (n + 1 > opts.keepCount) {\n try { await fs.unlink(src); } catch (e) {\n if ((e as NodeJS.ErrnoException).code !== \"ENOENT\") throw e;\n }\n } else {\n try { await fs.rename(src, dst); } catch (e) {\n if ((e as NodeJS.ErrnoException).code !== \"ENOENT\") throw e;\n }\n }\n }\n // current → .1\n await fs.rename(file, `${file}.1`);\n // create fresh empty current\n await fs.writeFile(file, \"\", { encoding: \"utf-8\" });\n return { rotated: true, from: file, to: `${file}.1` };\n });\n}\n","// src/control/protocol.ts\nimport { createServer, createConnection, type Server, type Socket } from \"node:net\";\nimport { existsSync, unlinkSync } from \"node:fs\";\n\n// Bump this on any change to the request/reply wire shape.\n// v1 is the first versioned release. Clients treat an absent _v as compatible\n// (pre-v1 rollout grace period); future bumps hard-fail on mismatch.\nexport const PROTOCOL_VERSION = 1;\n\nexport function encodeMsg(obj: unknown): string {\n return JSON.stringify(obj) + \"\\n\";\n}\n\nexport function createDecoder(onParseError?: (line: string) => void) {\n let buf = \"\";\n return {\n push(chunk: string): unknown[] {\n buf += chunk;\n const out: unknown[] = [];\n let idx: number;\n while ((idx = buf.indexOf(\"\\n\")) >= 0) {\n const line = buf.slice(0, idx);\n buf = buf.slice(idx + 1);\n if (!line.trim()) continue;\n try {\n const parsed = JSON.parse(line);\n // Silently discard keepalive frames (#94) — never surface to any consumer.\n if (typeof parsed === \"object\" && parsed !== null && (parsed as any).type === \"_keepalive\") continue;\n out.push(parsed);\n } catch {\n // #87: notify caller of malformed lines so the server can reply with a\n // structured error instead of silently dropping the frame.\n onParseError?.(line);\n }\n }\n return out;\n },\n // #87: exposes the unprocessed buffer content — bytes received but not yet\n // terminated with a newline. The server checks this on connection end to\n // detect newline-less input and reply with a fast structured error.\n remainder(): string {\n return buf;\n },\n };\n}\n\nexport type Handler = (msg: any) => Promise<unknown>;\n\n/** NetConn is the raw socket for a single client connection. */\nexport type NetConn = Socket;\n\n/** Injectable clock for startServer — lets tests drive keepalive timers without real timers. */\nexport interface ServerDeps {\n setInterval?: (fn: () => void, ms: number) => ReturnType<typeof setInterval>;\n clearInterval?: (id: ReturnType<typeof setInterval>) => void;\n}\n\n/**\n * Optional callbacks for long-lived attach connections (spec §4.5/§4.6).\n * When a connection sends {op:\"attach\",taskId} the socket is \"claimed\" by\n * the attach path and all subsequent frames on that socket are routed to\n * onAttachInbound rather than through the normal request/response handler.\n */\nexport interface ServerCallbacks {\n /** Normal request/response handler (required). */\n handler: Handler;\n /** Called once when a connection sends the {op:\"attach\",taskId} frame. */\n onAttach?: (conn: NetConn, frame: { op: \"attach\"; taskId: string }) => void;\n /** Called for every subsequent inbound frame on a claimed attach connection. */\n onAttachInbound?: (conn: NetConn, frame: AttachInbound) => void;\n /** Called when a claimed attach connection closes. */\n onAttachClose?: (conn: NetConn) => void;\n}\n\n/**\n * Red-team #2 (High): an unhandled server `error` (e.g. listen EADDRINUSE when\n * a second daemon races in) became an uncaughtException → process died →\n * launchd KeepAlive (no ThrottleInterval) tight-respawned = the crash-loop.\n * Default: log with timestamp and exit non-zero so launchd's ThrottleInterval\n * paces the restart instead of tight-looping. Tests inject a spy.\n */\nexport function defaultListenError(e: Error): void {\n process.stderr.write(`[squadrantd] ${new Date().toISOString()} server error: ${e.message}\\n`);\n process.exit(1);\n}\n\nexport function startServer(\n sockPath: string,\n handlerOrCallbacks: Handler | ServerCallbacks,\n onListenError: (e: Error) => void = defaultListenError,\n deps: ServerDeps = {},\n): Server {\n // Back-compat: accept a plain function as well as a ServerCallbacks object.\n const callbacks: ServerCallbacks =\n typeof handlerOrCallbacks === \"function\"\n ? { handler: handlerOrCallbacks }\n : handlerOrCallbacks;\n const { handler, onAttach, onAttachInbound, onAttachClose } = callbacks;\n const setIntervalFn = deps.setInterval ?? setInterval;\n const clearIntervalFn = deps.clearInterval ?? clearInterval;\n\n if (existsSync(sockPath)) {\n try { unlinkSync(sockPath); } catch { /* stale socket */ }\n }\n const server = createServer((conn) => {\n conn.setEncoding(\"utf-8\");\n let claimType: \"none\" | \"attach\" = \"none\";\n let keepaliveId: ReturnType<typeof setInterval> | undefined;\n\n // #87: reply with a structured error when a newline-terminated line fails to\n // parse as JSON, so the client gets a fast error instead of a silent drop.\n const dec = createDecoder((badLine) => {\n if (claimType !== \"attach\") {\n try {\n conn.write(encodeMsg({ ok: false, error: `malformed request: invalid JSON`, _v: PROTOCOL_VERSION }));\n } catch { /* conn already closed */ }\n }\n });\n\n conn.on(\"data\", async (chunk: string) => {\n for (const msg of dec.push(chunk)) {\n // If already claimed by attach, route all frames to the inbound handler.\n if (claimType === \"attach\") {\n onAttachInbound?.(conn, msg as AttachInbound);\n continue;\n }\n // Check for attach-claim frame BEFORE falling through to req/res.\n if (\n onAttach &&\n msg != null &&\n typeof msg === \"object\" &&\n (msg as any).op === \"attach\" &&\n typeof (msg as any).taskId === \"string\"\n ) {\n claimType = \"attach\";\n onAttach(conn, msg as { op: \"attach\"; taskId: string });\n // Start keepalive heartbeat for held-open attach connections (#94).\n keepaliveId = setIntervalFn(() => {\n try { conn.write(encodeFrame({ type: \"_keepalive\" })); } catch { /* conn closed */ }\n }, 10_000);\n continue;\n }\n // Normal request/response path.\n // #259: both writes are wrapped — a destroyed socket can throw synchronously\n // (write-after-end); that throw would escape the async data handler and become\n // an unhandled rejection, killing the daemon. Client-gone writes are silently\n // swallowed; the conn.on(\"error\") handler above covers the emitted error event.\n try {\n const reply = await handler(msg);\n try { conn.write(encodeMsg({ ok: true, reply, _v: PROTOCOL_VERSION })); } catch { /* client gone */ }\n } catch (e) {\n const errMsg = e instanceof Error ? e.message : String(e);\n try { conn.write(encodeMsg({ ok: false, error: errMsg, _v: PROTOCOL_VERSION })); } catch { /* client gone */ }\n }\n }\n });\n conn.on(\"error\", () => { /* client vanished; ignore */ });\n // #87: when the client half-closes (done sending) with bytes still in the\n // decoder buffer, the message had no newline terminator — send a fast error\n // instead of silently leaving the client to hit the 5s sendRequest timeout.\n conn.on(\"end\", () => {\n if (claimType !== \"attach\" && dec.remainder().trim()) {\n try {\n conn.write(encodeMsg({ ok: false, error: `malformed request: missing newline terminator`, _v: PROTOCOL_VERSION }));\n } catch { /* conn already closed */ }\n }\n });\n conn.on(\"close\", () => {\n if (keepaliveId !== undefined) clearIntervalFn(keepaliveId);\n if (claimType === \"attach\") onAttachClose?.(conn);\n });\n });\n server.on(\"error\", onListenError); // never let a server error become uncaughtException\n server.listen(sockPath);\n return server;\n}\n\n// #360: probe whether a live daemon owns this socket. Resolves true only when\n// a connection is accepted; false on ENOENT (no file) or ECONNREFUSED (stale\n// file / dead listener). Callers check this BEFORE startServer to avoid\n// unlink-then-bind stealing a live daemon's socket inode.\nexport function isDaemonSocketLive(sockPath: string, timeoutMs = 500): Promise<boolean> {\n return new Promise((resolve) => {\n if (!existsSync(sockPath)) { resolve(false); return; }\n const conn = createConnection(sockPath);\n const finish = (v: boolean) => { try { conn.destroy(); } catch { /* already gone */ } resolve(v); };\n const timer = setTimeout(() => finish(false), timeoutMs);\n conn.on(\"connect\", () => { clearTimeout(timer); finish(true); });\n conn.on(\"error\", () => { clearTimeout(timer); finish(false); });\n });\n}\n\nexport function sendRequest(sockPath: string, msg: unknown, timeoutMs = 5000): Promise<unknown> {\n return new Promise((resolve, reject) => {\n const conn = createConnection(sockPath);\n const dec = createDecoder();\n const timer = setTimeout(() => {\n conn.destroy();\n reject(new Error(\"control plane unavailable: request timed out\"));\n }, timeoutMs);\n conn.setEncoding(\"utf-8\");\n conn.on(\"connect\", () => conn.write(encodeMsg({ ...(msg as Record<string, unknown>), _v: PROTOCOL_VERSION })));\n conn.on(\"data\", (chunk: string) => {\n for (const m of dec.push(chunk) as any[]) {\n clearTimeout(timer);\n conn.destroy();\n if (m._v !== undefined && m._v !== PROTOCOL_VERSION) {\n reject(new Error(`squadrantd protocol v${m._v}, this client expects v${PROTOCOL_VERSION} — upgrade squadrantd or this CLI`));\n } else if (m.ok) {\n resolve(m.reply);\n } else {\n reject(new Error(m.error));\n }\n return;\n }\n });\n conn.on(\"error\", () => {\n clearTimeout(timer);\n reject(new Error(\"control plane unavailable: cannot reach squadrantd socket\"));\n });\n });\n}\n\n// ───────────────────────────────────────────────────────────────────────────\n// Streaming-subscribe frames for `squadrant crew chat / attach` (spec §4.5).\n// Additive; existing request/response verbs untouched. Cooperates with #87.\n\nexport type AttachFrame =\n | { type: \"delta\"; taskId: string; text: string }\n | { type: \"turn-started\"; taskId: string }\n | { type: \"turn-completed\"; taskId: string }\n | { type: \"input-requested\"; taskId: string; requestId: number; question: string }\n | { type: \"approval-requested\"; taskId: string; requestId: number; question: string; kind: string }\n | { type: \"gate-promoted\"; taskId: string; gateId: string }\n | { type: \"reattached\"; taskId: string }\n | { type: \"closed\"; taskId: string; reason: string }\n | { type: \"_keepalive\" };\n\nexport type AttachInbound =\n | { op: \"attach\"; taskId: string }\n | { op: \"say\"; taskId: string; text: string }\n | { op: \"steer\"; taskId: string; text: string }\n | { op: \"interrupt\"; taskId: string }\n | { op: \"answer\"; taskId: string; requestId: number; payload: unknown };\n\nexport function encodeFrame(f: AttachFrame): string {\n return JSON.stringify(f) + \"\\n\";\n}\n\nexport function decodeFrames(wire: string): AttachFrame[] {\n const out: AttachFrame[] = [];\n for (const line of wire.split(\"\\n\")) {\n if (!line.trim()) continue;\n try {\n const parsed = JSON.parse(line) as AttachFrame;\n if (parsed.type === \"_keepalive\") continue; // discard keepalive frames (#94)\n out.push(parsed);\n } catch { /* skip malformed */ }\n }\n return out;\n}\n","// src/control/liveness.ts\n//\n// PURE service-health layer (no I/O, no clock) — the #77 foundation. Mirrors\n// watchdog.ts: every function derives a verdict from records + an explicit `now`\n// so it is fully unit-testable. All runtime probing (cmux reads for captain\n// presence) is gathered by the caller (squadrantd) and passed in already-resolved;\n// this module never touches cmux.\nimport type { TaskState, Mode } from \"@squadrant/shared\";\n\nexport type ComponentKind = \"captain\" | \"crew\" | \"command\";\n\n// alive = seen within the stale window (healthy)\n// stale = quiet past stale but not yet gone (degrading)\n// gone = dark past the gone window (treat as down — a FAULT)\n// stopped = intentionally offline (user closed the captain workspace) — NOT a\n// fault. Distinct from `gone` so the surface never red-alarms an\n// expected shutdown (#324/#323).\n// unknown = no signal / not applicable (never alarms)\nexport type HealthState = \"alive\" | \"stale\" | \"gone\" | \"stopped\" | \"unknown\";\n\nexport interface ComponentHealth {\n kind: ComponentKind;\n project: string;\n /** crew name / captain name / \"command\". */\n ref: string;\n state: HealthState;\n /** epoch ms of last evidence of life, or null when there is no timestamp\n * source (captain/command presence is a boolean, not a heartbeat). */\n lastSeenMs: number | null;\n /** human-facing context — e.g. a recovery command. */\n detail?: string;\n}\n\n// Crews legitimately idle for long (24h interactive budget), so the surface uses\n// generous windows — these only flag a genuinely dark crew, and #139 already\n// reaps provably-dead ones. Display-only; does not drive any state transition.\nexport const CREW_STALE_MS = 5 * 60_000;\nexport const CREW_GONE_MS = 30 * 60_000;\n\n/**\n * Pure. Classify a last-seen timestamp into a health state.\n * null → \"unknown\"\n * age <= staleMs → \"alive\" (boundary inclusive)\n * age <= goneMs → \"stale\" (boundary inclusive)\n * else → \"gone\"\n */\nexport function classifyHealth(\n lastSeenMs: number | null,\n now: number,\n staleMs: number,\n goneMs: number,\n): HealthState {\n if (lastSeenMs == null) return \"unknown\";\n const age = now - lastSeenMs;\n if (age <= staleMs) return \"alive\";\n if (age <= goneMs) return \"stale\";\n return \"gone\";\n}\n\nconst TERMINAL: ReadonlySet<TaskState> = new Set([\"done\", \"failed\", \"cancelled\"]);\n\n/** Minimal crew shape the projection needs (subset of TaskRecord). */\nexport interface CrewLiveness {\n id: string;\n name?: string;\n state: TaskState;\n lastHeartbeat: number;\n mode: Mode;\n}\n\n/**\n * Pure. Project one project's component health from already-gathered inputs.\n * Emits: a captain row, a command row (only when applicable), and one row per\n * non-terminal crew.\n *\n * Captain liveness (#332): driven by the daemon-direct delivery loop.\n * captainStopped === false → captain surface was found on last delivery tick → ALIVE\n * captainStopped === true → surface gone for 3+ consecutive ticks → STOPPED\n * (intentional close — its crews are reaped and\n * delivery is paused; NOT a fault — #324/#323)\n * captainStopped === null → not yet checked / cmux unreachable → UNKNOWN\n */\nexport function projectHealth(input: {\n project: string;\n now: number;\n captainName: string;\n /** Delivery-loop captain surface state. See docs above. */\n captainStopped: boolean | null;\n /** true/false when a command workspace is expected; null = not applicable. */\n commandPresent: boolean | null;\n crews: CrewLiveness[];\n}): ComponentHealth[] {\n const { project, now, captainName, captainStopped, commandPresent, crews } = input;\n const out: ComponentHealth[] = [];\n\n // ── captain ────────────────────────────────────────────────────────────\n const captainState: HealthState =\n captainStopped === true ? \"stopped\" :\n captainStopped === false ? \"alive\" :\n \"unknown\";\n out.push({\n kind: \"captain\",\n project,\n ref: captainName,\n state: captainState,\n lastSeenMs: null,\n detail: captainState === \"stopped\" ? \"captain workspace closed — crews reaped; delivery paused\" : undefined,\n });\n\n // ── command (on-demand; only surfaced when applicable) ───────────────────\n if (commandPresent !== null) {\n out.push({\n kind: \"command\",\n project,\n ref: \"command\",\n state: presence(commandPresent),\n lastSeenMs: null,\n });\n }\n\n // ── crews (one row per non-terminal crew) ────────────────────────────────\n for (const c of crews) {\n if (TERMINAL.has(c.state)) continue;\n out.push({\n kind: \"crew\",\n project,\n ref: c.name ?? c.id.slice(0, 8),\n state: classifyHealth(c.lastHeartbeat, now, CREW_STALE_MS, CREW_GONE_MS),\n lastSeenMs: c.lastHeartbeat,\n detail: c.state,\n });\n }\n\n return out;\n}\n\nfunction presence(p: boolean | null): HealthState {\n if (p === null) return \"unknown\";\n return p ? \"alive\" : \"gone\";\n}\n\n/** Human-friendly age of the last-seen timestamp, or em-dash when there is none. */\nexport function ageText(lastSeenMs: number | null, now: number): string {\n if (lastSeenMs == null) return \"—\";\n const s = Math.max(0, Math.round((now - lastSeenMs) / 1000));\n if (s < 60) return `${s}s ago`;\n const m = Math.round(s / 60);\n if (m < 60) return `${m}m ago`;\n return `${Math.round(m / 60)}h ago`;\n}\n\n/**\n * Pure. Return the heal command string for a component that needs remediation,\n * or null when no action is needed (or when no heal verb exists for this kind).\n */\nexport function healCmdFor(c: ComponentHealth): string | null {\n // No heal verb for captain/crew — daemon-direct delivery handles recovery automatically.\n return null;\n}\n\n/** Per-project relay health — REMOVED (#332). No longer tracked by daemon. */\nexport type RelayHealth = never;\n","// src/control/store.ts\nimport {\n mkdirSync, readFileSync, readdirSync, renameSync, writeFileSync, existsSync,\n rmSync, statSync,\n} from \"node:fs\";\nimport { join, resolve, sep } from \"node:path\";\nimport type { TaskRecord } from \"@squadrant/shared\";\n\nexport interface Store {\n put(rec: TaskRecord): void;\n get(project: string, id: string): TaskRecord | undefined;\n list(project: string): TaskRecord[];\n listAll(): TaskRecord[];\n quarantine(project: string, id: string): void;\n delete(project: string, id: string): void;\n}\n\n/**\n * SECURITY (red-team #1, Critical): `project`/`id` arrive unsanitized from the\n * socket (dispatch + seed) and a crafted value (`..`, `/`, absolute, NUL) would\n * let a confused-deputy read/write arbitrary files as the user. A `project`/`id`\n * must be a single safe path segment — no separators, traversal, NUL, or dot\n * dirs. Enforced at the one chokepoint every fs op funnels through.\n */\nfunction safeSegment(kind: \"project\" | \"id\", s: unknown): string {\n if (typeof s !== \"string\" || s.length === 0) {\n throw new Error(`invalid ${kind}: must be a non-empty string`);\n }\n if (s.includes(\"\\0\")) throw new Error(`invalid ${kind}: NUL byte not allowed`);\n if (s === \".\" || s === \"..\" || /[/\\\\]/.test(s)) {\n throw new Error(`invalid ${kind}: '${s}' — path separators/traversal not allowed`);\n }\n return s;\n}\n\nexport function createStore(root: string): Store {\n const rootResolved = resolve(root);\n\n // Defense in depth: even after segment validation, never let a resolved\n // path escape the state root.\n const assertUnderRoot = (target: string): string => {\n const r = resolve(target);\n if (r !== rootResolved && !r.startsWith(rootResolved + sep)) {\n throw new Error(`path escapes state root: ${target}`);\n }\n return target;\n };\n\n const projDir = (p: string) => assertUnderRoot(join(root, safeSegment(\"project\", p)));\n const taskFile = (p: string, id: string) =>\n assertUnderRoot(join(projDir(p), `${safeSegment(\"id\", id)}.json`));\n\n return {\n put(rec) {\n mkdirSync(projDir(rec.project), { recursive: true });\n const dest = taskFile(rec.project, rec.id);\n const tmp = `${dest}.tmp`;\n writeFileSync(tmp, JSON.stringify(rec, null, 2));\n renameSync(tmp, dest); // atomic replace\n },\n get(project, id) {\n const f = taskFile(project, id);\n if (!existsSync(f)) return undefined;\n try {\n return JSON.parse(readFileSync(f, \"utf-8\")) as TaskRecord;\n } catch {\n return undefined; // corrupt file: caller handles (Task 6)\n }\n },\n list(project) {\n const d = projDir(project);\n if (!existsSync(d)) return [];\n return readdirSync(d)\n .filter((n) => n.endsWith(\".json\"))\n .map((n) => {\n try { return JSON.parse(readFileSync(join(d, n), \"utf-8\")) as TaskRecord; }\n catch { return undefined; }\n })\n .filter((r): r is TaskRecord => r !== undefined);\n },\n listAll() {\n if (!existsSync(root)) return [];\n return readdirSync(root)\n .filter((p) => { try { return statSync(join(root, p)).isDirectory(); } catch { return false; } })\n .flatMap((p) => this.list(p));\n },\n quarantine(project, id) {\n const f = taskFile(project, id);\n // suffix prevents clobber across process restarts\n if (existsSync(f)) renameSync(f, `${f}.corrupt.${Date.now()}`);\n },\n delete(project, id) {\n const f = taskFile(project, id);\n if (existsSync(f)) rmSync(f);\n },\n };\n}\n","// src/control/snapshot.ts\n//\n// PURE Tier 0/1/2 snapshot assembly (no I/O, no clock) for the read-only\n// `snapshot` socket verb — the observability-dashboard counterpart to\n// liveness.ts. Every derived value comes from already-gathered inputs + an\n// explicit `now`, so the whole module is trivially unit-testable. squadrantd.ts\n// performs the I/O (dist stat, log read, mailbox/store/results reads) and feeds\n// the gathered numbers in here; this module never touches the filesystem.\nimport type { ComponentHealth } from \"./liveness.js\";\nimport type { MailboxStats } from \"./mailbox.js\";\nexport type { MailboxStats };\n\nexport type BuildState = \"fresh\" | \"stale\";\n\n/**\n * Pure. The deploy-hygiene check: a daemon whose process started BEFORE the\n * current `dist/` build is running stale code (the recurring footgun). Fresh\n * requires the process to have started at or after the last build.\n * processStartedAt >= distBuiltAt → \"fresh\" (boundary inclusive)\n * else → \"stale\"\n */\nexport function buildFreshness(processStartedAt: number, distBuiltAt: number): BuildState {\n return processStartedAt >= distBuiltAt ? \"fresh\" : \"stale\";\n}\n\n// ── Tier 0: daemon root ───────────────────────────────────────────────────────\nexport interface DaemonRoot {\n pid: number;\n uptimeMs: number;\n version: string;\n build: { state: BuildState; processStartedAt: number; distBuiltAt: number };\n /** lastSweepAt/ageMs are null until the first sweep has run. */\n sweep: { lastSweepAt: number | null; ageMs: number | null; cadenceMs: number };\n log: { errorCount: number; sizeBytes: number; windowMs: number };\n}\n\n// ── Tier 2: per-project data plane + global results ───────────────────────────\n\nexport interface DeliveryLag {\n maxSeq: number;\n lastAckedSeq: number;\n /** maxSeq − lastAckedSeq, clamped at 0 — \"captain N behind\". */\n behind: number;\n}\n\nexport interface StoreStats {\n byState: Record<string, number>;\n corruptCount: number;\n}\n\nexport interface ResultArtifacts {\n fileCount: number;\n totalBytes: number;\n}\n\nexport interface ProjectDataPlane {\n project: string;\n mailbox: MailboxStats;\n delivery: DeliveryLag;\n store: StoreStats;\n}\n\nexport interface DaemonSnapshot {\n tier0: DaemonRoot;\n /** Tier 1 — per-component liveness across all projects (reuses projectHealth). */\n tier1: ComponentHealth[];\n tier2: {\n projects: ProjectDataPlane[];\n /** _results/ is a single global directory keyed by task id. */\n results: ResultArtifacts;\n };\n}\n\n/** Already-gathered (I/O-resolved) inputs the pure assembler turns into a DaemonSnapshot. */\nexport interface DaemonSnapshotInputs {\n pid: number;\n processStartedAt: number;\n version: string;\n distBuiltAt: number;\n lastSweepAt: number | null;\n sweepCadenceMs: number;\n log: { errorCount: number; sizeBytes: number; windowMs: number };\n health: ComponentHealth[];\n projects: Array<{\n project: string;\n mailbox: MailboxStats;\n lastAckedSeq: number;\n storeByState: Record<string, number>;\n corruptCount: number;\n }>;\n results: ResultArtifacts;\n}\n\n/**\n * Pure. Derive the full DaemonSnapshot from gathered inputs and an explicit now.\n */\nexport function assembleDaemonSnapshot(input: DaemonSnapshotInputs, now: number): DaemonSnapshot {\n return {\n tier0: {\n pid: input.pid,\n uptimeMs: now - input.processStartedAt,\n version: input.version,\n build: {\n state: buildFreshness(input.processStartedAt, input.distBuiltAt),\n processStartedAt: input.processStartedAt,\n distBuiltAt: input.distBuiltAt,\n },\n sweep: {\n lastSweepAt: input.lastSweepAt,\n ageMs: input.lastSweepAt == null ? null : now - input.lastSweepAt,\n cadenceMs: input.sweepCadenceMs,\n },\n log: input.log,\n },\n tier1: input.health,\n tier2: {\n projects: input.projects.map((p) => ({\n project: p.project,\n mailbox: p.mailbox,\n delivery: {\n maxSeq: p.mailbox.maxSeq,\n lastAckedSeq: p.lastAckedSeq,\n behind: Math.max(0, p.mailbox.maxSeq - p.lastAckedSeq),\n },\n store: { byState: p.storeByState, corruptCount: p.corruptCount },\n })),\n results: input.results,\n },\n };\n}\n","// src/control/launchd.ts\nimport { execFileSync } from \"node:child_process\";\nimport { mkdirSync, writeFileSync, readFileSync, existsSync, openSync, writeSync, closeSync, unlinkSync, constants } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { dirname, join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nexport const LABEL = \"com.squadrant.daemon\";\n\nexport function plistPath(): string {\n return join(homedir(), \"Library\", \"LaunchAgents\", `${LABEL}.plist`);\n}\n\n/**\n * Canonical path to the compiled daemon entrypoint, resolved relative to THIS\n * module (squadrantd.js is a sibling of the bundled entry in <dist>/). This is\n * the single source of truth — callers must NOT recompute it (a hardcoded\n * ~/.config/squadrant/dist path crash-loops the agent with MODULE_NOT_FOUND\n * because runtime-sync never mirrors compiled output there).\n */\nexport function daemonEntryPath(): string {\n const p = join(dirname(fileURLToPath(import.meta.url)), \"squadrantd.js\");\n if (!existsSync(p)) {\n throw new Error(\n `daemonEntryPath: compiled entry not found at '${p}'; ` +\n `run 'npm run build' — a src-tree or missing path in the launchd plist causes a MODULE_NOT_FOUND crash-loop (#259)`,\n );\n }\n return p;\n}\n\nfunction xmlEscape(s: string): string {\n return s.replace(/&/g, \"&amp;\").replace(/</g, \"&lt;\").replace(/>/g, \"&gt;\").replace(/\"/g, \"&quot;\");\n}\n\n/**\n * Strip per-shell ephemeral PATH entries (Claude Code plugin cache dirs) and\n * dedupe so the plist content is stable across squadrant invocations from\n * different shells. Without this, a captain shell (PATH includes\n * ~/.claude/plugins/cache/* bin dirs) vs a fresh login shell would each\n * rewrite the plist and kickstart -k the daemon, killing in-flight tasks\n * (incident 2026-05-21, observations 8704/8707/8711).\n */\nexport function sanitizePathForPlist(path: string): string {\n const seen = new Set<string>();\n const stable: string[] = [];\n for (const p of path.split(\":\")) {\n if (!p) continue;\n if (p.includes(\"/.claude/plugins/\")) continue;\n if (seen.has(p)) continue;\n seen.add(p);\n stable.push(p);\n }\n return stable.join(\":\");\n}\n\nexport const AGENT_BINS = [\"cmux\", \"claude\", \"opencode\", \"codex\", \"gemini\", \"node\"];\n\n/**\n * Resolve absolute directories for known agent + tool binaries via `which`, so\n * the launchd daemon's PATH includes them regardless of the install-time shell.\n * Missing binaries are skipped silently.\n */\nexport function resolveAgentBinDirs(): string[] {\n const dirs: string[] = [];\n for (const bin of AGENT_BINS) {\n try {\n const out = execFileSync(\"which\", [bin], { encoding: \"utf-8\", stdio: [\"ignore\", \"pipe\", \"ignore\"] });\n const resolved = out.trim();\n if (resolved) dirs.push(dirname(resolved));\n } catch {\n // binary not found on this machine — skip\n }\n }\n const seen = new Set<string>();\n return dirs.filter(d => {\n if (seen.has(d)) return false;\n seen.add(d);\n return true;\n });\n}\n\n/**\n * Compose a stable daemon PATH by prepending resolved agent bin dirs to the\n * sanitized install-shell PATH. Agent dirs take priority (prepended) and are\n * deduped against the sanitized entries so the output is deterministic.\n */\nexport function buildDaemonPath(shellPath: string): string {\n const agentDirs = resolveAgentBinDirs();\n const sanitized = sanitizePathForPlist(shellPath);\n if (agentDirs.length === 0) return sanitized;\n const parts = [...agentDirs, ...sanitized.split(\":\")];\n const seen = new Set<string>();\n return parts.filter(p => {\n if (!p || seen.has(p)) return false;\n seen.add(p);\n return true;\n }).join(\":\");\n}\n\n/**\n * Red-team #3 (High): launchd starts the daemon with a minimal PATH that does\n * NOT include where `claude`/`codex`/`opencode` live (nvm/cmux dirs), so every\n * headless `spawn` failed `ENOENT` in the real deployment (shell tests + fake\n * spawn hid it). We bake the installing process's PATH into the plist so the\n * daemon and its spawned crew children resolve the provider binaries.\n */\nexport function renderPlist(nodeBin: string, daemonEntry: string, pathEnv = \"\"): string {\n const logPath = join(homedir(), \".config\", \"squadrant\", \"squadrantd.log\");\n return `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n <key>Label</key><string>${LABEL}</string>\n <key>ProgramArguments</key>\n <array><string>${xmlEscape(nodeBin)}</string><string>${xmlEscape(daemonEntry)}</string></array>\n <key>EnvironmentVariables</key>\n <dict><key>PATH</key><string>${xmlEscape(pathEnv)}</string></dict>\n <key>RunAtLoad</key><true/>\n <key>KeepAlive</key><true/>\n <key>ThrottleInterval</key><integer>10</integer>\n <key>StandardErrorPath</key><string>${xmlEscape(logPath)}</string>\n <key>StandardOutPath</key><string>${xmlEscape(logPath)}</string>\n</dict>\n</plist>\n`;\n}\n\n/**\n * Semantic fingerprint of the <array> block inside the rendered plist. Used by\n * ensureDaemon to distinguish program-argument changes (merit a full restart)\n * from PATH-only changes (write updated plist, don't bounce the daemon).\n */\nexport function programArgsBlock(nodeBin: string, daemonEntry: string): string {\n return `<array><string>${xmlEscape(nodeBin)}</string><string>${xmlEscape(daemonEntry)}</string></array>`;\n}\n\n/**\n * Pure: which kickstart argv to use. `-k` (kill-then-restart) ONLY when the\n * plist changed. A plain `kickstart` starts a down daemon and is a no-op for a\n * healthy one — so a routine CLI call never bounces a running daemon (this was\n * a real bug: ensureDaemon ran on every `squadrant` invocation and `kickstart -k`\n * killed+restarted the daemon each time, orphaning in-flight headless crew).\n */\nexport function kickstartArgv(target: string, plistChanged: boolean): string[] {\n return plistChanged ? [\"kickstart\", \"-k\", target] : [\"kickstart\", target];\n}\n\n// In-process dedup: JS is single-threaded and ensureDaemon is synchronous, so\n// true re-entrancy is impossible; this flag prevents sequential re-calls within\n// the same process (e.g. index.ts + crew-control.ts) from re-running the\n// bootout/bootstrap pair needlessly.\nlet restartInFlight = false;\n\n/** @internal — reset only in tests; never call from production code */\nexport function _resetRestartInFlightForTest(): void {\n restartInFlight = false;\n}\n\nexport function daemonLockPath(): string {\n return join(homedir(), \".config\", \"squadrant\", \"daemon.lock\");\n}\n\n/**\n * Acquire a cross-process filesystem lock at ~/.config/squadrant/daemon.lock.\n * Uses O_EXCL for atomic, race-free creation. Cleans up stale locks (dead PID)\n * before the acquisition loop. Retries with a ~50 ms synchronous sleep up to\n * 20 times (~1 s total) before giving up.\n * Returns true on success, false if another live process holds the lock.\n */\nexport function tryAcquireDaemonLock(): boolean {\n const lp = daemonLockPath();\n\n // Stale-lock cleanup: if the owning PID is no longer alive, remove the file\n // so the next O_EXCL attempt succeeds.\n if (existsSync(lp)) {\n try {\n const pid = parseInt(readFileSync(lp, \"utf-8\").trim(), 10);\n if (!Number.isFinite(pid) || pid <= 0) {\n unlinkSync(lp);\n } else {\n try { process.kill(pid, 0); }\n catch { unlinkSync(lp); } // ESRCH → process dead, steal the lock\n }\n } catch { /* read/parse/unlink error — fall through to O_EXCL attempt */ }\n }\n\n // Atomic acquisition: O_EXCL guarantees only one process creates the file.\n for (let i = 0; i < 20; i++) {\n try {\n const fd = openSync(lp, constants.O_EXCL | constants.O_CREAT | constants.O_WRONLY);\n writeSync(fd, String(process.pid));\n closeSync(fd);\n return true;\n } catch {\n if (i < 19) {\n // Synchronous sleep: gives the lock-holder time to finish and release.\n Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, 50);\n }\n }\n }\n return false; // another live process held the lock for > ~1 s — skip restart\n}\n\n/** Release the lock written by tryAcquireDaemonLock. */\nexport function releaseDaemonLock(): void {\n try { unlinkSync(daemonLockPath()); } catch { /* already cleaned up */ }\n}\n\n/**\n * Idempotent & cheap. Never throws fatally. Writes/reloads the plist ONLY when\n * its content actually changed; Distinguishes program-argument drift (warrants\n * a full restart via bootout + bootstrap + kickstart) from PATH-only drift\n * (write the plist for the next natural restart but never bounce a healthy\n * daemon). Uses plain `kickstart` (never -k) to avoid the race between -k and\n * bootout's exit handler that produced exit-113 \"service not loaded\" errors.\n * The daemon entry is resolved internally (see daemonEntryPath) so no caller\n * can pass a wrong path.\n *\n * Concurrency guards:\n * - restartInFlight flag: prevents sequential re-calls within this process.\n * - tryAcquireDaemonLock: serialises concurrent SEPARATE squadrant processes\n * via a filesystem lock so only one runs bootout/bootstrap at a time.\n */\nexport function ensureDaemon(nodeBin: string = process.execPath): void {\n if (restartInFlight) return;\n restartInFlight = true;\n\n if (!tryAcquireDaemonLock()) {\n // Another process is handling the restart; it will be done by the time the\n // CLI tries to reach the daemon socket.\n return;\n }\n\n try {\n const p = plistPath();\n const entry = daemonEntryPath();\n const desired = renderPlist(nodeBin, entry, buildDaemonPath(process.env.PATH ?? \"\"));\n const current = existsSync(p) ? readFileSync(p, \"utf-8\") : null;\n const uid = process.getuid?.() ?? 0;\n const target = `gui/${uid}/${LABEL}`;\n\n const changed = current !== desired;\n // Semantic comparison: was the program-arg block itself different (not just\n // PATH)? Program-arg changes are rare (rebuild/reinstall) and merit a full\n // bootout+reload; PATH varies across terminals so it must NOT trigger a\n // bounce (would orphan in-flight RPCs).\n const programChanged = current !== null && changed\n && !current.includes(programArgsBlock(nodeBin, entry));\n\n if (changed) {\n mkdirSync(dirname(p), { recursive: true });\n writeFileSync(p, desired);\n }\n\n if (programChanged) {\n // unload the old instance so bootstrap picks up the new program args\n try { execFileSync(\"launchctl\", [\"bootout\", target], { stdio: \"ignore\" }); }\n catch { /* not loaded */ }\n }\n\n try { execFileSync(\"launchctl\", [\"bootstrap\", `gui/${uid}`, p], { stdio: \"ignore\" }); }\n catch { /* already bootstrapped */ }\n\n // Plain kickstart (never -k): no-op on a healthy daemon, starts one that\n // was booted-out above or that stopped for other reasons. -k is avoided\n // because it races with bootout's exit handler and produces exit-113 when\n // the service hasn't finished unloading.\n execFileSync(\"launchctl\", [\"kickstart\", target], { stdio: \"ignore\" });\n } catch (e) {\n // daemon ensure is best-effort (still don't throw); CLI fails loud on socket miss\n process.stderr.write(`[squadrant] warn: ensureDaemon failed (${e instanceof Error ? e.message : e})\\n`);\n } finally {\n releaseDaemonLock();\n }\n}\n","import { loadConfig } from \"@squadrant/shared\";\nimport type { RuntimeDriver, SquadrantConfig, TaskRecord } from \"@squadrant/shared\";\nimport type { DirectCmuxReader } from \"./interfaces.js\";\n\nconst TAIL_LINES = 25;\n\n// MUST match `titleFor` in src/commands/crew.ts — the crew tab title convention\n// the daemon uses to find a crew's pane (🔧 <project>:<name>).\nexport function crewPaneTitle(project: string, name: string): string {\n return `🔧 ${project}:${name}`;\n}\n\nexport type SurfaceLiveness = \"alive\" | \"gone\" | \"unknown\";\n\n/**\n * Pure: decide an interactive crew's surface liveness from a resolved surface\n * list (#139). Three-valued so a transient cmux outage never false-reaps a live\n * crew — \"gone\" means PROVABLY absent, not \"couldn't tell\":\n * - wantTitle null (crew has no name) → \"unknown\"\n * - surfaceTitles null (could not enumerate) → \"unknown\"\n * - title present in the list → \"alive\"\n * - title absent from an enumerated list → \"gone\"\n */\nexport function surfaceVerdict(surfaceTitles: string[] | null, wantTitle: string | null): SurfaceLiveness {\n if (!wantTitle) return \"unknown\";\n if (surfaceTitles == null) return \"unknown\";\n return surfaceTitles.includes(wantTitle) ? \"alive\" : \"gone\";\n}\n\n/**\n * I/O: enumerate the captain workspace's surface titles for a crew's project.\n * Returns null on ANY failure — surfaceVerdict maps null → \"unknown\" so we never\n * reap on an inconclusive probe. Never throws.\n */\nasync function listCaptainSurfaceTitles(\n rec: TaskRecord,\n makeRuntime: (project: string, config: SquadrantConfig) => RuntimeDriver | null,\n): Promise<string[] | null> {\n try {\n const config = loadConfig();\n const proj = config.projects[rec.project];\n if (!proj) return null;\n const runtime = makeRuntime(rec.project, config);\n if (!runtime) return null;\n const captain = await runtime.status(proj.captainName);\n if (!captain) return null;\n const surfaces = await runtime.listSurfaces(captain.id);\n return surfaces.map((s) => s.title ?? \"\");\n } catch {\n return null;\n }\n}\n\n/**\n * Build the daemon's interactive surface-liveness probe (#139 backstop).\n * @param makeRuntime Factory provided by the host (root package); omit for tests.\n */\nexport function createSurfaceLivenessProbe(\n makeRuntime?: (project: string, config: SquadrantConfig) => RuntimeDriver | null,\n): (rec: TaskRecord) => Promise<SurfaceLiveness> {\n return async (rec) => {\n if (rec.mode !== \"interactive\" || !rec.name) return \"unknown\";\n if (!makeRuntime) return \"unknown\";\n const titles = await listCaptainSurfaceTitles(rec, makeRuntime);\n return surfaceVerdict(titles, crewPaneTitle(rec.project, rec.name));\n };\n}\n\n/**\n * Build the daemon's best-effort crew-pane reader (Phase 2b).\n * @param makeRuntime Factory provided by the host; required for real pane reads.\n */\nexport function createCrewPaneReader(\n makeRuntime?: (project: string, config: SquadrantConfig) => RuntimeDriver | null,\n): (rec: TaskRecord) => Promise<string | null> {\n return async (rec) => {\n try {\n if (!rec.name || !makeRuntime) return null;\n const config = loadConfig();\n const proj = config.projects[rec.project];\n if (!proj) return null;\n const runtime = makeRuntime(rec.project, config);\n if (!runtime) return null;\n const captain = await runtime.status(proj.captainName);\n if (!captain) return null;\n const surfaces = await runtime.listSurfaces(captain.id);\n const want = crewPaneTitle(rec.project, rec.name);\n const pane = surfaces.find((s) => s.title === want);\n if (!pane) return null;\n const screen = await runtime.readPaneScreen(pane);\n if (!screen) return null;\n return screen.split(/\\r?\\n/).slice(-TAIL_LINES).join(\"\\n\");\n } catch {\n return null;\n }\n };\n}\n\n/**\n * Build a direct surface-liveness probe for daemon-direct mode (#332).\n * Uses DirectCmuxReader (seam interface implemented by DaemonCmux in root).\n */\nexport function createDirectSurfaceLivenessProbe(\n cmux: DirectCmuxReader,\n getCaptainTitle: (project: string) => string,\n): (rec: TaskRecord) => Promise<SurfaceLiveness> {\n return async (rec) => {\n try {\n if (rec.mode !== \"interactive\" || !rec.name) return \"unknown\";\n const wsId = await cmux.findWorkspaceId(getCaptainTitle(rec.project));\n if (!wsId) return \"unknown\";\n const surfaces = await cmux.listSurfaces(wsId);\n if (surfaces.length === 0) return \"unknown\";\n return surfaceVerdict(\n surfaces.map((s) => s.title ?? \"\"),\n crewPaneTitle(rec.project, rec.name),\n );\n } catch {\n return \"unknown\";\n }\n };\n}\n\n/**\n * Build a direct crew-pane reader for daemon-direct mode (#332).\n * Uses DirectCmuxReader (seam interface implemented by DaemonCmux in root).\n */\nexport function createDirectCrewPaneReader(\n cmux: DirectCmuxReader,\n getCaptainTitle: (project: string) => string,\n): (rec: TaskRecord) => Promise<string | null> {\n return async (rec) => {\n try {\n if (!rec.name) return null;\n const wsId = await cmux.findWorkspaceId(getCaptainTitle(rec.project));\n if (!wsId) return null;\n const surfaces = await cmux.listSurfaces(wsId);\n const want = crewPaneTitle(rec.project, rec.name);\n const pane = surfaces.find((s) => s.title === want);\n if (!pane) return null;\n const screen = await cmux.readPaneScreen(pane);\n if (!screen) return null;\n return screen.split(/\\r?\\n/).slice(-TAIL_LINES).join(\"\\n\");\n } catch {\n return null;\n }\n };\n}\n","export {};\n//# sourceMappingURL=interfaces.js.map","// src/control/codex/gate.ts\n// Pure helpers for the interactive-codex HITL gate primitive (spec §4.9).\nimport type { Gate } from \"@squadrant/shared\";\n\nexport function makeGate(opts: {\n taskId: string;\n kind: \"input\" | \"approval\";\n question: string;\n now: number;\n mkId: () => string;\n}): Gate {\n return {\n gateId: opts.mkId(),\n taskId: opts.taskId,\n kind: opts.kind,\n question: opts.question,\n state: \"pending\",\n createdAt: opts.now,\n };\n}\n\nexport function resolveGate(g: Gate, by: { resolvedBy: string; resolution: unknown }): Gate {\n return { ...g, state: \"resolved\", resolvedBy: by.resolvedBy, resolution: by.resolution };\n}\n\nexport function timeoutGate(g: Gate): Gate {\n return { ...g, state: \"timeout\" };\n}\n","// src/control/daemon/context.ts\n// SquadrantdOpts, defaultIsPidAlive, DaemonContext, and buildContext.\n// Kept here (not in squadrantd.ts) so daemon/* modules can import this file\n// without creating a circular dependency on the host entrypoint.\n// squadrantd.ts re-exports SquadrantdOpts and defaultIsPidAlive for backward compat.\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { spawn as realSpawn } from \"node:child_process\";\nimport { writeFileSync, mkdirSync } from \"node:fs\";\nimport { createStore } from \"../store.js\";\nimport { createDaemon } from \"../daemon.js\";\nimport { loadConfig } from \"@squadrant/shared\";\nimport type { TaskRecord, ControlEvent, Gate, AutoConfigResult } from \"@squadrant/shared\";\nimport type { Socket } from \"node:net\";\nimport type { PaneRef } from \"@squadrant/shared\";\nimport type { AgentDriver, OpencodeBridge, CmuxEventsBridge, DaemonSurfaceDriver } from \"../interfaces.js\";\nimport type { TelegramBridge } from \"../telegram/bridge.js\";\nimport type { AttachFrame } from \"../protocol.js\";\n\n// ── Public injectable options (equivalent of old squadrantd.ts SquadrantdOpts) ───\n\nexport interface SquadrantdOpts {\n stateRoot?: string;\n sockPath?: string;\n sweepMs?: number; // 0 disables the interval (tests)\n isPidAlive?: (pid: number) => boolean;\n isSurfaceAlive?: (rec: TaskRecord) => Promise<\"alive\" | \"gone\" | \"unknown\">;\n spawn?: typeof realSpawn;\n /**\n * Push-notification hook (#109). Defaults to appending a structured event\n * to the mailbox file at <stateRoot>/inbox/<project>.log; an injector\n * process inside the captain workspace tails the file and delivers entries\n * to the captain pane. Tests inject a fake to assert call shape.\n */\n notify?: (args: {\n project: string;\n message: string;\n record: TaskRecord;\n event: ControlEvent;\n }) => Promise<void> | void;\n /** Background rotation timer interval (ms). 0 disables. Default 60_000. */\n rotationIntervalMs?: number;\n /** Mailbox rotation thresholds (size/age/retention). */\n mailboxConfig?: {\n maxBytes?: number;\n maxAgeMs?: number;\n keepCount?: number;\n };\n /** Inject a fake driver for tests. Defaults to a real CodexInteractiveDriver. */\n codexDriver?: AgentDriver;\n /** Inject a fake headless launcher for tests to avoid real process spawns. */\n launchHeadless?: (rec: TaskRecord) => Promise<void>;\n /** Override which projects appear in the Tier 2 per-project snapshot. */\n registeredProjects?: string[];\n /** Inject a fake opencode SSE bridge for tests. */\n opencodeBridge?: OpencodeBridge;\n /** B1: inject a fake cmux events bridge for tests. */\n cmuxEventsBridge?: CmuxEventsBridge;\n /** Opt-in Telegram bridge (#65). Inject a fake for tests; in production the host\n * builds the real one only when config.telegram is present (and not under vitest,\n * since pushLifecycle is composed onto notify and would hit the network). */\n telegramBridge?: TelegramBridge;\n /** Inject a fake surface driver for testing daemon-direct delivery. */\n daemonCmux?: DaemonSurfaceDriver;\n /** Factory for constructing the surface driver in production. */\n makeDaemonCmux?: () => DaemonSurfaceDriver;\n /** Injected captain-surface mapping (project → PaneRef) for tests. */\n captainSurfaces?: Record<string, PaneRef>;\n /** #348: override the cmux socket auto-config re-check. */\n runCmuxAutoConfig?: () => Promise<AutoConfigResult>;\n}\n\nexport function defaultIsPidAlive(pid: number): boolean {\n try { process.kill(pid, 0); return true; }\n catch (e: any) { return e?.code === \"EPERM\"; } // EPERM = alive but not ours; ESRCH = dead\n}\n\n// ── Shared state bag ──────────────────────────────────────────────────────────\n\n/** All shared mutable state for the running daemon. Most fields are set in\n * buildContext; late-bound fields (d, notify, broadcast, etc.) are assigned\n * by start.ts after building the daemon and factories, before any event fires. */\nexport interface DaemonContext {\n opts: SquadrantdOpts;\n stateRoot: string;\n sockPath: string;\n store: ReturnType<typeof createStore>;\n bootedAt: number;\n /** Mutable box so sweep timer can update lastSweepAt without a closure rebind. */\n lastSweepAt: { value: number | null };\n taskTimeoutMs: number | undefined;\n isPidAlive: (pid: number) => boolean;\n spawn: typeof realSpawn;\n resultsDir: string;\n writeResult: (id: string, payload: string) => string;\n log: (m: string) => void;\n /** Per-task live attach connections (spec §4.5/§4.6). */\n attachConns: Map<string, Set<Socket>>;\n /** Tasks being launched headlessly with no pid yet (#259). */\n inFlightHeadlessIds: Set<string>;\n /** Cancel handles for in-flight headless runs. */\n activeHeadlessKills: Set<() => void>;\n /** #332 delivery streak counter per project for captain-absent reaping. */\n captainMissingStreak: Map<string, number>;\n /** #332 projects whose captain surface is confirmed gone. */\n stoppedProjects: Set<string>;\n\n // ── Late-bound: assigned by start.ts before any timer/server fires ──────────\n\n /** Resolved daemon instance. */\n d: ReturnType<typeof createDaemon>;\n /** Resolved notify function. */\n notify: (args: { project: string; message: string; record: TaskRecord; event: ControlEvent }) => Promise<void> | void;\n /** Resolved surface driver for daemon-direct delivery. */\n daemonCmux: DaemonSurfaceDriver | undefined;\n /** Resolved agent driver. */\n codexDriver: AgentDriver;\n /** Resolved opencode SSE bridge. */\n opencodeBridge: OpencodeBridge;\n /** Resolved cmux events bridge. */\n cmuxEventsBridge: CmuxEventsBridge;\n /** Resolved Telegram bridge — undefined when config.telegram is absent. */\n telegramBridge?: TelegramBridge;\n /** Fan-out to attach clients (set by createAttach). */\n broadcast: (taskId: string, f: AttachFrame) => void;\n /** Schedule gate promotion (set by createAttach). */\n schedulePromotion: (taskId: string, requestId: number, kind: \"input\" | \"approval\", question: string) => void;\n /** Cancel gate timers for a task (set by createAttach). */\n cancelPromotionsFor: (taskId: string) => void;\n}\n\n/** Initialize the pure-state fields of DaemonContext from opts.\n * Late-bound fields are zero-initialized and MUST be set by start.ts\n * (or squadrantd.ts for drivers) before any event, timer, or socket fires. */\nexport function buildContext(opts: SquadrantdOpts): DaemonContext {\n const stateRoot = opts.stateRoot ?? join(homedir(), \".config\", \"squadrant\", \"state\");\n const sockPath = opts.sockPath ?? join(homedir(), \".config\", \"squadrant\", \"squadrant.sock\");\n const store = createStore(stateRoot);\n const bootedAt = Date.now();\n const taskTimeoutMs = loadConfig().defaults.taskTimeoutMs;\n const isPidAlive = opts.isPidAlive ?? defaultIsPidAlive;\n const spawn = opts.spawn ?? realSpawn;\n const resultsDir = join(stateRoot, \"_results\");\n mkdirSync(resultsDir, { recursive: true });\n const writeResult = (id: string, payload: string) => {\n const p = join(resultsDir, `${id}.txt`);\n writeFileSync(p, payload);\n return p;\n };\n const log = (m: string) =>\n process.stderr.write(`[squadrantd] ${new Date().toISOString()} ${m}\\n`);\n\n return {\n opts,\n stateRoot,\n sockPath,\n store,\n bootedAt,\n lastSweepAt: { value: null },\n taskTimeoutMs,\n isPidAlive,\n spawn,\n resultsDir,\n writeResult,\n log,\n attachConns: new Map(),\n inFlightHeadlessIds: new Set(),\n activeHeadlessKills: new Set(),\n captainMissingStreak: new Map(),\n stoppedProjects: new Set(),\n // Late-bound — start.ts fills these before first use:\n d: null as unknown as ReturnType<typeof createDaemon>,\n notify: null as unknown as DaemonContext[\"notify\"],\n daemonCmux: undefined,\n codexDriver: null as unknown as AgentDriver,\n opencodeBridge: null as unknown as OpencodeBridge,\n cmuxEventsBridge: null as unknown as CmuxEventsBridge,\n telegramBridge: undefined,\n broadcast: () => {},\n schedulePromotion: () => {},\n cancelPromotionsFor: () => {},\n };\n}\n","// src/control/daemon/attach.ts\n// Attach fan-out and gate-promotion logic (spec §4.5/§4.6/§4.9).\nimport { randomUUID } from \"node:crypto\";\nimport { encodeFrame } from \"../protocol.js\";\nimport { makeGate } from \"../gate.js\";\nimport type { AttachFrame } from \"../protocol.js\";\nimport type { Gate } from \"@squadrant/shared\";\nimport type { DaemonContext } from \"./context.js\";\n\nexport interface AttachHandlers {\n broadcast: (taskId: string, f: AttachFrame) => void;\n schedulePromotion: (taskId: string, requestId: number, kind: \"input\" | \"approval\", question: string) => void;\n cancelPromotionsFor: (taskId: string) => void;\n}\n\n/** Build the attach fan-out and gate-promotion machinery. Call once in start.ts\n * immediately after buildContext; assign the returned handlers onto ctx so the\n * driver emit callbacks can reference them via the context object. */\nexport function createAttach(ctx: DaemonContext): AttachHandlers {\n const { attachConns, store, log } = ctx;\n\n function broadcast(taskId: string, f: AttachFrame): void {\n const conns = attachConns.get(taskId);\n if (!conns) return;\n const wire = encodeFrame(f);\n for (const conn of conns) {\n try { conn.write(wire); } catch { /* client gone; onAttachClose will clean up */ }\n }\n }\n\n // ── Gate promotion (spec §4.9) ─────────────────────────────────────────────\n // When a server-request event fires and no client is attached, start a 5s\n // timer. If still unattached at fire time, promote to a Gate in the store\n // and broadcast gate-promoted so any later-attaching client can offer takeover.\n const pendingGateTimers = new Map<string, { taskId: string; timer: NodeJS.Timeout }>();\n\n function schedulePromotion(\n taskId: string,\n requestId: number,\n kind: \"input\" | \"approval\",\n question: string,\n ): void {\n // If a client is already attached for this task, no promotion needed.\n const conns = attachConns.get(taskId);\n if (conns && conns.size > 0) return;\n const key = `${taskId}#${requestId}`;\n // Clear any prior timer for the same (taskId, requestId).\n const prior = pendingGateTimers.get(key);\n if (prior) clearTimeout(prior.timer);\n const timer = setTimeout(() => {\n pendingGateTimers.delete(key);\n // Re-check at fire time — a client may have attached in the 5s window.\n if (attachConns.get(taskId)?.size) return;\n const rec = store.listAll().find((r) => r.id === taskId);\n if (!rec) return;\n const gate: Gate = makeGate({ taskId, kind, question, now: Date.now(), mkId: () => randomUUID() });\n const gates = [...(rec.gates ?? []), gate];\n store.put({ ...rec, gates });\n broadcast(taskId, { type: \"gate-promoted\", taskId, gateId: gate.gateId });\n log(`gate promoted gateId=${gate.gateId} taskId=${taskId} kind=${kind}`);\n }, 5_000);\n timer.unref?.();\n pendingGateTimers.set(key, { taskId, timer });\n }\n\n function cancelPromotionsFor(taskId: string): void {\n for (const [key, slot] of pendingGateTimers.entries()) {\n if (slot.taskId === taskId) {\n clearTimeout(slot.timer);\n pendingGateTimers.delete(key);\n }\n }\n }\n\n return { broadcast, schedulePromotion, cancelPromotionsFor };\n}\n","// Daemon interactive-block probe: moved from commands/notify-relay.ts so\n// daemon/probes.ts (core) can import it without a core→commands back-edge.\nimport type { TaskRecord, ControlEvent } from \"@squadrant/shared\";\n\n// Entries older than this at session-start time are silently acked without\n// delivery — stale events from a prior session or dead crews.\nexport const STALE_THRESHOLD_MS = 5 * 60 * 1000;\n\n// A working interactive task with no heartbeat for this long is a probe\n// candidate: PostToolUse never fires while a permission prompt is up.\nexport const PROBE_QUIET_MS = 20_000;\n\n// ── Pure pane classifiers (inlined from interactive/pane-classifier.ts) ──────\n// Duplication is intentional: pane-classifier.ts stays in root for the relay\n// path; core can't import it (root → core boundary). Both copies are pure and\n// covered by pane-classifier.test.ts.\n\nfunction detectTrailingQuestion(text: string): string | null {\n if (!text) return null;\n let inFence = false;\n let lastLine: string | null = null;\n for (const raw of text.split(/\\r?\\n/)) {\n const line = raw.trim();\n if (line.startsWith(\"```\")) { inFence = !inFence; continue; }\n if (inFence || line === \"\") continue;\n lastLine = line;\n }\n if (lastLine && lastLine.endsWith(\"?\")) return lastLine;\n return null;\n}\n\nconst ERROR_BANNER_RE: RegExp[] = [\n /\\bAPI Error\\b/i,\n /\\bOverloaded\\b/,\n /\\b(?:429|500|502|503|504|529)\\b[^?]*\\b(?:overloaded|unavailable|internal server error|bad gateway|gateway timeout|too many requests|service unavailable)\\b/i,\n /\\bretr(?:y|ies)\\s+(?:exhausted|limit\\s+(?:reached|exceeded))\\b/i,\n /\\bmaximum\\s+retries\\b/i,\n];\nconst OPTION_RE = /^[❯>›]?\\s*(\\d+)\\.\\s+(.*\\S)\\s*$/;\nconst PURE_CHROME_RE = /^[\\s─━│┃╭╮╰╯┌┐└┘├┤┬┴┼═║╔╗╚╝╠╣╦╩╬▁▂▃▄▅▆▇█▔▏▕]+$/;\nconst STATUS_LINE_RE = /accept edits on|shift\\+tab|⏵⏵|\\? for shortcuts|esc to interrupt|tokens? (used|left)|context left/i;\n\nfunction stripChrome(raw: string): string | null {\n let line = raw.replace(/\\[[0-9;]*m/g, \"\");\n line = line.replace(/^[\\s│┃▏▕|]+/, \"\").replace(/[\\s│┃▏▕|]+$/, \"\");\n const trimmed = line.trim();\n if (trimmed === \"\") return null;\n if (PURE_CHROME_RE.test(trimmed)) return null;\n if (/^>\\s*$/.test(trimmed)) return null;\n if (STATUS_LINE_RE.test(trimmed)) return null;\n return trimmed;\n}\n\nfunction classifyPaneTail(\n tail: string,\n): { kind: \"approval\" | \"question\" | \"error\"; text: string } | null {\n if (!tail) return null;\n const raw = tail.split(/\\r?\\n/);\n const cleaned = raw.map(stripChrome);\n const options: { label: string; ci: number }[] = [];\n for (let i = 0; i < cleaned.length; i++) {\n const c = cleaned[i];\n if (c == null) continue;\n const m = c.match(OPTION_RE);\n if (m) options.push({ label: m[2], ci: i });\n }\n const hasYes = options.some((o) => /\\byes\\b/i.test(o.label));\n const hasNo = options.some((o) => /\\bno\\b/i.test(o.label));\n if (options.length >= 2 && hasYes && hasNo) {\n const firstOptCi = options[0].ci;\n for (let i = firstOptCi - 1; i >= 0; i--) {\n const c = cleaned[i];\n if (c == null) continue;\n if (c.endsWith(\"?\")) return { kind: \"approval\", text: c };\n }\n return { kind: \"approval\", text: \"Crew is awaiting permission approval.\" };\n }\n const region = cleaned.filter((c): c is string => c != null).join(\"\\n\");\n const q = detectTrailingQuestion(region);\n if (q) return { kind: \"question\", text: q };\n let errLine: string | null = null;\n for (const c of cleaned) {\n if (c != null && ERROR_BANNER_RE.some((re) => re.test(c))) errLine = c;\n }\n if (errLine) return { kind: \"error\", text: errLine.slice(0, 200) };\n return null;\n}\n\n// ── Interactive probe ─────────────────────────────────────────────────────────\n\ninterface InteractiveProbeDeps {\n project: string;\n listTasks: () => Promise<TaskRecord[]>;\n readPaneTail: (rec: TaskRecord) => Promise<string | null>;\n sendEvent: (event: ControlEvent) => Promise<void>;\n now: () => number;\n log: (m: string) => void;\n quietMs?: number;\n}\n\nexport function createInteractiveProbe(deps: InteractiveProbeDeps): {\n tick: () => Promise<void>;\n} {\n const quietMs = deps.quietMs ?? PROBE_QUIET_MS;\n const lastTail = new Map<string, string>();\n\n async function tick(): Promise<void> {\n let tasks: TaskRecord[];\n try {\n tasks = await deps.listTasks();\n } catch (e) {\n deps.log(`probe listTasks failed: ${(e as Error).message}`);\n return;\n }\n const now = deps.now();\n for (const rec of tasks) {\n if (rec.mode !== \"interactive\") continue;\n if (rec.state !== \"working\") continue;\n if (!rec.name) continue;\n if (now - rec.lastHeartbeat <= quietMs) continue;\n\n let tail: string | null;\n try {\n tail = await deps.readPaneTail(rec);\n } catch (e) {\n deps.log(`probe read failed for ${rec.id}: ${(e as Error).message}`);\n continue;\n }\n if (!tail) continue;\n if (lastTail.get(rec.id) === tail) continue;\n lastTail.set(rec.id, tail);\n\n const verdict = classifyPaneTail(tail);\n if (!verdict) continue;\n const event: ControlEvent =\n verdict.kind === \"error\"\n ? {\n type: \"task.failed\",\n id: rec.id,\n error: `crew session error (pane-detected): ${verdict.text}`,\n }\n : {\n type: \"task.blocked\",\n id: rec.id,\n reason:\n verdict.kind === \"approval\"\n ? \"crew awaiting permission (pane-detected)\"\n : \"crew asked a question (pane-detected)\",\n question: verdict.text,\n };\n try {\n await deps.sendEvent(event);\n const label = verdict.kind === \"error\" ? \"CREW FAILED\" : \"CREW BLOCKED\";\n deps.log(`probe -> ${label} ${rec.name} (${verdict.kind})`);\n } catch (e) {\n deps.log(`probe sendEvent failed for ${rec.id}: ${(e as Error).message}`);\n }\n }\n }\n\n return { tick };\n}\n","// src/control/daemon/probes.ts\n// Surface-liveness probe logic for the daemon-direct delivery path.\nimport { createInteractiveProbe } from \"./interactive-probe.js\";\nimport { createDirectCrewPaneReader, createDirectSurfaceLivenessProbe } from \"../crew-pane-reader.js\";\nimport { loadConfig } from \"@squadrant/shared\";\nimport type { TaskRecord } from \"@squadrant/shared\";\nimport type { DaemonSurfaceDriver } from \"../interfaces.js\";\nimport type { DaemonContext } from \"./context.js\";\n\nexport interface ProbeHandlers {\n /** Build the probe-tick function for the daemon-direct delivery loop.\n * Call once after the surface driver is resolved; returns a guarded tick. */\n buildInteractiveProbe: (deps: { cmux: DaemonSurfaceDriver }) => () => Promise<void>;\n /** Direct-cmux surface liveness probe for interactive task reaping. */\n directSurfaceProbe: (rec: TaskRecord) => Promise<\"alive\" | \"gone\" | \"unknown\">;\n}\n\n/** Resolve the captain pane name for a project from the config. */\nfunction captainNameForProject(project: string): string {\n const cfg = loadConfig();\n return cfg.projects?.[project]?.captainName ?? `${project}-captain`;\n}\n\nexport function createProbes(ctx: DaemonContext): ProbeHandlers {\n const { store, log } = ctx;\n\n // ── Daemon-direct: direct cmux surface probe ──────────────────────────────\n const directSurfaceProbe = (_rec: TaskRecord): Promise<\"alive\" | \"gone\" | \"unknown\"> => {\n return Promise.resolve(\"unknown\");\n };\n\n // ── Daemon-direct: blocked-crew detection ─────────────────────────────────\n // Reuses createInteractiveProbe with a direct cmux pane reader injected as\n // the readPaneTail dep. The returned tick must be called from the delivery\n // loop's interval.\n function buildInteractiveProbe(deps: { cmux: DaemonSurfaceDriver }): () => Promise<void> {\n const directPaneReader = createDirectCrewPaneReader(deps.cmux, captainNameForProject);\n const probe = createInteractiveProbe({\n project: \"_all_\",\n listTasks: async () => store.listAll(),\n readPaneTail: directPaneReader,\n sendEvent: async (event) => {\n const rec = store.listAll().find((r) => r.id === event.id);\n if (rec) {\n await ctx.d.handle({ kind: \"event\", project: rec.project, event });\n }\n },\n now: () => Date.now(),\n log,\n });\n let probing = false;\n return async () => {\n if (probing) return;\n probing = true;\n try { await probe.tick(); }\n finally { probing = false; }\n };\n }\n\n return { buildInteractiveProbe, directSurfaceProbe };\n}\n\n/** Build the surface-liveness probe used by createDaemon — always uses the\n * direct cmux path when a driver is available. Pure: no side effects. */\nexport function buildSurfaceProbe(\n ctx: DaemonContext,\n probes: ProbeHandlers,\n daemonCmux: DaemonSurfaceDriver | undefined,\n): (rec: TaskRecord) => Promise<\"alive\" | \"gone\" | \"unknown\"> {\n if (ctx.opts.isSurfaceAlive) return ctx.opts.isSurfaceAlive;\n if (daemonCmux) {\n return createDirectSurfaceLivenessProbe(daemonCmux, captainNameForProject);\n }\n return probes.directSurfaceProbe;\n}\n","/** Thrown by sendToSurface when the captain has a draft — delivery defers (#258/#302). */\nexport class DeferDelivery extends Error {\n constructor(public readonly draft: string | null = null) {\n super(\"deferred: captain composing\");\n this.name = \"DeferDelivery\";\n }\n}\n","import { DeferDelivery } from \"./defer-delivery.js\";\n\n/**\n * #332: extracted defer-while-typing state machine (#258/#302).\n *\n * Behaviour ported from notify-relay.ts drain() (#332):\n * - per-seq deferCounts / stableCounts / lastContent maps\n * - maxDefers / stableProbePolls thresholds\n * - stable-content probe escalation (#302)\n */\nexport interface CaptainDeliveryOptions {\n maxDefers: number;\n stableProbePolls: number;\n}\n\nexport type SendFn = (text: string, opts?: { probe?: boolean }) => Promise<void>;\nexport type DeliverResult = { delivered: true } | { deferred: true };\n\n/**\n * Unified-formatter helper (#214/#210): the daemon's formatMessage is the single\n * source of truth for the captain-facing message. Returns null for entries the\n * daemon chose not to surface (null/empty message fields).\n */\nexport function deliverable(entry: { message?: string | null }): string | null {\n const msg = entry.message;\n if (msg == null) return null;\n const trimmed = msg.trim();\n return trimmed.length > 0 ? msg : null;\n}\n\nexport class CaptainDelivery {\n private deferCounts = new Map<number, number>();\n private lastContent = new Map<number, string | null>();\n private stableCounts = new Map<number, number>();\n\n constructor(private readonly opts: CaptainDeliveryOptions) {}\n\n /**\n * Attempt to deliver one mailbox entry to the captain. Calls `send(text, opts)`\n * and, if the send throws DeferDelivery, tracks defer/stable counts for the\n * entry's seq and returns {deferred: true} (caller should NOT advance cursor).\n * On success or null message returns {delivered: true} (caller SHOULD advance).\n */\n async deliver(\n entry: { seq: number; message?: string | null },\n send: SendFn,\n ): Promise<DeliverResult> {\n const msg = deliverable(entry);\n if (!msg) return { delivered: true };\n\n const seq = entry.seq;\n const deferCount = this.deferCounts.get(seq) ?? 0;\n // #302: probe early once content has been stable for stableProbePolls\n // polls (captain not typing) — kills the ~5min stall; the 300-defer\n // backstop still guarantees delivery never hangs forever.\n const stable = (this.stableCounts.get(seq) ?? 0) >= this.opts.stableProbePolls;\n const probe = stable || deferCount >= this.opts.maxDefers;\n\n try {\n await send(msg, probe ? { probe: true } : undefined);\n this.deferCounts.delete(seq);\n this.stableCounts.delete(seq);\n this.lastContent.delete(seq);\n return { delivered: true };\n } catch (e) {\n if (e instanceof DeferDelivery) {\n this.deferCounts.set(seq, deferCount + 1);\n // Track content stability: byte-identical non-empty draft across\n // consecutive polls means the captain isn't actively typing (#302).\n const content = e.draft;\n if (content && content === this.lastContent.get(seq)) {\n this.stableCounts.set(seq, (this.stableCounts.get(seq) ?? 0) + 1);\n } else {\n this.stableCounts.set(seq, 0);\n }\n this.lastContent.set(seq, content);\n return { deferred: true };\n }\n // Non-DeferDelivery errors: don't advance cursor, retry next poll.\n return { deferred: true };\n }\n }\n}\n","// src/control/daemon/delivery.ts\n// Mailbox notification + daemon-direct captain delivery loop (#332).\nimport { appendToMailbox, readCursor, writeCursor, readFromCursor } from \"../mailbox.js\";\nimport { CaptainDelivery } from \"../delivery/captain-delivery.js\";\nimport { loadConfig, TERMINAL_STATES } from \"@squadrant/shared\";\nimport { STALE_THRESHOLD_MS } from \"./interactive-probe.js\";\nimport type { TaskRecord, ControlEvent } from \"@squadrant/shared\";\nimport type { PaneRef } from \"@squadrant/shared\";\nimport type { Store } from \"../store.js\";\nimport type { DaemonSurfaceDriver } from \"../interfaces.js\";\nimport type { DaemonContext } from \"./context.js\";\n\nconst CURSOR_SUBSCRIBER = \"captain\";\nconst CAPTAIN_GONE_STREAK_K = 3;\n\n/** Pure: find the captain surface by title in a surface list (#332). */\nexport function discoverCaptainSurface(surfaces: PaneRef[], captainTitle: string): PaneRef | null {\n return surfaces.find((s) => s.title === captainTitle) ?? null;\n}\n\n/**\n * Reap a stopped project's orphaned crews (#324). When the user closes the\n * captain workspace, its crew panes die with it — every non-terminal\n * interactive crew is orphaned. Terminalize them to 'cancelled' with a distinct\n * `captain-stopped` marker (traceable; not a fault). Silent: no push fires (the\n * captain that would receive it is gone). Returns the count reaped.\n *\n * Headless crews are excluded — they run as detached processes, not panes in the\n * captain's workspace, and are reconciled by their own pid liveness instead.\n */\nexport function reapOrphanedCrews(store: Pick<Store, \"list\" | \"put\">, project: string): number {\n let reaped = 0;\n for (const r of store.list(project)) {\n if (TERMINAL_STATES.has(r.state)) continue;\n if (r.mode !== \"interactive\") continue;\n store.put({ ...r, state: \"cancelled\", lastEvent: \"captain-stopped\" });\n reaped++;\n }\n return reaped;\n}\n\nexport interface DeliveryResult {\n defaultNotify: (args: { project: string; message: string; record: TaskRecord; event: ControlEvent }) => Promise<void>;\n /** Guarded delivery tick — undefined when daemon-direct mode is OFF. */\n deliveryTick: (() => Promise<void>) | undefined;\n}\n\nexport function createDelivery(\n ctx: DaemonContext,\n daemonCmux: DaemonSurfaceDriver | undefined,\n): DeliveryResult {\n const { stateRoot, store, log, captainMissingStreak, stoppedProjects, opts } = ctx;\n\n // ── Default push-notification wiring (mailbox-injector spec) ─────────────\n const defaultNotify = async (args: {\n project: string;\n message: string;\n record: TaskRecord;\n event: ControlEvent;\n }): Promise<void> => {\n try {\n await appendToMailbox({\n stateRoot,\n project: args.project,\n taskRecord: args.record,\n event: args.event,\n // Persist the daemon-rendered message (#214/#210): delivered verbatim\n // rather than re-derived from the raw event (which drifted).\n message: args.message,\n });\n } catch (e) {\n log(`mailbox append failed project=${args.project}: ${(e as Error).message}`);\n }\n };\n\n // ── Daemon-direct delivery loop ───────────────────────────────────────────\n if (!daemonCmux) {\n return { defaultNotify, deliveryTick: undefined };\n }\n\n const cmux = daemonCmux;\n const cfg = loadConfig();\n const deliveries = new Map<string, CaptainDelivery>();\n // Captured once at delivery-loop setup. Entries older than\n // sessionStartMs - STALE_THRESHOLD_MS are silently acked (cursor advanced)\n // without delivery. This stops a fresh/empty cursor from re-delivering the\n // entire historical backlog.\n const sessionStartMs = Date.now();\n\n // Re-entrancy guard: each tick does multiple slow cmux subprocess calls and\n // can exceed the 1s interval.\n let delivering = false;\n\n const deliveryCore = async () => {\n const injectedSurfaces = opts.captainSurfaces ?? {};\n const allProjects = [...new Set([\n ...Object.keys(cfg.projects ?? {}),\n ...Object.keys(injectedSurfaces),\n ...store.listAll().map((t) => t.project),\n ])];\n\n for (const project of allProjects) {\n const projCfg = cfg.projects?.[project];\n const captainTitle = projCfg?.captainName ?? `${project}-captain`;\n\n // Try real discovery from cmux.\n const wsId = cmux.findWorkspaceId ? await cmux.findWorkspaceId(captainTitle) : null;\n let surface: PaneRef | null = null;\n let surfacesLength = 0;\n\n if (wsId) {\n const surfaces = await cmux.listSurfaces(wsId);\n surfacesLength = surfaces.length;\n surface = discoverCaptainSurface(surfaces, captainTitle);\n }\n\n // Fall back to injected surface (tests / config-less projects).\n if (!surface) surface = injectedSurfaces[project] ?? null;\n\n if (surface) {\n // Captain found — if previously reaped, un-reap and reset streak.\n if (stoppedProjects.has(project)) {\n stoppedProjects.delete(project);\n captainMissingStreak.set(project, 0);\n }\n captainMissingStreak.set(project, 0);\n } else {\n // Streak tracking: surfaces.length > 0 means cmux is reachable but the\n // captain's pane is provably absent. surfaces.length === 0 means cmux\n // was unreachable (fail-soft → []), treat as \"unknown\" — never increment.\n if (surfacesLength > 0) {\n const streak = (captainMissingStreak.get(project) ?? 0) + 1;\n captainMissingStreak.set(project, streak);\n if (streak >= CAPTAIN_GONE_STREAK_K) {\n if (!stoppedProjects.has(project)) {\n stoppedProjects.add(project);\n const reaped = reapOrphanedCrews(store, project);\n log(`captain ${captainTitle}: surface gone for ${CAPTAIN_GONE_STREAK_K} sweeps — stopping delivery${reaped > 0 ? `, reaped ${reaped} orphaned crew(s)` : \"\"}`);\n }\n }\n }\n continue;\n }\n\n const cursor = await readCursor({ stateRoot, project, subscriber: CURSOR_SUBSCRIBER });\n const lastAcked = cursor?.lastAckedSeq ?? 0;\n let d = deliveries.get(project);\n if (!d) {\n d = new CaptainDelivery({\n maxDefers: cfg.delivery?.maxDeferDeliveries ?? 300,\n stableProbePolls: cfg.delivery?.stableProbePolls ?? 3,\n });\n deliveries.set(project, d);\n }\n for await (const entry of readFromCursor({ stateRoot, project, fromSeq: lastAcked + 1 })) {\n // #332 storm BUG 3: silently ack entries that pre-date this daemon\n // session by more than STALE_THRESHOLD_MS.\n if (new Date(entry.ts).getTime() < sessionStartMs - STALE_THRESHOLD_MS) {\n await writeCursor({ stateRoot, project, subscriber: CURSOR_SUBSCRIBER, lastAckedSeq: entry.seq });\n continue;\n }\n const result = await d.deliver(entry, (text, sendOpts) =>\n cmux.send(surface!, text, sendOpts),\n );\n if (\"delivered\" in result) {\n await writeCursor({ stateRoot, project, subscriber: CURSOR_SUBSCRIBER, lastAckedSeq: entry.seq });\n } else {\n break;\n }\n }\n }\n };\n\n const deliveryTick = async () => {\n if (delivering) return;\n delivering = true;\n try {\n await deliveryCore();\n } finally {\n delivering = false;\n }\n };\n\n return { defaultNotify, deliveryTick };\n}\n","// src/control/daemon/gates.ts\n// resolveInteractiveGate: route the captain's approve/deny to the owning driver.\n// Reads ctx.codexDriver and ctx.opencodeBridge lazily (set by squadrantd.ts before\n// any gate message can arrive on the socket).\nimport type { DaemonContext } from \"./context.js\";\n\nexport function createGateResolver(ctx: DaemonContext) {\n return async (taskId: string, payload: unknown): Promise<void> => {\n const rec = ctx.store.listAll().find((r) => r.id === taskId);\n try {\n if (rec?.provider === \"opencode\") {\n // Only an explicit \"approve\" approves; any other reply denies —\n // never auto-approve a permission gate.\n const decision = (payload as { decision?: string })?.decision === \"approve\" ? \"approve\" : \"deny\";\n await ctx.opencodeBridge.answer(taskId, decision);\n } else {\n await ctx.codexDriver.answer(taskId, payload);\n }\n } catch (e) { ctx.log(`gate-resolve answer failed: ${(e as Error).message}`); }\n };\n}\n","// src/control/daemon/server.ts\n// IPC socket server: message router + attach fan-in.\n// All state lives on DaemonContext; callbacks that can't yet be on ctx are\n// passed via ServerHandlers (built once in squadrantd.ts/start.ts).\nimport { startServer, encodeFrame } from \"../protocol.js\";\nimport type { AttachFrame, AttachInbound } from \"../protocol.js\";\nimport type { ComponentHealth } from \"../liveness.js\";\nimport type { DaemonSnapshotInputs } from \"../snapshot.js\";\nimport type { DaemonContext } from \"./context.js\";\n\nexport interface ServerHandlers {\n /** Build per-component health list (optionally filtered to one project). */\n buildHealth: (project?: string) => ComponentHealth[];\n /** Gather full snapshot inputs (all I/O). */\n gatherSnapshotInputs: (now: number) => Promise<DaemonSnapshotInputs>;\n /** Cancel pending gate-promotion timers when a client attaches. */\n cancelPromotionsFor: (taskId: string) => void;\n /** Fan-out an AttachFrame to all clients watching a task. */\n broadcast: (taskId: string, f: AttachFrame) => void;\n}\n\nexport function createServer(\n ctx: DaemonContext,\n handlers: ServerHandlers,\n) {\n const { store, log, attachConns } = ctx;\n const { buildHealth, gatherSnapshotInputs, cancelPromotionsFor, broadcast } = handlers;\n\n return startServer(ctx.sockPath, {\n handler: async (msg: any) => {\n if (msg.kind === \"seed\") { store.put(msg.record); return { ok: true }; }\n // Crew-close teardown for codex: the cmux pane only hosts the `crew attach`\n // renderer — the thread lives on the shared app-server, so closing the pane\n // doesn't reap it. `squadrant crew close` calls this to archive the thread and\n // its per-thread MCP servers (else they leak ~53MB/crew). Fires for terminal\n // and non-terminal crews alike.\n if (msg.kind === \"codex-close\") {\n await ctx.codexDriver.close(msg.taskId).catch((e: unknown) => log(`codex close err: ${e}`));\n return { ok: true };\n }\n // #77 service-health surface: per-component liveness for the queried project (or all).\n if (msg.kind === \"health\") {\n return buildHealth(msg.project as string | undefined);\n }\n // #44 dashboard: read-only full system snapshot (Tier 0/1/2).\n if (msg.kind === \"snapshot\") {\n const now = Date.now();\n const { assembleDaemonSnapshot } = await import(\"../snapshot.js\");\n return assembleDaemonSnapshot(await gatherSnapshotInputs(now), now);\n }\n if (msg.kind === \"event\") {\n return ctx.d.handle(msg);\n }\n return ctx.d.handle(msg);\n },\n onAttach: (conn, frame) => {\n let set = attachConns.get(frame.taskId);\n if (!set) { set = new Set(); attachConns.set(frame.taskId, set); }\n set.add(conn);\n // A client arriving within the 5s window defuses any pending gate timer.\n cancelPromotionsFor(frame.taskId);\n // Immediately ack the attach so the client knows it's live.\n try { conn.write(encodeFrame({ type: \"reattached\", taskId: frame.taskId })); } catch { /* ignore */ }\n },\n onAttachInbound: (_conn, frame) => {\n const f = frame as AttachInbound;\n if (f.op === \"say\")\n void ctx.codexDriver.say(f.taskId, f.text).catch((e: unknown) => log(`say err: ${e}`));\n else if (f.op === \"steer\")\n void ctx.codexDriver.steer(f.taskId, f.text).catch((e: unknown) => log(`steer err: ${e}`));\n else if (f.op === \"interrupt\")\n void ctx.codexDriver.interrupt(f.taskId).catch((e: unknown) => log(`interrupt err: ${e}`));\n else if (f.op === \"answer\")\n void ctx.codexDriver.answer(f.taskId, f.payload).catch((e: unknown) => log(`answer err: ${e}`));\n },\n onAttachClose: (conn) => {\n for (const set of attachConns.values()) set.delete(conn);\n },\n });\n}\n","// src/control/daemon/snapshot-gather.ts\n// Snapshot I/O edge: pure helpers that gather raw inputs for the snapshot verb.\n// Each tolerates missing files and never throws.\nimport { fileURLToPath } from \"node:url\";\nimport { join } from \"node:path\";\nimport {\n statSync, openSync, readSync, closeSync, readdirSync, readFileSync,\n} from \"node:fs\";\nimport type { DaemonSnapshotInputs, ResultArtifacts } from \"../snapshot.js\";\nimport type { TaskRecord } from \"@squadrant/shared\";\n\n// The compiled snapshot-gather.js shares the dist/ build time with squadrantd.js\n// (tsup compiles all entries in the same pass), so its mtime == dist build-time.\nconst SELF_PATH = fileURLToPath(import.meta.url);\n\n/** mtime (epoch ms) of the running daemon's compiled code, for build-freshness. */\nexport function distBuiltAt(): number {\n try { return statSync(SELF_PATH).mtimeMs; } catch { return 0; }\n}\n\n/** Daemon-log error count (last window) + total size. Reads only the tail so a\n * large log never makes the snapshot tick expensive. */\nexport function gatherLogStats(path: string, now: number, windowMs: number): DaemonSnapshotInputs[\"log\"] {\n let sizeBytes = 0;\n try { sizeBytes = statSync(path).size; }\n catch { return { errorCount: 0, sizeBytes: 0, windowMs }; }\n if (sizeBytes === 0) return { errorCount: 0, sizeBytes, windowMs };\n const CAP = 256 * 1024;\n const start = Math.max(0, sizeBytes - CAP);\n const len = sizeBytes - start;\n let text = \"\";\n try {\n const fd = openSync(path, \"r\");\n try {\n const buf = Buffer.alloc(len);\n readSync(fd, buf, 0, len, start);\n text = buf.toString(\"utf-8\");\n } finally { closeSync(fd); }\n } catch { return { errorCount: 0, sizeBytes, windowMs }; }\n const cutoff = now - windowMs;\n let errorCount = 0;\n for (const line of text.split(\"\\n\")) {\n if (!/error|failed/i.test(line)) continue;\n // Lines carry an ISO timestamp (\"[squadrantd] 2026-... msg\"); skip ones older\n // than the window. Lines without a parseable timestamp are counted (conservative).\n const m = line.match(/\\d{4}-\\d{2}-\\d{2}T[\\d:.]+Z/);\n if (m) { const ts = Date.parse(m[0]); if (!Number.isNaN(ts) && ts < cutoff) continue; }\n errorCount++;\n }\n return { errorCount, sizeBytes, windowMs };\n}\n\n/** Per-project store state counts + corrupt/quarantined file count. */\nexport function gatherStoreStats(\n store: { list: (p: string) => TaskRecord[] },\n stateRoot: string,\n project: string,\n): { byState: Record<string, number>; corruptCount: number } {\n const byState: Record<string, number> = {};\n for (const r of store.list(project)) byState[r.state] = (byState[r.state] ?? 0) + 1;\n let corruptCount = 0;\n const dir = join(stateRoot, project);\n try {\n for (const n of readdirSync(dir)) {\n if (n.includes(\".corrupt.\")) { corruptCount++; continue; }\n if (!n.endsWith(\".json\")) continue;\n try { JSON.parse(readFileSync(join(dir, n), \"utf-8\")); }\n catch { corruptCount++; }\n }\n } catch { /* no project dir yet */ }\n return { byState, corruptCount };\n}\n\n/** Global _results/ artifact count + total bytes (unbounded-growth watch). */\nexport function gatherResults(resultsDir: string): ResultArtifacts {\n let fileCount = 0;\n let totalBytes = 0;\n try {\n for (const n of readdirSync(resultsDir)) {\n try {\n const s = statSync(join(resultsDir, n));\n if (s.isFile()) { fileCount++; totalBytes += s.size; }\n } catch { /* vanished mid-scan */ }\n }\n } catch { /* no results dir */ }\n return { fileCount, totalBytes };\n}\n","// src/control/daemon/start.ts\n// Core daemon assembly: wires all daemon/* factories, runs boot recovery,\n// starts timers, and returns the DaemonHandle.\n// Concrete driver construction (CodexInteractiveDriver, DaemonCmux, etc.)\n// lives in the host (squadrantd.ts) — this file stays free of those imports.\nimport { join, dirname } from \"node:path\";\nimport { readdir } from \"node:fs/promises\";\nimport { createDaemon } from \"../daemon.js\";\nimport { createProbes, buildSurfaceProbe } from \"./probes.js\";\nimport { createDelivery } from \"./delivery.js\";\nimport { createGateResolver } from \"./gates.js\";\nimport { createServer } from \"./server.js\";\nimport { rotateIfNeeded, mailboxStats, readCursor } from \"../mailbox.js\";\nimport { projectHealth, type ComponentHealth } from \"../liveness.js\";\nimport type { DaemonSnapshotInputs } from \"../snapshot.js\";\nimport { loadConfig, TERMINAL_STATES, ensureCmuxAutoConfig } from \"@squadrant/shared\";\nimport { distBuiltAt, gatherLogStats, gatherStoreStats, gatherResults } from \"./snapshot-gather.js\";\nimport type { SquadrantdOpts, DaemonContext } from \"./context.js\";\n\nconst CURSOR_SUBSCRIBER = \"captain\";\nconst SNAPSHOT_LOG_WINDOW_MS = 60 * 60 * 1000;\n\nexport interface DaemonHandle {\n stop(): Promise<void>;\n tickDelivery: (() => Promise<void>) | undefined;\n tickProbe: (() => Promise<void>) | undefined;\n}\n\n/** Wire all daemon/* factories, run boot recovery, start timers.\n * ctx must already have: attach handlers, codexDriver, opencodeBridge,\n * cmuxEventsBridge, daemonCmux, daemonDirectCmux set on it by the host. */\nexport function startDaemon(ctx: DaemonContext, opts: SquadrantdOpts, pkgVersion: string): DaemonHandle {\n const {\n stateRoot, store, log, isPidAlive, resultsDir,\n taskTimeoutMs, inFlightHeadlessIds, activeHeadlessKills,\n broadcast, cancelPromotionsFor,\n } = ctx;\n const { daemonCmux } = ctx;\n\n const probes = createProbes(ctx);\n const { defaultNotify, deliveryTick: initialDeliveryTick } = createDelivery(ctx, daemonCmux);\n // Compose the Telegram outbound push onto the notify fan-out: a captain\n // notification also pushes to the project's Telegram topic. When no bridge is\n // configured, notify is the base function unchanged (zero behavior change).\n // pushLifecycle is best-effort and never throws (the bridge swallows errors),\n // so it can't delay or break captain delivery.\n const baseNotify = opts.notify ?? defaultNotify;\n const notify: DaemonContext[\"notify\"] = ctx.telegramBridge\n ? async (args) => {\n await baseNotify(args);\n ctx.telegramBridge!.pushLifecycle(args.project, args.event);\n }\n : baseNotify;\n const surfaceProbe = buildSurfaceProbe(ctx, probes, daemonCmux);\n\n const ingest = (project: string) => (e: import(\"@squadrant/shared\").ControlEvent) =>\n void ctx.d.handle({ kind: \"event\", project, event: e });\n\n const d = createDaemon({\n store, now: () => Date.now(), isPidAlive, notify, taskTimeoutMs,\n isSurfaceAlive: surfaceProbe,\n launchHeadless: opts.launchHeadless!,\n isHeadlessInFlight: (id) => inFlightHeadlessIds.has(id),\n launchInteractive: async (rec) => {\n if (rec.provider === \"codex\") {\n await ctx.codexDriver.dispatch(rec as any);\n return;\n }\n if (rec.provider === \"claude\") {\n ingest(rec.project)({ type: \"task.started\", id: rec.id });\n return;\n }\n if (rec.provider === \"opencode\") {\n ingest(rec.project)({ type: \"task.started\", id: rec.id });\n if (rec.serverPort) ctx.opencodeBridge.start({ taskId: rec.id, port: rec.serverPort });\n return;\n }\n throw new Error(\n `interactive mode is not yet implemented for provider '${rec.provider}'; only 'codex', 'claude', and 'opencode' are supported`,\n );\n },\n resolveInteractiveGate: createGateResolver(ctx),\n });\n\n ctx.d = d;\n\n // ── Health + snapshot ─────────────────────────────────────────────────────\n\n function buildHealth(only?: string): ComponentHealth[] {\n const config = loadConfig();\n const now = Date.now();\n const known = new Set<string>([\n ...Object.keys(config.projects),\n ...store.listAll().map((t) => t.project),\n ]);\n const names = only ? [only] : [...known];\n const out: ComponentHealth[] = [];\n for (const project of names) {\n const proj = config.projects[project];\n const captainName = proj?.captainName ?? `${project}-captain`;\n // Captain liveness from the delivery loop: stopped=true → gone,\n // streak===0 → alive (last tick found the surface), else unknown.\n const stopped = ctx.stoppedProjects.has(project);\n const streak = ctx.captainMissingStreak.get(project);\n const captainStopped: boolean | null = stopped ? true : streak === 0 ? false : null;\n out.push(\n ...projectHealth({\n project, now, captainName,\n captainStopped,\n commandPresent: null,\n crews: store.list(project),\n }),\n );\n }\n return out;\n }\n\n async function gatherSnapshotInputs(now: number): Promise<DaemonSnapshotInputs> {\n const logPath = join(dirname(stateRoot), \"squadrantd.log\");\n const tier2Projects = opts.registeredProjects ?? Object.keys(loadConfig().projects);\n const projects = await Promise.all(\n tier2Projects.map(async (project) => {\n const cursor = await readCursor({ stateRoot, project, subscriber: CURSOR_SUBSCRIBER });\n const storeStats = gatherStoreStats(store, stateRoot, project);\n return {\n project,\n mailbox: await mailboxStats(stateRoot, project),\n lastAckedSeq: cursor?.lastAckedSeq ?? 0,\n storeByState: storeStats.byState,\n corruptCount: storeStats.corruptCount,\n };\n }),\n );\n return {\n pid: process.pid,\n processStartedAt: ctx.bootedAt,\n version: pkgVersion,\n distBuiltAt: distBuiltAt(),\n lastSweepAt: ctx.lastSweepAt.value,\n sweepCadenceMs: opts.sweepMs ?? 30_000,\n log: gatherLogStats(logPath, now, SNAPSHOT_LOG_WINDOW_MS),\n health: buildHealth(),\n projects,\n results: gatherResults(resultsDir),\n };\n }\n\n // ── Boot recovery ─────────────────────────────────────────────────────────\n\n void (async () => {\n try { await d.reconcile(); }\n catch (e) { log(`reconcile on boot failed: ${(e as Error).message}`); }\n\n // Restart-reattach: reattach live codex crews. Guard against the storm\n // (each reattach re-spawns per-thread MCP servers). Skip terminal and stale tasks.\n // Inline predicate avoids importing from the concrete codex driver module.\n const bootNow = Date.now();\n const REATTACH_STALE_MS = 10 * 60_000;\n for (const rec of store.listAll()) {\n if (rec.provider !== \"codex\" || rec.mode !== \"interactive\") continue;\n if (TERMINAL_STATES.has(rec.state)) continue;\n // Inline of shouldReattachCodex (concrete driver module stays in host).\n const lastAttempt = rec.attempts?.at(-1);\n const last = lastAttempt?.lastHeartbeatAt ?? rec.lastHeartbeat ?? 0;\n if (bootNow - last > REATTACH_STALE_MS) continue;\n if (!lastAttempt?.resumeRef) continue;\n ctx.codexDriver.reattach(rec).catch((e: unknown) => {\n log(`reattach failed for ${rec.id}: ${(e as Error).message}`);\n });\n }\n\n // Re-subscribe opencode SSE bridge after a daemon bounce.\n for (const rec of store.listAll()) {\n if (rec.provider !== \"opencode\" || rec.mode !== \"interactive\") continue;\n if (TERMINAL_STATES.has(rec.state)) continue;\n if (!rec.serverPort) continue;\n ctx.opencodeBridge.start({ taskId: rec.id, port: rec.serverPort });\n }\n\n // B1: start cmux native-events bridge. Skipped under vitest unless injected.\n const enableCmuxEvents = loadConfig().defaults.cmuxEventsBridge !== false;\n const cmuxEventsSafe = !!opts.cmuxEventsBridge || !process.env.VITEST;\n if (enableCmuxEvents && cmuxEventsSafe) {\n try { ctx.cmuxEventsBridge.start(); }\n catch (e) { log(`cmux events bridge start failed: ${(e as Error).message}`); }\n }\n\n // Telegram inbound long-poll (opt-in). The real bridge is only constructed\n // by the host when config.telegram is present and not under vitest, so\n // ctx.telegramBridge here is either that real bridge or an injected fake.\n if (ctx.telegramBridge) {\n try { ctx.telegramBridge.start(); }\n catch (e) { log(`telegram bridge start failed: ${(e as Error).message}`); }\n }\n\n // #348: cmux socket auto-config on boot.\n const autoConfigSafe = !!opts.runCmuxAutoConfig || !process.env.VITEST;\n if (autoConfigSafe) {\n try {\n const r = await (opts.runCmuxAutoConfig ?? ensureCmuxAutoConfig)();\n if (r.configChanged) log(`cmux autoconfig: wrote automation socket mode to ${r.configPath}`);\n if (r.needsRestart && r.promptedThisRun) {\n log(\"cmux autoconfig: socket still rejects the daemon — restart cmux to enable daemon-direct delivery\");\n }\n } catch (e) {\n log(`cmux autoconfig failed: ${(e as Error).message}`);\n }\n }\n })();\n\n // ── Server + timers ───────────────────────────────────────────────────────\n\n const server = createServer(ctx, { buildHealth, gatherSnapshotInputs, cancelPromotionsFor, broadcast });\n log(`started pid=${process.pid} sock=${ctx.sockPath} stateRoot=${stateRoot}`);\n\n let deliveryTick: (() => Promise<void>) | undefined = initialDeliveryTick;\n let probeTick: (() => Promise<void>) | undefined;\n\n if (daemonCmux) {\n probeTick = probes.buildInteractiveProbe({ cmux: daemonCmux });\n }\n\n let deliveryTimer: NodeJS.Timeout | undefined;\n if (daemonCmux && opts.sweepMs && opts.sweepMs > 0) {\n deliveryTimer = setInterval(() => {\n void deliveryTick!().catch((e: unknown) => log(`delivery tick error: ${(e as Error).message}`));\n }, 1000);\n deliveryTimer.unref?.();\n }\n\n let probeTimer: NodeJS.Timeout | undefined;\n if (daemonCmux && opts.sweepMs && opts.sweepMs > 0) {\n probeTimer = setInterval(() => {\n void probeTick!().catch((e: unknown) => log(`probe tick error: ${(e as Error).message}`));\n }, 10_000);\n probeTimer.unref?.();\n }\n\n let timer: NodeJS.Timeout | undefined;\n if (opts.sweepMs && opts.sweepMs > 0) {\n let sweeping = false;\n timer = setInterval(() => {\n if (sweeping) return;\n sweeping = true;\n ctx.lastSweepAt.value = Date.now();\n void d.sweep()\n .catch((e: unknown) => log(`sweep failed: ${(e as Error).message}`))\n .finally(() => { sweeping = false; });\n }, opts.sweepMs);\n timer.unref?.();\n }\n\n const rotationInterval = opts.rotationIntervalMs ?? 60_000;\n const mboxCfg = {\n maxBytes: opts.mailboxConfig?.maxBytes ?? 5 * 1024 * 1024,\n maxAgeMs: opts.mailboxConfig?.maxAgeMs ?? 7 * 24 * 60 * 60 * 1000,\n keepCount: opts.mailboxConfig?.keepCount ?? 3,\n };\n let rotationTimer: NodeJS.Timeout | undefined;\n if (rotationInterval > 0) {\n const inboxPath = join(stateRoot, \"inbox\");\n rotationTimer = setInterval(async () => {\n try {\n let entries: string[];\n try { entries = await readdir(inboxPath); } catch { return; }\n const projects = new Set(\n entries.filter((e) => e.endsWith(\".log\")).map((e) => e.slice(0, -\".log\".length)),\n );\n for (const project of projects) await rotateIfNeeded({ stateRoot, project, ...mboxCfg });\n } catch (e) {\n log(`rotation timer error: ${(e as Error).message}`);\n }\n }, rotationInterval);\n rotationTimer.unref?.();\n }\n\n return {\n stop(): Promise<void> {\n if (deliveryTimer) clearInterval(deliveryTimer);\n if (probeTimer) clearInterval(probeTimer);\n if (timer) clearInterval(timer);\n if (rotationTimer) clearInterval(rotationTimer);\n try { ctx.cmuxEventsBridge.stop(); } catch { /* best-effort */ }\n try { ctx.telegramBridge?.stop(); } catch { /* best-effort */ }\n try { ctx.codexDriver.stop?.(); } catch { /* best-effort */ }\n for (const kill of ctx.activeHeadlessKills) kill();\n return new Promise<void>((resolve) => server.close(() => { log(\"stopped\"); resolve(); }));\n },\n tickDelivery: deliveryTick,\n tickProbe: probeTick,\n };\n}\n","// Session freshness logic — daily + templateHash rotation.\n// Extracted from packages/cli/src/commands/launch.ts so it can be\n// unit-tested without spawning real processes.\n\nimport crypto from \"node:crypto\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\n\nexport interface SessionRecord {\n lastLaunched: string; // YYYY-MM-DD\n templateHash: string;\n}\n\nexport interface SessionsFile {\n workspaces: Record<string, SessionRecord>;\n}\n\nexport function loadSessions(sessionsPath: string): SessionsFile {\n try {\n return JSON.parse(fs.readFileSync(sessionsPath, \"utf-8\")) as SessionsFile;\n } catch {\n return { workspaces: {} };\n }\n}\n\nexport function saveSessions(sessionsPath: string, sessions: SessionsFile): void {\n const dir = path.dirname(sessionsPath);\n fs.mkdirSync(dir, { recursive: true });\n fs.writeFileSync(sessionsPath, JSON.stringify(sessions, null, 2) + \"\\n\");\n}\n\nexport function computeTemplateHash(role: string, templatesDir: string): string {\n const hash = crypto.createHash(\"sha256\");\n\n const roleFile = path.join(templatesDir, `${role}.claude.md`);\n const legacyRoleFile = path.join(templatesDir, `${role}.CLAUDE.md`);\n if (fs.existsSync(roleFile)) {\n hash.update(fs.readFileSync(roleFile, \"utf-8\"));\n } else if (fs.existsSync(legacyRoleFile)) {\n hash.update(fs.readFileSync(legacyRoleFile, \"utf-8\"));\n }\n\n const pluginSkillsDir = path.join(templatesDir, \"..\", \"plugin\", \"skills\");\n if (fs.existsSync(pluginSkillsDir)) {\n for (const skill of fs.readdirSync(pluginSkillsDir).sort()) {\n const skillFile = path.join(pluginSkillsDir, skill, \"SKILL.md\");\n if (fs.existsSync(skillFile)) {\n hash.update(fs.readFileSync(skillFile, \"utf-8\"));\n }\n }\n }\n\n return hash.digest(\"hex\").slice(0, 16);\n}\n\nexport function shouldStartFresh(\n workspaceName: string,\n role: string,\n opts: { sessionsPath: string; templatesDir: string },\n): { fresh: boolean; reason?: string } {\n const sessions = loadSessions(opts.sessionsPath);\n const record = sessions.workspaces[workspaceName];\n const today = new Date().toISOString().slice(0, 10);\n const currentHash = computeTemplateHash(role, opts.templatesDir);\n\n if (!record) {\n return { fresh: true, reason: \"first launch\" };\n }\n\n if (record.lastLaunched !== today) {\n return { fresh: true, reason: \"new day — starting fresh session\" };\n }\n\n if (record.templateHash !== currentHash) {\n return { fresh: true, reason: \"template instructions updated\" };\n }\n\n return { fresh: false };\n}\n\nexport function recordSession(\n workspaceName: string,\n role: string,\n opts: { sessionsPath: string; templatesDir: string },\n): void {\n const sessions = loadSessions(opts.sessionsPath);\n sessions.workspaces[workspaceName] = {\n lastLaunched: new Date().toISOString().slice(0, 10),\n templateHash: computeTemplateHash(role, opts.templatesDir),\n };\n saveSessions(opts.sessionsPath, sessions);\n}\n","// Pure crew protocol and naming primitives — no I/O, no external-package deps.\n// Extracted from packages/cli/src/commands/crew.ts so they are unit-testable\n// and importable by packages other than cli.\n\n/** Configuration for the post-send acceptance check that replaces a naive\n * screen-changed comparison. For agents whose idle splash keeps mutating\n * (opencode's \"Ask anything…\" with blinking cursor / status line), the old\n * check would always see a different screen and never re-send a dropped turn. */\nexport interface TurnAcceptanceConfig {\n /** Text that identifies the idle splash state. When set, acceptance requires\n * this marker to be absent from the screen (e.g. \"Ask anything…\" for opencode).\n * Without it, acceptance defaults to \"screen changed\" (claude behavior). */\n splashMarker?: string;\n /** Max rounds of \"wait, check, re-send\" after the initial send. Defaults to 2\n * (initial + 1 re-send) to match the pre-retry behavior for claude. Use 3 for\n * opencode which has a wider boot-race window. */\n retryLimit?: number;\n}\n\n/** Pure-function decision: was the first turn accepted by the TUI?\n * - With splashMarker: accepted = the marker is no longer visible (the TUI left\n * its idle splash, confirming the keystroke was received).\n * - Without splashMarker (claude): accepted = the screen changed after sending. */\nexport function isTurnAccepted(\n preSendScreen: string,\n afterScreen: string,\n config?: TurnAcceptanceConfig,\n): boolean {\n if (config?.splashMarker) {\n return !afterScreen.includes(config.splashMarker);\n }\n return afterScreen !== preSendScreen;\n}\n\n/** Builds the completion-protocol suffix baked into claude + opencode first turns (#278).\n * Substituting --task-id and --project at source makes the signal robust to env-var\n * races (Mode 1) and gives the model a concrete imperative at the point of action (Mode 2).\n *\n * WARNING: The exact output text is load-bearing — a single byte change silently\n * breaks crew DONE. Any modification must be validated against the crew-lifecycle\n * checklist CP-DONE checkpoint. A snapshot test guards against drift. */\nexport function buildCompletionProtocol(taskId: string, project: string): string {\n return [\n \"---\",\n \"COMPLETION PROTOCOL (required): When this task is fully complete, your FINAL action MUST be to run exactly:\",\n ` squadrant crew signal done --task-id ${taskId} --project ${project} --message \"<one-line summary>\"`,\n \"Run it as a discrete final step AFTER you report your results. If you are blocked or need a decision, instead run:\",\n ` squadrant crew signal blocked --task-id ${taskId} --project ${project} --question \"<your question>\"`,\n \"If this task failed because of a defect in squadrant itself (not an API/infra blip, a config/user error, or an expected failure), say so in your signal done/blocked message so the captain can check tu11aa/squadrant and file it. Don't file issues from the crew.\",\n ].join(\"\\n\");\n}\n\n// POSIX single-quote a path so it is safe to embed in a shell command even\n// when the path contains spaces or special characters.\nexport function shellQuote(p: string): string {\n return \"'\" + p.replace(/'/g, \"'\\\\''\") + \"'\";\n}\n\nexport function titleFor(project: string, name: string): string {\n return `🔧 ${project}:${name}`;\n}\n\nexport function isCrewTitle(project: string, title: string): boolean {\n return title.startsWith(`🔧 ${project}:`);\n}\n\nexport function nameFromTitle(project: string, title: string): string {\n return title.slice(`🔧 ${project}:`.length);\n}\n\nexport function nextAutoName(existingTitles: string[], project: string): string {\n const used = new Set<number>();\n for (const title of existingTitles) {\n const n = nameFromTitle(project, title).match(/^crew-(\\d+)$/);\n if (n) used.add(Number(n[1]));\n }\n let i = 1;\n while (used.has(i)) i++;\n return `crew-${i}`;\n}\n","// Crew child-process lifecycle management.\n// Extracted from packages/cli/src/commands/crew.ts so it is importable from\n// packages other than cli and testable with an injected exec function.\n\nimport { exec as nodeExec } from \"node:child_process\";\n\ntype ExecFn = (\n cmd: string,\n opts: { maxBuffer: number },\n cb: (err: Error | null, stdout: string) => void,\n) => void;\n\n/** Kill every process that inherited SQUADRANT_CREW_TASK_ID=<taskId> from the\n * crew's shell env prefix. Uses `ps auxE` which exposes env vars for node\n * processes on macOS (vitest workers, the crew CLI, etc.). Best-effort:\n * swallows all errors so a childless crew still closes cleanly.\n *\n * @param graceMs - ms between SIGTERM and SIGKILL (default 2 s; pass a short\n * value in tests to avoid waiting)\n * @param execFn - injectable for testing; defaults to node:child_process.exec\n */\nexport async function reapCrewChildren(\n taskId: string,\n graceMs = 2000,\n execFn: ExecFn = nodeExec,\n): Promise<void> {\n const marker = `SQUADRANT_CREW_TASK_ID=${taskId}`;\n try {\n const stdout = await new Promise<string>((resolve, reject) => {\n // `ps auxE` dumps every process's full env, which on a busy machine far\n // exceeds exec's default 1 MB maxBuffer (~2.7 MB with ~1k procs). Without\n // a raised cap the call errors with \"maxBuffer length exceeded\", the outer\n // catch swallows it, and the reap silently no-ops — leaving crew children\n // alive. 64 MB comfortably covers thousands of processes.\n execFn(\"ps auxE\", { maxBuffer: 64 * 1024 * 1024 }, (err, out) =>\n err ? reject(err) : resolve(out),\n );\n });\n const pids: number[] = [];\n for (const line of stdout.split(\"\\n\").slice(1)) {\n if (!line.includes(marker)) continue;\n const pid = parseInt(line.trim().split(/\\s+/)[1], 10);\n if (!isNaN(pid) && pid !== process.pid) pids.push(pid);\n }\n if (pids.length === 0) return;\n for (const pid of pids) {\n try { process.kill(pid, \"SIGTERM\"); } catch { /* already gone */ }\n }\n await new Promise<void>((r) => setTimeout(r, graceMs));\n for (const pid of pids) {\n try { process.kill(pid, \"SIGKILL\"); } catch { /* already gone */ }\n }\n } catch { /* best-effort */ }\n}\n","// Pure auth predicates for the Telegram CONTROL surfaces (auto-launch, general\n// commands). No I/O. Fail-closed: control requires both the master switch and a\n// user-id match — chat membership alone is never enough for control.\nimport type { TelegramConfig } from \"@squadrant/shared\";\n\nexport function isControlEnabled(cfg: TelegramConfig): boolean {\n return cfg.remoteControl === true;\n}\n\nexport function isAuthorized(fromId: number | undefined, cfg: TelegramConfig): boolean {\n if (fromId === undefined) return false;\n return Array.isArray(cfg.users) && cfg.users.includes(fromId);\n}\n","// Curated registry for the Telegram GENERAL command channel (#402). Pure logic:\n// parses \"/cmd args\" into a squadrant CLI argv vector — never a shell string. No\n// I/O, no execution (Task 5 wires argv → async execFile). Default-deny on\n// /config set: only WRITABLE_CONFIG_KEYS may be written over Telegram, so secrets\n// (botToken/users/chats/supergroupId) can never be set from the phone.\n//\n// argv tokens are verified against the real CLI (packages/cli/src/commands/):\n// status → `status`, projects → `projects list`, crews → `crew list <p>`,\n// launch → `launch <p>`, effort → `effort [mode]`, config → `config get|set`,\n// spawn → `crew spawn <p> <task>`.\n\nexport type ParsedCommand =\n | { kind: \"ok\"; name: string; argv: string[] } // argv to pass to the squadrant CLI\n | { kind: \"usage\"; name: string; message: string } // known command, bad args\n | { kind: \"unknown\"; message: string } // not in registry / not a slash command\n | { kind: \"denied\"; message: string }; // e.g. /config set on a protected key\n\n/** Default-deny allowlist of config keys writable over Telegram (#321). Starts\n * intentionally tiny; extend deliberately. Secrets are NEVER added here. */\nexport const WRITABLE_CONFIG_KEYS: readonly string[] = [\"defaults.effort\"];\n\nconst EFFORT_MODES = new Set([\"max\", \"balance\", \"low\"]);\n\ninterface Entry {\n /** Build the argv (or a usage/denied result) from the post-name token list. */\n build(args: string[]): ParsedCommand;\n usage: string;\n}\n\nfunction ok(name: string, argv: string[]): ParsedCommand {\n return { kind: \"ok\", name, argv };\n}\nfunction usage(name: string, message: string): ParsedCommand {\n return { kind: \"usage\", name, message };\n}\n\nconst REGISTRY: Record<string, Entry> = {\n status: { usage: \"/status\", build: () => ok(\"status\", [\"status\"]) },\n projects: { usage: \"/projects\", build: () => ok(\"projects\", [\"projects\", \"list\"]) },\n crews: {\n usage: \"/crews <project>\",\n build: (a) => (a[0] ? ok(\"crews\", [\"crew\", \"list\", a[0]]) : usage(\"crews\", \"usage: /crews <project>\")),\n },\n launch: {\n usage: \"/launch <project>\",\n build: (a) => (a[0] ? ok(\"launch\", [\"launch\", a[0]]) : usage(\"launch\", \"usage: /launch <project>\")),\n },\n effort: {\n usage: \"/effort [max|balance|low]\",\n build: (a) => {\n if (a.length === 0) return ok(\"effort\", [\"effort\"]);\n if (!EFFORT_MODES.has(a[0])) return usage(\"effort\", \"usage: /effort [max|balance|low]\");\n return ok(\"effort\", [\"effort\", a[0]]);\n },\n },\n config: {\n usage: \"/config get <key> | /config set <key> <value>\",\n build: (a) => {\n const sub = a[0];\n if (sub === \"get\") {\n const key = a[1];\n if (!key) return usage(\"config\", \"usage: /config get <key>\");\n return ok(\"config\", [\"config\", \"get\", key]);\n }\n if (sub === \"set\") {\n const key = a[1];\n const value = a.slice(2).join(\" \");\n if (!key || value === \"\") return usage(\"config\", \"usage: /config set <key> <value>\");\n if (!WRITABLE_CONFIG_KEYS.includes(key)) {\n return {\n kind: \"denied\",\n message: `⛔ '${key}' is not writable over Telegram. Allowed: ${WRITABLE_CONFIG_KEYS.join(\", \")}`,\n };\n }\n return ok(\"config\", [\"config\", \"set\", key, value]);\n }\n return usage(\"config\", \"usage: /config get <key> | /config set <key> <value>\");\n },\n },\n spawn: {\n usage: \"/spawn <project> <task...>\",\n build: (a) => {\n const project = a[0];\n const task = a.slice(1).join(\" \");\n if (!project || task === \"\") return usage(\"spawn\", \"usage: /spawn <project> <task...>\");\n return ok(\"spawn\", [\"crew\", \"spawn\", project, task]);\n },\n },\n};\n\nfunction helpText(): string {\n const lines = Object.values(REGISTRY).map((e) => ` ${e.usage}`);\n return [\"Available commands:\", ...lines, \" /help\"].join(\"\\n\");\n}\n\n/** Parse a raw Telegram message into a curated command. Non-slash text and\n * unregistered commands return `unknown`. */\nexport function parseCommand(text: string): ParsedCommand {\n const trimmed = text.trim();\n if (!trimmed.startsWith(\"/\")) {\n return { kind: \"unknown\", message: \"unknown command — send /help\" };\n }\n const tokens = trimmed.slice(1).split(/\\s+/).filter((t) => t.length > 0);\n const name = (tokens[0] ?? \"\").toLowerCase();\n const args = tokens.slice(1);\n\n if (name === \"help\") {\n return { kind: \"usage\", name: \"help\", message: helpText() };\n }\n const entry = REGISTRY[name];\n if (!entry) {\n return { kind: \"unknown\", message: `unknown command '/${name}' — send /help` };\n }\n return entry.build(args);\n}\n","// Boot-if-down capability for Telegram auto-launch (#403). Mirrors the\n// `group dispatch` warmup pattern (liveness probe → spawn `squadrant launch` →\n// bounded warmup poll) but as an injectable factory: deps are stubbed in tests\n// and wired from the daemon host (Task 5). The bridge stays decoupled from\n// captain lifecycle — it only sees the returned `ensure(project)` closure.\n//\n// Debounce: concurrent calls for the same project share ONE launch + poll loop\n// via an in-flight promise map, so a burst of inbound messages can't spawn N\n// captains. The map entry clears on resolution (alive | launched | timeout).\n\nexport type EnsureResult = \"alive\" | \"launched\" | \"timeout\";\n\nexport interface EnsureCaptainDeps {\n isAlive: (project: string) => Promise<boolean>; // liveness probe\n launch: (project: string) => Promise<void>; // spawn `squadrant launch <project>`\n warmupTimeoutMs?: number; // default 120_000\n pollMs?: number; // default 1_000\n sleep?: (ms: number) => Promise<void>; // injectable for tests\n now?: () => number; // injectable for tests\n}\n\nconst DEFAULT_WARMUP_TIMEOUT_MS = 120_000;\nconst DEFAULT_POLL_MS = 1_000;\nconst defaultSleep = (ms: number) => new Promise<void>((r) => setTimeout(r, ms));\n\nexport function createEnsureCaptainAlive(\n deps: EnsureCaptainDeps,\n): (project: string) => Promise<EnsureResult> {\n const warmupTimeoutMs = deps.warmupTimeoutMs ?? DEFAULT_WARMUP_TIMEOUT_MS;\n const pollMs = deps.pollMs ?? DEFAULT_POLL_MS;\n const sleep = deps.sleep ?? defaultSleep;\n const now = deps.now ?? (() => Date.now());\n\n const inFlight = new Map<string, Promise<EnsureResult>>();\n\n async function run(project: string): Promise<EnsureResult> {\n if (await deps.isAlive(project)) return \"alive\";\n await deps.launch(project);\n const deadline = now() + warmupTimeoutMs;\n while (now() < deadline) {\n if (await deps.isAlive(project)) return \"launched\";\n await sleep(pollMs);\n }\n return \"timeout\";\n }\n\n return function ensure(project: string): Promise<EnsureResult> {\n // The guard is read+set synchronously (no await before set) so concurrent\n // callers for the same project provably share a single launch.\n const existing = inFlight.get(project);\n if (existing) return existing;\n const p = run(project).finally(() => inFlight.delete(project));\n inFlight.set(project, p);\n return p;\n };\n}\n","// Pure formatters for the Telegram bridge. No I/O, no side effects.\nimport type { ControlEvent } from \"@squadrant/shared\";\n\n/** Forum-topic title for a project. v1 uses the project name verbatim. */\nexport function topicName(project: string): string {\n return project;\n}\n\n/** Outbound text pushed to a project's Telegram topic for a lifecycle event. */\nexport function formatLifecycle(project: string, ev: ControlEvent): string {\n switch (ev.type) {\n case \"task.done\":\n return `✅ [${project}] CREW DONE · ${ev.id}` + (ev.message ? `\\n${ev.message}` : \"\");\n case \"task.blocked\":\n return `🚧 [${project}] CREW BLOCKED · ${ev.id}\\n${ev.question}`;\n case \"task.idle\":\n return `💤 [${project}] CREW IDLE · ${ev.id}`;\n default:\n return `ℹ️ [${project}] ${ev.type} · ${ev.id}`;\n }\n}\n\n/** Captain-pane rendering of an inbound Telegram reply — labeled as external. */\nexport function formatInbound(text: string): string {\n return `📩 [from Telegram] ${text}`;\n}\n\n/** Mask all but the last 4 characters of a bot token for safe display. */\nexport function maskToken(token: string): string {\n if (token.length <= 4) return token;\n return \"*\".repeat(token.length - 4) + token.slice(-4);\n}\n","// Persisted Telegram bridge state: getUpdates offset + (project,scope) → topicId\n// registry. Synchronous JSON in stateRoot/telegram-state.json.\nimport fs from \"node:fs\";\nimport path from \"node:path\";\n\nexport interface TelegramState {\n offset: number;\n /** key = `${project}::${scope}` (see topicKey); value = message_thread_id. */\n topics: Record<string, number>;\n}\n\nfunction statePath(stateRoot: string): string {\n return path.join(stateRoot, \"telegram-state.json\");\n}\n\n/** Registry key for a topic. v1 only ever uses scope \"project\"; per-crew routing\n * (scope \"crew:<taskId>\") is additive later without a schema change. */\nexport function topicKey(project: string, scope = \"project\"): string {\n return `${project}::${scope}`;\n}\n\nexport function loadState(stateRoot: string): TelegramState {\n try {\n const raw = fs.readFileSync(statePath(stateRoot), \"utf-8\");\n const data = JSON.parse(raw) as Partial<TelegramState>;\n return {\n offset: typeof data.offset === \"number\" ? data.offset : 0,\n topics: data.topics ?? {},\n };\n } catch {\n return { offset: 0, topics: {} };\n }\n}\n\nexport function saveState(stateRoot: string, s: TelegramState): void {\n fs.mkdirSync(stateRoot, { recursive: true });\n fs.writeFileSync(statePath(stateRoot), JSON.stringify(s, null, 2) + \"\\n\");\n}\n\nexport function setTopic(\n stateRoot: string,\n project: string,\n topicId: number,\n scope = \"project\",\n): void {\n const s = loadState(stateRoot);\n s.topics[topicKey(project, scope)] = topicId;\n saveState(stateRoot, s);\n}\n\nexport function findProjectByThread(\n stateRoot: string,\n threadId: number,\n): { project: string; scope: string } | null {\n const s = loadState(stateRoot);\n for (const [key, id] of Object.entries(s.topics)) {\n if (id !== threadId) continue;\n const sep = key.indexOf(\"::\");\n if (sep === -1) continue;\n return { project: key.slice(0, sep), scope: key.slice(sep + 2) };\n }\n return null;\n}\n","// Telegram Bot API over plain fetch — no runtime SDK (keeps the tsup single\n// binary lean). @grammyjs/types is a devDependency: type-only, erased at build.\nimport type { Update } from \"@grammyjs/types\";\n\nexport interface TelegramClient {\n /** Long-poll for updates. timeoutSec is the Bot API `timeout` (default 50s). */\n getUpdates(offset: number, timeoutSec?: number): Promise<Update[]>;\n sendMessage(chatId: number, threadId: number | undefined, text: string): Promise<void>;\n /** Returns the new topic's message_thread_id. */\n createForumTopic(chatId: number, name: string): Promise<number>;\n /** Verify the bot token and return the bot identity. */\n getMe(): Promise<{ id: number; username: string }>;\n}\n\ninterface TgResponse<T> {\n ok: boolean;\n result?: T;\n error_code?: number;\n description?: string;\n}\n\nexport function createTelegramClient(opts: { token: string; fetch?: typeof fetch }): TelegramClient {\n const fetchImpl = opts.fetch ?? fetch;\n const base = `https://api.telegram.org/bot${opts.token}`;\n\n async function call<T>(method: string, body: Record<string, unknown>): Promise<T> {\n const res = await fetchImpl(`${base}/${method}`, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify(body),\n });\n const json = (await res.json()) as TgResponse<T>;\n if (!res.ok || !json.ok) {\n const code = json.error_code ?? res.status;\n const desc = json.description ?? \"unknown error\";\n throw new Error(`telegram ${method} failed (${code}): ${desc}`);\n }\n return json.result as T;\n }\n\n return {\n async getMe() {\n const r = await call<{ id: number; username: string }>(\"getMe\", {});\n return { id: r.id, username: r.username };\n },\n getUpdates(offset, timeoutSec = 50) {\n return call<Update[]>(\"getUpdates\", { offset, timeout: timeoutSec });\n },\n async sendMessage(chatId, threadId, text) {\n const body: Record<string, unknown> = { chat_id: chatId, text };\n if (threadId !== undefined) body.message_thread_id = threadId;\n await call<unknown>(\"sendMessage\", body);\n },\n async createForumTopic(chatId, name) {\n const r = await call<{ message_thread_id: number }>(\"createForumTopic\", { chat_id: chatId, name });\n return r.message_thread_id;\n },\n };\n}\n","// Daemon-internal Telegram subsystem (modeled on CmuxEventsBridge). Owns one\n// outbound hook (pushLifecycle) and one inbound getUpdates long-poll. Opt-in and\n// crash-contained: no send/poll error may escape into the daemon.\nimport type { ControlEvent, TelegramConfig } from \"@squadrant/shared\";\nimport type { TelegramClient } from \"./client.js\";\nimport { isAuthorized, isControlEnabled } from \"./auth.js\";\nimport { parseCommand } from \"./commands.js\";\nimport type { EnsureResult } from \"./ensure-captain.js\";\nimport { formatInbound, formatLifecycle, topicName } from \"./format.js\";\nimport { findProjectByThread, loadState, saveState, setTopic, topicKey } from \"./state.js\";\n\nexport interface TelegramBridge {\n start(): void;\n stop(): void;\n /** Outbound, best-effort: a Telegram failure is swallowed (logged), never thrown. */\n pushLifecycle(project: string, ev: ControlEvent): void;\n}\n\nexport interface TelegramBridgeOptions {\n cfg: TelegramConfig;\n stateRoot: string;\n client: TelegramClient;\n appendCaptainMessage: (a: { stateRoot: string; project: string; text: string; source: \"telegram\" }) => Promise<void>;\n log: (msg: string) => void;\n // ── Control surfaces (#402/#403/#321) — all optional. When undefined the bridge\n // keeps exact v1 behavior (queue-only project topics, General topic dropped).\n /** Boot-if-down before delivering to a project topic. Injected by the daemon host. */\n ensureCaptainAlive?: (project: string) => Promise<EnsureResult>;\n /** Execute a curated squadrant CLI argv and return capped output. */\n runCommand?: (argv: string[]) => Promise<string>;\n /** Post a reply to the General topic (threadId undefined) or a project topic. */\n sendReply?: (threadId: number | undefined, text: string) => Promise<void>;\n}\n\n// Bot API long-poll window. The loop also sleeps cfg.pollMs between iterations so\n// a fast-returning poll can't busy-loop.\nconst LONG_POLL_SEC = 50;\n\nconst sleep = (ms: number) => new Promise<void>((r) => setTimeout(r, ms));\n\nexport function createTelegramBridge(opts: TelegramBridgeOptions): TelegramBridge {\n const { cfg, stateRoot, client, appendCaptainMessage, log, ensureCaptainAlive, runCommand, sendReply } = opts;\n const pollMs = cfg.pollMs ?? 1000;\n let running = false;\n\n function persistOffset(next: number): void {\n const s = loadState(stateRoot);\n s.offset = next;\n saveState(stateRoot, s);\n }\n\n // Outbound: resolve (or lazily create) the project's topic, then send.\n async function deliverOutbound(project: string, ev: ControlEvent): Promise<void> {\n let threadId = loadState(stateRoot).topics[topicKey(project)];\n if (threadId === undefined) {\n threadId = await client.createForumTopic(cfg.supergroupId, topicName(project));\n setTopic(stateRoot, project, threadId);\n }\n await client.sendMessage(cfg.supergroupId, threadId, formatLifecycle(project, ev));\n }\n\n // Reply best-effort: a send failure must never escape into the poll loop.\n async function reply(threadId: number | undefined, text: string): Promise<void> {\n if (!sendReply) return;\n try {\n await sendReply(threadId, text);\n } catch (e) {\n log(`telegram reply failed: ${(e as Error).message}`);\n }\n }\n\n // General topic (no thread id): curated command channel (#402). Fail-closed —\n // a slash command runs ONLY when remoteControl is on AND the sender is\n // allowlisted. Freeform text gets a /help hint (never silently dropped).\n // Command/reply failures are caught here so they can't escape the poll loop.\n async function handleGeneral(text: string, fromId: number | undefined): Promise<void> {\n if (!text.startsWith(\"/\")) {\n await reply(undefined, \"Send /help for commands.\");\n return;\n }\n if (!isControlEnabled(cfg) || !isAuthorized(fromId, cfg)) {\n await reply(undefined, \"⛔ not authorized\");\n return;\n }\n const parsed = parseCommand(text);\n if (parsed.kind !== \"ok\") {\n await reply(undefined, parsed.message);\n return;\n }\n try {\n const out = runCommand ? await runCommand(parsed.argv) : \"(command runner unavailable)\";\n await reply(undefined, out);\n } catch (e) {\n await reply(undefined, `⚠️ command failed: ${(e as Error).message}`);\n log(`telegram command failed argv=${JSON.stringify(parsed.argv)}: ${(e as Error).message}`);\n }\n }\n\n // Project topic: the v1 captain.message flow + Gap-1 auto-launch (#403). When\n // control is off OR the sender isn't allowlisted, behaves exactly as v1\n // (append only). The append throws on delivery-infra failure so the caller can\n // decline to advance the offset (at-least-once); auto-launch failures are\n // contained and never block the append.\n async function handleProjectTopic(text: string, threadId: number, fromId: number | undefined): Promise<void> {\n const resolved = findProjectByThread(stateRoot, threadId);\n if (!resolved) return; // no project bound to this topic\n if (ensureCaptainAlive && isControlEnabled(cfg) && isAuthorized(fromId, cfg)) {\n try {\n const r = await ensureCaptainAlive(resolved.project);\n if (r === \"timeout\") await reply(threadId, \"⚠️ captain didn't warm up; message queued.\");\n } catch (e) {\n log(`telegram auto-launch failed project=${resolved.project}: ${(e as Error).message}`);\n }\n }\n await appendCaptainMessage({ stateRoot, project: resolved.project, text: formatInbound(text), source: \"telegram\" });\n }\n\n // Inbound: classify by thread id. General topic → command channel; project\n // topic → captain.message (+ auto-launch). Throws only on append failure.\n async function handleUpdate(u: { message?: { chat: { id: number }; message_thread_id?: number; text?: string; from?: { id: number } } }): Promise<void> {\n const m = u.message;\n if (!m || m.text === undefined) return;\n if (!cfg.chats.includes(m.chat.id)) return; // not an allowlisted chat (coarse filter)\n if (m.message_thread_id === undefined) {\n await handleGeneral(m.text, m.from?.id);\n return;\n }\n await handleProjectTopic(m.text, m.message_thread_id, m.from?.id);\n }\n\n async function pollLoop(): Promise<void> {\n while (running) {\n try {\n const offset = loadState(stateRoot).offset;\n const updates = await client.getUpdates(offset, LONG_POLL_SEC);\n for (const u of updates) {\n await handleUpdate(u);\n persistOffset(u.update_id + 1);\n }\n } catch (e) {\n log(`telegram inbound poll failed: ${(e as Error).message}`);\n }\n if (running) await sleep(pollMs);\n }\n }\n\n return {\n start() {\n if (running) return;\n running = true;\n void pollLoop();\n },\n stop() {\n running = false;\n },\n pushLifecycle(project, ev) {\n // Fire-and-forget; all errors swallowed so outbound can never throw into\n // the daemon's notify path.\n void deliverOutbound(project, ev).catch((e) => {\n log(`telegram outbound failed project=${project}: ${(e as Error).message}`);\n });\n },\n };\n}\n","// Pure helpers for the interactive `squadrant telegram setup` wizard.\n// These are exported for testing with injected dependencies.\n// getUpdates is single-consumer — setup runs before the daemon starts polling (#321).\nimport fs from \"node:fs\";\nimport type { TelegramClient } from \"./client.js\";\n\n/**\n * Poll getUpdates until a supergroup message arrives, returning both the chat id\n * and the sender's user id (the latter seeds the control allowlist, #321).\n * Injects `sleep` for testability; never used with real delays in tests.\n */\nexport async function detectGroupAndUser(\n client: TelegramClient,\n opts: { timeoutMs?: number; sleep?: (ms: number) => Promise<void> } = {},\n): Promise<{ supergroupId: number; userId: number | undefined }> {\n const timeoutMs = opts.timeoutMs ?? 60_000;\n const sleep = opts.sleep ?? ((ms: number) => new Promise((r) => setTimeout(r, ms)));\n const deadline = Date.now() + timeoutMs;\n let offset = 0;\n\n while (Date.now() < deadline) {\n const updates = await client.getUpdates(offset, 10);\n for (const u of updates) {\n if (u.update_id >= offset) offset = u.update_id + 1;\n if (u.message?.chat?.type === \"supergroup\") {\n return { supergroupId: u.message.chat.id, userId: u.message.from?.id };\n }\n }\n await sleep(2000);\n }\n\n throw new Error(\"Timed out waiting for the bot to receive a message in a supergroup\");\n}\n\n/** Convenience wrapper that returns only the supergroup id. */\nexport async function detectGroupId(\n client: TelegramClient,\n opts: { timeoutMs?: number; sleep?: (ms: number) => Promise<void> } = {},\n): Promise<number> {\n return (await detectGroupAndUser(client, opts)).supergroupId;\n}\n\n/**\n * Write or update the telegram block in a squadrant config file.\n * Preserves all existing keys; creates the file with defaults if absent.\n */\nexport function writeTelegramConfig(\n configPath: string,\n opts: { token: string; supergroupId: number; users?: number[]; remoteControl?: boolean },\n): void {\n let config: Record<string, unknown>;\n let raw: string | null = null;\n\n try {\n raw = fs.readFileSync(configPath, \"utf-8\");\n } catch (err: unknown) {\n if ((err as NodeJS.ErrnoException).code !== \"ENOENT\") {\n throw new Error(`refusing to overwrite unreadable config at ${configPath}: ${String(err)}`);\n }\n }\n\n if (raw !== null) {\n try {\n config = JSON.parse(raw) as Record<string, unknown>;\n } catch (err: unknown) {\n throw new Error(`refusing to overwrite corrupt config at ${configPath}: ${String(err)}`);\n }\n } else {\n config = {};\n }\n\n // Idempotent: re-running setup updates the token/group but preserves existing\n // control fields (users/remoteControl) unless this run supplies new ones.\n const prev = (config.telegram && typeof config.telegram === \"object\")\n ? (config.telegram as Record<string, unknown>) : {};\n const next: Record<string, unknown> = {\n botToken: opts.token,\n supergroupId: opts.supergroupId,\n chats: [opts.supergroupId],\n };\n const users = opts.users ?? prev.users;\n const remoteControl = opts.remoteControl ?? prev.remoteControl;\n if (users !== undefined) next.users = users;\n if (remoteControl !== undefined) next.remoteControl = remoteControl;\n config.telegram = next;\n\n fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + \"\\n\");\n}\n","// @squadrant/core Telegram subsystem barrel.\nexport * from \"./auth.js\";\nexport * from \"./commands.js\";\nexport * from \"./ensure-captain.js\";\nexport * from \"./format.js\";\nexport * from \"./state.js\";\nexport * from \"./client.js\";\nexport * from \"./bridge.js\";\nexport * from \"./setup.js\";\n","// @squadrant/core — driver-agnostic daemon / control-plane core.\nexport * from \"./daemon.js\";\nexport * from \"./mailbox.js\";\nexport * from \"./protocol.js\";\nexport * from \"./state-machine.js\";\nexport * from \"./liveness.js\";\nexport * from \"./watchdog.js\";\nexport * from \"./store.js\";\nexport * from \"./snapshot.js\";\nexport * from \"./launchd.js\";\nexport * from \"./crew-pane-reader.js\";\nexport * from \"./interfaces.js\";\nexport * from \"./gate.js\";\nexport * from \"./daemon/context.js\";\nexport * from \"./daemon/attach.js\";\nexport * from \"./daemon/start.js\";\nexport * from \"./daemon/delivery.js\";\nexport * from \"./daemon/interactive-probe.js\";\nexport * from \"./delivery/captain-delivery.js\";\nexport * from \"./delivery/defer-delivery.js\";\nexport * from \"./session-freshness.js\";\nexport * from \"./crew-protocol.js\";\nexport * from \"./crew-lifecycle.js\";\nexport * from \"./telegram/index.js\";\n","import { execFile, execFileSync } from \"node:child_process\";\nimport type { RuntimeDriver, RuntimeProbeResult, RuntimeSpawnOptions, WorkspaceRef, PaneRef, RuntimePaneOptions } from \"./types.js\";\nimport { resolveCmuxBin } from \"@squadrant/shared\";\nimport { checkToolCompat } from \"@squadrant/shared\";\nimport { compatManifest } from \"@squadrant/shared\";\n\n// 15s — cmux operations are local IPC (sub-50ms normally). 15s covers unusual\n// system load or a momentarily stuck cmux server without causing the captain\n// blindness that an unbounded hang would (see #209).\nexport const CMUX_TIMEOUT = 15_000;\n\nexport class CmuxTimeoutError extends Error {\n constructor(cmd: string) {\n super(`cmux timeout after ${CMUX_TIMEOUT}ms on: ${cmd}`);\n this.name = \"CmuxTimeoutError\";\n }\n}\n\n// Re-exported so root consumers keep the same import path (root → core direction).\nimport { DeferDelivery } from \"@squadrant/core\";\nexport { DeferDelivery };\n\n/** True when running inside a cmux workspace (CMUX_WORKSPACE_ID is set). */\nexport function isInsideCmux(): boolean {\n return !!process.env.CMUX_WORKSPACE_ID;\n}\n\n// Synchronous cmux invocation for select-workspace / current-workspace calls\n// not yet abstracted behind RuntimeDriver. Uses execFileSync (no shell) with\n// stderr piped so cmux diagnostic messages (e.g. \"Pane not found\") don't leak\n// to the parent terminal. Returns trimmed stdout.\nexport function cmuxLocal(args: string[]): string {\n return execFileSync(resolveCmuxBin(), args, {\n encoding: \"utf-8\",\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n timeout: CMUX_TIMEOUT,\n }).trim();\n}\n\n// Invoke cmux with an argv array and NO shell. Every element (especially crew\n// prompt text passed through send/send-to-surface) reaches cmux as a single\n// literal argument — backticks, $(), quotes are never parsed. See #118.\n// Async to avoid blocking the Node.js event loop during daemon timer ticks.\nfunction cmux(args: string[]): Promise<string> {\n return new Promise((resolve, reject) => {\n execFile(\n resolveCmuxBin(),\n args,\n // CMUX_QUIET=1 silences cmux 0.64's one-time deprecation hints (e.g. the\n // \"list-workspaces is now an alias for cmux workspace list\" notice). Those\n // notices print to the command's stdout and would otherwise pollute the\n // output we parse. Inherit the rest of the environment unchanged.\n { encoding: \"utf-8\", timeout: CMUX_TIMEOUT, env: { ...process.env, CMUX_QUIET: \"1\" } },\n (err, stdout) => {\n if (err) {\n reject((err as NodeJS.ErrnoException).code === \"ETIMEDOUT\"\n ? new CmuxTimeoutError(args.join(\" \"))\n : err);\n return;\n }\n resolve((stdout as string).trim());\n },\n );\n });\n}\n\n// Shape of `cmux workspace list --json` (cmux 0.64.16). Only the fields we\n// consume are typed; everything else in the payload is ignored.\ninterface CmuxWorkspaceListJson {\n workspaces?: Array<{\n ref?: string;\n custom_title?: string | null;\n has_custom_title?: boolean;\n current_directory?: string | null;\n }>;\n}\n\n// Shape of `cmux tree --json` (cmux 0.64.16). Surfaces nest as\n// windows[].workspaces[].panes[].surfaces[]; only consumed fields are typed.\ninterface CmuxTreeJson {\n windows?: Array<{\n workspaces?: Array<{\n ref?: string;\n panes?: Array<{\n surfaces?: Array<{ ref?: string; surface_ref?: string; title?: string | null }>;\n }>;\n }>;\n }>;\n}\n\n// Parse `cmux workspace list --json` into WorkspaceRefs. Replaces the old\n// regex over the human-readable `list-workspaces` text (audit B2). The display\n// name is the workspace's custom title when set (byte-identical to what the\n// text form showed, e.g. \"⚓ squadrant-captain\" — this is what squadrant matches\n// captains by), falling back to the cwd for untitled workspaces.\nfunction parseList(output: string): WorkspaceRef[] {\n let parsed: CmuxWorkspaceListJson;\n try {\n parsed = JSON.parse(output) as CmuxWorkspaceListJson;\n } catch {\n return [];\n }\n const refs: WorkspaceRef[] = [];\n for (const ws of parsed.workspaces ?? []) {\n if (!ws.ref) continue;\n refs.push({\n id: ws.ref,\n name: (ws.has_custom_title && ws.custom_title) ? ws.custom_title : (ws.current_directory ?? ws.ref),\n status: \"running\",\n });\n }\n return refs;\n}\n\n// cmux `send` treats \\n, \\r (and \\t) as Enter/Tab keystrokes, so any newline in a\n// multi-line message would submit it line-by-line. Collapse all newline/CR/tab\n// (real bytes AND literal backslash-escapes) to single spaces so the whole message\n// is delivered as one line, then the explicit send-key Enter submits it once.\nexport function sanitizeForCmuxSend(text: string): string {\n return text\n .replace(/\\\\[nrt]/g, \" \")\n .replace(/[\\n\\r\\t]+/g, \" \")\n .replace(/ {2,}/g, \" \")\n .trim();\n}\n\n/**\n * Extract the in-progress draft from a cmux read-screen capture (#258 / #268).\n * Scans from the bottom of the screen so history lines that contain `> ` are\n * ignored; only the actual input area (the last matching line) is returned.\n * Handles both `>` (synthetic/test) and `❯` (U+276F, the real Claude Code\n * prompt character) as the input caret. The real prompt is followed by a\n * non-breaking space (U+00A0); JS `\\s` covers it, so `\\s+` matches either.\n * Also handles box-drawing `│ ❯ text │` variants.\n *\n * Three-state return (#268):\n * \"draft text\" — input box found with content → caller must DEFER\n * \"\" — input box positively confirmed empty → caller may DELIVER\n * null — HR boundaries not found (overlay/menu/scrolled) → caller must DEFER\n */\nexport function parseDraftFromScreen(screen: string): string | null {\n // Empty screen means the input box is definitely not visible — defer (#268).\n if (!screen) return null;\n const lines = screen.split(/\\r?\\n/);\n\n // Locate the last two HR lines (runs of U+2500 ─) — they are the bottom and top\n // boundaries of the live input box. Everything above the top HR is transcript\n // content and is never scanned, preventing sent user messages with a ❯/> prefix\n // from being mistaken for the live draft (#258).\n const HR_RE = /^\\s*─{10,}\\s*$/;\n let bottomHR = -1;\n let topHR = -1;\n for (let i = lines.length - 1; i >= 0; i--) {\n if (HR_RE.test(lines[i])) {\n if (bottomHR === -1) {\n bottomHR = i;\n } else {\n topHR = i;\n break;\n }\n }\n }\n\n // Can't locate both boundaries — input box not visible (overlay/menu/scrolled\n // transcript). Defer so keystrokes never land in an unknown UI state (#268).\n if (topHR === -1) return null;\n\n // Extract content lines strictly between the two HRs (the live input box only).\n const inputLines = lines.slice(topHR + 1, bottomHR);\n\n for (const line of inputLines) {\n let extracted: string | undefined;\n // Box-drawing input line: │ [>❯] text │\n const boxMatch = line.match(/│\\s*[>❯]\\s+(.*?)\\s*│/);\n if (boxMatch) {\n extracted = boxMatch[1].trim();\n } else {\n // Plain input line — allow empty content after the prompt glyph\n const plainMatch = line.match(/^\\s*[>❯]\\s*(.*)$/);\n if (plainMatch) extracted = plainMatch[1].trim();\n }\n if (extracted !== undefined) {\n // Heuristic #1 — Leading cursor glyph (▌/█) at position 0.\n // CC renders its input cursor via native ANSI terminal positioning, NOT as a ▌ cell\n // character: a live cmux read-screen of an idle CC session with cursor at position 0\n // yields ❯\\xa0 with no ▌ (confirmed by 258-parse-bug-fixture.txt L24 and a fresh\n // crew session capture). Therefore ▌ at the start cannot arise from the user moving\n // the cursor to the beginning of real typed text — it only appears when CC itself\n // renders a UI placeholder at that position (#294). Safe to treat as empty. (#297)\n if (/^[▌█▔▎▏▌█]/.test(extracted)) continue;\n\n // Strip terminal cursor glyphs (▌, █, etc.) that trail the caret position\n const draft = extracted.replace(/\\s*[▌█▔▎▏▌█]+\\s*$/, \"\").trim();\n\n // Claude Code UI placeholder: appears in Working state when input is locked\n // (user cannot type). \"Press [key] to [action]\" strings are UI instructions\n // shown as ghost suggestions — never real user-typed content (#294).\n if (/^Press\\s+(?:up|down|left|right|enter|escape|esc|tab|any\\s+key|ctrl|shift|alt)\\s+to\\s+/i.test(draft)) continue;\n\n if (draft) return draft;\n }\n }\n\n return \"\";\n}\n\n/**\n * Extract the RAW input-box content for the #302 buffer-liveness probe — all\n * content lines between the last two HRs, joined, with the prompt glyph and any\n * trailing cursor glyph stripped (but NOT the #294 ghost heuristics: the probe\n * needs the literal rendered text to diff before/after a backspace). Returns\n * null if the box boundaries aren't visible (overlay/scroll). Unlike\n * parseDraftFromScreen this captures EVERY content line, so a multi-line draft's\n * change on its last line is not missed.\n */\nexport function readInputBoxRaw(screen: string): string | null {\n if (!screen) return null;\n const lines = screen.split(/\\r?\\n/);\n const HR_RE = /^\\s*─{10,}\\s*$/;\n let bottomHR = -1;\n let topHR = -1;\n for (let i = lines.length - 1; i >= 0; i--) {\n if (HR_RE.test(lines[i])) {\n if (bottomHR === -1) bottomHR = i;\n else { topHR = i; break; }\n }\n }\n if (topHR === -1) return null;\n const parts: string[] = [];\n for (const line of lines.slice(topHR + 1, bottomHR)) {\n let s = line.replace(/│/g, \" \"); // drop box-drawing borders\n s = s.replace(/^\\s*[>❯]\\s?/, \"\"); // drop the leading prompt glyph + one space\n s = s.replace(/\\s*[▌█▔▎▏]+\\s*$/, \"\"); // drop a trailing cursor glyph\n parts.push(s);\n }\n return parts.join(\"\").replace(/\\s+$/, \"\"); // trim only the trailing edge\n}\n\n// #292: Claude Code renders a persistent bottom status block once its TUI is past\n// the cold-init splash — the auto-mode indicator (⏵⏵), the context meter\n// (\"Ctx Used\"), the shortcuts hint, or the accept-edits toggle. Absence of all of\n// these means we're still on the loading/splash screen, where keystrokes are\n// silently dropped (#235). Grounded in docs/reports/258-parse-bug-fixture.txt.\nconst CC_INITIALIZED_RE = /⏵⏵|Ctx Used|for shortcuts|accept edits/i;\n\n// A live turn shows a working spinner. The whimsical verb (\"Working…\",\n// \"Cerebrating…\", \"Crunched…\") varies across versions, so we key on stable\n// markers instead. CRUCIAL: a turn is NOT always streaming tokens — during a\n// tool wait (e.g. the shell commands the captain startup checklist runs first)\n// the spinner reads \"✻ Crunched for 27s · 1 shell still running\", which carries\n// NO token-down-counter and no \"esc to interrupt\". Keying only on those two\n// (the original #292 mistake) misread a shell-waiting captain as \"idle\", so the\n// startup-prompt loop re-sent on every poll → 3 duplicate startup runs. We now\n// also match the shell-running hint and the in-parens elapsed timer (\"(4s\",\n// \"(1m 4s\") — both confined to the live spinner line, never on an idle,\n// input-ready screen. Grounded in docs/reports/258-parse-bug-fixture.txt\n// (line 4: shell-wait, no counter; line 22: token-stream).\nconst CC_WORKING_RE = /↓\\s*[\\d.]+\\s*k?\\s*tokens?\\b|esc to interrupt|\\bshell still running\\b|·\\s*\\d+\\s*shell\\b|\\(\\d+m?\\s*\\d*s\\b/i;\n\n/**\n * Classify a captain surface's read-screen into the three states #292's\n * deterministic startup delivery needs:\n * \"loading\" — splash / cold-init; keystrokes would be dropped, do not send yet.\n * \"idle\" — TUI up and accepting input; safe to deliver the startup prompt.\n * \"working\" — a turn is in flight; sending would queue a DUPLICATE startup run.\n * \"working\" is checked first so an active spinner above an (empty) input box wins.\n */\nexport function classifyStartupSurface(screen: string): \"loading\" | \"idle\" | \"working\" {\n if (CC_WORKING_RE.test(screen)) return \"working\";\n if (CC_INITIALIZED_RE.test(screen)) return \"idle\";\n return \"loading\";\n}\n\n// #339 instrumentation gate. The DONE→captain submit is a text burst then a\n// SEPARATE send-key Enter (two distinct socket writes); intermittently the Enter\n// lands as a newline instead of a submit, stranding the payload in the input box.\n// Root-causing needs ONE real frame in the wild. Gated behind SQUADRANT_DEBUG_SEND\n// so it is a strict no-op — zero extra reads, zero latency — when unset.\nexport function sendDebugEnabled(): boolean {\n return !!process.env.SQUADRANT_DEBUG_SEND;\n}\n\n// Classify a post-send input-box read into a submit verdict for #339:\n// \"submitted\" — box empty after Enter (the payload left the input box)\n// \"stuck\" — box still holds the payload (Enter inserted a newline, no submit)\n// \"box-gone\" — box not visible post-send (overlay/scroll — inconclusive)\n// \"unknown\" — box has unrelated content (a fresh draft / next turn rendered)\nexport function classifySendOutcome(payload: string, postBox: string | null): string {\n if (postBox === null) return \"box-gone\";\n if (postBox === \"\") return \"submitted\";\n if (postBox === payload || postBox.includes(payload)) return \"stuck\";\n return \"unknown\";\n}\n\nexport function createCmuxDriver(): RuntimeDriver {\n return {\n name: \"cmux\",\n\n async probe(): Promise<RuntimeProbeResult> {\n try {\n const version = await cmux([\"--version\"]);\n const warn = checkToolCompat(\"cmux\", version, compatManifest.tools.cmux);\n if (warn) process.stderr.write(`[squadrant] ${warn}\\n`);\n return { installed: true, version };\n } catch {\n return { installed: false, version: \"\" };\n }\n },\n\n async list(): Promise<WorkspaceRef[]> {\n try {\n // --json: structured output (B2); --id-format refs: ids as\n // workspace:N refs, not numeric (from #325). Both are required.\n return parseList(await cmux([\"workspace\", \"list\", \"--json\", \"--id-format\", \"refs\"]));\n } catch {\n return [];\n }\n },\n\n async status(nameOrId: string): Promise<WorkspaceRef | null> {\n const refs = await this.list();\n const hit = refs.find((r) => r.name === nameOrId || r.id === nameOrId);\n return hit ?? null;\n },\n\n async spawn(opts: RuntimeSpawnOptions): Promise<WorkspaceRef> {\n const newWorkspaceArgs = [\"workspace\", \"create\", \"--command\", opts.command];\n if (opts.workdir) newWorkspaceArgs.push(\"--cwd\", opts.workdir);\n const output = await cmux(newWorkspaceArgs);\n const id = output.match(/workspace:\\d+/)?.[0] || output.split(/\\s+/).pop() || \"\";\n if (!id) {\n throw new Error(`cmux spawn did not return a workspace id: ${output}`);\n }\n await cmux([\"workspace\", \"rename\", id, \"--title\", opts.name]);\n // Rename the initial tab to the workspace name so send() can route to it\n let initialSurface: string | undefined;\n try {\n const tree = await cmux([\"tree\", \"--workspace\", id, \"--id-format\", \"refs\"]);\n const m = tree.match(/surface\\s+(surface:\\d+)\\s+\\[\\w+\\]\\s+\"([^\"]*)\"/);\n if (m) {\n initialSurface = m[1];\n await cmux([\"rename-tab\", \"--workspace\", id, \"--surface\", m[1], opts.name]);\n }\n } catch { /* rename is best-effort */ }\n if (opts.pinToTop) {\n try {\n await cmux([\"workspace-action\", \"--workspace\", id, \"--action\", \"pin\"]);\n } catch { /* workspace may not be pinned — proceed to close regardless */ }\n if (initialSurface) {\n try {\n await cmux([\"tab-action\", \"--workspace\", id, \"--surface\", initialSurface, \"--action\", \"pin\"]);\n } catch { /* tab pin is best-effort */ }\n }\n }\n return { id, name: opts.name, status: \"running\" };\n },\n\n async send(ref: string, message: string): Promise<void> {\n // Route to the tab named after the workspace (e.g. \":captain\" tab) so\n // messages don't land on a focused crew tab by mistake. Fall back to\n // workspace-level send when no matching tab is found.\n const allRefs = await this.list();\n const ws = allRefs.find((r) => r.id === ref);\n if (ws) {\n try {\n const surfaces = await this.listSurfaces(ws.id);\n const target = surfaces.find((s) => s.title === ws.name);\n if (target) {\n await cmux([\"send\", \"--workspace\", ws.id, \"--surface\", target.surfaceId, sanitizeForCmuxSend(message)]);\n await cmux([\"send-key\", \"--workspace\", ws.id, \"--surface\", target.surfaceId, \"Enter\"]);\n return;\n }\n } catch { /* fall through to default */ }\n }\n await cmux([\"send\", \"--workspace\", ref, sanitizeForCmuxSend(message)]);\n await cmux([\"send-key\", \"--workspace\", ref, \"Enter\"]);\n },\n\n async sendKey(ref: string, key: string): Promise<void> {\n await cmux([\"send-key\", \"--workspace\", ref, key]);\n },\n\n async readScreen(ref: string): Promise<string> {\n try {\n return await cmux([\"read-screen\", \"--workspace\", ref]);\n } catch {\n return \"\";\n }\n },\n\n async stop(ref: string): Promise<void> {\n // cmux 0.64.16 refuses to close a pinned workspace. Unpin first so that\n // squadrant launch --fresh works even when the captain workspace is pinned.\n try {\n await cmux([\"workspace-action\", \"--workspace\", ref, \"--action\", \"unpin\"]);\n } catch { /* workspace may not be pinned — proceed to close regardless */ }\n try {\n await cmux([\"workspace\", \"close\", ref]);\n } catch { /* may already be closed */ }\n },\n\n async newPane(opts: RuntimePaneOptions): Promise<PaneRef> {\n // #295 / audit A1+B3: a crew tab must never steal focus from the captain.\n // cmux 0.64.16's new-surface and new-pane both DEFAULT to --focus false,\n // so we pass it explicitly (intent + resilience if the default changes)\n // and create the surface focus-neutrally. This REPLACES the old\n // snapshot-then-move-surface refocus dance, which depended on the fragile\n // \"tree order == array index\" invariant that the 0.64 freeform canvas +\n // staggered restore broke — risking a focus-steal regression.\n const cmd = opts.direction === \"tab\"\n ? [\"new-surface\", \"--type\", \"terminal\", \"--workspace\", opts.workspaceId, \"--focus\", \"false\"]\n : [\"new-pane\", \"--type\", \"terminal\", \"--direction\", opts.direction, \"--workspace\", opts.workspaceId, \"--focus\", \"false\"];\n const output = await cmux(cmd);\n const surfaceId = output.match(/surface:\\d+/)?.[0];\n if (!surfaceId) {\n const verb = opts.direction === \"tab\" ? \"new-surface\" : \"new-pane\";\n throw new Error(`cmux ${verb} did not return a surface id: ${output}`);\n }\n if (opts.title) {\n try {\n await cmux([\"rename-tab\", \"--workspace\", opts.workspaceId, \"--surface\", surfaceId, \"--title\", opts.title]);\n } catch { /* rename is best-effort */ }\n }\n return { workspaceId: opts.workspaceId, surfaceId };\n },\n\n async closePane(pane: PaneRef): Promise<void> {\n try {\n await cmux([\"close-surface\", \"--workspace\", pane.workspaceId, \"--surface\", pane.surfaceId]);\n } catch { /* may already be closed */ }\n },\n\n async sendToPane(pane: PaneRef, message: string): Promise<void> {\n await cmux([\"send\", \"--workspace\", pane.workspaceId, \"--surface\", pane.surfaceId, sanitizeForCmuxSend(message)]);\n await cmux([\"send-key\", \"--workspace\", pane.workspaceId, \"--surface\", pane.surfaceId, \"Enter\"]);\n },\n\n async readPaneScreen(pane: PaneRef): Promise<string> {\n try {\n return await cmux([\"read-screen\", \"--workspace\", pane.workspaceId, \"--surface\", pane.surfaceId]);\n } catch {\n return \"\";\n }\n },\n\n async spawnInjector(opts: {\n captainWorkspace: WorkspaceRef;\n command: string;\n title?: string;\n placement: \"background\" | \"visible\";\n }): Promise<PaneRef> {\n // Both placements use a background tab (new-surface) in the captain's\n // existing pane — full-height, NO split. A split-pane is wrong here:\n // cmux 0.62.2 has no resize/hide verb, so a `new-pane` split can never be\n // shrunk and stays an ugly full-height 50/50 split forever (#117). The\n // relay still runs as a cmux descendant in the same workspace, preserving\n // the in-cmux delivery requirement (#112).\n //\n // cmux 0.64.16's new-surface DEFAULTS to --focus false, so \"background\"\n // passes --focus false and the relay tab is created without ever stealing\n // focus from the captain — no snapshot-then-move-surface refocus dance\n // (audit A1+B3; the 0.64 freeform canvas broke the old tree-order==index\n // assumption it relied on). \"visible\" passes --focus true to leave the\n // debug tab focused for ergonomics.\n const wsId = opts.captainWorkspace.id;\n const focus = opts.placement === \"visible\" ? \"true\" : \"false\";\n const output = await cmux([\"new-surface\", \"--type\", \"terminal\", \"--workspace\", wsId, \"--focus\", focus]);\n const surfaceId = output.match(/surface:\\d+/)?.[0];\n if (!surfaceId) {\n throw new Error(`cmux spawnInjector did not return a surface id: ${output}`);\n }\n if (opts.title) {\n try {\n await cmux([\"rename-tab\", \"--workspace\", wsId, \"--surface\", surfaceId, \"--title\", opts.title]);\n } catch { /* rename is best-effort */ }\n }\n await cmux([\"send\", \"--workspace\", wsId, \"--surface\", surfaceId, opts.command]);\n await cmux([\"send-key\", \"--workspace\", wsId, \"--surface\", surfaceId, \"Enter\"]);\n return { workspaceId: wsId, surfaceId, title: opts.title };\n },\n\n async sendToSurface(surface: PaneRef, text: string, opts?: { probe?: boolean }): Promise<void> {\n const ws = surface.workspaceId;\n const sf = surface.surfaceId;\n const deliver = async () => {\n // #339 debug-gated instrumentation. When OFF this is the exact two-write\n // submit it always was (no extra reads, no latency). When ON we capture\n // one real frame: the input box BEFORE the send, the payload, and the box\n // AFTER the Enter — so a stranded submit can be told apart from a clean one.\n const dbg = sendDebugEnabled();\n let preBox: string | null = null;\n if (dbg) {\n try {\n preBox = readInputBoxRaw(await cmux([\"read-screen\", \"--workspace\", ws, \"--surface\", sf]));\n } catch { /* unreadable — leave preBox null, logged as such */ }\n }\n const payload = sanitizeForCmuxSend(text);\n await cmux([\"send\", \"--workspace\", ws, \"--surface\", sf, payload]);\n await cmux([\"send-key\", \"--workspace\", ws, \"--surface\", sf, \"Enter\"]);\n // Post-send read-back is READ-ONLY — never a re-send — so it can NEVER\n // double-submit (the #339 constraint). It only observes whether the box\n // still holds the payload (Enter mis-landed) or is empty (submit took).\n if (dbg) {\n let postBox: string | null = null;\n try {\n postBox = readInputBoxRaw(await cmux([\"read-screen\", \"--workspace\", ws, \"--surface\", sf]));\n } catch { /* unreadable — leave postBox null, classified box-gone */ }\n const verdict = classifySendOutcome(payload, postBox);\n process.stderr.write(`[squadrant] send-debug ${JSON.stringify({ surface: sf, verdict, payload, preBox, postBox })}\\n`);\n }\n };\n\n // #258/#268 Approach B: deliver only when the captain's input is positively\n // confirmed empty. null = box not visible (overlay/menu/scroll) → always defer.\n let screen = \"\";\n try {\n screen = await cmux([\"read-screen\", \"--workspace\", ws, \"--surface\", sf]);\n } catch { /* screen unreadable — parseDraftFromScreen(\"\") → null → defer below */ }\n const draft = parseDraftFromScreen(screen);\n\n // null = box not confirmed visible → never keystroke into an overlay (#268).\n if (draft === null) throw new DeferDelivery(null);\n\n // Empty input — nothing to protect, deliver directly.\n if (draft === \"\") { await deliver(); return; }\n\n // A draft is present. On the hot path (no probe) we NEVER keystroke — we\n // defer and carry the content so the relay can track stability (#302).\n if (!opts?.probe) throw new DeferDelivery(draft);\n\n // #302 buffer-liveness probe (replaces the old destructive backspace×N\n // clear + re-paste, which MATERIALIZED ghost suggestions). A real draft is\n // the ONLY thing that yields the \"last char removed, still non-empty\"\n // signature under ONE backspace (verified live, CC 2.1.x); a ghost either\n // stays invariant or dismisses to empty. So we PROTECT only on that exact\n // signature, and we NEVER re-paste screen-read content.\n const before = readInputBoxRaw(screen);\n await cmux([\"send-key\", \"--workspace\", ws, \"--surface\", sf, \"backspace\"]);\n let afterScreen = \"\";\n try {\n afterScreen = await cmux([\"read-screen\", \"--workspace\", ws, \"--surface\", sf]);\n } catch { /* unreadable after probe — treat as no real draft, fall through to deliver */ }\n const after = readInputBoxRaw(afterScreen);\n\n if (before !== null && after !== null && after.length > 0 && after === before.slice(0, -1)) {\n // Confirmed REAL draft. Restore the single char our probe removed (NOT a\n // full re-paste — at most one known char), then defer. Never clobber, and\n // a ghost can never reach this branch, so it can never be materialized.\n await cmux([\"send\", \"--workspace\", ws, \"--surface\", sf, before.slice(-1)]);\n throw new DeferDelivery(draft);\n }\n\n // No real draft (ghost dismissed/invariant, or buffer now empty) → deliver.\n await deliver();\n },\n\n async listSurfaces(workspaceId: string): Promise<PaneRef[]> {\n let output: string;\n try {\n // --json: structured output (B2); --id-format refs: surface ids as\n // surface:N refs, not numeric (from #325). Both are required.\n output = await cmux([\"tree\", \"--workspace\", workspaceId, \"--json\", \"--id-format\", \"refs\"]);\n } catch {\n return [];\n }\n let parsed: CmuxTreeJson;\n try {\n parsed = JSON.parse(output) as CmuxTreeJson;\n } catch {\n return [];\n }\n // Navigate windows[].workspaces[].panes[].surfaces[], collecting every\n // surface that belongs to the requested workspace. Replaces the old regex\n // over `cmux tree` text (audit B2). Surface refs are globally unique, so\n // filtering by the parent workspace ref is sufficient.\n const surfaces: PaneRef[] = [];\n for (const win of parsed.windows ?? []) {\n for (const ws of win.workspaces ?? []) {\n if (ws.ref !== workspaceId) continue;\n for (const pane of ws.panes ?? []) {\n for (const sf of pane.surfaces ?? []) {\n const ref = sf.ref ?? sf.surface_ref;\n if (ref) surfaces.push({ workspaceId, surfaceId: ref, title: sf.title ?? \"\" });\n }\n }\n }\n }\n return surfaces;\n },\n };\n}\n","import type { SquadrantConfig } from \"@squadrant/shared\";\nimport type { RuntimeDriver, RuntimeProbeResult } from \"./types.js\";\n\nconst DEFAULT_RUNTIME = \"cmux\";\n\nexport class RuntimeRegistry {\n constructor(private drivers: Record<string, RuntimeDriver>) {}\n\n forProject(projectName: string, config: SquadrantConfig): RuntimeDriver {\n const projectRuntime = config.projects[projectName]?.runtime;\n const runtimeName = projectRuntime ?? config.runtime ?? DEFAULT_RUNTIME;\n return this.get(runtimeName);\n }\n\n global(config: SquadrantConfig): RuntimeDriver {\n const runtimeName = config.runtime ?? DEFAULT_RUNTIME;\n return this.get(runtimeName);\n }\n\n get(name: string): RuntimeDriver {\n const driver = this.drivers[name];\n if (!driver) {\n throw new Error(`Unknown runtime '${name}' — no driver registered`);\n }\n return driver;\n }\n\n async probeAll(): Promise<Record<string, RuntimeProbeResult>> {\n const results: Record<string, RuntimeProbeResult> = {};\n for (const [name, driver] of Object.entries(this.drivers)) {\n results[name] = await driver.probe();\n }\n return results;\n }\n}\n","export { createCmuxDriver, DeferDelivery, CMUX_TIMEOUT, classifyStartupSurface, isInsideCmux, cmuxLocal } from \"./cmux.js\";\nexport { RuntimeRegistry } from \"./registry.js\";\nexport type {\n RuntimeDriver,\n RuntimeProbeResult,\n RuntimeSpawnOptions,\n WorkspaceRef,\n PaneRef,\n PanePlacement,\n RuntimePaneOptions,\n} from \"./types.js\";\n","import { execFileSync, execSync } from \"node:child_process\";\nimport type {\n NotifierDriver,\n NotifierProbeResult,\n NotifierScope,\n} from \"./types.js\";\nimport { CMUX_TIMEOUT } from \"../runtimes/cmux.js\";\n\nexport function createCmuxNotifier(_scope: NotifierScope): NotifierDriver {\n return {\n name: \"cmux\",\n\n async probe(): Promise<NotifierProbeResult> {\n try {\n execSync(\"squadrant runtime status --command\", { encoding: \"utf-8\", stdio: \"pipe\" });\n return { installed: true, reachable: true };\n } catch (err) {\n const code = (err as { code?: string }).code;\n if (code === \"ENOENT\") {\n return { installed: false, reachable: false };\n }\n // Any non-ENOENT error: squadrant shim crashed, workspace down, or\n // config unreadable all collapse to \"installed but not reachable\".\n return { installed: true, reachable: false };\n }\n },\n\n async notify(message: string): Promise<void> {\n // execFileSync with an argv array and NO shell: the message is one literal\n // argv element, so backticks / $() in notification text are never parsed\n // by a shell. See #120 (same class as #118/#119).\n execFileSync(\"squadrant\", [\"runtime\", \"send\", \"--command\", message], { encoding: \"utf-8\", timeout: CMUX_TIMEOUT });\n },\n };\n}\n","import type { SquadrantConfig } from \"@squadrant/shared\";\nimport type {\n NotifierDriver,\n NotifierFactory,\n NotifierProbeResult,\n} from \"./types.js\";\n\nconst DEFAULT_NOTIFIER = \"cmux\";\n\nexport class NotifierRegistry {\n constructor(private factories: Record<string, NotifierFactory>) {}\n\n get(config: SquadrantConfig): NotifierDriver {\n const name = config.notifier ?? DEFAULT_NOTIFIER;\n return this.getFactory(name)({});\n }\n\n getFactory(name: string): NotifierFactory {\n const factory = this.factories[name];\n if (!factory) {\n throw new Error(`Unknown notifier provider '${name}' — no factory registered`);\n }\n return factory;\n }\n\n async probeAll(): Promise<Record<string, NotifierProbeResult>> {\n const results: Record<string, NotifierProbeResult> = {};\n for (const [name, factory] of Object.entries(this.factories)) {\n try {\n results[name] = await factory({}).probe();\n } catch {\n results[name] = { installed: false, reachable: false };\n }\n }\n return results;\n }\n}\n","export { createCmuxNotifier } from \"./cmux.js\";\nexport { NotifierRegistry } from \"./registry.js\";\nexport type {\n NotifierDriver,\n NotifierFactory,\n NotifierProbeResult,\n NotifierScope,\n} from \"./types.js\";\n","import fs from \"node:fs/promises\";\nimport { existsSync } from \"node:fs\";\nimport path from \"node:path\";\nimport type {\n WorkspaceDriver,\n WorkspaceProbeResult,\n WorkspaceScope,\n} from \"@squadrant/shared\";\n\n// Rejects `../` escapes and absolute paths via lexical containment check.\n// Does NOT resolve symlinks — a symlink inside the vault pointing outside\n// will be followed by fs.* calls. Vault contents are trusted in the squadrant\n// threat model (user-owned, not untrusted input). Tracked in issue #25.\nfunction resolveInRoot(root: string, relative: string): string {\n const joined = path.resolve(root, relative);\n const normalized = path.resolve(root) + path.sep;\n if (joined !== path.resolve(root) && !joined.startsWith(normalized)) {\n throw new Error(`Path '${relative}' escapes workspace root`);\n }\n return joined;\n}\n\nexport function createObsidianDriver(scope: WorkspaceScope): WorkspaceDriver {\n const root = scope.root;\n if (typeof root !== \"string\" || root === \"\") {\n throw new Error(\"ObsidianDriver requires scope.root (string)\");\n }\n\n return {\n name: \"obsidian\",\n\n async probe(): Promise<WorkspaceProbeResult> {\n return {\n installed: true,\n rootExists: existsSync(root),\n };\n },\n\n async read(rel: string): Promise<string> {\n return fs.readFile(resolveInRoot(root, rel), \"utf-8\");\n },\n\n async write(rel: string, content: string): Promise<void> {\n const abs = resolveInRoot(root, rel);\n await fs.mkdir(path.dirname(abs), { recursive: true });\n await fs.writeFile(abs, content);\n },\n\n async exists(rel: string): Promise<boolean> {\n try {\n await fs.access(resolveInRoot(root, rel));\n return true;\n } catch {\n return false;\n }\n },\n\n async list(rel: string): Promise<string[]> {\n try {\n return await fs.readdir(resolveInRoot(root, rel));\n } catch {\n return [];\n }\n },\n\n async mkdir(rel: string): Promise<void> {\n await fs.mkdir(resolveInRoot(root, rel), { recursive: true });\n },\n };\n}\n","import { resolveHome, type SquadrantConfig } from \"@squadrant/shared\";\nimport type {\n WorkspaceDriver,\n WorkspaceFactory,\n WorkspaceProbeResult,\n} from \"@squadrant/shared\";\n\nconst DEFAULT_WORKSPACE = \"obsidian\";\n\nexport class WorkspaceRegistry {\n constructor(private factories: Record<string, WorkspaceFactory>) {}\n\n hub(config: SquadrantConfig): WorkspaceDriver {\n const name = config.workspace ?? DEFAULT_WORKSPACE;\n return this.get(name)({ root: resolveHome(config.hubVault) });\n }\n\n forProject(projectName: string, config: SquadrantConfig): WorkspaceDriver {\n const proj = config.projects[projectName];\n if (!proj) throw new Error(`Project '${projectName}' not found`);\n const name = proj.workspace ?? config.workspace ?? DEFAULT_WORKSPACE;\n return this.get(name)({ root: resolveHome(proj.spokeVault) });\n }\n\n get(name: string): WorkspaceFactory {\n const factory = this.factories[name];\n if (!factory) {\n throw new Error(`Unknown workspace provider '${name}' — no factory registered`);\n }\n return factory;\n }\n\n async probeAll(config: SquadrantConfig): Promise<Record<string, WorkspaceProbeResult>> {\n const results: Record<string, WorkspaceProbeResult> = {};\n for (const [name, factory] of Object.entries(this.factories)) {\n const scope = { root: resolveHome(config.hubVault) };\n results[name] = await factory(scope).probe();\n }\n return results;\n }\n}\n","export { createObsidianDriver } from \"./obsidian.js\";\nexport { WorkspaceRegistry } from \"./registry.js\";\nexport type {\n WorkspaceDriver,\n WorkspaceFactory,\n WorkspaceProbeResult,\n WorkspaceScope,\n} from \"@squadrant/shared\";\n","// src/control/cmux/events-bridge.ts\n// Daemon-side bridge from cmux's native event stream to squadrant ControlEvents\n// (audit item B1 — reduce fragile screen-scraping).\n//\n// Unlike the per-crew OpencodeSseBridge, `cmux events` is a SINGLE global stream\n// for the whole cmux app: one newline-delimited JSON frame per cmux event,\n// carrying every agent's hook events. So this bridge is ONE long-lived\n// subscription owned by the daemon. Each `agent` frame is correlated back to a\n// crew TaskRecord by cwd (each interactive crew runs in a unique worktree path)\n// and classified into a run-state (deriveRunState):\n// - `agent.hook.Stop` — the \"turn ended / crew idle\" signal the pane reader\n// infers by scraping — → `task.turn.completed`.\n// - `agent.hook.PreToolUse` / `UserPromptSubmit` (a turn is live) →\n// `task.progress` (B4/A3): a real-activity signal that refreshes the crew's\n// liveness clock so the watchdog does not false-stall a crew mid long,\n// screen-quiet tool call (#292).\n//\n// ADDITIVE & SAFE: this runs ALONGSIDE the existing relay-proxy/pane-reader path,\n// which stays as the fallback. Both emissions are liveness, NOT completion\n// (anti-#2576): terminal state still comes from the explicit `squadrant crew signal\n// done`. The state-machine reducer already absorbs duplicate/late\n// task.turn.completed and task.progress (a blocked crew stays blocked), so\n// feeding them from BOTH paths is harmless.\nimport type { ChildProcess } from \"node:child_process\";\nimport { spawn as nodeSpawn } from \"node:child_process\";\nimport { resolveCmuxBin } from \"@squadrant/shared\";\nimport type { ControlEvent } from \"@squadrant/shared\";\n\n/** Minimal subset of ChildProcess this bridge needs (injectable for tests). */\nexport interface CmuxEventsChild {\n stdout: NodeJS.ReadableStream | null;\n kill(signal?: NodeJS.Signals): boolean | void;\n on(event: \"exit\", cb: (code: number | null) => void): unknown;\n on(event: \"error\", cb: (err: Error) => void): unknown;\n}\n\n/** Per-surface agent run-state derived from the hook stream (B4/A3). */\nexport type RunState = \"working\" | \"idle\";\n\n/**\n * Pure. Classify an `agent.hook.*` event name into the crew's run-state, or\n * null for hooks that carry no run-state signal.\n *\n * PreToolUse / UserPromptSubmit → \"working\" (a turn is live)\n * Stop → \"idle\" (turn ended)\n * SubagentStop / anything else → null (subagent end ≠ turn end)\n *\n * `Stop` is the existing turn-end signal (→ task.turn.completed). The \"working\"\n * hooks are the B4/A3 addition: they let the daemon keep a crew's liveness clock\n * fresh while it is mid (possibly long, screen-quiet) tool call, so the watchdog\n * does not false-stall it (#292). Only `PreToolUse` is live-confirmed in cmux\n * 0.64.16; `UserPromptSubmit` is mapped opportunistically (harmless if absent).\n */\nexport function deriveRunState(eventName: string): RunState | null {\n switch (eventName) {\n case \"agent.hook.PreToolUse\":\n case \"agent.hook.UserPromptSubmit\":\n return \"working\";\n case \"agent.hook.Stop\":\n return \"idle\";\n default:\n return null;\n }\n}\n\n/** A correlated hook frame, passed to the caller's record resolver. */\nexport interface CmuxAgentHook {\n cwd?: string;\n /** The emitting agent kind (`payload._source`, e.g. \"claude\"). */\n source?: string;\n /** The agent session id (`payload.session_id`). */\n sessionId?: string;\n}\n\nexport interface CmuxEventsBridgeDeps {\n /** Ingress into the daemon's event pipeline (resolves project + handles). */\n emit: (ev: ControlEvent) => void;\n /**\n * Map an agent hook frame to its owning crew record, or undefined if none.\n * The daemon supplies this from the store (non-terminal interactive records\n * matched by cwd). Keeping it injected keeps the bridge pure and testable.\n */\n resolve: (hook: CmuxAgentHook) => { id: string } | undefined;\n /** Durable resume cursor passed to `cmux events --cursor-file`. */\n cursorFile: string;\n /** Injectable spawn for tests; defaults to spawning the real cmux binary. */\n spawnImpl?: (bin: string, args: string[]) => CmuxEventsChild;\n /** Injectable cmux binary path; defaults to resolveCmuxBin(). */\n cmuxBin?: string;\n /** Injectable backoff for tests; defaults to setTimeout. */\n sleep?: (ms: number) => Promise<void>;\n /** Backoff between respawn attempts after the child exits (ms, default 1000). */\n reconnectMs?: number;\n log?: (msg: string) => void;\n /** Test-only: stop after the first child exits (don't respawn). */\n stopAfterFirstRun?: boolean;\n}\n\n/**\n * One long-lived `cmux events` subscription for the whole daemon. The CLI's\n * `--reconnect` resumes the socket in-process; `--cursor-file` makes resume\n * durable across daemon (and child) restarts. If the child process itself dies,\n * we respawn with backoff so the consumer self-heals.\n */\nexport class CmuxEventsBridge {\n private child: CmuxEventsChild | null = null;\n private stopped = false;\n private buf = \"\";\n private deps: CmuxEventsBridgeDeps;\n\n constructor(deps: CmuxEventsBridgeDeps) {\n this.deps = deps;\n }\n\n /** Begin the subscription. Idempotent. */\n start(): void {\n if (this.child || this.stopped) return;\n void this.run();\n }\n\n /** Stop the subscription and kill the child (daemon shutdown). */\n stop(): void {\n this.stopped = true;\n const c = this.child;\n this.child = null;\n if (c) {\n try { c.kill(); } catch { /* already gone */ }\n }\n }\n\n private async run(): Promise<void> {\n const spawnImpl =\n this.deps.spawnImpl ??\n ((bin, args) => nodeSpawn(bin, args, { stdio: [\"ignore\", \"pipe\", \"ignore\"] }) as ChildProcess as unknown as CmuxEventsChild);\n const bin = this.deps.cmuxBin ?? resolveCmuxBin();\n const sleep = this.deps.sleep ?? ((ms: number) => new Promise((r) => setTimeout(r, ms)));\n const reconnectMs = this.deps.reconnectMs ?? 1000;\n const args = [\n \"events\",\n \"--reconnect\",\n \"--cursor-file\", this.deps.cursorFile,\n \"--category\", \"agent\",\n \"--no-heartbeat\",\n ];\n\n while (!this.stopped) {\n this.buf = \"\";\n let child: CmuxEventsChild;\n try {\n child = spawnImpl(bin, args);\n } catch (e) {\n this.deps.log?.(`cmux events spawn failed: ${(e as Error).message}`);\n if (this.deps.stopAfterFirstRun) return;\n await sleep(reconnectMs);\n continue;\n }\n this.child = child;\n await new Promise<void>((resolve) => {\n let settled = false;\n const done = () => { if (!settled) { settled = true; resolve(); } };\n child.stdout?.on(\"data\", (b: Buffer | string) => this.onData(b));\n child.stdout?.on(\"end\", done);\n child.on(\"exit\", done);\n child.on(\"error\", (err) => {\n this.deps.log?.(`cmux events child error: ${err.message}`);\n done();\n });\n });\n this.child = null;\n if (this.stopped || this.deps.stopAfterFirstRun) break;\n // Child died (cmux app restart, binary error): resume from the cursor.\n await sleep(reconnectMs);\n }\n }\n\n private onData(chunk: Buffer | string): void {\n this.buf += typeof chunk === \"string\" ? chunk : chunk.toString(\"utf-8\");\n let nl: number;\n while ((nl = this.buf.indexOf(\"\\n\")) >= 0) {\n const line = this.buf.slice(0, nl);\n this.buf = this.buf.slice(nl + 1);\n this.handleLine(line);\n }\n }\n\n private handleLine(rawLine: string): void {\n const line = rawLine.trim();\n if (!line || line[0] !== \"{\") return;\n let f:\n | {\n type?: string;\n category?: string;\n name?: string;\n source?: string;\n payload?: { _source?: string; session_id?: string; cwd?: string; phase?: string; tool_name?: string };\n }\n | undefined;\n try {\n f = JSON.parse(line);\n } catch {\n return; // partial/non-JSON keepalive or ack we don't parse\n }\n // Only agent hook events; ignore ack/heartbeat and other categories.\n if (f?.type !== \"event\" || f.category !== \"agent\") return;\n // Classify the hook into a run-state. `Stop` is the main-session turn-end;\n // PreToolUse/UserPromptSubmit mean a turn is live; SubagentStop and any\n // other hook carry no turn-level run-state and are ignored.\n const runState = f.name ? deriveRunState(f.name) : null;\n if (!runState) return;\n const p = f.payload ?? {};\n // Each hook fires a \"received\" then \"completed\" phase frame; act on the\n // settled one so we emit exactly once per hook.\n if (p.phase === \"received\") return;\n const rec = this.deps.resolve({\n cwd: p.cwd,\n source: p._source ?? f.source,\n sessionId: p.session_id,\n });\n if (!rec) return;\n if (runState === \"idle\") {\n // Turn-end / idle — the signal the pane reader infers by scraping.\n this.deps.emit({\n type: \"task.turn.completed\",\n id: rec.id,\n turnId: p.session_id ?? \"cmux\",\n });\n return;\n }\n // working: feed a real-activity signal into the liveness path. task.progress\n // refreshes lastHeartbeatAt (the clock evaluateStall keys off), so a crew\n // that is mid long tool-call but screen-quiet is NOT false-stalled (#292),\n // and a crew the scrape path wrongly idled resumes to 'working'. ADDITIVE:\n // the reducer absorbs this idempotently, and a blocked crew stays blocked.\n // #354: carry the tool name on PreToolUse so the reducer can open a\n // tool-in-flight window (pendingTool) — the discriminator the watchdog uses\n // to tell a hung tool call apart from a quiet thinking turn.\n this.deps.emit({ type: \"task.progress\", id: rec.id, note: f.name, tool: p.tool_name });\n }\n}\n","import type { RuntimeDriver, PaneRef } from \"../runtimes/types.js\";\nimport { DeferDelivery } from \"../runtimes/cmux.js\";\n\n/**\n * #332: daemon-side cmux access. The daemon (a launchd process, NOT a cmux\n * descendant) can now drive cmux directly because the CLI auto-discovers its\n * canonical socket (~/.local/state/cmux/cmux.sock) from any process.\n *\n * Every method is FAIL-SOFT: a cmux/socket error degrades to a safe sentinel\n * ([] / null / no-op) so a transient failure NEVER false-reaps a live crew.\n * The ONE exception is DeferDelivery, which `send` re-throws so the delivery\n * loop can defer-while-typing (#258/#302).\n *\n * This is the seam #333's LifecycleSource port sits beside.\n */\nexport class DaemonCmux {\n constructor(private readonly driver: RuntimeDriver) {}\n\n async send(surface: PaneRef, text: string, opts?: { probe?: boolean }): Promise<void> {\n try {\n await this.driver.sendToSurface(surface, text, opts);\n } catch (e) {\n if (e instanceof DeferDelivery) throw e;\n }\n }\n\n async listSurfaces(workspaceId: string): Promise<PaneRef[]> {\n try { return await this.driver.listSurfaces(workspaceId); }\n catch { return []; }\n }\n\n async readScreen(ref: string): Promise<string | null> {\n try { return await this.driver.readScreen(ref); }\n catch { return null; }\n }\n\n async readPaneScreen(pane: PaneRef): Promise<string | null> {\n try { return await this.driver.readPaneScreen(pane); }\n catch { return null; }\n }\n\n async findWorkspaceId(name: string): Promise<string | null> {\n try {\n const ref = await this.driver.status(name);\n return ref?.id ?? null;\n } catch {\n return null;\n }\n }\n\n async isAvailable(): Promise<boolean> {\n try { await this.driver.listSurfaces(\"\"); return true; }\n catch { return false; }\n }\n}\n","// Runtime-bound crew-pane helpers — discovery, first-turn delivery, captain\n// workspace resolution. Extracted from packages/cli/src/commands/crew.ts so\n// they are unit-testable with a mock RuntimeDriver.\n\nimport net from \"node:net\";\nimport { loadConfig } from \"@squadrant/shared\";\nimport type { PaneRef, RuntimeDriver } from \"@squadrant/shared\";\nimport { RuntimeRegistry } from \"./runtimes/registry.js\";\nimport { createCmuxDriver } from \"./runtimes/cmux.js\";\nimport { titleFor, isCrewTitle, isTurnAccepted } from \"@squadrant/core\";\nimport type { TurnAcceptanceConfig } from \"@squadrant/core\";\n\n// Poll-based first-turn delivery timing constants.\nconst SEND_FIRST_TURN_FLOOR_MS = 1500;\nconst POLL_INTERVAL_MS = 750;\nconst SEND_FIRST_TURN_TIMEOUT_MS = 20000;\nconst POST_SEND_CHECK_MS = 750;\n\n/** Reserve an ephemeral TCP port for a crew's embedded HTTP server. Binds :0,\n * reads the OS-assigned port, then releases it. A small TOCTOU window exists\n * between release and the crew binding the port; acceptable for local\n * single-user spawns. */\nexport function getFreePort(): Promise<number> {\n return new Promise((resolve, reject) => {\n const srv = net.createServer();\n srv.once(\"error\", reject);\n srv.listen(0, \"127.0.0.1\", () => {\n const addr = srv.address();\n const port = typeof addr === \"object\" && addr ? addr.port : 0;\n srv.close(() => (port ? resolve(port) : reject(new Error(\"no free port assigned\"))));\n });\n });\n}\n\nexport async function listProjectCrews(\n runtime: RuntimeDriver,\n workspaceId: string,\n project: string,\n): Promise<PaneRef[]> {\n const surfaces = await runtime.listSurfaces(workspaceId);\n return surfaces.filter((s) => s.title && isCrewTitle(project, s.title));\n}\n\nexport async function findCrew(\n runtime: RuntimeDriver,\n workspaceId: string,\n project: string,\n name: string,\n): Promise<PaneRef | null> {\n const want = titleFor(project, name);\n const surfaces = await runtime.listSurfaces(workspaceId);\n return surfaces.find((s) => s.title === want) ?? null;\n}\n\nexport async function resolveCaptainWorkspace(project: string): Promise<{\n runtime: RuntimeDriver;\n workspaceId: string;\n}> {\n const config = loadConfig();\n const proj = config.projects[project];\n if (!proj) {\n throw new Error(`Project '${project}' not found. Run 'squadrant projects list'.`);\n }\n const runtime = new RuntimeRegistry({ cmux: createCmuxDriver() }).forProject(project, config);\n const captain = await runtime.status(proj.captainName);\n if (!captain) {\n throw new Error(\n `Captain workspace '${proj.captainName}' is not running. Run 'squadrant launch ${project}' first.`,\n );\n }\n return { runtime, workspaceId: captain.id };\n}\n\nexport async function sendFirstTurnWhenReady(\n runtime: Pick<RuntimeDriver, \"readPaneScreen\" | \"sendToPane\">,\n pane: PaneRef,\n task: string,\n preLaunchScreen: string,\n acceptanceConfig?: TurnAcceptanceConfig,\n): Promise<void> {\n await new Promise((r) => setTimeout(r, SEND_FIRST_TURN_FLOOR_MS));\n\n const maxPolls = Math.floor(\n (SEND_FIRST_TURN_TIMEOUT_MS - SEND_FIRST_TURN_FLOOR_MS) / POLL_INTERVAL_MS,\n );\n let previousScreen = \"\";\n let stable = false;\n\n for (let i = 0; i < maxPolls && !stable; i++) {\n const screen = (await runtime.readPaneScreen(pane)) ?? \"\";\n // Ready = the agent prompt is actually up: screen is non-empty, settled\n // (unchanged between two consecutive reads), AND has advanced past the\n // un-entered launch command line. The last condition prevents sending the\n // task onto the shell line before the TUI takes over — which concatenates\n // onto the launch command and triggers a shell parse error (opencode\n // boot-race). A momentarily static launch line is not readiness.\n if (screen.length > 0 && screen === previousScreen && screen !== preLaunchScreen) {\n stable = true;\n } else {\n previousScreen = screen;\n await new Promise((r) => setTimeout(r, POLL_INTERVAL_MS));\n }\n }\n\n // Snapshot the screen immediately before sending so the post-send check can\n // tell whether the keystrokes were received. Comparing against the raw task\n // text is unreliable: sendToPane collapses newlines to spaces (#136), so a\n // multi-line task never appears verbatim in the single-line pane render and\n // the check would always re-send a duplicate first turn (#168).\n const preSendScreen = (await runtime.readPaneScreen(pane)) ?? \"\";\n await runtime.sendToPane(pane, task);\n\n // Bounded retry loop (#235): after sending, poll the pane for evidence that\n // the TUI actually accepted the turn.\n const retryLimit = acceptanceConfig?.retryLimit ?? 2;\n for (let attempt = 0; attempt < retryLimit; attempt++) {\n await new Promise((r) => setTimeout(r, POST_SEND_CHECK_MS));\n const afterScreen = (await runtime.readPaneScreen(pane)) ?? \"\";\n if (isTurnAccepted(preSendScreen, afterScreen, acceptanceConfig)) {\n return;\n }\n if (attempt < retryLimit - 1) {\n await runtime.sendToPane(pane, task);\n }\n }\n}\n","// @squadrant/workspaces — environment/surface seam (cmux runtime · obsidian vault · cmux notifier).\nexport * from \"./runtimes/index.js\";\nexport * from \"./notifiers/index.js\";\nexport * from \"./workspaces/index.js\";\nexport { CmuxEventsBridge, deriveRunState } from \"./cmux/events-bridge.js\";\nexport type { RunState, CmuxEventsChild, CmuxAgentHook, CmuxEventsBridgeDeps } from \"./cmux/events-bridge.js\";\nexport { DaemonCmux } from \"./cmux/daemon-cmux.js\";\nexport { getFreePort, listProjectCrews, findCrew, resolveCaptainWorkspace, sendFirstTurnWhenReady } from \"./crew-pane.js\";\n","import { execSync } from \"node:child_process\";\nimport type { AgentDriver, AgentProbeResult, SpawnOptions, AgentResult } from \"./types.js\";\n\nexport function createClaudeDriver(): AgentDriver {\n return {\n name: \"claude\",\n templateSuffix: \"claude\",\n\n async probe(): Promise<AgentProbeResult> {\n try {\n const version = execSync(\"claude --version\", { encoding: \"utf-8\" }).trim();\n return {\n installed: true,\n version,\n capabilities: [\n \"teams\",\n \"json_output\",\n \"model_routing\",\n \"skills\",\n \"auto_approve\",\n \"streaming\",\n \"prompt_file\",\n ],\n };\n } catch {\n return { installed: false, version: \"\", capabilities: [] };\n }\n },\n\n buildCommand(opts: SpawnOptions): string {\n let cmd = \"claude\";\n\n if (opts.model) {\n cmd += ` --model ${opts.model}`;\n }\n\n if (opts.autoApprove) {\n cmd += \" --dangerously-skip-permissions\";\n } else if (opts.permissionMode) {\n cmd += ` --permission-mode ${opts.permissionMode}`;\n }\n\n if (opts.promptFile) {\n cmd += ` --append-system-prompt-file ${opts.promptFile}`;\n }\n\n if (opts.settingsPath) {\n cmd += ` --settings ${opts.settingsPath}`;\n }\n\n // Load squadrant plugin for skills\n const pluginDir = `${process.env.HOME}/.config/squadrant/plugin`;\n cmd += ` --plugin-dir ${pluginDir}`;\n\n if (!opts.interactive) {\n cmd += ` -p \"${opts.prompt.replace(/\"/g, '\\\\\"')}\"`;\n }\n return cmd;\n },\n\n parseOutput(raw: string): AgentResult {\n const lines = raw.trim().split(\"\\n\").filter((l) => l.startsWith(\"{\"));\n if (lines.length === 0) {\n return { status: \"success\", output: raw.trim() };\n }\n try {\n const last = JSON.parse(lines[lines.length - 1]);\n return { status: \"success\", output: last.result || last.content || raw.trim() };\n } catch {\n return { status: \"success\", output: raw.trim() };\n }\n },\n\n async stop(pid: number): Promise<void> {\n try {\n process.kill(pid, \"SIGTERM\");\n } catch {\n // process may already be gone\n }\n },\n };\n}\n","import { execSync } from \"node:child_process\";\nimport type { AgentDriver, AgentProbeResult, SpawnOptions, AgentResult } from \"./types.js\";\n\nexport function createCodexDriver(): AgentDriver {\n return {\n name: \"codex\",\n templateSuffix: \"generic\",\n\n async probe(): Promise<AgentProbeResult> {\n try {\n const version = execSync(\"codex --version\", { encoding: \"utf-8\", stdio: [\"pipe\", \"pipe\", \"pipe\"] }).trim();\n const help = execSync(\"codex --help\", { encoding: \"utf-8\", stdio: [\"pipe\", \"pipe\", \"pipe\"] });\n const hasExec = help.includes(\"exec\");\n return {\n installed: true,\n version,\n capabilities: [\n \"auto_approve\",\n \"json_output\",\n \"sandbox\",\n ...(hasExec ? [\"streaming\" as const] : []),\n ],\n };\n } catch {\n return { installed: false, version: \"\", capabilities: [] };\n }\n },\n\n buildCommand(opts: SpawnOptions): string {\n let cmd = `codex exec \"${opts.prompt.replace(/\"/g, '\\\\\"')}\" --json`;\n if (opts.autoApprove) cmd += \" --full-auto\";\n return cmd;\n },\n\n parseOutput(raw: string): AgentResult {\n const lines = raw.trim().split(\"\\n\").filter((l) => l.startsWith(\"{\"));\n if (lines.length === 0) {\n return { status: \"success\", output: raw.trim() };\n }\n try {\n const last = JSON.parse(lines[lines.length - 1]);\n return { status: \"success\", output: last.output || last.result || raw.trim() };\n } catch {\n return { status: \"success\", output: raw.trim() };\n }\n },\n\n async stop(pid: number): Promise<void> {\n try { process.kill(pid, \"SIGTERM\"); } catch { /* already gone */ }\n },\n };\n}\n","import { execSync } from \"node:child_process\";\nimport type { AgentDriver, AgentProbeResult, SpawnOptions, AgentResult } from \"./types.js\";\n\nexport function createGeminiDriver(): AgentDriver {\n return {\n name: \"gemini\",\n templateSuffix: \"generic\",\n\n async probe(): Promise<AgentProbeResult> {\n try {\n const version = execSync(\"gemini --version\", { encoding: \"utf-8\", stdio: [\"pipe\", \"pipe\", \"pipe\"] }).trim();\n return {\n installed: true,\n version,\n capabilities: [\"auto_approve\", \"json_output\", \"streaming\"],\n };\n } catch {\n return { installed: false, version: \"\", capabilities: [] };\n }\n },\n\n buildCommand(opts: SpawnOptions): string {\n let cmd = `gemini -p \"${opts.prompt.replace(/\"/g, '\\\\\"')}\"`;\n if (opts.autoApprove) cmd += \" --yolo\";\n if (opts.jsonOutput) cmd += \" --output-format json\";\n return cmd;\n },\n\n parseOutput(raw: string): AgentResult {\n try {\n const parsed = JSON.parse(raw.trim());\n return { status: \"success\", output: parsed.response || raw.trim() };\n } catch {\n return { status: \"success\", output: raw.trim() };\n }\n },\n\n async stop(pid: number): Promise<void> {\n try { process.kill(pid, \"SIGTERM\"); } catch { /* already gone */ }\n },\n };\n}\n","import { execSync } from \"node:child_process\";\nimport type { AgentDriver, AgentProbeResult, SpawnOptions, AgentResult } from \"./types.js\";\n\nexport function createOpencodeDriver(): AgentDriver {\n return {\n name: \"opencode\",\n templateSuffix: \"opencode\",\n\n async probe(): Promise<AgentProbeResult> {\n try {\n const version = execSync(\"opencode --version\", { encoding: \"utf-8\", stdio: [\"pipe\", \"pipe\", \"pipe\"] }).trim();\n return {\n installed: true,\n version,\n capabilities: [\"auto_approve\", \"json_output\", \"streaming\", \"model_routing\"],\n };\n } catch {\n return { installed: false, version: \"\", capabilities: [] };\n }\n },\n\n buildCommand(opts: SpawnOptions): string {\n // Interactive crews: boot the TUI; the caller delivers opts.prompt as the\n // first turn via runtime.send once the session is ready, so the crew stays\n // alive for follow-up turns through `squadrant crew send`. When a port is\n // given, bind the embedded HTTP server on it so the daemon's SSE bridge\n // can subscribe to /event for turn-end detection (the bare TUI uses an\n // ephemeral unix socket with no reachable /event endpoint).\n if (opts.interactive) return opts.port ? `opencode --port ${opts.port}` : \"opencode\";\n let cmd = `opencode run \"${opts.prompt.replace(/\"/g, '\\\\\"')}\"`;\n if (opts.jsonOutput) cmd += \" --format json\";\n if (opts.model) cmd += ` -m ${opts.model}`;\n return cmd;\n },\n\n parseOutput(raw: string): AgentResult {\n try {\n const parsed = JSON.parse(raw.trim());\n return { status: \"success\", output: parsed.response || parsed.output || raw.trim() };\n } catch {\n return { status: \"success\", output: raw.trim() };\n }\n },\n\n async stop(pid: number): Promise<void> {\n try { process.kill(pid, \"SIGTERM\"); } catch { /* already gone */ }\n },\n };\n}\n","export type AgentCapability =\n | \"teams\"\n | \"json_output\"\n | \"sandbox\"\n | \"model_routing\"\n | \"skills\"\n | \"auto_approve\"\n | \"streaming\"\n | \"prompt_file\";\n\nexport type Role = \"command\" | \"captain\" | \"crew\" | \"exploration\" | \"side\";\n\nexport interface AgentProbeResult {\n installed: boolean;\n version: string;\n capabilities: AgentCapability[];\n}\n\nexport interface SpawnOptions {\n prompt: string;\n workdir: string;\n role: Role;\n model?: string;\n autoApprove?: boolean;\n jsonOutput?: boolean;\n promptFile?: string;\n // Claude's --permission-mode value (e.g. \"acceptEdits\", \"plan\", \"default\").\n // \"acceptEdits\" auto-accepts file edits while still prompting for risky ops\n // (Bash, etc.) — the semi-automatic gate used for cheaper-model crews. If\n // autoApprove is also set, --dangerously-skip-permissions supersedes this.\n permissionMode?: string;\n // Interactive crew sessions: drivers should NOT bake the prompt into the\n // command (no `-p`). Caller will deliver the prompt via runtime.send after\n // the CLI is ready, so the session stays alive between turns.\n interactive?: boolean;\n // TCP port for an agent's embedded HTTP server. Opencode interactive crews\n // launch as `opencode --port <N>` so the daemon's SSE bridge can subscribe\n // to the crew's /event stream for reliable turn-end detection.\n port?: number;\n // Per-invocation settings file (Claude's --settings flag). The\n // daemon-supervised claude crew spawn writes a per-crew settings.json\n // containing the squadrant Stop hook and passes the path here so the hook\n // is scoped to this session only (no global ~/.claude/settings.json edit).\n settingsPath?: string;\n}\n\nexport interface AgentResult {\n status: \"success\" | \"error\" | \"timeout\";\n output: string;\n filesChanged?: string[];\n}\n\nexport interface AgentDriver {\n name: string;\n templateSuffix: string;\n\n probe(): Promise<AgentProbeResult>;\n buildCommand(opts: SpawnOptions): string;\n parseOutput(raw: string): AgentResult;\n stop(pid: number): Promise<void>;\n}\n\nexport interface RoleRequirements {\n required: AgentCapability[];\n preferred: AgentCapability[];\n}\n\nexport const ROLE_REQUIREMENTS: Record<Role, RoleRequirements> = {\n command: { required: [\"auto_approve\"], preferred: [\"teams\", \"json_output\"] },\n captain: { required: [\"auto_approve\"], preferred: [\"teams\", \"model_routing\", \"skills\"] },\n crew: { required: [\"auto_approve\"], preferred: [\"json_output\", \"sandbox\"] },\n exploration: { required: [\"auto_approve\"], preferred: [] },\n side: { required: [\"auto_approve\"], preferred: [\"skills\"] },\n};\n","import { ROLE_REQUIREMENTS, type AgentCapability, type AgentDriver, type AgentProbeResult, type Role } from \"./types.js\";\n\nexport interface ValidationResult {\n allowed: boolean;\n missingRequired: AgentCapability[];\n missingPreferred: AgentCapability[];\n reason?: string;\n}\n\nexport class CapabilityRegistry {\n private drivers: Record<string, AgentDriver>;\n private probeResults: Record<string, AgentProbeResult> = {};\n\n constructor(drivers: Record<string, AgentDriver>) {\n this.drivers = drivers;\n }\n\n async probeAll(): Promise<void> {\n for (const [name, driver] of Object.entries(this.drivers)) {\n this.probeResults[name] = await driver.probe();\n }\n }\n\n get(name: string): AgentDriver | undefined {\n return this.drivers[name];\n }\n\n getDriver(name: string): AgentDriver {\n const driver = this.drivers[name];\n if (!driver) {\n throw new Error(`No driver registered for agent '${name}'`);\n }\n return driver;\n }\n\n getProbeResult(name: string): AgentProbeResult | undefined {\n return this.probeResults[name];\n }\n\n validateRole(agent: string, role: Role): ValidationResult {\n const probe = this.probeResults[agent];\n if (!probe || !probe.installed) {\n return {\n allowed: false,\n missingRequired: [],\n missingPreferred: [],\n reason: `Agent '${agent}' is not installed`,\n };\n }\n\n const reqs = ROLE_REQUIREMENTS[role];\n const caps = new Set(probe.capabilities);\n\n const missingRequired = reqs.required.filter((c) => !caps.has(c));\n const missingPreferred = reqs.preferred.filter((c) => !caps.has(c));\n\n if (missingRequired.length > 0) {\n return {\n allowed: false,\n missingRequired,\n missingPreferred,\n reason: `${agent} cannot be ${role}: missing required capabilities [${missingRequired.join(\", \")}]`,\n };\n }\n\n return { allowed: true, missingRequired: [], missingPreferred };\n }\n\n installedAgents(): string[] {\n return Object.entries(this.probeResults)\n .filter(([, probe]) => probe.installed)\n .map(([name]) => name);\n }\n}\n","// buildAgentCmd — build the CLI command string used to launch a captain/command\n// session. Extracted from packages/cli/src/commands/launch.ts so it can be\n// unit-tested without spawning real processes.\n\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport type { Role } from \"./types.js\";\nimport type { CapabilityRegistry } from \"./registry.js\";\n\n/**\n * Build the shell command string that launches an agent session for a given\n * role. For Claude, handles fresh/continue, permission-mode flags, role\n * template file, and plugin-dir. For all other agents, delegates to the\n * driver's own buildCommand.\n *\n * @param agentName - e.g. \"claude\", \"opencode\", \"codex\"\n * @param registry - populated CapabilityRegistry\n * @param role - \"captain\" | \"command\" | \"crew\" | …\n * @param fresh - true → new session; false → continue last session\n * @param permissionMode - \"acceptEdits\" | \"auto\" | \"bypassPermissions\"\n * @param model - optional model override\n * @param templatesDir - resolved path to ~/.config/squadrant/templates\n */\nexport function buildAgentCmd(\n agentName: string,\n registry: CapabilityRegistry,\n role: string,\n fresh: boolean,\n permissionMode: string,\n model?: string,\n templatesDir?: string,\n): string {\n const driver = registry.getDriver(agentName);\n\n if (driver.name === \"claude\") {\n let cmd = fresh ? \"claude\" : \"claude -c\";\n\n if (permissionMode === \"acceptEdits\") {\n cmd += \" --permission-mode acceptEdits\";\n } else if (permissionMode === \"auto\") {\n cmd += \" --permission-mode auto\";\n } else if (permissionMode === \"bypassPermissions\") {\n cmd += \" --dangerously-skip-permissions\";\n }\n\n if (model) {\n cmd += ` --model ${model}`;\n }\n\n if (templatesDir) {\n const roleFile = path.join(templatesDir, `${role}.claude.md`);\n const legacyRoleFile = path.join(templatesDir, `${role}.CLAUDE.md`);\n const actualRoleFile = fs.existsSync(roleFile)\n ? roleFile\n : fs.existsSync(legacyRoleFile) ? legacyRoleFile : null;\n if (actualRoleFile) {\n cmd += ` --append-system-prompt-file ${actualRoleFile}`;\n }\n\n const pluginDir = path.join(templatesDir, \"..\", \"plugin\");\n if (fs.existsSync(pluginDir)) {\n cmd += ` --plugin-dir ${pluginDir}`;\n }\n }\n\n return cmd;\n }\n\n // Non-Claude agents: delegate to driver.buildCommand.\n const roleFile = templatesDir\n ? path.join(templatesDir, `${role}.${driver.templateSuffix}.md`)\n : undefined;\n return driver.buildCommand({\n prompt: `You are a squadrant ${role}. Read your instructions from ${roleFile ?? role} and begin.`,\n workdir: process.cwd(),\n role: role as Role,\n model,\n autoApprove: true,\n promptFile: roleFile && fs.existsSync(roleFile) ? roleFile : undefined,\n });\n}\n","export { createClaudeDriver } from \"./claude.js\";\nexport { createCodexDriver } from \"./codex.js\";\nexport { createGeminiDriver } from \"./gemini.js\";\nexport { createOpencodeDriver } from \"./opencode.js\";\nexport { CapabilityRegistry } from \"./registry.js\";\nexport { buildAgentCmd } from \"./launch-cmd.js\";\nexport type {\n AgentDriver,\n AgentCapability,\n AgentProbeResult,\n AgentResult,\n SpawnOptions,\n Role,\n RoleRequirements,\n} from \"./types.js\";\nexport { ROLE_REQUIREMENTS } from \"./types.js\";\n","import { mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport os from \"node:os\";\nimport type {\n ProjectionEmitResult,\n ProjectionEmitter,\n ProjectionSource,\n} from \"@squadrant/shared\";\n\nfunction renderMdc(source: ProjectionSource): string {\n const skillSections = source.skills\n .map(\n (s) =>\n `## Skill: ${s.name}\\n\\n*${s.description}*\\n\\n${s.content}`,\n )\n .join(\"\\n\\n\");\n\n const body = [source.instructions.trim(), skillSections]\n .filter((s) => s.length > 0)\n .join(\"\\n\\n\");\n\n const frontmatter = [\n \"---\",\n \"description: Squadrant-projected rules and skills\",\n \"globs: ['**/*']\",\n \"alwaysApply: true\",\n \"---\",\n \"\",\n ].join(\"\\n\");\n\n return `${frontmatter}${body}\\n`;\n}\n\nasync function readExisting(p: string): Promise<string | null> {\n try {\n return await readFile(p, \"utf-8\");\n } catch (err) {\n if ((err as { code?: string }).code === \"ENOENT\") return null;\n throw err;\n }\n}\n\nfunction buildDiff(existing: string | null, generated: string): string {\n if (existing === null) return `NEW FILE\\n---\\n${generated}`;\n if (existing === generated) return \"UNCHANGED\";\n return `OVERWRITE\\n--- old\\n${existing}\\n--- new\\n${generated}`;\n}\n\nexport function createCursorEmitter(): ProjectionEmitter {\n return {\n name: \"cursor\",\n\n destinations(scope, projectRoot) {\n if (scope === \"user\") {\n return [\n {\n path: path.join(os.homedir(), \".cursor/rules/squadrant-global.mdc\"),\n shared: false,\n format: \"mdc\",\n },\n ];\n }\n if (!projectRoot) return [];\n return [\n {\n path: path.join(projectRoot, \".cursor/rules/squadrant.mdc\"),\n shared: false,\n format: \"mdc\",\n },\n ];\n },\n\n async emit(source, dest, opts): Promise<ProjectionEmitResult> {\n const generated = renderMdc(source);\n const existing = await readExisting(dest.path);\n\n if (opts?.dryRun) {\n return {\n written: false,\n path: dest.path,\n bytesWritten: 0,\n diff: buildDiff(existing, generated),\n };\n }\n\n await mkdir(path.dirname(dest.path), { recursive: true });\n await writeFile(dest.path, generated, \"utf-8\");\n\n return {\n written: true,\n path: dest.path,\n bytesWritten: Buffer.byteLength(generated, \"utf-8\"),\n };\n },\n };\n}\n","export const MARKER_START = \"<!-- squadrant:start -->\";\nexport const MARKER_END = \"<!-- squadrant:end -->\";\n\nexport function mergeWithMarkers(existing: string | null, generated: string): string {\n const body = generated.replace(/\\s+$/, \"\");\n const block = `${MARKER_START}\\n${body}\\n${MARKER_END}\\n`;\n\n if (!existing) return block;\n\n const startIdx = existing.indexOf(MARKER_START);\n const endIdx = existing.indexOf(MARKER_END);\n\n if (startIdx === -1 && endIdx === -1) {\n const sep = existing.endsWith(\"\\n\") ? \"\\n\" : \"\\n\\n\";\n return `${existing}${sep}${block}`;\n }\n\n if (startIdx === -1 || endIdx === -1) {\n throw new Error(\n `Corrupted squadrant markers — found only ${startIdx === -1 ? \"end\" : \"start\"} marker. ` +\n `Remove the stray marker or delete the file and re-run projection emit.`,\n );\n }\n\n if (endIdx < startIdx) {\n throw new Error(`Corrupted squadrant markers — end appears before start. Manual repair needed.`);\n }\n\n const before = existing.slice(0, startIdx);\n const after = existing.slice(endIdx + MARKER_END.length);\n const trimmedAfter = after.startsWith(\"\\n\") ? after.slice(1) : after;\n return `${before}${block}${trimmedAfter}`;\n}\n","import { mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport os from \"node:os\";\nimport { mergeWithMarkers } from \"./marker.js\";\nimport type {\n ProjectionEmitResult,\n ProjectionEmitter,\n ProjectionSource,\n} from \"@squadrant/shared\";\n\nfunction renderMarkdown(source: ProjectionSource): string {\n const skillSections = source.skills\n .map((s) => `## Skill: ${s.name}\\n\\n*${s.description}*\\n\\n${s.content}`)\n .join(\"\\n\\n\");\n return [source.instructions.trim(), skillSections]\n .filter((s) => s.length > 0)\n .join(\"\\n\\n\");\n}\n\nasync function readExisting(p: string): Promise<string | null> {\n try { return await readFile(p, \"utf-8\"); }\n catch (err) {\n if ((err as { code?: string }).code === \"ENOENT\") return null;\n throw err;\n }\n}\n\nexport function createCodexEmitter(): ProjectionEmitter {\n return {\n name: \"codex\",\n\n destinations(scope, projectRoot) {\n if (scope === \"user\") {\n return [{\n path: path.join(os.homedir(), \".codex/AGENTS.md\"),\n shared: true,\n format: \"markdown\",\n }];\n }\n if (!projectRoot) return [];\n return [{\n path: path.join(projectRoot, \"AGENTS.md\"),\n shared: true,\n format: \"markdown\",\n }];\n },\n\n async emit(source, dest, opts): Promise<ProjectionEmitResult> {\n const body = renderMarkdown(source);\n const existing = await readExisting(dest.path);\n const generated = mergeWithMarkers(existing, body);\n\n if (opts?.dryRun) {\n return {\n written: false,\n path: dest.path,\n bytesWritten: 0,\n diff: existing === generated ? \"UNCHANGED\" : `MERGE\\n--- old\\n${existing ?? \"\"}\\n--- new\\n${generated}`,\n };\n }\n\n await mkdir(path.dirname(dest.path), { recursive: true });\n await writeFile(dest.path, generated, \"utf-8\");\n\n return {\n written: true,\n path: dest.path,\n bytesWritten: Buffer.byteLength(generated, \"utf-8\"),\n };\n },\n };\n}\n","import { mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport os from \"node:os\";\nimport { mergeWithMarkers } from \"./marker.js\";\nimport type {\n ProjectionEmitResult,\n ProjectionEmitter,\n ProjectionSource,\n} from \"@squadrant/shared\";\n\nfunction renderMarkdown(source: ProjectionSource): string {\n const skillSections = source.skills\n .map((s) => `## Skill: ${s.name}\\n\\n*${s.description}*\\n\\n${s.content}`)\n .join(\"\\n\\n\");\n return [source.instructions.trim(), skillSections]\n .filter((s) => s.length > 0)\n .join(\"\\n\\n\");\n}\n\nasync function readExisting(p: string): Promise<string | null> {\n try { return await readFile(p, \"utf-8\"); }\n catch (err) {\n if ((err as { code?: string }).code === \"ENOENT\") return null;\n throw err;\n }\n}\n\nexport function createGeminiEmitter(): ProjectionEmitter {\n return {\n name: \"gemini\",\n\n destinations(scope, projectRoot) {\n if (scope === \"user\") {\n return [{\n path: path.join(os.homedir(), \".gemini/GEMINI.md\"),\n shared: true,\n format: \"markdown\",\n }];\n }\n if (!projectRoot) return [];\n return [{\n path: path.join(projectRoot, \"GEMINI.md\"),\n shared: true,\n format: \"markdown\",\n }];\n },\n\n async emit(source, dest, opts): Promise<ProjectionEmitResult> {\n const body = renderMarkdown(source);\n const existing = await readExisting(dest.path);\n const generated = mergeWithMarkers(existing, body);\n\n if (opts?.dryRun) {\n return {\n written: false,\n path: dest.path,\n bytesWritten: 0,\n diff: existing === generated ? \"UNCHANGED\" : `MERGE\\n--- old\\n${existing ?? \"\"}\\n--- new\\n${generated}`,\n };\n }\n\n await mkdir(path.dirname(dest.path), { recursive: true });\n await writeFile(dest.path, generated, \"utf-8\");\n\n return {\n written: true,\n path: dest.path,\n bytesWritten: Buffer.byteLength(generated, \"utf-8\"),\n };\n },\n };\n}\n","import { mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport os from \"node:os\";\nimport { mergeWithMarkers } from \"./marker.js\";\nimport type {\n ProjectionEmitResult,\n ProjectionEmitter,\n ProjectionSource,\n} from \"@squadrant/shared\";\n\nfunction renderMarkdown(source: ProjectionSource): string {\n const skillSections = source.skills\n .map((s) => `## Skill: ${s.name}\\n\\n*${s.description}*\\n\\n${s.content}`)\n .join(\"\\n\\n\");\n return [source.instructions.trim(), skillSections]\n .filter((s) => s.length > 0)\n .join(\"\\n\\n\");\n}\n\nasync function readExisting(p: string): Promise<string | null> {\n try { return await readFile(p, \"utf-8\"); }\n catch (err) {\n if ((err as { code?: string }).code === \"ENOENT\") return null;\n throw err;\n }\n}\n\nexport function createOpencodeEmitter(): ProjectionEmitter {\n return {\n name: \"opencode\",\n\n destinations(scope, projectRoot) {\n if (scope === \"user\") {\n return [{\n path: path.join(os.homedir(), \".config\", \"opencode\", \"AGENTS.md\"),\n shared: true,\n format: \"markdown\",\n }];\n }\n if (!projectRoot) return [];\n return [{\n path: path.join(projectRoot, \"AGENTS.md\"),\n shared: true,\n format: \"markdown\",\n }];\n },\n\n async emit(source, dest, opts): Promise<ProjectionEmitResult> {\n const body = renderMarkdown(source);\n const existing = await readExisting(dest.path);\n const generated = mergeWithMarkers(existing, body);\n\n if (opts?.dryRun) {\n return {\n written: false,\n path: dest.path,\n bytesWritten: 0,\n diff: existing === generated ? \"UNCHANGED\" : `MERGE\\n--- old\\n${existing ?? \"\"}\\n--- new\\n${generated}`,\n };\n }\n\n await mkdir(path.dirname(dest.path), { recursive: true });\n await writeFile(dest.path, generated, \"utf-8\");\n\n return {\n written: true,\n path: dest.path,\n bytesWritten: Buffer.byteLength(generated, \"utf-8\"),\n };\n },\n };\n}\n","import type { ProjectionEmitter, ProjectionEmitterFactory } from \"@squadrant/shared\";\n\nexport class ProjectionRegistry {\n constructor(private factories: Record<string, ProjectionEmitterFactory>) {}\n\n get(name: string): ProjectionEmitter {\n const factory = this.factories[name];\n if (!factory) {\n const available = Object.keys(this.factories).join(\", \") || \"(none)\";\n throw new Error(\n `Unknown projection target '${name}'. Available: ${available}.`,\n );\n }\n return factory();\n }\n\n list(): string[] {\n return Object.keys(this.factories);\n }\n}\n","export { createCursorEmitter } from \"./cursor.js\";\nexport { createCodexEmitter } from \"./codex.js\";\nexport { createGeminiEmitter } from \"./gemini.js\";\nexport { createOpencodeEmitter } from \"./opencode.js\";\nexport { ProjectionRegistry } from \"./registry.js\";\nexport { mergeWithMarkers, MARKER_START, MARKER_END } from \"./marker.js\";\nexport type {\n ProjectionSource,\n ProjectionDestination,\n ProjectionEmitter,\n ProjectionEmitResult,\n ProjectionEmitterFactory,\n} from \"@squadrant/shared\";\n","// src/control/codex/app-server-client.ts\n// Typed JSON-RPC 2.0 client for `codex app-server` v2.\n// Transport: stdio (newline-delimited JSON). See spec §3.\n// Defensive parser per orca codex-fetcher.ts:160-164: ignore non-JSON lines.\n\nimport { EventEmitter } from \"node:events\";\nimport { spawn as nodeSpawn, type ChildProcessByStdio } from \"node:child_process\";\nimport type { Readable, Writable } from \"node:stream\";\n\ntype Child = ChildProcessByStdio<Writable, Readable, Readable>;\n\nexport interface AppServerClientOpts {\n /** Override for tests; defaults to spawning real `codex app-server`. */\n spawn?: () => Child;\n clientInfo?: { name: string; version: string };\n}\n\nexport function _parseChunk(acc: { buf: string }, chunk: string): unknown[] {\n acc.buf += chunk;\n const out: unknown[] = [];\n let idx: number;\n while ((idx = acc.buf.indexOf(\"\\n\")) >= 0) {\n const line = acc.buf.slice(0, idx);\n acc.buf = acc.buf.slice(idx + 1);\n if (!line.trim()) continue;\n try { out.push(JSON.parse(line)); } catch { /* skip non-JSON defensively */ }\n }\n return out;\n}\n\nexport class AppServerClient extends EventEmitter {\n private proc?: Child;\n private acc = { buf: \"\" };\n private opts: AppServerClientOpts;\n constructor(opts: AppServerClientOpts = {}) { super(); this.opts = opts; }\n\n start(): void {\n if (this.proc) throw new Error(\"AppServerClient already started\");\n const sp = this.opts.spawn ?? defaultSpawn;\n this.proc = sp();\n this.proc.stdout.on(\"data\", (d: Buffer | string) => this._onStdout(d.toString()));\n this.proc.stderr.on(\"data\", (d: Buffer | string) => this.emit(\"stderr\", d.toString()));\n this.proc.on(\"exit\", (code, signal) => {\n this._onClosed();\n this.emit(\"closed\", { code, signal });\n });\n this.proc.on(\"error\", (e) => this.emit(\"error\", e));\n }\n\n kill(): void {\n if (this.proc) this.proc.kill();\n }\n\n async initialize(): Promise<unknown> {\n if (this._handshakeDone) return;\n if (!this.proc) throw new Error(\"AppServerClient not started\");\n const info = this.opts.clientInfo ?? { name: \"squadrant\", version: \"0\" };\n // Send initialize directly (bypass gate) — only initialize may pre-handshake.\n const id = this.nextId++;\n const env = { jsonrpc: \"2.0\", id, method: \"initialize\", params: { clientInfo: info } };\n const res = await new Promise<unknown>((resolve, reject) => {\n this.pending.set(id, { resolve, reject });\n this.proc!.stdin.write(JSON.stringify(env) + \"\\n\");\n });\n // Send 'initialized' as a notification (no id).\n this.proc.stdin.write(JSON.stringify({ jsonrpc: \"2.0\", method: \"initialized\" }) + \"\\n\");\n this._handshakeDone = true;\n return res;\n }\n\n async startThread(params: { cwd: string; model?: string; sandbox?: string; approvalPolicy?: string; developerInstructions?: string }): Promise<{ threadId: string }> {\n const res = await this._sendRequest(\"thread/start\", params) as { thread?: { id?: string } };\n const id = res?.thread?.id;\n if (typeof id !== \"string\") throw new Error(`thread/start: unexpected response shape (no thread.id): ${JSON.stringify(res).slice(0, 200)}`);\n return { threadId: id };\n }\n\n resumeThread(params: { threadId: string; cwd?: string }): Promise<unknown> {\n return this._sendRequest(\"thread/resume\", params);\n }\n\n /** Archive a thread so the app-server tears it down (and reaps any per-thread\n * MCP servers it spawned). Called when a codex crew closes. */\n archiveThread(threadId: string): Promise<unknown> {\n return this._sendRequest(\"thread/archive\", { threadId });\n }\n\n readThread(params: { threadId: string; lastN?: number }): Promise<unknown> {\n return this._sendRequest(\"thread/read\", params);\n }\n\n async sendTurn(threadId: string, text: string): Promise<{ turnId: string }> {\n const ack = await this._sendRequest(\"turn/start\", {\n threadId, input: [{ type: \"text\", text }],\n }) as { turn?: { id?: string } };\n const turnId = ack?.turn?.id;\n if (typeof turnId !== \"string\") throw new Error(`turn/start: unexpected ack shape (no turn.id): ${JSON.stringify(ack).slice(0, 200)}`);\n return new Promise((resolve, reject) => {\n const onNote = (n: { method: string; params?: any }) => {\n if (n.params?.turn?.id !== turnId) return;\n if (n.method === \"turn/completed\") { cleanup(); resolve({ turnId }); }\n if (n.method === \"turn/failed\") { cleanup(); reject(new Error(n.params?.error ?? \"turn failed\")); }\n };\n const onClientClosed = () => { cleanup(); reject(new Error(\"AppServerClient: client closed before turn completed\")); };\n const cleanup = () => {\n this.off(\"notification\", onNote);\n this.off(\"_clientClosed\", onClientClosed);\n };\n this.on(\"notification\", onNote);\n this.once(\"_clientClosed\", onClientClosed);\n });\n }\n\n steerTurn(threadId: string, text: string): Promise<unknown> {\n return this._sendRequest(\"turn/steer\", { threadId, input: [{ type: \"text\", text }] });\n }\n\n interruptTurn(threadId: string): Promise<unknown> {\n return this._sendRequest(\"turn/interrupt\", { threadId });\n }\n\n injectItems(threadId: string, items: unknown[]): Promise<unknown> {\n return this._sendRequest(\"thread/inject_items\", { threadId, items });\n }\n\n respondToServerRequest(id: number, result: unknown): void {\n if (!this.proc) throw new Error(\"AppServerClient not started\");\n this.proc.stdin.write(JSON.stringify({ jsonrpc: \"2.0\", id, result }) + \"\\n\");\n }\n\n private nextId = 1;\n private pending = new Map<number, { resolve: (v: unknown) => void; reject: (e: Error) => void }>();\n protected _handshakeDone = false;\n\n private _onClosed(): void {\n // Mass-reject pending RPC promises so callers don't hang on child death.\n const closedErr = new Error(\"AppServerClient: child closed before response\");\n for (const slot of this.pending.values()) slot.reject(closedErr);\n this.pending.clear();\n // Tell any waiters listening for child-close (sendTurn) to bail.\n this.emit(\"_clientClosed\");\n }\n\n protected _sendRequest(method: string, params?: unknown): Promise<unknown> {\n if (!this._handshakeDone && method !== \"initialize\") {\n throw new Error(`AppServerClient: cannot call '${method}' before handshake (spec §3.2)`);\n }\n if (!this.proc) throw new Error(\"AppServerClient not started\");\n const id = this.nextId++;\n const env = { jsonrpc: \"2.0\", id, method, params: params ?? {} };\n return new Promise((resolve, reject) => {\n this.pending.set(id, { resolve, reject });\n this.proc!.stdin.write(JSON.stringify(env) + \"\\n\");\n });\n }\n\n private _dispatchResponse(msg: any): boolean {\n if (typeof msg?.id !== \"number\") return false;\n const slot = this.pending.get(msg.id);\n if (!slot) return false;\n this.pending.delete(msg.id);\n if (msg.error) slot.reject(new Error(`${msg.error.message ?? \"rpc-error\"} (code ${msg.error.code})`));\n else slot.resolve(msg.result);\n return true;\n }\n\n private _onStdout(s: string): void {\n for (const msg of _parseChunk(this.acc, s)) this._dispatch(msg);\n }\n\n private _dispatch(msg: unknown): void {\n if (this._dispatchResponse(msg)) return;\n const m = msg as any;\n if (typeof m?.method === \"string\" && typeof m?.id === \"number\") {\n this.emit(\"serverRequest\", { id: m.id, method: m.method, params: m.params });\n return;\n }\n if (typeof m?.method === \"string\" && m?.id === undefined) {\n this.emit(\"notification\", { method: m.method, params: m.params });\n }\n }\n}\n\nfunction defaultSpawn(): Child {\n return nodeSpawn(\"codex\", [\"app-server\"], { stdio: [\"pipe\", \"pipe\", \"pipe\"] }) as Child;\n}\n","// src/control/codex/config.ts\n// Read the user's codex config (~/.codex/config.toml or $CODEX_HOME/config.toml)\n// and resolve the active model, applying [notice.model_migrations] so squadrant\n// uses the same model the TUI would use (e.g. gpt-5.3-codex → gpt-5.5).\n\nimport { readFile } from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\n\nexport async function resolveCodexModel(): Promise<string | undefined> {\n const home = process.env[\"CODEX_HOME\"] ?? join(homedir(), \".codex\");\n const configPath = join(home, \"config.toml\");\n\n let text: string;\n try {\n text = await readFile(configPath, \"utf8\");\n } catch {\n return undefined;\n }\n\n // Extract top-level `model = \"...\"` (only before the first section header).\n const topLevel = text.split(/^\\[/m)[0] ?? \"\";\n const modelMatch = topLevel.match(/^model\\s*=\\s*\"([^\"]+)\"/m);\n if (!modelMatch) return undefined;\n let model = modelMatch[1]!;\n\n // Apply [notice.model_migrations] — the TUI uses this map to upgrade legacy\n // model names (e.g. gpt-5.3-codex → gpt-5.5) before calling thread/start.\n // Without this, the app-server sends the stale name and ChatGPT OAuth rejects\n // it with a 400: \"The 'gpt-5.3-codex' model is not supported\".\n // Capture the section body up to the next section header (`^[`) or end of\n // input. JS regex has no `\\z`; `(?![\\s\\S])` is the end-of-input assertion so\n // migrations still resolve when the section is the last one in the file.\n const migSection = text.match(/^\\[notice\\.model_migrations\\]([\\s\\S]*?)(?=^\\[|(?![\\s\\S]))/m);\n if (migSection) {\n const migRe = /^\"([^\"]+)\"\\s*=\\s*\"([^\"]+)\"/mg;\n let m: RegExpExecArray | null;\n while ((m = migRe.exec(migSection[1]!)) !== null) {\n if (m[1] === model) { model = m[2]!; break; }\n }\n }\n\n return model;\n}\n","// src/control/codex/normalize.ts\n// Pure mapping from app-server ServerNotification → squadrant ControlEvent.\n// Spec §4.7. Unknown methods return null (status-line only / forward-compat).\n//\n// Anti-#2576 invariant: NO codex notification maps to task.done.\n// task.done is emitted exclusively by the driver on clean process exit.\n//\n// NOTE: Server-requests (frames that carry an `id` field alongside `method`)\n// are NOT handled here — they are routed by CodexInteractiveDriver (Task 2.4).\n// Extending this function with request handling would be incorrect.\nimport type { ControlEvent } from \"@squadrant/shared\";\n\n/** Minimal shape accepted from the JSON-RPC notification stream. */\nexport type AppServerNotification = { method: string; params?: Record<string, unknown> };\n\n/**\n * Map one app-server notification to a ControlEvent, or null when the\n * notification is informational (token-usage, compaction, status-change)\n * and does not need to enter the squadrant event bus.\n *\n * @param taskId The squadrant task ID that owns this notification stream.\n * @param n Raw notification frame from the app-server JSON-RPC channel.\n */\nexport function normalizeAppServerNotification(\n taskId: string,\n n: AppServerNotification,\n): ControlEvent | null {\n const p = n.params ?? {};\n\n switch (n.method) {\n // ── turn lifecycle ────────────────────────────────────────────────────\n case \"turn/started\":\n return {\n type: \"task.turn.started\",\n id: taskId,\n // TurnStartedNotification carries params.turn.id, not a top-level turnId.\n turnId: String((p[\"turn\"] as Record<string, unknown>)?.[\"id\"] ?? \"\"),\n };\n\n case \"turn/completed\":\n return {\n type: \"task.turn.completed\",\n id: taskId,\n // TurnCompletedNotification: same shape as TurnStartedNotification.\n turnId: String((p[\"turn\"] as Record<string, unknown>)?.[\"id\"] ?? \"\"),\n };\n\n // ── streaming delta (heartbeat / content) ─────────────────────────────\n // AgentMessageDeltaNotification: { threadId, turnId, itemId, delta }\n case \"item/agentMessage/delta\":\n // ReasoningTextDeltaNotification: { threadId, turnId, itemId, delta, contentIndex }\n case \"item/reasoning/textDelta\":\n // CommandExecutionOutputDeltaNotification: { threadId, turnId, itemId, delta }\n case \"item/commandExecution/outputDelta\":\n return {\n type: \"task.delta\",\n id: taskId,\n turnId: String(p[\"turnId\"] ?? \"\"),\n chunk: String(p[\"delta\"] ?? \"\"),\n };\n\n // command/exec/outputDelta is connection-scoped (no turnId); map to delta\n // with empty turnId so the bus can still forward it.\n // CommandExecOutputDeltaNotification: { processId, stream, deltaBase64, capReached }\n case \"command/exec/outputDelta\":\n return {\n type: \"task.delta\",\n id: taskId,\n turnId: \"\",\n chunk: String(p[\"deltaBase64\"] ?? \"\"),\n };\n\n // ── error ─────────────────────────────────────────────────────────────\n // ErrorNotification: { error: TurnError, willRetry, threadId, turnId }\n case \"error\": {\n const err = p[\"error\"] as Record<string, unknown> | undefined;\n const message = String(err?.[\"message\"] ?? p[\"message\"] ?? \"error\");\n return { type: \"task.failed\", id: taskId, error: message };\n }\n\n // ── status-line only — return null ────────────────────────────────────\n // ThreadTokenUsageUpdatedNotification: { threadId, turnId, tokenUsage }\n case \"thread/tokenUsage/updated\":\n // ContextCompactedNotification (deprecated): { threadId, turnId }\n case \"thread/compacted\":\n // ThreadStatusChangedNotification\n case \"thread/status/changed\":\n return null;\n\n // ── unknown / future methods ──────────────────────────────────────────\n default:\n return null;\n }\n}\n","// src/control/codex/driver.ts\n// Daemon-side interactive driver for codex. Owns ONE long-lived AppServerClient\n// child, maps TaskRecord ↔ threadId, emits squadrant ControlEvents via the\n// injected emit() hook. Notification mapping delegates to\n// normalizeAppServerNotification (Task 2.3); the driver only routes server-\n// requests and lifecycle. Spec §4.1/§4.6/§4.7.\n\nimport { AppServerClient } from \"./app-server-client.js\";\nimport { resolveCodexModel } from \"./config.js\";\nimport { normalizeAppServerNotification } from \"./normalize.js\";\nimport type { ControlEvent, TaskRecord } from \"@squadrant/shared\";\nimport { TERMINAL_STATES } from \"@squadrant/shared\";\n\n/**\n * Boot-time guard for the daemon's codex reattach loop. Reattaching a thread\n * re-spawns its per-thread MCP servers (gitnexus/pay), so reattaching EVERY\n * non-terminal codex task on boot re-storms one MCP set per historical crew\n * (observed: 22 zombie tasks → 22 gitnexus servers → RAM exhaustion). Only\n * reattach a task that is (a) interactive codex, (b) non-terminal — closed\n * crews are `cancelled` via codex-close, so they're skipped, (c) still fresh:\n * a dead crew's pane is gone and hasn't heartbeat within the staleness window,\n * and (d) has a resumeRef to resume from.\n */\nexport function shouldReattachCodex(\n rec: TaskRecord,\n now: number,\n staleMs: number,\n): boolean {\n if (rec.provider !== \"codex\" || rec.mode !== \"interactive\") return false;\n if (TERMINAL_STATES.has(rec.state)) return false;\n const last = rec.attempts.at(-1)?.lastHeartbeatAt ?? rec.lastHeartbeat ?? 0;\n if (now - last > staleMs) return false;\n return Boolean(rec.attempts.at(-1)?.resumeRef);\n}\n\nexport interface DriverDeps {\n /** Override for tests; defaults to a real AppServerClient. */\n makeClient?: () => AppServerClient;\n /** Ingress into the daemon's event pipeline. */\n emit: (ev: ControlEvent) => void;\n}\n\nexport class CodexInteractiveDriver {\n private client?: AppServerClient;\n private handshakeP?: Promise<void>;\n private threadByTask = new Map<string, string>();\n private taskByThread = new Map<string, string>();\n /**\n * taskId → in-flight dispatch promise. The first-turn say() can arrive while\n * dispatch() is still awaiting startThread (threadByTask not yet set); say()\n * awaits this gate before reading threadByTask so the first turn isn't lost\n * with \"no thread for task\" (issue #212).\n */\n private dispatchByTask = new Map<string, Promise<void>>();\n /** taskId → last pending server-request {id, method} (for answer()) */\n private serverRequestByTask = new Map<string, { id: number; method: string }>();\n private deps: DriverDeps;\n\n constructor(deps: DriverDeps) { this.deps = deps; }\n\n private async ensureClient(): Promise<AppServerClient> {\n if (this.client) return this.client;\n const c = (this.deps.makeClient ?? (() => new AppServerClient({ clientInfo: { name: \"squadrant\", version: \"iv\" } })))();\n this.client = c;\n c.start();\n c.on(\"notification\", (n) => this.onNotification(n));\n c.on(\"serverRequest\", (r) => this.onServerRequest(r));\n c.on(\"closed\", () => { this.client = undefined; this.handshakeP = undefined; });\n return c;\n }\n\n private async ensureHandshake(): Promise<void> {\n const c = await this.ensureClient();\n if (!this.handshakeP) this.handshakeP = c.initialize().then(() => {});\n return this.handshakeP;\n }\n\n async dispatch(rec: TaskRecord & { cwd?: string; model?: string }): Promise<void> {\n // Register the in-flight dispatch synchronously so a concurrent first-turn\n // say() can await it (see dispatchByTask / issue #212). Cleared once the\n // thread is mapped (or dispatch failed), after which say() reads the map.\n const p = this.runDispatch(rec);\n this.dispatchByTask.set(rec.id, p.then(() => {}, () => {}));\n try {\n await p;\n } finally {\n this.dispatchByTask.delete(rec.id);\n }\n }\n\n private async runDispatch(rec: TaskRecord & { cwd?: string; model?: string }): Promise<void> {\n try {\n const c = await this.ensureClient();\n await withTimeout(this.ensureHandshake(), 10_000, \"handshake timed out\");\n // When no model is explicitly set on the task record, read the user's\n // codex config and apply model migrations (e.g. gpt-5.3-codex → gpt-5.5).\n // Without this the app-server falls back to the raw config value and\n // ChatGPT OAuth rejects it with a 400 (verified: gpt-5.5 succeeds).\n const model = rec.model ?? await resolveCodexModel();\n const { threadId } = await c.startThread({\n cwd: rec.cwd ?? process.cwd(),\n model,\n // Parity with claude/opencode crews, which run UNSANDBOXED (no Seatbelt).\n // Codex was the only agent under `workspace-write`, and that FS sandbox\n // blocked `squadrant crew signal …` from reaching the daemon socket (which\n // lives outside the workspace) — breaking the done/blocked/failed\n // lifecycle. Codex's AF_UNIX-socket allowance has no stable config path\n // (it's gated behind the experimental_network feature), so the surgical\n // writable_roots escape is not viable. danger-full-access removes the FS\n // jail so signals work; approvalPolicy still gates risky ops when set to\n // \"untrusted\" (the gate axis is independent of the sandbox axis).\n sandbox: \"danger-full-access\",\n approvalPolicy: rec.approvalPolicy ?? \"never\",\n developerInstructions: buildCodexDeveloperInstructions(rec),\n });\n this.threadByTask.set(rec.id, threadId);\n this.taskByThread.set(threadId, rec.id);\n this.deps.emit({ type: \"task.session\", id: rec.id, resumeRef: threadId });\n this.deps.emit({ type: \"task.started\", id: rec.id });\n } catch (e) {\n const msg = e instanceof Error ? e.message : String(e);\n this.deps.emit({ type: \"task.failed\", id: rec.id, error: `handshake/start failed: ${msg}` });\n throw e;\n }\n }\n\n async say(taskId: string, text: string): Promise<void> {\n // Wait out any in-flight dispatch so the first turn isn't dropped during\n // the startThread window (#212). The gate never rejects; a failed dispatch\n // simply leaves threadByTask empty → the existing \"no thread\" throw stands.\n await this.dispatchByTask.get(taskId);\n const c = this.client!;\n const tid = this.threadByTask.get(taskId);\n if (!tid) throw new Error(`no thread for task ${taskId}`);\n await c.sendTurn(tid, text);\n }\n\n async steer(taskId: string, text: string): Promise<void> {\n const c = this.client!;\n const tid = this.threadByTask.get(taskId);\n if (!tid) throw new Error(`no thread for task ${taskId}`);\n await c.steerTurn(tid, text);\n }\n\n async interrupt(taskId: string): Promise<void> {\n const c = this.client!;\n const tid = this.threadByTask.get(taskId);\n if (!tid) throw new Error(`no thread for task ${taskId}`);\n await c.interruptTurn(tid);\n }\n\n /**\n * Tear down a task's thread when its crew closes. Squadrant runs ONE shared\n * app-server with a thread per crew; closing the cmux pane only kills the\n * `crew attach` renderer, so without this the thread — and the gitnexus/pay\n * MCP servers it spawned — leak forever (verified: ~53MB per orphaned crew).\n * Archiving the thread lets the app-server reap it and its MCP children.\n */\n async close(taskId: string): Promise<void> {\n const tid = this.threadByTask.get(taskId);\n this.serverRequestByTask.delete(taskId);\n if (!tid) return;\n this.threadByTask.delete(taskId);\n this.taskByThread.delete(tid);\n try {\n await this.client?.archiveThread(tid);\n } catch {\n // Best-effort: the app-server may already be gone. The maps are cleared\n // regardless so a daemon restart won't try to reattach a dead thread.\n }\n }\n\n /** Kill the long-lived app-server child process on daemon shutdown. */\n stop(): void {\n this.client?.kill();\n }\n\n async answer(taskId: string, payload: unknown): Promise<void> {\n const c = this.client!;\n const rec = this.serverRequestByTask.get(taskId);\n if (rec == null) throw new Error(`no pending server-request for task ${taskId}`);\n c.respondToServerRequest(rec.id, this.mapAnswerPayload(payload, rec.method));\n this.serverRequestByTask.delete(taskId);\n }\n\n /**\n * Map the captain-facing payload ({text, decision}) to the response shape\n * the codex app-server expects for the specific request method.\n *\n * Old protocol (applyPatchApproval / execCommandApproval):\n * { decision: ReviewDecision } where ReviewDecision = \"approved\" | \"denied\" | …\n *\n * v2 protocol (item/commandExecution/requestApproval / item/fileChange/requestApproval):\n * { decision: CommandExecutionApprovalDecision } where decision = \"accept\" | \"decline\" | …\n *\n * Non-approval requests (text input) pass through unchanged.\n */\n private mapAnswerPayload(payload: unknown, method: string): unknown {\n if (typeof payload !== \"object\" || !payload) return payload;\n const p = payload as Record<string, unknown>;\n if (typeof p.decision !== \"string\") return payload;\n if (method === \"applyPatchApproval\" || method === \"execCommandApproval\") {\n const d = p.decision === \"approve\" ? \"approved\" : \"denied\";\n return { decision: d };\n }\n if (method === \"item/commandExecution/requestApproval\" || method === \"item/fileChange/requestApproval\") {\n const d = p.decision === \"approve\" ? \"accept\" : \"decline\";\n return { decision: d };\n }\n // Unknown method — send the raw decision value\n return { decision: p.decision };\n }\n\n async reattach(rec: TaskRecord & { cwd?: string }): Promise<void> {\n await this.ensureHandshake();\n const c = this.client!;\n const resumeRef = rec.attempts.at(-1)?.resumeRef;\n if (!resumeRef) throw new Error(`reattach: no resumeRef on task ${rec.id}`);\n await c.resumeThread({ threadId: resumeRef, cwd: rec.cwd });\n this.threadByTask.set(rec.id, resumeRef);\n this.taskByThread.set(resumeRef, rec.id);\n this.deps.emit({ type: \"task.reattached\", id: rec.id });\n }\n\n private onNotification(n: { method: string; params?: any }): void {\n const tid = n.params?.threadId ?? n.params?.thread_id;\n const taskId = tid ? this.taskByThread.get(tid) : undefined;\n if (!taskId) return; // status-line only\n const ev = normalizeAppServerNotification(taskId, n);\n if (ev) this.deps.emit(ev);\n }\n\n private onServerRequest(r: { id: number; method: string; params?: any }): void {\n const tid = r.params?.threadId ?? r.params?.thread_id;\n let taskId = tid ? this.taskByThread.get(tid) : undefined;\n if (!taskId && !tid) {\n // Codex approval-shaped server-requests don't reliably carry threadId.\n // Fall back to the sole active task if exactly one exists; otherwise drop.\n if (this.taskByThread.size === 1) {\n taskId = this.taskByThread.values().next().value;\n } else {\n process.stderr.write(\n `[codex/driver] serverRequest ${r.method} dropped: no threadId and ${this.taskByThread.size} active tasks\\n`,\n );\n return;\n }\n }\n if (!taskId) return;\n this.serverRequestByTask.set(taskId, { id: r.id, method: r.method });\n const isApproval = r.method.includes(\"Approval\") || r.method.includes(\"approval\");\n if (isApproval) {\n this.deps.emit({\n type: \"task.approval.requested\",\n id: taskId,\n requestId: r.id,\n question: String(r.params?.question ?? r.method),\n kind: r.method,\n });\n } else {\n this.deps.emit({\n type: \"task.input.requested\",\n id: taskId,\n requestId: r.id,\n question: String(r.params?.question ?? r.method),\n });\n }\n }\n}\n\n/**\n * Build the per-thread developerInstructions for a codex crew. Unlike\n * claude/opencode (which get SQUADRANT_CREW_* env vars on their shell launch\n * line), codex tasks share ONE long-lived app-server child, so a process-level\n * env var would be wrong for concurrent tasks. Instead we tell each thread its\n * concrete task id + project and the exact flag-based signal command, so the\n * codex crew can report terminal state via `squadrant crew signal`. Appended\n * after the crew role body (when present) so the role still leads.\n */\nexport function buildCodexDeveloperInstructions(\n rec: { id: string; project: string; roleInstructions?: string },\n): string {\n const directive =\n `You are squadrant crew task ${rec.id} in project ${rec.project}. ` +\n `When you finish, run EXACTLY: squadrant crew signal done --task-id ${rec.id} --project ${rec.project} --message \"<one-line summary>\". ` +\n `If you are blocked or fail, run squadrant crew signal blocked|failed with the same --task-id ${rec.id} --project ${rec.project} flags.`;\n return rec.roleInstructions ? `${rec.roleInstructions}\\n\\n${directive}` : directive;\n}\n\nfunction withTimeout<T>(p: Promise<T>, ms: number, msg: string): Promise<T> {\n return new Promise((resolve, reject) => {\n const t = setTimeout(() => reject(new Error(msg)), ms);\n p.then(\n (v) => { clearTimeout(t); resolve(v); },\n (e) => { clearTimeout(t); reject(e); },\n );\n });\n}\n","// src/control/opencode/sse-bridge.ts\n// Daemon-side bridge from an opencode crew's HTTP event bus to squadrant\n// ControlEvents. Interactive opencode crews launch as `opencode --port <N>`,\n// which binds a local HTTP server exposing an SSE stream at GET /event. The TUI\n// itself is just one client of that server; the daemon is another. We subscribe\n// once per crew and translate the documented `session.idle` event (emitted when\n// a turn finishes) into `task.turn.completed`, which the state-machine reduces\n// to `awaiting-input`. This gives opencode the same reliable turn-end signal\n// codex gets from its app-server — WITHOUT the crew shelling out to squadrant.\n//\n// `session.idle` is liveness, NOT completion (anti-#2576): a finished turn is\n// not a finished task. Terminal state still comes from the explicit\n// `squadrant crew signal done` in the crew template; the reducer absorbs any\n// session.idle that arrives after the task is already terminal.\nimport type { ControlEvent } from \"@squadrant/shared\";\n\nexport interface OpencodeSseBridgeDeps {\n /** Ingress into the daemon's event pipeline (resolves project + handles). */\n emit: (ev: ControlEvent) => void;\n /** Injectable for tests; defaults to global fetch. */\n fetchImpl?: typeof fetch;\n /** Injectable backoff for tests; defaults to setTimeout. */\n sleep?: (ms: number) => Promise<void>;\n /** Backoff between reconnect attempts (ms, default 500). */\n reconnectMs?: number;\n /** Attempts to reach the server before giving up the boot wait (default 60 ≈ 30s). */\n maxBootAttempts?: number;\n log?: (msg: string) => void;\n}\n\n/**\n * One long-lived SSE subscription per opencode crew. Keyed by taskId so the\n * daemon can stop it when the crew closes. Self-stops when the server's stream\n * ends (crew CLI exited) — at that point terminal state has already been\n * recorded via signal, or the watchdog/close path will reconcile.\n */\nexport class OpencodeSseBridge {\n private controllers = new Map<string, AbortController>();\n /** taskId → the crew's opencode server port (for permission-reply POSTs). */\n private portByTask = new Map<string, number>();\n /** taskId → the last unresolved permission on the bus (for answer()). */\n private pendingPermByTask = new Map<string, { permID: string; sessionID: string }>();\n /** Synthetic monotonic request id. opencode has no numeric id on the bus, but\n * task.approval.requested carries one (codex parity) to key gate promotion. */\n private nextRequestId = 1;\n private deps: OpencodeSseBridgeDeps;\n\n constructor(deps: OpencodeSseBridgeDeps) {\n this.deps = deps;\n }\n\n /** Begin subscribing to the crew's /event stream. Idempotent per task. */\n start(o: { taskId: string; port: number }): void {\n if (this.controllers.has(o.taskId)) return;\n this.portByTask.set(o.taskId, o.port);\n const ac = new AbortController();\n this.controllers.set(o.taskId, ac);\n void this.run(o.taskId, o.port, ac);\n }\n\n /** Stop subscribing for a task (crew closed / terminal). */\n stop(taskId: string): void {\n const ac = this.controllers.get(taskId);\n if (ac) { ac.abort(); this.controllers.delete(taskId); }\n this.portByTask.delete(taskId);\n this.pendingPermByTask.delete(taskId);\n }\n\n /**\n * Resolve a pending opencode permission by POSTing the captain's decision to\n * the crew's server (live-verified, opencode 1.15.13: POST\n * /session/{sessionID}/permissions/{permissionID} with\n * { response: \"once\" | \"reject\" } → 200, fires permission.replied). Mirrors\n * codex's driver.answer(). Returns true if there WAS a pending permission (so\n * the caller knows the answer was an approval, not a reply to a plain `signal\n * blocked` question); false if nothing was pending (already resolved on the\n * bus, or no gate).\n */\n async answer(taskId: string, decision: \"approve\" | \"deny\"): Promise<boolean> {\n const pend = this.pendingPermByTask.get(taskId);\n const port = this.portByTask.get(taskId);\n if (!pend || port == null) return false;\n this.pendingPermByTask.delete(taskId);\n const fetchImpl = this.deps.fetchImpl ?? fetch;\n const response = decision === \"approve\" ? \"once\" : \"reject\";\n try {\n await fetchImpl(`http://127.0.0.1:${port}/session/${pend.sessionID}/permissions/${pend.permID}`, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify({ response }),\n });\n } catch (e) {\n this.deps.log?.(`opencode permission reply failed for ${taskId}: ${(e as Error).message}`);\n }\n // Clear blocked → working; the crew continues (or aborts) the turn, and a\n // later session.idle settles it back to awaiting-input.\n this.deps.emit({ type: \"task.started\", id: taskId });\n return true;\n }\n\n private async run(taskId: string, port: number, ac: AbortController): Promise<void> {\n const fetchImpl = this.deps.fetchImpl ?? fetch;\n const sleep = this.deps.sleep ?? ((ms: number) => new Promise((r) => setTimeout(r, ms)));\n const reconnectMs = this.deps.reconnectMs ?? 500;\n const maxBoot = this.deps.maxBootAttempts ?? 60;\n const url = `http://127.0.0.1:${port}/event`;\n let booted = false;\n let bootAttempts = 0;\n\n while (!ac.signal.aborted) {\n try {\n const res = await fetchImpl(url, {\n signal: ac.signal,\n headers: { accept: \"text/event-stream\" },\n });\n if (!res.ok || !res.body) throw new Error(`status ${res.status}`);\n booted = true;\n await this.consume(taskId, res.body, ac);\n // Stream ended cleanly: the opencode server closed (crew CLI exited).\n // Nothing more to subscribe to — stop without reconnecting.\n break;\n } catch (e) {\n if (ac.signal.aborted) return;\n if (!booted) {\n bootAttempts++;\n if (bootAttempts >= maxBoot) {\n this.deps.log?.(\n `opencode SSE bridge: gave up connecting to ${url} after ${bootAttempts} attempts: ${(e as Error).message}`,\n );\n this.controllers.delete(taskId);\n return;\n }\n }\n await sleep(reconnectMs);\n }\n }\n this.controllers.delete(taskId);\n }\n\n private async consume(\n taskId: string,\n body: ReadableStream<Uint8Array>,\n ac: AbortController,\n ): Promise<void> {\n const reader = body.getReader();\n const decoder = new TextDecoder();\n let buf = \"\";\n try {\n while (!ac.signal.aborted) {\n const { done, value } = await reader.read();\n if (done) return;\n buf += decoder.decode(value, { stream: true });\n let nl: number;\n while ((nl = buf.indexOf(\"\\n\")) >= 0) {\n const line = buf.slice(0, nl);\n buf = buf.slice(nl + 1);\n this.handleLine(taskId, line);\n }\n }\n } finally {\n try { await reader.cancel(); } catch { /* already closed */ }\n }\n }\n\n private handleLine(taskId: string, rawLine: string): void {\n let line = rawLine.trim();\n if (!line) return;\n // SSE field form `data: {json}`; opencode also emits bare JSON lines.\n if (line.startsWith(\"data:\")) line = line.slice(5).trim();\n if (!line.startsWith(\"{\")) return;\n let json:\n | {\n type?: string;\n properties?: {\n id?: string;\n sessionID?: string;\n requestID?: string;\n permission?: string;\n patterns?: string[];\n };\n }\n | undefined;\n try {\n json = JSON.parse(line);\n } catch {\n return; // partial/non-JSON keepalive line\n }\n if (json?.type === \"session.idle\") {\n // turnId is informational for opencode (no per-turn id on the bus); use\n // the session id so the ledger attempt carries a stable correlation key.\n this.deps.emit({\n type: \"task.turn.completed\",\n id: taskId,\n turnId: json.properties?.sessionID ?? \"opencode\",\n });\n } else if (json?.type === \"permission.asked\") {\n // A gated tool (e.g. bash, when --approval set bash:\"ask\") needs approval.\n // Live-verified payload (opencode 1.15.13): properties = PermissionRequest\n // { id:\"per_…\", sessionID:\"ses_…\", permission:\"bash\", patterns:[cmd], … }.\n // Record the pending request so answer() can POST the decision, and surface\n // it as task.approval.requested (codex parity) — the reducer turns it into\n // blocked and the relay renders CREW BLOCKED with the tool + command.\n const p = json.properties;\n if (p?.id && p?.sessionID) {\n this.pendingPermByTask.set(taskId, { permID: p.id, sessionID: p.sessionID });\n const tool = p.permission ?? \"a tool\";\n const cmd = Array.isArray(p.patterns) && p.patterns.length ? `: ${p.patterns.join(\" \")}` : \"\";\n this.deps.emit({\n type: \"task.approval.requested\",\n id: taskId,\n requestId: this.nextRequestId++,\n question: `opencode requests permission to run ${tool}${cmd}`,\n kind: tool,\n });\n }\n } else if (json?.type === \"permission.replied\") {\n // The permission was resolved on the bus (by us or another client) — clear\n // pending state so a later captain answer is a no-op rather than a stale POST.\n this.pendingPermByTask.delete(taskId);\n }\n }\n}\n","import { execSync } from \"node:child_process\";\nimport { readFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport type { InteractiveHookAdapter } from \"./types.js\";\nimport type { ControlEvent } from \"@squadrant/shared\";\n\n// PostToolUse fires after EVERY tool call mid-turn — it is the only liveness\n// signal that refreshes the heartbeat while a crew is still working.\n// Stop fires at turn completion and maps to task.turn.completed so the task\n// transitions to awaiting-input (immune to stall detection) — without this,\n// a captain AFK for >heartbeatBudgetMs would get a false CREW STALLED.\n// SubagentStop fires only at a turn boundary but is liveness-only — it fires\n// while the parent agent still owns the turn. SessionEnd is NOT liveness: it\n// signals the session is gone (crash / Ctrl-C / /exit), so it terminalizes the\n// record (→ task.session.ended) rather than resuming 'working' (#139).\nconst EVENTS = [\"Stop\", \"SubagentStop\", \"SessionEnd\", \"PostToolUse\", \"Notification\"] as const;\n\n/**\n * Probe whether the local Claude CLI supports `--settings <path>`. The\n * daemon-supervised crew path needs per-invocation settings to inject the\n * squadrant Stop hook without polluting the user's global `~/.claude/settings.json`\n * (the scrapped PR #71 mistake). Returns \"flag\" when --settings is available\n * (the happy path), \"project-dir\" when the fallback (write `.claude/settings.json`\n * under the project dir + cd) is needed.\n */\nexport function probeClaudeSettingsFlag(): \"flag\" | \"project-dir\" {\n try {\n const help = execSync(\"claude --help\", { encoding: \"utf-8\", stdio: [\"ignore\", \"pipe\", \"ignore\"] });\n return help.includes(\"--settings \") ? \"flag\" : \"project-dir\";\n } catch {\n return \"project-dir\";\n }\n}\n\n/**\n * Pure: returns true when a Notification hook message indicates Claude is waiting\n * for the user to grant a tool-use permission. Idle notifications (\"Waiting for\n * your input\", \"Claude is thinking\") return false — only permission/approval\n * language triggers the fast-path task.blocked path.\n */\nexport function isPermissionNotification(message: string): boolean {\n if (!message || !message.trim()) return false;\n const lower = message.toLowerCase();\n return lower.includes(\"permission\") || lower.includes(\"approve\");\n}\n\n/** Pure, idempotent merge of squadrant hooks into a Claude settings object. */\nexport function mergeClaudeHooks(settings: any, hookCmd: string): any {\n const next = structuredClone(settings ?? {});\n next.hooks ??= {};\n for (const ev of EVENTS) {\n if (!Array.isArray(next.hooks[ev])) next.hooks[ev] = [];\n const already = next.hooks[ev].some((m: any) =>\n Array.isArray(m?.hooks) && m.hooks.some((h: any) => typeof h.command === \"string\" && h.command.includes(hookCmd)),\n );\n if (!already) {\n next.hooks[ev].push({ matcher: \"\", hooks: [{ type: \"command\", command: `${hookCmd} ${ev}`, timeout: 10 }] });\n }\n }\n return next;\n}\n\n/**\n * Pure, conservative detector for a trailing question that needs captain input.\n * Returns the question text when the LAST non-empty line of the message (outside\n * any fenced code block) ends with \"?\", else null. Intentionally narrow to avoid\n * false-blocked: rhetorical mid-text questions and questions inside ```fences```\n * are ignored because only the final visible line counts. When unsure → null.\n */\nexport function detectTrailingQuestion(text: string): string | null {\n if (!text) return null;\n let inFence = false;\n let lastLine: string | null = null;\n for (const raw of text.split(/\\r?\\n/)) {\n const line = raw.trim();\n if (line.startsWith(\"```\")) { inFence = !inFence; continue; }\n if (inFence || line === \"\") continue;\n lastLine = line;\n }\n if (lastLine && lastLine.endsWith(\"?\")) return lastLine;\n return null;\n}\n\n/**\n * Pure: derive the Claude transcript JSONL path for a session. Claude stores\n * transcripts at ~/.claude/projects/<escaped-cwd>/<session_id>.jsonl, where the\n * cwd is escaped by replacing every non-alphanumeric char with \"-\" (verified\n * against the live ~/.claude/projects layout — e.g. /Users/q3labsadmin/.claude-mem\n * -> -Users-q3labsadmin--claude-mem). Returns null if sessionId or cwd is missing.\n * This is the layered fallback for #174 when the Stop payload omits transcript_path.\n */\nexport function deriveTranscriptPath(sessionId: string, cwd: string): string | null {\n if (!sessionId || !cwd) return null;\n const escaped = cwd.replace(/[^a-zA-Z0-9]/g, \"-\");\n return join(homedir(), \".claude\", \"projects\", escaped, `${sessionId}.jsonl`);\n}\n\n/**\n * I/O: read the LAST assistant message text from a Claude transcript JSONL file.\n * Kept separate from the pure detector so the detector stays trivially testable.\n * Never throws — returns null on any read/parse failure (the hook must exit 0).\n */\nfunction readLastAssistantText(transcriptPath: string): string | null {\n try {\n const raw = readFileSync(transcriptPath, \"utf-8\");\n const lines = raw.split(/\\r?\\n/);\n for (let i = lines.length - 1; i >= 0; i--) {\n const line = lines[i].trim();\n if (!line) continue;\n let entry: any;\n try { entry = JSON.parse(line); } catch { continue; }\n const isAssistant = entry?.type === \"assistant\" || entry?.message?.role === \"assistant\";\n if (!isAssistant) continue;\n const content = entry?.message?.content;\n if (typeof content === \"string\") return content;\n if (Array.isArray(content)) {\n const txt = content\n .filter((b: any) => b?.type === \"text\" && typeof b.text === \"string\")\n .map((b: any) => b.text)\n .join(\"\\n\")\n .trim();\n return txt || null;\n }\n return null;\n }\n return null;\n } catch {\n return null;\n }\n}\n\n/**\n * I/O: obtain the last-assistant text from a LAYERED source, first hit wins:\n * 0. payload.last_assistant_message — the field Claude puts the final assistant\n * text in DIRECTLY on the Stop payload (verified against claude-cli 2.1.156:\n * carries the full final message, including a trailing question, no I/O). This\n * is the primary source and the real #174 delivery fix — earlier diagnoses\n * chased transcript_path (which can be absent), but the message is right here.\n * 1. else payload.transcript_path (documented field, when present + readable);\n * 2. else the path derived from payload.session_id + cwd (defensive fallback for\n * older clients that omit both of the above).\n * cwd preference: payload.cwd (Claude hook contract) → SQUADRANT_CREW_CWD → cwd().\n * Best-effort: a null/miss from one source falls through to the next; never throws.\n */\nfunction resolveLastAssistantText(payload: unknown): string | null {\n const p = payload as any;\n const direct = p?.last_assistant_message;\n if (typeof direct === \"string\" && direct.trim()) return direct;\n const candidates: string[] = [];\n const tp = p?.transcript_path;\n if (typeof tp === \"string\" && tp) candidates.push(tp);\n const cwd = (typeof p?.cwd === \"string\" && p.cwd) ? p.cwd : (process.env.SQUADRANT_CREW_CWD || process.cwd());\n const derived = deriveTranscriptPath(p?.session_id, cwd);\n if (derived) candidates.push(derived);\n for (const path of candidates) {\n const text = readLastAssistantText(path);\n if (text != null) return text;\n }\n return null;\n}\n\n/**\n * Map a Claude hook event name to a squadrant ControlEvent. Codifies the anti-#2576\n * invariant: NO Claude hook ever maps to `task.done`/`task.failed`.\n * PostToolUse/SubagentStop = resume-liveness only (task.progress). SessionEnd is\n * the lone terminalizing hook: the session is gone, so it maps to\n * task.session.ended → cancelled (#139) — silent, never done/failed.\n * Terminal `done`/`failed` come exclusively from explicit `squadrant crew signal`.\n *\n * Stop = turn boundary. It normally maps to task.turn.completed → awaiting-input\n * (stall-immune) so a captain reviewing output never trips a false CREW STALLED\n * (fixes #131). NARROW EXCEPTION #1 (#174): when the crew's last assistant message\n * ENDS with a direct question, Stop maps to task.blocked instead, surfacing the\n * question to the captain as CREW BLOCKED. The last-assistant text is obtained from\n * a LAYERED source (last_assistant_message on the payload → transcript_path →\n * derived path from session_id+cwd); the payload field is the primary, I/O-free\n * source. All transcript I/O is best-effort and never throws (hook must exit 0).\n *\n * Notification = Claude needs user attention. NARROW EXCEPTION #2\n * (#notification-hook): when the payload.message indicates a permission request\n * (isPermissionNotification), this maps to task.blocked instantly — bypassing the\n * ~20-30s relay poll. The relay poll remains as a fallback for opencode crews and\n * as a safety net; both may fire task.blocked for the same prompt, but the\n * state-machine idempotency (already-blocked → no-op, from #176) deduplicates.\n * Non-permission notifications (idle liveness) → task.progress. Missing/non-string\n * message → task.progress (never throws, hook must exit 0).\n */\nexport function mapClaudeHookToEvent(\n event: string,\n payload: unknown,\n taskId: string,\n): ControlEvent | null {\n switch (event) {\n case \"Stop\": {\n const text = resolveLastAssistantText(payload);\n const question = text ? detectTrailingQuestion(text) : null;\n if (question) {\n return { type: \"task.blocked\", id: taskId, reason: \"crew asked a question (auto-detected)\", question };\n }\n return { type: \"task.turn.completed\", id: taskId, turnId: \"hook-stop\" };\n }\n case \"Notification\": {\n const msg = (payload as any)?.message;\n if (typeof msg === \"string\" && isPermissionNotification(msg)) {\n return { type: \"task.blocked\", id: taskId, reason: \"crew awaiting permission (notification hook)\", question: msg };\n }\n return { type: \"task.progress\", id: taskId, note: \"notification\" };\n }\n case \"SessionEnd\":\n // #139: the session is GONE. NOT liveness — mapping this to task.progress\n // resumed a dead crew to 'working' (awaiting-input → working), where\n // nothing heartbeats and the watchdog false-stalled it ~budget later.\n // Terminalize the record instead (reducer: task.session.ended → cancelled).\n return { type: \"task.session.ended\", id: taskId };\n case \"SubagentStop\":\n case \"PostToolUse\":\n // The only resume-liveness hooks: PostToolUse fires after every tool call\n // mid-turn; SubagentStop fires while the parent still owns the turn.\n return { type: \"task.progress\", id: taskId, note: event.toLowerCase() };\n default:\n return null;\n }\n}\n\nexport const claudeInteractive: InteractiveHookAdapter = {\n provider: \"claude\",\n tier: \"strong\",\n injectHook(launchSpec) {\n // Claude reads merged ~/.config settings; nothing to add to argv here.\n // The settings merge is performed by the launcher (Task 18) before spawn.\n return launchSpec;\n },\n};\n","import { detectTrailingQuestion } from \"./claude.js\";\n\n/**\n * Pure classifier for a crew pane's TAIL (last ~25 lines), used by the daemon's\n * fast interactive-prompt probe (Phase 2b). A crew blocked at a permission\n * prompt shows daemon state=working with NO heartbeat — the hook bridge only\n * fires PostToolUse, which never happens while the prompt is up — so the daemon\n * cannot see the block until the multi-minute stall budget. This detector lets\n * the probe surface that wait as CREW BLOCKED within one probe cadence.\n *\n * - \"approval\": a permission-dialog shape — a \"Do you want to ...?\" prompt line\n * plus a numbered Yes/No option block. text = the human-readable prompt line.\n * - \"question\": the agent's output region (TUI chrome stripped) ends in a\n * direct question. Mainly the opencode path; Claude turn-end questions are\n * already handled by the #174 Stop-hook transcript path.\n * - \"error\": the pane shows a fatal CLI error banner (e.g. Anthropic\n * `API Error: 529 Overloaded`, an HTTP 5xx, retry exhaustion). A turn that\n * dies on a transient API error leaves the process ALIVE with the banner\n * frozen in the pane and no further heartbeat — the probe's only window onto\n * it (#196). text = the banner line. Checked LAST so a genuine approval /\n * question that merely mentions an error stays recoverable, never terminal.\n * - else null.\n *\n * Conservative by design: it only runs against a quiet working pane and must not\n * false-block, so an ambiguous tail returns null.\n */\nexport function classifyPaneTail(\n tail: string,\n): { kind: \"approval\" | \"question\" | \"error\"; text: string } | null {\n if (!tail) return null;\n const raw = tail.split(/\\r?\\n/);\n // cleaned[i] is the agent-region text of line i, or null if the line is pure\n // TUI chrome (box border, empty input prompt, status line) and should be ignored.\n const cleaned = raw.map(stripChrome);\n\n // ── approval: numbered Yes/No option block + a \"?\"-terminated prompt above ──\n const options: { label: string; ci: number }[] = [];\n for (let i = 0; i < cleaned.length; i++) {\n const c = cleaned[i];\n if (c == null) continue;\n const m = c.match(OPTION_RE);\n if (m) options.push({ label: m[2], ci: i });\n }\n const hasYes = options.some((o) => /\\byes\\b/i.test(o.label));\n const hasNo = options.some((o) => /\\bno\\b/i.test(o.label));\n if (options.length >= 2 && hasYes && hasNo) {\n // The prompt is the nearest \"?\"-terminated agent line above the first option.\n const firstOptCi = options[0].ci;\n for (let i = firstOptCi - 1; i >= 0; i--) {\n const c = cleaned[i];\n if (c == null) continue;\n if (c.endsWith(\"?\")) return { kind: \"approval\", text: c };\n }\n // Unmistakable Yes/No dialog but no \"?\"-line extracted → still actionable.\n return { kind: \"approval\", text: \"Crew is awaiting permission approval.\" };\n }\n\n // ── question: trailing question in the chrome-stripped agent output region ──\n const region = cleaned.filter((c): c is string => c != null).join(\"\\n\");\n const q = detectTrailingQuestion(region);\n if (q) return { kind: \"question\", text: q };\n\n // ── error: a fatal CLI error banner (#196), checked LAST so a recoverable\n // approval/question above always wins. Match the LAST banner line (the final\n // error after any retry chatter is the most informative).\n let errLine: string | null = null;\n for (const c of cleaned) {\n if (c != null && ERROR_BANNER_RE.some((re) => re.test(c))) errLine = c;\n }\n if (errLine) return { kind: \"error\", text: errLine.slice(0, 200) };\n\n return null;\n}\n\n// Distinctive fatal-error-banner signatures a crew's CLI prints when a turn\n// dies (Anthropic / OpenAI / opencode). Anchored to CLI banner SHAPES — never a\n// bare \"error\" / lone status code — so a crew merely discussing errors in prose\n// is never mis-failed. Combined with the probe's working+quiet precondition,\n// these only fire on a genuinely stalled, error-frozen pane.\nconst ERROR_BANNER_RE: RegExp[] = [\n /\\bAPI Error\\b/i, // Claude: \"API Error: 529 ...\"\n /\\bOverloaded\\b/, // Anthropic overloaded_error message\n /\\b(?:429|500|502|503|504|529)\\b[^?]*\\b(?:overloaded|unavailable|internal server error|bad gateway|gateway timeout|too many requests|service unavailable)\\b/i,\n /\\bretr(?:y|ies)\\s+(?:exhausted|limit\\s+(?:reached|exceeded))\\b/i,\n /\\bmaximum\\s+retries\\b/i,\n];\n\n// A numbered option line, after chrome stripping: an optional cursor marker\n// (❯ / > / ›), a number, a dot, then the label. e.g. \"❯ 1. Yes\".\nconst OPTION_RE = /^[❯>›]?\\s*(\\d+)\\.\\s+(.*\\S)\\s*$/;\n\n// Box-drawing / rule characters that make up a pure-chrome line.\nconst PURE_CHROME_RE = /^[\\s─━│┃╭╮╰╯┌┐└┘├┤┬┴┼═║╔╗╚╝╠╣╦╩╬▁▂▃▄▅▆▇█▔▏▕]+$/;\nconst STATUS_LINE_RE = /accept edits on|shift\\+tab|⏵⏵|\\? for shortcuts|esc to interrupt|tokens? (used|left)|context left/i;\n\n/**\n * Strip the box-drawing border / cursor padding from one pane line and decide\n * whether it carries agent content. Returns the trimmed content, or null if the\n * line is pure TUI chrome (border, empty input prompt, status line) that the\n * classifier must ignore.\n */\nfunction stripChrome(raw: string): string | null {\n // Defensive ANSI strip — cmux read-screen is usually plain text, but a stray\n // escape would otherwise leak into the extracted prompt text.\n let line = raw.replace(/\u001b\\[[0-9;]*m/g, \"\");\n // Peel leading/trailing vertical box borders and surrounding whitespace.\n line = line.replace(/^[\\s│┃▏▕|]+/, \"\").replace(/[\\s│┃▏▕|]+$/, \"\");\n const trimmed = line.trim();\n if (trimmed === \"\") return null;\n if (PURE_CHROME_RE.test(trimmed)) return null;\n if (/^>\\s*$/.test(trimmed)) return null; // empty input prompt\n if (STATUS_LINE_RE.test(trimmed)) return null;\n return trimmed;\n}\n","import type { InteractiveHookAdapter } from \"./types.js\";\nimport { claudeInteractive } from \"./claude.js\";\n\nconst ADAPTERS: Record<string, InteractiveHookAdapter> = {\n claude: claudeInteractive,\n};\n\nexport function getInteractiveAdapter(provider: string): InteractiveHookAdapter {\n const a = ADAPTERS[provider];\n if (!a) throw new Error(`no interactive adapter for provider '${provider}'`);\n return a;\n}\n","export {};\n//# sourceMappingURL=types.js.map","// src/control/headless/types.ts\nexport const HEADLESS_ERROR_TAIL = 2000;\n\nexport interface HeadlessResult {\n outcome: \"done\" | \"failed\";\n /** Always a string: result text, JSON-stringified non-string result, or raw stdout fallback. Becomes resultRef contents. */\n payload?: string;\n sessionId?: string;\n error?: string;\n exitCode?: number;\n parseWarning?: boolean;\n}\n\nexport interface HeadlessAdapter {\n provider: string;\n buildCommand(task: string, sessionId?: string): string[];\n parseResult(stdout: string, exitCode: number): HeadlessResult;\n}\n","// src/control/headless/claude.ts\nimport type { HeadlessAdapter } from \"./types.js\";\nimport { HEADLESS_ERROR_TAIL } from \"./types.js\";\n\nexport const claudeHeadless: HeadlessAdapter = {\n provider: \"claude\",\n buildCommand(task, sessionId) {\n const argv = [\"claude\", \"-p\", \"--output-format\", \"json\"];\n if (sessionId) argv.push(\"--resume\", sessionId);\n argv.push(task);\n return argv;\n },\n parseResult(stdout, exitCode) {\n if (exitCode !== 0) {\n return { outcome: \"failed\", exitCode, error: stdout.slice(-HEADLESS_ERROR_TAIL) };\n }\n try {\n const j = JSON.parse(stdout);\n if (j.is_error) return { outcome: \"failed\", error: String(j.result ?? \"is_error\"), sessionId: j.session_id };\n const payload = typeof j.result === \"string\" ? j.result : j.result == null ? \"\" : JSON.stringify(j.result);\n return { outcome: \"done\", sessionId: j.session_id, payload };\n } catch {\n return { outcome: \"done\", parseWarning: true, payload: stdout };\n }\n },\n};\n","// src/control/headless/opencode.ts\nimport type { HeadlessAdapter } from \"./types.js\";\nimport { HEADLESS_ERROR_TAIL } from \"./types.js\";\n\n// opencode `run` is used for one-shot; serve-session wiring is a later spec.\n// Process-exit is the done-signal here (foundational scope).\nexport const opencodeHeadless: HeadlessAdapter = {\n provider: \"opencode\",\n buildCommand(task, sessionId) {\n const argv = [\"opencode\", \"run\", \"--format\", \"json\"];\n if (sessionId) argv.push(\"--session\", sessionId);\n argv.push(task);\n return argv;\n },\n parseResult(stdout, exitCode) {\n if (exitCode !== 0) return { outcome: \"failed\", exitCode, error: stdout.slice(-HEADLESS_ERROR_TAIL) };\n try {\n const j = JSON.parse(stdout);\n const payload = typeof j.result === \"string\" ? j.result : JSON.stringify(j.result ?? stdout);\n return { outcome: \"done\", sessionId: j.sessionID ?? j.session_id, payload };\n } catch {\n return { outcome: \"done\", parseWarning: true, payload: stdout };\n }\n },\n};\n","// src/control/headless/codex.ts\nimport type { HeadlessAdapter } from \"./types.js\";\nimport { HEADLESS_ERROR_TAIL } from \"./types.js\";\n\nexport const codexHeadless: HeadlessAdapter = {\n provider: \"codex\",\n buildCommand(task, sessionId) {\n // Verified against codex-cli 0.130.0 `codex exec [OPTIONS] [PROMPT]`:\n // --json: JSONL events to stdout (valid).\n // --skip-git-repo-check: REQUIRED — the daemon spawns codex with a\n // non-trusted/non-git cwd under launchd; without it codex aborts with\n // \"Not inside a trusted directory and --skip-git-repo-check was not\n // specified.\" (real production failure, red-team/verify-on-implement).\n // resume is a SUBCOMMAND (`codex exec resume <id>`), NOT a `--session`\n // flag. Resume is unused in foundational scope (multi-turn/reply\n // deferred) — kept best-effort; flag order is verify-on-implement when\n // the interactive-wiring spec lands.\n // --sandbox workspace-write: codex exec defaults to a READ-ONLY sandbox,\n // so a crew could analyze/spec but never edit code (real prod finding:\n // codex bailed \"workspace is mounted read-only\"). workspace-write lets it\n // edit within its cwd (set by the launcher per-task) — NOT full-disk\n // (danger-full-access) which would be reckless for an autonomous agent.\n const opts = [\"--json\", \"--skip-git-repo-check\", \"--sandbox\", \"workspace-write\"];\n if (sessionId) return [\"codex\", \"exec\", \"resume\", sessionId, ...opts, task];\n return [\"codex\", \"exec\", ...opts, task];\n },\n parseResult(stdout, exitCode) {\n if (exitCode !== 0) return { outcome: \"failed\", exitCode, error: stdout.slice(-HEADLESS_ERROR_TAIL) };\n // codex result format undocumented; keep raw, never guess failure.\n return { outcome: \"done\", payload: stdout };\n },\n};\n","// src/control/headless/registry.ts\nimport type { HeadlessAdapter } from \"./types.js\";\nimport { claudeHeadless } from \"./claude.js\";\nimport { opencodeHeadless } from \"./opencode.js\";\nimport { codexHeadless } from \"./codex.js\";\n\nconst ADAPTERS: Record<string, HeadlessAdapter> = {\n claude: claudeHeadless,\n opencode: opencodeHeadless,\n codex: codexHeadless,\n};\n\nexport function getHeadlessAdapter(provider: string): HeadlessAdapter {\n const a = ADAPTERS[provider];\n if (!a) throw new Error(`no headless adapter for provider '${provider}'`);\n return a;\n}\n","// src/control/headless-launcher.ts\nimport type { spawn as nodeSpawn } from \"node:child_process\";\nimport type { ControlEvent } from \"@squadrant/shared\";\nimport { getHeadlessAdapter } from \"./headless/registry.js\";\n\nexport interface RunHeadlessOpts {\n provider: string;\n task: string;\n id: string;\n sessionId?: string;\n /**\n * Working dir for the spawned child. Headless previously inherited the\n * daemon's launchd cwd (`/`) — wrong for every provider, and the reason\n * codex could only do read-only work. Unset → inherit (back-compat).\n */\n cwd?: string;\n spawn: typeof nodeSpawn;\n emit: (e: ControlEvent) => void;\n /** Where to persist captured payload; defaults handled by caller (Task 17). */\n writeResult?: (id: string, payload: string) => string;\n}\n\nexport interface HeadlessHandle {\n result: Promise<void>;\n kill: () => void;\n}\n\n// Max bytes retained in the stdout/stderr capture buffers (oldest dropped).\nconst OUT_CAP = 4 * 1024 * 1024;\nconst ERR_CAP = 4 * 1024 * 1024;\n// Emit task.progress at most once per interval OR once per batch, whichever first.\nconst PROGRESS_INTERVAL_MS = 250;\nconst PROGRESS_CHUNK_BATCH = 50;\n\nexport function runHeadless(opts: RunHeadlessOpts): HeadlessHandle {\n const adapter = getHeadlessAdapter(opts.provider);\n const argv = adapter.buildCommand(opts.task, opts.sessionId);\n const child = opts.spawn(argv[0], argv.slice(1), {\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n cwd: opts.cwd, // undefined → inherit daemon cwd (back-compat)\n });\n opts.emit({ type: \"task.started\", id: opts.id, pid: child.pid ?? undefined });\n\n let out = \"\";\n let err = \"\";\n\n // Debounce state — coalesces task.progress to avoid O(chunks) file writes.\n let lastProgressAt = 0;\n let chunksSinceProgress = 0;\n let debounceTimer: ReturnType<typeof setTimeout> | null = null;\n\n function flushProgress(): void {\n if (debounceTimer) { clearTimeout(debounceTimer); debounceTimer = null; }\n lastProgressAt = Date.now();\n chunksSinceProgress = 0;\n opts.emit({ type: \"task.progress\", id: opts.id }); // stdout activity = liveness\n }\n\n child.stdout?.on(\"data\", (d) => {\n out += String(d);\n if (out.length > OUT_CAP) out = out.slice(out.length - OUT_CAP);\n chunksSinceProgress++;\n const now = Date.now();\n if (chunksSinceProgress >= PROGRESS_CHUNK_BATCH || now - lastProgressAt >= PROGRESS_INTERVAL_MS) {\n flushProgress();\n } else if (!debounceTimer) {\n const delay = PROGRESS_INTERVAL_MS - (now - lastProgressAt);\n debounceTimer = setTimeout(() => { debounceTimer = null; flushProgress(); }, delay);\n }\n });\n child.stderr?.on(\"data\", (d) => {\n err += String(d);\n if (err.length > ERR_CAP) err = err.slice(err.length - ERR_CAP);\n });\n\n const result = new Promise<void>((resolve) => {\n child.once(\"error\", (e: Error) => {\n if (debounceTimer) { clearTimeout(debounceTimer); debounceTimer = null; }\n opts.emit({ type: \"task.failed\", id: opts.id, error: `spawn error: ${e.message}`, exitCode: undefined });\n resolve(); // never hang the daemon; resolve() is idempotent\n });\n child.on(\"close\", (code) => {\n // Flush any batched-but-not-yet-emitted activity before the terminal event.\n if (chunksSinceProgress > 0) flushProgress();\n else if (debounceTimer) { clearTimeout(debounceTimer); debounceTimer = null; }\n const parseInput = (code !== 0 && err) ? err : (out || err);\n const res = adapter.parseResult(parseInput, code ?? 0);\n if (res.outcome === \"failed\") {\n opts.emit({ type: \"task.failed\", id: opts.id, error: res.error ?? \"non-zero exit\", exitCode: res.exitCode });\n } else {\n const ref = opts.writeResult ? opts.writeResult(opts.id, res.payload ?? \"\") : \"\";\n opts.emit({ type: \"task.done\", id: opts.id, resultRef: ref, parseWarning: res.parseWarning });\n }\n resolve();\n });\n });\n\n return { result, kill: () => child.kill(\"SIGTERM\") };\n}\n","// @squadrant/agents — AI-agent driver seam (claude · codex · opencode · gemini).\nexport * from \"./drivers/index.js\";\nexport * from \"./projection/index.js\";\nexport * from \"./codex/app-server-client.js\";\nexport * from \"./codex/driver.js\";\nexport * from \"./codex/normalize.js\";\nexport * from \"./opencode/sse-bridge.js\";\nexport * from \"./interactive/claude.js\";\nexport * from \"./interactive/pane-classifier.js\";\nexport * from \"./interactive/registry.js\";\nexport * from \"./interactive/types.js\";\nexport * from \"./headless/registry.js\";\nexport * from \"./headless/types.js\";\nexport * from \"./headless-launcher.js\";\n","#!/usr/bin/env node\n\nimport { Command } from \"commander\";\nimport { readFileSync, existsSync, writeFileSync } from \"node:fs\";\nimport { fileURLToPath } from \"node:url\";\nimport { dirname, join } from \"node:path\";\nimport { homedir } from \"node:os\";\nimport { ensureRuntimeSynced } from \"@squadrant/shared\";\nimport { ensureDaemon } from \"@squadrant/core\";\nimport { doctorCommand } from \"./commands/doctor.js\";\nimport { initCommand } from \"./commands/init.js\";\nimport { projectsCommand } from \"./commands/projects.js\";\nimport { statusCommand } from \"./commands/status.js\";\nimport { commandCommand } from \"./commands/command.js\";\nimport { crewCommand } from \"./commands/crew.js\";\nimport { sideCommand } from \"./commands/side.js\";\nimport { addControlPlaneCrewCommands } from \"./commands/crew-control.js\";\nimport { dashboardCommand } from \"./commands/dashboard.js\";\nimport { launchCommand } from \"./commands/launch.js\";\nimport { shutdownCommand } from \"./commands/shutdown.js\";\nimport { feedbackCommand } from \"./commands/feedback.js\";\nimport { standupCommand } from \"./commands/standup.js\";\nimport { retroCommand } from \"./commands/retro.js\";\nimport { runtimeCommand } from \"./commands/runtime.js\";\nimport { workspaceCommand } from \"./commands/workspace.js\";\nimport { notifyCommand } from \"./commands/notify.js\";\nimport { projectionCommand } from \"./commands/projection.js\";\nimport { codexChatSmokeCommand } from \"./commands/codex-chat-smoke.js\";\nimport { configCommand } from \"./commands/config.js\";\nimport { healCommand } from \"./commands/heal.js\";\nimport { groupCommand } from \"./commands/group.js\";\nimport { cmuxCommand } from \"./commands/cmux.js\";\nimport { effortCommand } from \"./commands/effort.js\";\nimport { telegramCommand } from \"./commands/telegram.js\";\nimport { detectDrift } from \"@squadrant/shared\";\nimport { needsCheck, withStamp } from \"@squadrant/shared\";\nimport { getDefaultConfig } from \"@squadrant/shared\";\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\nconst pkg = JSON.parse(readFileSync(join(__dirname, \"..\", \"package.json\"), \"utf-8\"));\n\n// Self-heal the runtime copy of source-managed dirs before any command runs,\n// so source changes (skills, role templates, scripts) can never silently\n// drift from ~/.config/squadrant. Never throws.\nensureRuntimeSynced({\n sourceRoot: join(__dirname, \"..\"),\n runtimeRoot: join(homedir(), \".config\", \"squadrant\"),\n});\n\n// Non-blocking config-drift banner. Suppressed during \"squadrant config\" —\n// the config command already surfaces drift, making the banner redundant.\n// Detect + print only — never mutates config and never throws.\nif (process.argv[2] !== \"config\") {\n try {\n const cfgPath = join(homedir(), \".config\", \"squadrant\", \"config.json\");\n if (existsSync(cfgPath)) {\n const cfg = JSON.parse(readFileSync(cfgPath, \"utf-8\"));\n if (needsCheck(cfg, pkg.version)) {\n const items = detectDrift(cfg, getDefaultConfig());\n if (items.length === 0) {\n writeFileSync(cfgPath, JSON.stringify(withStamp(cfg, pkg.version), null, 2) + \"\\n\");\n } else {\n const from = cfg._squadrantVersion ?? \"an earlier version\";\n process.stderr.write(\n `\\n\\u26A1 squadrant updated ${from} \\u2192 ${pkg.version} \\u2014 ${items.length} config change(s) detected.\\n` +\n ` Run \\`squadrant config check\\` (or use the config-doctor skill) to reconcile.\\n\\n`,\n );\n }\n }\n }\n } catch {\n // Drift banner is best-effort; never block the CLI.\n }\n}\n\n// Self-heal the control-plane daemon the same way we self-heal the runtime:\n// best-effort, never throws; the CLI fails loud later if the socket is unreachable.\n// ensureDaemon resolves its own entrypoint (see launchd.daemonEntryPath) — no\n// path is passed here so no call site can get it wrong.\n// SQUADRANT_DAEMON_SKIP short-circuits this for read-only / CI invocations that must\n// not attempt to boot the daemon (e.g. config-check tests on Linux without launchctl).\nif (!process.env.SQUADRANT_DAEMON_SKIP) {\n ensureDaemon();\n}\n\nconst program = new Command();\n\nprogram\n .name(\"squadrant\")\n .description(\"Multi-project orchestration for your coding agents (Claude, Codex, opencode, Gemini)\")\n .version(pkg.version);\n\nprogram.addCommand(doctorCommand);\nprogram.addCommand(initCommand);\nprogram.addCommand(projectsCommand);\nprogram.addCommand(statusCommand);\n// Legacy crew verbs (spawn/send/read/close/list) stay intact for live captains;\n// control-plane verbs (dispatch/status/tasks/reply) are attached onto the same\n// `squadrant crew` command so PR #85 doesn't break the captain-ops playbook.\naddControlPlaneCrewCommands(crewCommand);\nprogram.addCommand(crewCommand);\nprogram.addCommand(sideCommand);\nprogram.addCommand(commandCommand);\nprogram.addCommand(dashboardCommand);\nprogram.addCommand(launchCommand);\nprogram.addCommand(shutdownCommand);\nprogram.addCommand(feedbackCommand);\nprogram.addCommand(standupCommand);\nprogram.addCommand(retroCommand);\nprogram.addCommand(runtimeCommand);\nprogram.addCommand(workspaceCommand);\nprogram.addCommand(notifyCommand);\nprogram.addCommand(projectionCommand);\nprogram.addCommand(codexChatSmokeCommand);\nprogram.addCommand(configCommand);\nprogram.addCommand(healCommand);\nprogram.addCommand(groupCommand);\nprogram.addCommand(cmuxCommand);\nprogram.addCommand(effortCommand);\nprogram.addCommand(telegramCommand);\n\nprogram.parseAsync().catch((e) => {\n process.stderr.write(`error: ${e instanceof Error ? e.message : String(e)}\\n`);\n process.exit(1);\n});\n","import { Command } from \"commander\";\nimport { execSync } from \"node:child_process\";\nimport fs from \"node:fs\";\nimport { stat } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport chalk from \"chalk\";\nimport { loadConfig } from \"@squadrant/shared\";\nimport { compatManifest, type ToolEntry } from \"@squadrant/shared\";\nimport { checkToolCompat } from \"@squadrant/shared\";\nimport { createCmuxDriver, RuntimeRegistry, createCmuxNotifier, NotifierRegistry, createObsidianDriver, WorkspaceRegistry } from \"@squadrant/workspaces\";\nimport { queryHealth, printServiceHealth } from \"./health-view.js\";\nimport {\n createCursorEmitter,\n createCodexEmitter,\n createGeminiEmitter,\n createOpencodeEmitter,\n ProjectionRegistry,\n} from \"@squadrant/agents\";\n\nfunction commandExists(cmd: string): boolean {\n try {\n execSync(`which ${cmd}`, { stdio: \"ignore\" });\n return true;\n } catch {\n return false;\n }\n}\n\nfunction claudeVersionOk(): boolean {\n try {\n const version = execSync(\"claude --version\", { encoding: \"utf-8\" }).trim();\n const match = version.match(/(\\d+)\\.(\\d+)\\.(\\d+)/);\n if (!match) return false;\n const [major, minor, patch] = match.slice(1).map(Number);\n const [minMajor, minMinor, minPatch] = compatManifest.tools.claude.min.split(\".\").map(Number);\n return (\n major > minMajor ||\n (major === minMajor && minor > minMinor) ||\n (major === minMajor && minor === minMinor && patch >= minPatch)\n );\n } catch {\n return false;\n }\n}\n\nfunction settingsHaveAgentTeams(): boolean {\n try {\n const home = process.env.HOME || \"\";\n const settings = JSON.parse(\n fs.readFileSync(`${home}/.claude/settings.json`, \"utf-8\"),\n );\n return settings?.env?.CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS === \"1\";\n } catch {\n return false;\n }\n}\n\nfunction pluginInstalled(pluginKey: string): boolean {\n try {\n const home = process.env.HOME || \"\";\n const plugins = JSON.parse(\n fs.readFileSync(\n `${home}/.claude/plugins/installed_plugins.json`,\n \"utf-8\",\n ),\n );\n return pluginKey in (plugins?.plugins || {});\n } catch {\n return false;\n }\n}\n\nfunction nodeVersionOk(): boolean {\n const major = parseInt(process.versions.node.split(\".\")[0], 10);\n const [minMajor] = compatManifest.tools.node.min.split(\".\").map(Number);\n return major >= minMajor;\n}\n\nfunction tryGetVersion(cmd: string): string {\n try {\n return execSync(`${cmd} --version`, { encoding: \"utf-8\" }).trim();\n } catch {\n return \"\";\n }\n}\n\nfunction check(label: string, pass: boolean): boolean {\n const icon = pass ? chalk.green(\"✔ PASS\") : chalk.red(\"✘ FAIL\");\n console.log(` ${icon} ${label}`);\n return pass;\n}\n\nexport const doctorCommand = new Command(\"doctor\")\n .description(\"Check system health and prerequisites\")\n .action(async () => {\n console.log(chalk.bold(\"\\nSquadrant Doctor\\n\"));\n\n const results: boolean[] = [];\n\n results.push(check(\"Claude Code installed\", commandExists(\"claude\")));\n results.push(check(`Claude Code version >= ${compatManifest.tools.claude.min}`, claudeVersionOk()));\n results.push(check(\"Obsidian installed\", commandExists(\"obsidian\") || fs.existsSync(\"/Applications/Obsidian.app\")));\n results.push(check(\"Node.js >= 18\", nodeVersionOk()));\n results.push(\n check(\n \"Agent Teams enabled (CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1)\",\n settingsHaveAgentTeams(),\n ),\n );\n results.push(check(\"Plugin: superpowers\", pluginInstalled(\"superpowers@claude-plugins-official\")));\n results.push(\n check(\"Plugin: claude-mem\", pluginInstalled(\"claude-mem@thedotmack\")),\n );\n results.push(check(\"Plugin: context7\", pluginInstalled(\"context7@claude-plugins-official\")));\n\n const config = loadConfig();\n\n const runtimes = new RuntimeRegistry({ cmux: createCmuxDriver() });\n const probeResults = await runtimes.probeAll();\n\n // Global runtime must be installed\n const globalRuntimeName = config.runtime ?? \"cmux\";\n const globalProbe = probeResults[globalRuntimeName];\n results.push(check(\n `Runtime '${globalRuntimeName}' installed`,\n !!globalProbe?.installed,\n ));\n\n // Any project-level override must also be installed\n const overrides = new Set<string>();\n for (const proj of Object.values(config.projects)) {\n if (proj.runtime && proj.runtime !== globalRuntimeName) overrides.add(proj.runtime);\n }\n for (const runtimeName of overrides) {\n const probe = probeResults[runtimeName];\n results.push(check(\n `Runtime '${runtimeName}' installed (project override)`,\n !!probe?.installed,\n ));\n }\n\n // Probe workspace providers\n const workspaces = new WorkspaceRegistry({ obsidian: createObsidianDriver });\n const hubDriver = workspaces.hub(config);\n const hubProbe = await hubDriver.probe();\n results.push(check(\n `Workspace '${config.workspace ?? \"obsidian\"}' — hub reachable`,\n hubProbe.installed && hubProbe.rootExists,\n ));\n\n for (const [name] of Object.entries(config.projects)) {\n const spokeDriver = workspaces.forProject(name, config);\n const probe = await spokeDriver.probe();\n results.push(check(\n `Workspace — spoke '${name}' reachable`,\n probe.installed && probe.rootExists,\n ));\n }\n\n // Probe notifier providers\n const notifiers = new NotifierRegistry({ cmux: createCmuxNotifier });\n const notifierProbes = await notifiers.probeAll();\n for (const [name, probe] of Object.entries(notifierProbes)) {\n results.push(check(\n `Notifier '${name}' installed`,\n probe.installed,\n ));\n if (probe.installed) {\n results.push(check(\n `Notifier '${name}' reachable`,\n probe.reachable,\n ));\n }\n }\n\n // Probe projection targets\n console.log(chalk.bold(\"\\nProjection\"));\n const projectionRegistry = new ProjectionRegistry({\n cursor: createCursorEmitter,\n codex: createCodexEmitter,\n gemini: createGeminiEmitter,\n opencode: createOpencodeEmitter,\n });\n for (const name of projectionRegistry.list()) {\n const emitter = projectionRegistry.get(name);\n const [userDest] = emitter.destinations(\"user\");\n if (!userDest) continue;\n const dir = path.dirname(userDest.path);\n let status: string;\n try {\n await stat(dir);\n status = chalk.green(\"✓ dir writable\");\n } catch {\n status = chalk.yellow(\"! dir missing (will be created on emit)\");\n }\n console.log(` ${name.padEnd(10)} ${userDest.path} — ${status}`);\n }\n\n results.push(\n check(\n \"Squadrant config exists\",\n fs.existsSync(\n process.env.SQUADRANT_CONFIG ||\n `${process.env.HOME}/.config/squadrant/config.json`,\n ),\n ),\n );\n\n const passed = results.filter(Boolean).length;\n const total = results.length;\n\n console.log(\n `\\n${passed === total ? chalk.green(\"All checks passed\") : chalk.yellow(`${passed}/${total} checks passed`)}\\n`,\n );\n\n // #77 service-health: live per-component liveness from the daemon. Printed\n // before the prereq-fail exit so a degraded install still shows what is up.\n printServiceHealth(await queryHealth());\n\n // Non-blocking version compat drift for every tool in the manifest.\n // Tools not installed are skipped silently; only drift (below min / above\n // lastVerified) produces a warning line — nothing here causes an exit.\n console.log(chalk.bold(\"\\nTool Version Compat\\n\"));\n const toolVersionMap: Record<string, string> = {\n cmux: probeResults[\"cmux\"]?.version ?? \"\",\n claude: tryGetVersion(\"claude\"),\n node: process.versions.node,\n codex: tryGetVersion(\"codex\"),\n gemini: tryGetVersion(\"gemini\"),\n opencode: tryGetVersion(\"opencode\"),\n };\n for (const [name, entry] of Object.entries(compatManifest.tools) as [string, ToolEntry][]) {\n const version = toolVersionMap[name] ?? \"\";\n if (!version) continue;\n const warn = checkToolCompat(name, version, entry);\n if (warn) {\n console.log(` ${chalk.yellow(\"⚠ WARN\")} ${name}: ${warn}`);\n } else {\n console.log(` ${chalk.green(\"✔ OK \")} ${name}: ${version}`);\n }\n }\n\n if (results.some((r) => !r)) {\n process.exit(1);\n }\n\n // --- Agent Probes ---\n console.log(chalk.bold(\"\\nAgent Drivers\\n\"));\n\n const { createClaudeDriver, createCodexDriver, createGeminiDriver, createOpencodeDriver, CapabilityRegistry } = await import(\"@squadrant/agents\");\n\n const agentDrivers = {\n claude: createClaudeDriver(),\n codex: createCodexDriver(),\n gemini: createGeminiDriver(),\n opencode: createOpencodeDriver(),\n };\n\n const registry = new CapabilityRegistry(agentDrivers);\n await registry.probeAll();\n\n for (const [name, driver] of Object.entries(agentDrivers)) {\n const probe = registry.getProbeResult(name);\n if (!probe || !probe.installed) {\n console.log(` ${chalk.gray(\"○ SKIP\")} ${name} — not installed`);\n continue;\n }\n const caps = probe.capabilities.join(\", \");\n console.log(` ${chalk.green(\"✔ FOUND\")} ${name} ${chalk.gray(probe.version)} — [${caps}]`);\n }\n\n // Show role assignments from config\n if (config.defaults.roles) {\n console.log(chalk.bold(\"\\nRole Assignments\\n\"));\n for (const [role, assignment] of Object.entries(config.defaults.roles)) {\n const validation = registry.validateRole(assignment.agent, role as any);\n const statusIcon = validation.allowed ? chalk.green(\"✔\") : chalk.red(\"✘\");\n const warns = validation.missingPreferred.length > 0\n ? chalk.yellow(` (missing preferred: ${validation.missingPreferred.join(\", \")})`)\n : \"\";\n console.log(` ${statusIcon} ${role}: ${assignment.agent}${assignment.model ? ` (${assignment.model})` : \"\"}${warns}`);\n if (!validation.allowed && validation.reason) {\n console.log(` ${chalk.red(validation.reason)}`);\n }\n }\n }\n });\n","// src/commands/health-view.ts\n//\n// Client + pure renderer for the daemon's #77 service-health surface. Shared by\n// `squadrant doctor` and `squadrant status --detailed`. The query is a RAW socket\n// call (never kickstarts the daemon); rendering is pure and unit-tested.\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport chalk from \"chalk\";\nimport { sendRequest, ageText } from \"@squadrant/core\";\nexport { ageText } from \"@squadrant/core\";\nimport type { ComponentHealth, HealthState } from \"@squadrant/core\";\n\nconst SOCK = join(homedir(), \".config\", \"squadrant\", \"squadrant.sock\");\n\n/**\n * Query the daemon for component liveness. Returns null when the daemon is\n * unreachable (the surface shows \"daemon unreachable\" rather than kickstarting\n * it). Optionally scoped to one project.\n */\nexport async function queryHealth(project?: string): Promise<ComponentHealth[] | null> {\n try {\n const reply = await sendRequest(SOCK, { kind: \"health\", project });\n return Array.isArray(reply) ? (reply as ComponentHealth[]) : [];\n } catch {\n return null;\n }\n}\n\nexport function healthIcon(state: HealthState): string {\n switch (state) {\n case \"alive\": return \"✔\";\n case \"stale\": return \"•\";\n case \"gone\": return \"✘\";\n case \"stopped\": return \"⏻\";\n case \"unknown\": return \"○\";\n }\n}\n\n/** Color the state token without affecting the plain-text rendering used in tests. */\nexport function colorState(state: HealthState): string {\n switch (state) {\n case \"alive\": return chalk.green(state);\n case \"stale\": return chalk.yellow(state);\n case \"gone\": return chalk.red(state);\n // stopped = intentional shutdown, not a fault — magenta, never alarm-red.\n case \"stopped\": return chalk.magenta(state);\n case \"unknown\": return chalk.dim(state);\n }\n}\n\n/** Pure plain-text row (no color) — kept colorless so it is trivially testable. */\nexport function healthRow(c: ComponentHealth, now: number): string {\n const head = `${healthIcon(c.state)} ${c.kind.padEnd(8)} ${c.ref.padEnd(16)} ${c.state.padEnd(8)} ${ageText(c.lastSeenMs, now)}`;\n return c.detail ? `${head} ${c.detail}` : head;\n}\n\n/**\n * Print the Service Health section to stdout (used by doctor + status --detailed).\n * Groups rows by project; flags the daemon being unreachable.\n */\nexport function printServiceHealth(rows: ComponentHealth[] | null, now: number = Date.now()): void {\n console.log(chalk.bold(\"\\nService Health\\n\"));\n if (rows == null) {\n console.log(` ${chalk.red(\"✘\")} daemon unreachable — squadrant liveness is unknown (start the daemon)`);\n return;\n }\n if (rows.length === 0) {\n console.log(chalk.dim(\" no registered projects\"));\n return;\n }\n const byProject = new Map<string, ComponentHealth[]>();\n for (const c of rows) {\n const list = byProject.get(c.project) ?? [];\n list.push(c);\n byProject.set(c.project, list);\n }\n for (const [project, comps] of byProject) {\n console.log(` ${chalk.cyan(project)}`);\n for (const c of comps) {\n // Reuse the pure row for layout; recolor the state token in place.\n const plain = healthRow(c, now);\n console.log(` ${plain.replace(c.state, colorState(c.state))}`);\n }\n }\n}\n","import { Command } from \"commander\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport os from \"node:os\";\nimport { execSync } from \"node:child_process\";\nimport chalk from \"chalk\";\nimport {\n getDefaultConfig,\n saveConfig,\n DEFAULT_CONFIG_PATH,\n resolveHome,\n} from \"@squadrant/shared\";\nimport { createObsidianDriver, WorkspaceRegistry } from \"@squadrant/workspaces\";\nimport { ensureRuntimeSynced } from \"@squadrant/shared\";\n\nfunction findPackageRoot(): string {\n let dir = path.dirname(new URL(import.meta.url).pathname);\n while (dir !== \"/\") {\n if (fs.existsSync(path.join(dir, \"package.json\"))) return dir;\n dir = path.dirname(dir);\n }\n return process.cwd();\n}\n\nfunction copyDirRecursive(src: string, dest: string): void {\n fs.mkdirSync(dest, { recursive: true });\n for (const entry of fs.readdirSync(src, { withFileTypes: true })) {\n const srcPath = path.join(src, entry.name);\n const destPath = path.join(dest, entry.name);\n if (entry.isDirectory()) {\n copyDirRecursive(srcPath, destPath);\n } else {\n fs.copyFileSync(srcPath, destPath);\n }\n }\n}\n\nexport const initCommand = new Command(\"init\")\n .description(\"First-time setup: scaffold hub vault, scripts, and config\")\n .option(\"--hub <path>\", \"Hub vault path\", \"~/squadrant-hub\")\n .action((opts: { hub: string }) => {\n const hubPath = resolveHome(opts.hub);\n const pkgRoot = findPackageRoot();\n const configDir = path.join(os.homedir(), \".config\", \"squadrant\");\n\n console.log(chalk.bold(\"\\nSquadrant Init\\n\"));\n\n // Verify the default workspace provider is registered (squadrant ships obsidian;\n // if user already has a config pointing to an unknown provider, bail early)\n const registry = new WorkspaceRegistry({ obsidian: createObsidianDriver });\n try {\n if (fs.existsSync(DEFAULT_CONFIG_PATH)) {\n const existing = JSON.parse(fs.readFileSync(DEFAULT_CONFIG_PATH, \"utf-8\"));\n const wsName = existing.workspace ?? \"obsidian\";\n registry.get(wsName);\n }\n } catch (err) {\n console.log(chalk.red(` ✘ ${(err as Error).message}`));\n return;\n }\n\n // 1. Create config\n if (fs.existsSync(DEFAULT_CONFIG_PATH)) {\n console.log(chalk.yellow(\" ⚠ Config already exists, skipping creation\"));\n } else {\n const config = getDefaultConfig();\n config.hubVault = hubPath;\n saveConfig(config);\n console.log(chalk.green(` ✔ Config created at ${DEFAULT_CONFIG_PATH}`));\n }\n\n // 2. Scaffold hub vault from template\n const hubTemplate = path.join(pkgRoot, \"obsidian\", \"hub\");\n if (fs.existsSync(hubPath)) {\n console.log(chalk.yellow(` ⚠ Hub vault already exists at ${hubPath}, skipping`));\n } else if (fs.existsSync(hubTemplate)) {\n copyDirRecursive(hubTemplate, hubPath);\n console.log(chalk.green(` ✔ Hub vault scaffolded at ${hubPath}`));\n } else {\n fs.mkdirSync(hubPath, { recursive: true });\n console.log(chalk.yellow(` ⚠ Hub template not found; created empty dir at ${hubPath}`));\n }\n\n // 2b. Always refresh dashboard.md and ensure projects/ exists (idempotent — see #44)\n const hubDashboardSrc = path.join(pkgRoot, \"obsidian\", \"hub\", \"dashboard.md\");\n const hubDashboardDest = path.join(hubPath, \"dashboard.md\");\n if (fs.existsSync(hubDashboardSrc)) {\n fs.copyFileSync(hubDashboardSrc, hubDashboardDest);\n console.log(chalk.green(` ✔ Dashboard page refreshed at ${hubDashboardDest}`));\n }\n const projectsDir = path.join(hubPath, \"projects\");\n fs.mkdirSync(projectsDir, { recursive: true });\n\n // 3. Sync source-managed runtime dirs (plugin, scripts, templates) via\n // the same self-heal path the CLI runs on every invocation: copy +\n // prune + chmod, so a re-init never leaves stale files behind.\n ensureRuntimeSynced({ sourceRoot: pkgRoot, runtimeRoot: configDir });\n console.log(chalk.green(` ✔ Runtime assets synced to ${configDir}`));\n\n // 6. Enable Agent Teams in settings.json if not set\n const settingsPath = path.join(os.homedir(), \".claude\", \"settings.json\");\n try {\n let settings: Record<string, unknown> = {};\n if (fs.existsSync(settingsPath)) {\n settings = JSON.parse(fs.readFileSync(settingsPath, \"utf-8\"));\n }\n const env = (settings.env as Record<string, string>) || {};\n if (env.CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS !== \"1\") {\n settings.env = { ...env, CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS: \"1\" };\n fs.mkdirSync(path.dirname(settingsPath), { recursive: true });\n fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + \"\\n\");\n console.log(chalk.green(\" ✔ Agent Teams enabled in ~/.claude/settings.json\"));\n } else {\n console.log(chalk.green(\" ✔ Agent Teams already enabled\"));\n }\n } catch {\n console.log(chalk.yellow(\" ⚠ Could not update ~/.claude/settings.json\"));\n }\n\n // 5. Print manual steps\n console.log(chalk.bold(\"\\nManual steps required:\\n\"));\n console.log(\" 1. Install plugins in Claude Code:\");\n console.log(chalk.cyan(\" /plugin marketplace add thedotmack/claude-mem\"));\n console.log(chalk.cyan(\" /plugin install claude-mem\"));\n console.log(\" Install context7 and superpowers from /plugin marketplace\");\n console.log(\"\");\n console.log(\" 2. Install cmux if not already installed:\");\n console.log(chalk.cyan(\" npm install -g cmux\"));\n console.log(\"\");\n console.log(\" 3. Open Obsidian and add the hub vault:\");\n console.log(chalk.cyan(` ${hubPath}`));\n console.log(\"\");\n console.log(\" 4. Run \" + chalk.cyan(\"squadrant doctor\") + \" to verify setup\\n\");\n\n if (!fs.existsSync(\"/Applications/cmux.app\")) {\n console.log(chalk.yellow(\" ⚠ cmux not found — download from https://cmux.dev\\n\"));\n }\n });\n","import { Command } from \"commander\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport chalk from \"chalk\";\nimport {\n loadConfig,\n saveConfig,\n resolveHome,\n ProjectConfig,\n} from \"@squadrant/shared\";\n\nfunction findPackageRoot(): string {\n let dir = path.dirname(new URL(import.meta.url).pathname);\n while (dir !== \"/\") {\n if (fs.existsSync(path.join(dir, \"package.json\"))) return dir;\n dir = path.dirname(dir);\n }\n return process.cwd();\n}\n\nfunction copyDirRecursive(src: string, dest: string): void {\n fs.mkdirSync(dest, { recursive: true });\n for (const entry of fs.readdirSync(src, { withFileTypes: true })) {\n const srcPath = path.join(src, entry.name);\n const destPath = path.join(dest, entry.name);\n if (entry.isDirectory()) {\n copyDirRecursive(srcPath, destPath);\n } else {\n fs.copyFileSync(srcPath, destPath);\n }\n }\n}\n\nconst listCmd = new Command(\"list\")\n .description(\"List registered projects\")\n .action(() => {\n const config = loadConfig();\n const projects = Object.entries(config.projects);\n\n if (projects.length === 0) {\n console.log(chalk.yellow(\"\\nNo projects registered. Use: squadrant projects add <name> <path>\\n\"));\n return;\n }\n\n console.log(chalk.bold(\"\\nRegistered Projects\\n\"));\n console.log(\n chalk.dim(\n ` ${\"NAME\".padEnd(18)} ${\"CAPTAIN\".padEnd(22)} ${\"GROUP\".padEnd(15)} ${\"ROLE\".padEnd(18)} PATH`,\n ),\n );\n console.log(chalk.dim(\" \" + \"─\".repeat(100)));\n\n for (const [name, project] of projects) {\n const group = project.group || chalk.dim(\"—\");\n const role = project.groupRole || chalk.dim(\"—\");\n console.log(\n ` ${name.padEnd(18)} ${project.captainName.padEnd(22)} ${String(group).padEnd(15)} ${String(role).padEnd(18)} ${project.path}`,\n );\n }\n console.log(\"\");\n });\n\nconst addCmd = new Command(\"add\")\n .description(\"Register a project\")\n .argument(\"<name>\", \"Project name\")\n .argument(\"<path>\", \"Path to project directory\")\n .option(\"--captain <name>\", \"Captain workspace name (default: <project>-captain)\")\n .option(\"--spoke <path>\", \"Spoke vault path (default: ~/squadrant-hub/spokes/<name>)\")\n .option(\"--group <name>\", \"Project group name (siblings share context)\")\n .option(\"--group-role <role>\", \"Role within the group (auto-set to 'primary' if first in group)\")\n .action((name: string, projectPath: string, opts: { captain?: string; spoke?: string; group?: string; groupRole?: string }) => {\n const config = loadConfig();\n\n if (config.projects[name]) {\n console.log(chalk.yellow(`\\n⚠ Project '${name}' already registered. Remove it first.\\n`));\n process.exit(1);\n }\n\n const resolvedPath = resolveHome(projectPath);\n\n // Warn if path doesn't look like a git repo\n if (!fs.existsSync(path.join(resolvedPath, \".git\"))) {\n console.log(chalk.yellow(`\\n ⚠ No .git found at ${resolvedPath}. Make sure this is the project root, not a parent directory.\\n`));\n }\n\n const captainName = opts.captain || `\\u2693 ${name}-captain`;\n\n // Validate captain name is unique across all projects\n const existingCaptains = Object.entries(config.projects)\n .map(([pName, p]) => ({ project: pName, captain: p.captainName }));\n const conflict = existingCaptains.find((c) => c.captain === captainName);\n if (conflict) {\n console.log(chalk.red(`\\n ✘ Captain name '${captainName}' already used by project '${conflict.project}'.`));\n console.log(chalk.dim(` Use --captain <unique-name> to specify a different name.\\n`));\n process.exit(1);\n }\n\n // Captain name must not collide with command workspace name\n if (captainName === (config.commandName || \"command\")) {\n console.log(chalk.red(`\\n ✘ Captain name '${captainName}' conflicts with the command workspace name.\\n`));\n process.exit(1);\n }\n // Handle project groups\n let group = opts.group;\n let groupRole = opts.groupRole;\n if (group) {\n const siblings = Object.entries(config.projects)\n .filter(([, p]) => p.group === group);\n const primary = siblings.find(([, p]) => p.groupRole === \"primary\");\n\n if (siblings.length === 0) {\n // First project in this group — auto-assign primary\n if (!groupRole) {\n groupRole = \"primary\";\n console.log(chalk.dim(` Auto-assigned as primary for group '${group}'`));\n }\n } else if (!groupRole) {\n // Group exists, no role specified — show siblings and require a role\n console.log(chalk.yellow(`\\n Group '${group}' already has ${siblings.length} project(s):`));\n for (const [sName, sProj] of siblings) {\n console.log(chalk.dim(` - ${sName} (${sProj.groupRole || \"no role\"})`));\n }\n if (primary) {\n console.log(chalk.red(`\\n ✘ Please specify --group-role (e.g., \"fork of ${primary[0]}\", \"landing page\", \"docs\")\\n`));\n } else {\n console.log(chalk.red(`\\n ✘ Please specify --group-role (e.g., \"primary\", \"fork\", \"landing page\", \"docs\")\\n`));\n }\n process.exit(1);\n }\n\n // Warn if trying to set primary when one already exists\n if (groupRole === \"primary\" && primary) {\n console.log(chalk.yellow(`\\n ⚠ Group '${group}' already has '${primary[0]}' as primary. Overriding.`));\n }\n }\n\n const spokeVault = opts.spoke\n ? resolveHome(opts.spoke)\n : path.join(config.hubVault, \"spokes\", name);\n\n const project: ProjectConfig = {\n path: resolvedPath,\n captainName,\n spokeVault,\n host: \"local\",\n ...(group && { group }),\n ...(groupRole && { groupRole }),\n };\n\n config.projects[name] = project;\n saveConfig(config);\n console.log(chalk.green(`\\n ✔ Project '${name}' registered`));\n\n // Scaffold spoke vault from template\n const pkgRoot = findPackageRoot();\n const spokeTemplate = path.join(pkgRoot, \"obsidian\", \"spoke\");\n\n if (fs.existsSync(spokeVault)) {\n console.log(chalk.yellow(` ⚠ Spoke vault already exists at ${spokeVault}, skipping scaffold`));\n } else if (fs.existsSync(spokeTemplate)) {\n copyDirRecursive(spokeTemplate, spokeVault);\n // Update project field in status.md frontmatter\n const statusPath = path.join(spokeVault, \"status.md\");\n if (fs.existsSync(statusPath)) {\n const content = fs.readFileSync(statusPath, \"utf-8\");\n const updated = content.replace(/^project: unnamed/m, `project: ${name}`);\n fs.writeFileSync(statusPath, updated);\n }\n console.log(chalk.green(` ✔ Spoke vault scaffolded at ${spokeVault}`));\n } else {\n fs.mkdirSync(spokeVault, { recursive: true });\n console.log(chalk.yellow(` ⚠ Spoke template not found; created empty dir at ${spokeVault}`));\n }\n\n console.log(\"\");\n });\n\nconst removeCmd = new Command(\"remove\")\n .description(\"Unregister a project (does not delete files)\")\n .argument(\"<name>\", \"Project name\")\n .action((name: string) => {\n const config = loadConfig();\n\n if (!config.projects[name]) {\n console.log(chalk.yellow(`\\n⚠ Project '${name}' not found.\\n`));\n process.exit(1);\n }\n\n delete config.projects[name];\n saveConfig(config);\n console.log(chalk.green(`\\n ✔ Project '${name}' removed from config (files untouched)\\n`));\n });\n\nexport const projectsCommand = new Command(\"projects\")\n .description(\"Manage registered projects\")\n .addCommand(listCmd)\n .addCommand(addCmd)\n .addCommand(removeCmd);\n","import { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport matter from \"gray-matter\";\nimport { loadConfig } from \"@squadrant/shared\";\nimport { createObsidianDriver, WorkspaceRegistry } from \"@squadrant/workspaces\";\nimport { queryHealth, printServiceHealth } from \"./health-view.js\";\n\ninterface StatusFrontmatter {\n project?: string;\n captain_session?: string;\n last_updated?: string;\n active_crew?: number;\n tasks_total?: number;\n tasks_completed?: number;\n tasks_in_progress?: number;\n tasks_pending?: number;\n}\n\nfunction timeAgo(dateStr: string | undefined): string {\n if (!dateStr) return chalk.dim(\"—\");\n const date = new Date(dateStr);\n if (isNaN(date.getTime())) return chalk.dim(\"—\");\n\n const diff = Date.now() - date.getTime();\n const mins = Math.floor(diff / 60_000);\n const hours = Math.floor(diff / 3_600_000);\n const days = Math.floor(diff / 86_400_000);\n\n if (mins < 1) return \"just now\";\n if (mins < 60) return `${mins}m ago`;\n if (hours < 24) return `${hours}h ago`;\n return `${days}d ago`;\n}\n\nfunction progressBar(completed: number, total: number): string {\n if (total === 0) return chalk.dim(\"no tasks\");\n const pct = Math.round((completed / total) * 100);\n const filled = Math.round(pct / 10);\n const bar = \"█\".repeat(filled) + \"░\".repeat(10 - filled);\n return `${bar} ${pct}%`;\n}\n\nexport const statusCommand = new Command(\"status\")\n .description(\"Show status of all projects from spoke vault status files\")\n .option(\"--detailed\", \"also show live per-component service health from the daemon (#77)\")\n .action(async (opts: { detailed?: boolean }) => {\n const config = loadConfig();\n const projects = Object.entries(config.projects);\n const registry = new WorkspaceRegistry({ obsidian: createObsidianDriver });\n\n if (projects.length === 0) {\n console.log(chalk.yellow(\"\\nNo projects registered. Use: squadrant projects add <name> <path>\\n\"));\n return;\n }\n\n console.log(chalk.bold(\"\\nProject Status\\n\"));\n console.log(\n chalk.dim(\n ` ${\"PROJECT\".padEnd(18)} ${\"CAPTAIN\".padEnd(12)} ${\"CREW\".padEnd(6)} ${\"PROGRESS\".padEnd(25)} LAST UPDATE`,\n ),\n );\n console.log(chalk.dim(\" \" + \"─\".repeat(85)));\n\n for (const [name, project] of projects) {\n const workspace = registry.forProject(name, config);\n\n if (!(await workspace.exists(\"status.md\"))) {\n console.log(` ${name.padEnd(18)} ${chalk.dim(\"no status.md\")}`);\n continue;\n }\n\n let fm: StatusFrontmatter = {};\n try {\n const raw = await workspace.read(\"status.md\");\n fm = matter(raw).data as StatusFrontmatter;\n } catch {\n console.log(` ${name.padEnd(18)} ${chalk.red(\"error reading status.md\")}`);\n continue;\n }\n\n const sessionIndicator =\n fm.captain_session === \"active\"\n ? chalk.green(\"●\")\n : chalk.dim(\"○\");\n const captainDisplay = `${project.captainName.padEnd(11)} ${sessionIndicator}`;\n const crew = String(fm.active_crew ?? 0).padEnd(6);\n const progress = progressBar(\n fm.tasks_completed ?? 0,\n fm.tasks_total ?? 0,\n ).padEnd(25);\n const updated = timeAgo(fm.last_updated);\n\n console.log(\n ` ${name.padEnd(18)} ${captainDisplay} ${crew} ${progress} ${updated}`,\n );\n }\n\n console.log(\"\");\n\n // #77: --detailed adds the live service-health view (relay/captain/crew/\n // command per-component last-seen + state) queried from the daemon.\n if (opts.detailed) {\n printServiceHealth(await queryHealth());\n }\n });\n","import { Command } from \"commander\";\nimport { execSync } from \"node:child_process\";\nimport path from \"node:path\";\nimport os from \"node:os\";\nimport chalk from \"chalk\";\nimport { loadConfig } from \"@squadrant/shared\";\nimport { createCmuxDriver, RuntimeRegistry } from \"@squadrant/workspaces\";\nimport type { PaneRef } from \"@squadrant/workspaces\";\nimport {\n createClaudeDriver,\n createCodexDriver,\n createGeminiDriver,\n createOpencodeDriver,\n CapabilityRegistry,\n} from \"@squadrant/agents\";\nimport { resolveCmuxBin } from \"@squadrant/shared\";\n\nconst TEMPLATES_DIR = path.join(os.homedir(), \".config\", \"squadrant\", \"templates\");\n\ntype CommandTask = \"briefing\" | \"learnings-review\" | \"wiki-aggregate\";\n\nconst TASK_PROMPTS: Record<CommandTask, string> = {\n briefing:\n \"Run your daily briefing using the squadrant:command-ops skill. Read all spoke handoffs, yesterday's logs, current status; produce a concise cross-project briefing; save to {hubVault}/daily-logs/YYYY-MM-DD.md; then exit.\",\n \"learnings-review\":\n \"Run a learnings review using the squadrant:command-ops skill. Scan {spokeVault}/learnings across all projects, identify cross-project patterns, propose captured-skill or fix actions, and exit when done.\",\n \"wiki-aggregate\":\n \"Run a wiki aggregation pass using the squadrant:command-ops skill. Scan each spoke wiki index, identify shared knowledge worth promoting, write hub wiki pages, and exit when done.\",\n};\n\nexport interface CommandSpawnInput {\n task: CommandTask;\n direction?: \"right\" | \"left\" | \"up\" | \"down\";\n agent?: string;\n}\n\nfunction detectCurrentWorkspace(): string {\n const out = execSync(`\"${resolveCmuxBin()}\" current-workspace`, { encoding: \"utf-8\" }).trim();\n const match = out.match(/workspace:\\d+/);\n if (!match) {\n throw new Error(\"Could not detect current cmux workspace. Run `squadrant command` from inside a cmux workspace.\");\n }\n return match[0];\n}\n\nexport async function runCommandSpawn(input: CommandSpawnInput): Promise<PaneRef> {\n const prompt = TASK_PROMPTS[input.task];\n if (!prompt) {\n throw new Error(`Unknown task '${input.task}'. Known: briefing, learnings-review, wiki-aggregate.`);\n }\n\n const config = loadConfig();\n const runtime = new RuntimeRegistry({ cmux: createCmuxDriver() }).global(config);\n\n const workspaceId = detectCurrentWorkspace();\n\n const agents = new CapabilityRegistry({\n claude: createClaudeDriver(),\n codex: createCodexDriver(),\n gemini: createGeminiDriver(),\n opencode: createOpencodeDriver(),\n });\n const agentName = input.agent ?? \"claude\";\n const agent = agents.get(agentName);\n if (!agent) {\n throw new Error(`Unknown agent '${agentName}'. Known: claude, codex, gemini, opencode.`);\n }\n\n const promptFile = path.join(TEMPLATES_DIR, `command.${agent.templateSuffix}.md`);\n const cliCommand = agent.buildCommand({\n prompt,\n workdir: process.cwd(),\n role: \"command\",\n promptFile,\n });\n\n const direction = input.direction ?? \"right\";\n const title = `🤖 command-${input.task}`;\n const pane = await runtime.newPane({ workspaceId, direction, title });\n await runtime.sendToPane(pane, cliCommand);\n return pane;\n}\n\nexport const commandCommand = new Command(\"command\")\n .description(\"Spawn a one-shot Command session in a split pane (briefing | learnings-review | wiki-aggregate)\")\n .option(\"--task <name>\", \"Task prompt to bake in (briefing|learnings-review|wiki-aggregate)\", \"briefing\")\n .option(\"--direction <dir>\", \"Split direction (right|left|up|down)\", \"right\")\n .option(\"--agent <name>\", \"Agent CLI to use (claude|codex|gemini|opencode)\", \"claude\")\n .action(async (opts: { task: CommandTask; direction: \"right\" | \"left\" | \"up\" | \"down\"; agent: string }) => {\n try {\n const pane = await runCommandSpawn({ task: opts.task, direction: opts.direction, agent: opts.agent });\n console.log(chalk.green(`✔ Command spawned in ${pane.workspaceId} ${pane.surfaceId} (task: ${opts.task})`));\n } catch (err) {\n console.error(chalk.red((err as Error).message));\n process.exit(1);\n }\n });\n","import { Command } from \"commander\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport os from \"node:os\";\nimport chalk from \"chalk\";\nimport { loadConfig } from \"@squadrant/shared\";\nimport { addWorktree, removeWorktree, resolveWorktreeBase, resolveTextInput, TERMINAL_STATES } from \"@squadrant/shared\";\nimport type { TaskRecord } from \"@squadrant/shared\";\nimport { resolveCrewRoute } from \"../control/crew-routing.js\";\nimport { createCmuxDriver, RuntimeRegistry } from \"@squadrant/workspaces\";\nimport { listProjectCrews, findCrew, resolveCaptainWorkspace, sendFirstTurnWhenReady, getFreePort } from \"@squadrant/workspaces\";\nimport type { PaneRef, PanePlacement, RuntimeDriver } from \"@squadrant/workspaces\";\nimport {\n createClaudeDriver,\n createCodexDriver,\n createGeminiDriver,\n createOpencodeDriver,\n CapabilityRegistry,\n} from \"@squadrant/agents\";\nimport { buildDispatchRequest, squadrantdCall, sendCodexFirstTurn } from \"./crew-control.js\";\nimport { tailLines } from \"./crew-output.js\";\nimport { writePerCrewSettingsLocal, writePerCrewOpencodeConfig } from \"../lib/per-crew-settings.js\";\nimport { buildCompletionProtocol, shellQuote, titleFor, nameFromTitle, nextAutoName, reapCrewChildren } from \"@squadrant/core\";\nimport type { TurnAcceptanceConfig } from \"@squadrant/core\";\n\nconst TEMPLATES_DIR = path.join(os.homedir(), \".config\", \"squadrant\", \"templates\");\n\n// Base branch for `--worktree` crew branches is derived at spawn time from\n// origin/HEAD so repos using main, trunk, etc. work out of the box (#359).\n// Still avoids \"current HEAD\" deliberately — basing off the captain's volatile\n// HEAD would reintroduce the coupling this isolation feature exists to remove.\n\nexport interface CrewSpawnInput {\n project: string;\n task: string;\n name?: string;\n direction?: PanePlacement;\n agent?: string;\n approvalPolicy?: string;\n /** Opt-out (#296): run this crew in the root checkout instead of an isolated\n * worktree. Pass true for small/one-off tasks that don't need branch isolation.\n * Default (undefined/false) = isolated worktree — parallel-safe. */\n shared?: boolean;\n /** CP3 opt-in: gate risky tools (bash) so the captain approves them.\n * codex maps this to approvalPolicy='untrusted'; opencode maps it to a\n * bash:\"ask\" per-crew config. Default (false) = fully autonomous. */\n approval?: boolean;\n /** Per-spawn model override — takes precedence over defaults.roles.crew.model.\n * Agent-specific alias (e.g. \"sonnet\", \"opus\" for claude; \"gpt-5.5\" for codex). */\n model?: string;\n /** True when --agent was explicitly passed by the caller; suppresses crew routing. */\n agentExplicit?: boolean;\n}\n\nexport async function runCrewSpawn(input: CrewSpawnInput): Promise<PaneRef> {\n const config = loadConfig();\n const proj = config.projects[input.project];\n if (!proj) {\n throw new Error(`Project '${input.project}' not found. Run 'squadrant projects list'.`);\n }\n\n const runtime = new RuntimeRegistry({ cmux: createCmuxDriver() }).forProject(input.project, config);\n const captain = await runtime.status(proj.captainName);\n if (!captain) {\n throw new Error(\n `Captain workspace '${proj.captainName}' is not running. Run 'squadrant launch ${input.project}' first.`,\n );\n }\n\n const existing = await listProjectCrews(runtime, captain.id, input.project);\n const existingTitles = existing.map((s) => s.title!);\n if (input.name) {\n const wantTitle = titleFor(input.project, input.name);\n if (existingTitles.includes(wantTitle)) {\n throw new Error(\n `Crew '${input.name}' already exists for ${input.project}. Use 'squadrant crew send ${input.project} ${input.name}' to send a follow-up, or pick a different --name.`,\n );\n }\n }\n const name = input.name ?? nextAutoName(existingTitles, input.project);\n\n // Crews run in an isolated worktree+branch by default so multiple parallel\n // crews never collide on a shared HEAD (#296). Pass shared:true (CLI: --shared)\n // for small/one-off tasks that should run on the root checkout.\n // Build/daemon still run from the MAIN checkout's dist (#216): worktrees edit\n // source only. The worktree path becomes the crew's cwd via the existing cwd\n // plumbing (dispatch record + buildCommand workdir).\n const spawnCwd = !input.shared\n ? addWorktree({\n repoRoot: proj.path,\n worktreeDir: config.defaults.worktreeDir ?? \".worktrees\",\n project: input.project,\n name,\n base: resolveWorktreeBase(proj.path),\n })\n : proj.path;\n\n // #275 leveled crew routing: consult routing rules when agent/model were not\n // explicitly provided by the caller. Explicit --agent or --model always win.\n const route = !input.agentExplicit && !input.model\n ? resolveCrewRoute(input.task, config)\n : null;\n if (route) {\n console.log(chalk.dim(`routed: tier=${route.tier} → ${route.agent}${route.model ? `/${route.model}` : \"\"} (rule: \"${route.matchedRule}\")`));\n }\n\n const agents = new CapabilityRegistry({\n claude: createClaudeDriver(),\n codex: createCodexDriver(),\n gemini: createGeminiDriver(),\n opencode: createOpencodeDriver(),\n });\n const agentName = route?.agent ?? input.agent ?? \"claude\";\n const agent = agents.get(agentName);\n if (!agent) {\n throw new Error(`Unknown agent '${agentName}'. Known: claude, codex, gemini, opencode.`);\n }\n\n // Codex: route through the interactive control-plane daemon (PR #98) instead\n // of the print-mode CLI path. The dispatched task is driven via the\n // crew-attach renderer running in the captain tab, so 'crew send' / 'crew\n // read' / 'crew close' work identically to the Claude crew UX.\n if (agentName === \"codex\") {\n // Mirror claude's --append-system-prompt-file: read the crew role template\n // and forward it to codex via thread/start.developerInstructions so the\n // session knows it's a crew member, not a bare shell.\n const codexRoleFile = path.join(TEMPLATES_DIR, `crew.${agent.templateSuffix}.md`);\n const roleInstructions = fs.existsSync(codexRoleFile)\n ? fs.readFileSync(codexRoleFile, \"utf8\")\n : undefined;\n return runCodexInteractiveSpawn({\n project: input.project,\n task: input.task,\n cwd: spawnCwd,\n runtime,\n workspaceId: captain.id,\n name,\n direction: input.direction ?? \"tab\",\n approvalPolicy: input.approvalPolicy,\n roleInstructions,\n });\n }\n\n const promptFile = path.join(TEMPLATES_DIR, `crew.${agent.templateSuffix}.md`);\n // Claude crews run interactively (no -p) so the session stays alive between\n // turns; the task is sent via cmux after the CLI boots. Other agents that\n // don't yet honor `interactive` will keep their existing print-mode shape —\n // a known limitation tracked for future work.\n const interactive = agent.name === \"claude\" || agent.name === \"opencode\";\n // Honor configured model routing only when the spawn agent matches the\n // configured role agent — model names are agent-specific (e.g. \"sonnet\" is\n // a Claude alias; codex/gemini have their own routing). Cross-agent crews\n // fall back to the agent's own default to avoid passing an invalid model arg.\n const crewRole = config.defaults.roles?.crew;\n const configModel = crewRole && crewRole.agent === agent.name ? crewRole.model : undefined;\n const crewModel = input.model ?? route?.model ?? configModel;\n\n // Claude crews route through the control-plane daemon (PR #85 + this spec)\n // so the captain learns terminal state via `squadrant crew status` instead\n // of scraping the pane. The cmux tab still does the actual CLI launch —\n // the daemon doesn't own Claude's PID (Approach 3 boundary). Hook bridge\n // (per-crew settings.json with Stop/SubagentStop/SessionEnd → squadrant\n // crew _hook) keeps the daemon's heartbeat fresh; explicit\n // `squadrant crew signal done` from the crew template emits terminal state.\n if (agentName === \"claude\") {\n const req = buildDispatchRequest({\n provider: \"claude\",\n mode: \"interactive\",\n project: input.project,\n cwd: spawnCwd,\n task: input.task,\n name,\n });\n // Fail loud if daemon unreachable — refusal-to-degrade.\n const rec = (await squadrantdCall(req)) as TaskRecord;\n // Write squadrant hooks to <cwd>/.claude/settings.local.json so they are\n // auto-loaded as a project-local settings source. The cmux claude wrapper\n // injects its own hooks via --settings (level 2 precedence), but hooks\n // merge across *different* settings sources — only multiple --settings\n // flags collide. .claude/settings.local.json is gitignored and merges\n // with any existing user hooks (#134).\n writePerCrewSettingsLocal({ projectCwd: spawnCwd });\n const cliCommand = agent.buildCommand({\n prompt: input.task,\n workdir: spawnCwd,\n role: \"crew\",\n promptFile,\n interactive: true,\n // Permission mode is config-driven (defaults.permissions.crew) so squadrant\n // can default crews to 'auto' or keep the semi-automatic 'acceptEdits'\n // gate (auto-accept edits, still prompt for risky ops). Falls back to\n // 'acceptEdits' when unset.\n permissionMode: config.defaults.permissions?.crew ?? \"acceptEdits\",\n ...(crewModel ? { model: crewModel } : {}),\n });\n const direction: PanePlacement = input.direction ?? \"tab\";\n const title = titleFor(input.project, name);\n const pane = await runtime.newPane({ workspaceId: captain.id, direction, title });\n // Prefix the CLI command with env so the hook bridge + signal verb\n // running inside the crew's cmux tab can identify their task.\n const envPrefix = `SQUADRANT_CREW_TASK_ID=${rec.id} SQUADRANT_CREW_PROJECT=${input.project}`;\n await runtime.sendToPane(pane, `cd ${shellQuote(spawnCwd)} && ${envPrefix} ${cliCommand}`);\n const preLaunchScreen = (await runtime.readPaneScreen(pane)) ?? \"\";\n await sendFirstTurnWhenReady(runtime, pane, `${input.task}\\n\\n${buildCompletionProtocol(rec.id, input.project)}`, preLaunchScreen);\n return { ...pane, title };\n }\n\n // Opencode crews route through the control-plane daemon so the captain\n // learns terminal state via `squadrant crew status` instead of scraping the\n // pane. Same approach as claude: daemon owns the state ledger, cmux tab\n // does the actual CLI launch. No hook bridge (opencode has no hooks); the\n // crew template instructs explicit `squadrant crew signal done|blocked|failed`.\n if (agentName === \"opencode\") {\n // Bind the crew's embedded opencode HTTP server on a known port so the\n // daemon's SSE bridge can subscribe to /event for turn-end detection.\n const serverPort = await getFreePort();\n const req = buildDispatchRequest({\n provider: \"opencode\",\n mode: \"interactive\",\n project: input.project,\n cwd: spawnCwd,\n task: input.task,\n name,\n // opencode has no heartbeat hook, so a normal budget would false-stall\n // every crew after 5min; use a 24h budget to effectively disable stall\n // detection. The SSE bridge (serverPort) provides turn-end liveness.\n budgetMs: 86400000,\n serverPort,\n });\n const rec = (await squadrantdCall(req)) as TaskRecord;\n const opencodeConfigPath = writePerCrewOpencodeConfig({\n stateRoot: path.join(os.homedir(), \".config\", \"squadrant\", \"state\"),\n project: input.project,\n taskId: rec.id,\n // CP3 opt-in: --approval gates bash so the captain approves shell commands.\n // Without it, bash stays auto-approved (default behavior unchanged).\n ...(input.approval ? { gateBash: true } : {}),\n });\n const cliCommand = agent.buildCommand({\n prompt: input.task,\n workdir: spawnCwd,\n role: \"crew\",\n promptFile,\n interactive: true,\n model: crewModel,\n port: serverPort,\n });\n const direction: PanePlacement = input.direction ?? \"tab\";\n const title = titleFor(input.project, name);\n const pane = await runtime.newPane({ workspaceId: captain.id, direction, title });\n const envPrefix = `SQUADRANT_CREW_TASK_ID=${rec.id} SQUADRANT_CREW_PROJECT=${input.project}`;\n await runtime.sendToPane(pane, `cd ${shellQuote(spawnCwd)} && ${envPrefix} OPENCODE_CONFIG=${opencodeConfigPath} ${cliCommand}`);\n const preLaunchScreen = (await runtime.readPaneScreen(pane)) ?? \"\";\n await sendFirstTurnWhenReady(runtime, pane, `${input.task}\\n\\n${buildCompletionProtocol(rec.id, input.project)}`, preLaunchScreen, {\n // #235: opencode's idle splash (\"Ask anything…\") keeps mutating (cursor\n // blink, status line toggle), so the old screen-changed check would always\n // see a *different* screen and never re-send a dropped turn. The splashMarker\n // confirms the TUI actually left splash before declaring acceptance.\n splashMarker: \"Ask anything…\",\n // opencode has a wider boot-race window than claude, so allow 3 retries\n // instead of the default 2.\n retryLimit: 3,\n } satisfies TurnAcceptanceConfig);\n return { ...pane, title };\n }\n\n const cliCommand = agent.buildCommand({\n prompt: input.task,\n workdir: spawnCwd,\n role: \"crew\",\n promptFile,\n interactive,\n model: crewModel,\n });\n\n const direction: PanePlacement = input.direction ?? \"tab\";\n const title = titleFor(input.project, name);\n const pane = await runtime.newPane({ workspaceId: captain.id, direction, title });\n\n // Step 1: launch the CLI in the new tab.\n await runtime.sendToPane(pane, cliCommand);\n\n // Step 2: for interactive sessions, poll until the CLI is ready, then send\n // the task as the first prompt. For non-interactive (legacy) the prompt is\n // already baked into cliCommand, so we're done.\n if (interactive) {\n const preLaunchScreen = (await runtime.readPaneScreen(pane)) ?? \"\";\n await sendFirstTurnWhenReady(runtime, pane, input.task, preLaunchScreen);\n }\n\n return { ...pane, title };\n}\n\nasync function runCodexInteractiveSpawn(o: {\n project: string;\n task: string;\n cwd: string;\n runtime: RuntimeDriver;\n workspaceId: string;\n name: string;\n direction: PanePlacement;\n approvalPolicy?: string;\n roleInstructions?: string;\n}): Promise<PaneRef> {\n const req = buildDispatchRequest({\n provider: \"codex\",\n mode: \"interactive\",\n project: o.project,\n cwd: o.cwd,\n task: o.task,\n name: o.name,\n ...(o.approvalPolicy ? { approvalPolicy: o.approvalPolicy } : {}),\n ...(o.roleInstructions ? { roleInstructions: o.roleInstructions } : {}),\n });\n const rec = (await squadrantdCall(req)) as TaskRecord;\n const title = titleFor(o.project, o.name);\n const pane = await o.runtime.newPane({\n workspaceId: o.workspaceId,\n direction: o.direction,\n title,\n });\n await o.runtime.sendToPane(pane, `squadrant crew attach ${rec.id}`);\n // Match the claude UX where the task arg becomes the first turn. The codex\n // dispatch only opens the thread; the task text never reaches the model\n // unless we send it. Fire-and-forget: the renderer in the tab will pick up\n // streamed deltas once it attaches. Skip the deprecated \"(interactive)\"\n // placeholder which `crew chat` passes when no task was provided.\n if (o.task && o.task !== \"(interactive)\") {\n void sendCodexFirstTurn(rec.id, o.task).catch((e: unknown) => {\n process.stderr.write(`(first-turn delivery failed: ${(e as Error).message})\\n`);\n });\n }\n return { ...pane, title };\n}\n\nexport async function runCrewSend(project: string, name: string, message: string): Promise<void> {\n const { runtime, workspaceId } = await resolveCaptainWorkspace(project);\n const crew = await findCrew(runtime, workspaceId, project, name);\n if (!crew) {\n throw new Error(`Crew '${name}' not found for ${project}. Run 'squadrant crew list ${project}'.`);\n }\n // Best-effort attention-state handling before delivering the captain's answer.\n // Terminal task (done/failed): reopen so the next signal done fires CREW DONE (#148).\n // Blocked task: emit task.started to clear blocked→working so a subsequent real\n // permission prompt re-fires CREW BLOCKED (#182). Without this the second block\n // hits the idempotency guard (state-machine:69) and the captain misses it.\n // Awaiting-input task: same resume — crew re-enters working so the next block fires.\n try {\n const tasks = (await squadrantdCall({ kind: \"list\", project })) as TaskRecord[];\n const task = tasks.find((t) => t.name === name);\n if (task) {\n if (TERMINAL_STATES.has(task.state)) {\n await squadrantdCall({ kind: \"event\", project, event: { type: \"task.reopened\", id: task.id } });\n } else if (task.state === \"blocked\" || task.state === \"awaiting-input\") {\n await squadrantdCall({ kind: \"event\", project, event: { type: \"task.started\", id: task.id } });\n }\n }\n } catch {\n // Swallow daemon errors so crews without a daemon or offline daemon\n // still receive the sent message.\n }\n await runtime.sendToPane(crew, message);\n}\n\nexport async function runCrewRead(project: string, name: string): Promise<string> {\n const { runtime, workspaceId } = await resolveCaptainWorkspace(project);\n const crew = await findCrew(runtime, workspaceId, project, name);\n if (!crew) {\n throw new Error(`Crew '${name}' not found for ${project}. Run 'squadrant crew list ${project}'.`);\n }\n return runtime.readPaneScreen(crew);\n}\n\nexport async function runCrewClose(project: string, name: string): Promise<void> {\n const { runtime, workspaceId } = await resolveCaptainWorkspace(project);\n // resolveCaptainWorkspace already validated the project exists; reload for its\n // root path so we can tell a worktree crew (cwd != root) from a root crew.\n const projRoot = loadConfig().projects[project]?.path;\n // Terminalize the daemon task FIRST — before (and independent of) finding the\n // cmux pane (#184, hardened for #139). Without this, non-terminal tasks\n // (blocked/working/awaiting-input) linger in the daemon ledger and keep firing\n // phantom CREW BLOCKED/IDLE/STALLED pushes. Crucially, a DEAD crew's pane is\n // already gone, so gating terminalization on findCrew (the old order) left that\n // zombie record dangling forever. 'cancelled' is terminal but NOT in\n // ATTENTION_STATES, so firePush stays silent — captain initiated the close.\n let taskId: string | undefined;\n // Worktree to clean up after the pane closes — set only when this crew ran in\n // its own worktree (cwd recorded by the daemon differs from the root checkout).\n // A non-worktree crew has cwd === root (or unset), so this stays undefined and\n // close is unaffected (#216).\n let worktreeCwd: string | undefined;\n try {\n const tasks = (await squadrantdCall({ kind: \"list\", project })) as TaskRecord[];\n const task = tasks.find((t) => t.name === name);\n if (task) {\n taskId = task.id;\n if (task.cwd && projRoot && task.cwd !== projRoot) {\n worktreeCwd = task.cwd;\n }\n if (!TERMINAL_STATES.has(task.state)) {\n await squadrantdCall({ kind: \"event\", project, event: { type: \"task.cancelled\", id: task.id, reason: \"closed by captain\" } });\n }\n // Codex teardown: the pane only hosts the `crew attach` renderer; the thread\n // (and its per-thread MCP servers) live on the shared app-server, so closing\n // the pane alone leaks them. Tell the daemon to archive the thread. Fires for\n // terminal and non-terminal crews alike (a finished codex crew still holds a\n // live thread until archived).\n if (task.provider === \"codex\") {\n await squadrantdCall({ kind: \"codex-close\", taskId: task.id });\n }\n }\n } catch {\n // Swallow daemon errors — a crew without a daemon must still close.\n }\n // Close the cmux pane if it still exists. A dead crew's pane is already gone —\n // that is not an error (the record is terminalized above); proceed to reap\n // children / clean the worktree. Only a genuine miss (no pane AND no daemon\n // task) is a typo → surface the not-found error.\n const crew = await findCrew(runtime, workspaceId, project, name);\n if (crew) {\n await runtime.closePane(crew);\n } else if (taskId === undefined) {\n throw new Error(`Crew '${name}' not found for ${project}. Run 'squadrant crew list ${project}'.`);\n }\n // Reap any surviving child processes (vitest workers, node subprocs, etc.)\n // that the cmux pane-close cascade may have missed.\n if (taskId !== undefined) {\n await reapCrewChildren(taskId);\n }\n // Auto-clean the crew's worktree AFTER its processes are gone, so we don't\n // yank a dir out from under a live shell. Best-effort: a failed removal must\n // not break close (the branch is preserved regardless).\n if (worktreeCwd && projRoot) {\n try {\n removeWorktree(projRoot, worktreeCwd);\n } catch (e) {\n process.stderr.write(`(worktree remove failed: ${(e as Error).message})\\n`);\n }\n }\n}\n\nexport async function runCrewList(project: string): Promise<Array<{ name: string; surfaceId: string }>> {\n const { runtime, workspaceId } = await resolveCaptainWorkspace(project);\n const crews = await listProjectCrews(runtime, workspaceId, project);\n return crews.map((c) => ({\n name: nameFromTitle(project, c.title!),\n surfaceId: c.surfaceId,\n }));\n}\n\nexport const crewCommand = new Command(\"crew\").description(\n \"Spawn and manage interactive crew sessions next to the project's captain\",\n);\n\ncrewCommand\n .command(\"spawn\")\n .description(\n \"Spawn an interactive crew session as a tab in the captain's workspace (use --direction to split into a pane instead)\",\n )\n .argument(\"<project>\", \"Project name (must be registered)\")\n .argument(\"[task]\", \"Initial task prompt for the crew session (omit with --task-file)\")\n .option(\"--name <name>\", \"Crew name (default: auto-generated crew-N)\")\n .option(\"--direction <dir>\", \"Placement: tab (default) or split direction (right|left|up|down)\", \"tab\")\n .option(\"--agent <name>\", \"Agent CLI to use (claude|codex|gemini|opencode)\", \"claude\")\n .option(\"--approval\", \"gate risky tools so the captain approves them (codex: approvalPolicy='untrusted'; opencode: bash:'ask')\", false)\n .option(\"--shared\", \"run the crew in the root checkout instead of an isolated worktree (for small/one-off tasks)\", false)\n .option(\"--task-file <path>\", \"Read task prompt from file instead of positional arg ('-' for stdin)\")\n .option(\"--model <alias>\", \"Override crew model for this spawn (e.g. sonnet, opus); takes precedence over config defaults.roles.crew.model\")\n .action(\n async (\n project: string,\n task: string | undefined,\n opts: { name?: string; direction: PanePlacement; agent: string; approval: boolean; shared: boolean; taskFile?: string; model?: string },\n cmd: Command,\n ) => {\n try {\n const resolvedTask = await resolveTextInput({ positional: task, filePath: opts.taskFile, label: \"task\" });\n const agentExplicit = cmd.getOptionValueSource(\"agent\") === \"cli\";\n const pane = await runCrewSpawn({\n project,\n task: resolvedTask,\n name: opts.name,\n direction: opts.direction,\n agent: opts.agent,\n agentExplicit,\n // --approval is provider-agnostic: codex consumes approvalPolicy,\n // opencode consumes the `approval` flag (→ bash:\"ask\" per-crew config).\n ...(opts.approval ? { approvalPolicy: \"untrusted\", approval: true } : {}),\n ...(opts.shared ? { shared: true } : {}),\n ...(opts.model ? { model: opts.model } : {}),\n });\n console.log(chalk.green(`✔ Crew '${pane.title}' spawned (${pane.surfaceId})`));\n } catch (err) {\n console.error(chalk.red((err as Error).message));\n process.exit(1);\n }\n },\n );\n\ncrewCommand\n .command(\"list\")\n .description(\"List live crew sessions for a project\")\n .argument(\"<project>\", \"Project name\")\n .action(async (project: string) => {\n try {\n const crews = await runCrewList(project);\n if (crews.length === 0) {\n console.log(chalk.yellow(`No live crew sessions for ${project}.`));\n return;\n }\n for (const c of crews) {\n console.log(` ${c.name} (${c.surfaceId})`);\n }\n } catch (err) {\n console.error(chalk.red((err as Error).message));\n process.exit(1);\n }\n });\n\ncrewCommand\n .command(\"send\")\n .description(\"Send a follow-up message to an existing crew session\")\n .argument(\"<project>\", \"Project name\")\n .argument(\"<name>\", \"Crew name (e.g. crew-1)\")\n .argument(\"[message]\", \"Message to send (omit with --message-file)\")\n .option(\"--message-file <path>\", \"Read message from file instead of positional arg ('-' for stdin)\")\n .action(async (project: string, name: string, message: string | undefined, opts: { messageFile?: string }) => {\n try {\n const resolvedMessage = await resolveTextInput({ positional: message, filePath: opts.messageFile, label: \"message\" });\n await runCrewSend(project, name, resolvedMessage);\n console.log(chalk.green(`✔ Sent to ${project}:${name}`));\n } catch (err) {\n console.error(chalk.red((err as Error).message));\n process.exit(1);\n }\n });\n\ncrewCommand\n .command(\"read\")\n .description(\"Read the current screen of a crew session (tail by default; use --full for the entire scrollback)\")\n .argument(\"<project>\", \"Project name\")\n .argument(\"<name>\", \"Crew name\")\n .option(\"--lines <N>\", \"Number of trailing lines to show\", \"40\")\n .option(\"--full\", \"Show the entire scrollback (overrides --lines)\")\n .action(async (project: string, name: string, opts: { lines?: string; full?: boolean }) => {\n try {\n const screen = await runCrewRead(project, name);\n const out = opts.full ? screen : tailLines(screen, Number(opts.lines ?? 40));\n console.log(out);\n } catch (err) {\n console.error(chalk.red((err as Error).message));\n process.exit(1);\n }\n });\n\ncrewCommand\n .command(\"close\")\n .description(\"Shutdown a crew session (closes its tab)\")\n .argument(\"<project>\", \"Project name\")\n .argument(\"<name>\", \"Crew name\")\n .action(async (project: string, name: string) => {\n try {\n await runCrewClose(project, name);\n console.log(chalk.green(`✔ Closed ${project}:${name}`));\n } catch (err) {\n console.error(chalk.red((err as Error).message));\n process.exit(1);\n }\n });\n","import type { SquadrantConfig } from \"@squadrant/shared\";\n\nexport interface CrewRouteResult {\n agent: string;\n model?: string;\n tier: string;\n matchedRule: string;\n}\n\n/**\n * Resolve a crew route from task text against config.defaults.crewRouting.rules.\n * Returns the first matching rule's agent/model, or null if no rule matches or\n * crewRouting is absent. Pure — no side effects.\n */\nexport function resolveCrewRoute(taskText: string, config: SquadrantConfig): CrewRouteResult | null {\n const rules = config.defaults.crewRouting?.rules;\n if (!rules || rules.length === 0) return null;\n for (const rule of rules) {\n const re = new RegExp(rule.match, \"i\");\n if (re.test(taskText)) {\n return {\n agent: rule.agent,\n ...(rule.model !== undefined ? { model: rule.model } : {}),\n tier: rule.tier,\n matchedRule: rule.match,\n };\n }\n }\n return null;\n}\n","// src/commands/crew-control.ts\nimport { Command } from \"commander\";\nimport { createConnection } from \"node:net\";\nimport { randomUUID } from \"node:crypto\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { mkdirSync, writeFileSync } from \"node:fs\";\nimport { sendRequest } from \"@squadrant/core\";\nimport { ensureDaemon } from \"@squadrant/core\";\nimport type { ControlEvent, Mode, Provider, TaskRecord } from \"@squadrant/shared\";\nimport { mapClaudeHookToEvent } from \"@squadrant/agents\";\nimport { filterTasks, formatCompactTasks } from \"./crew-output.js\";\nimport { crewAttachCommand } from \"./crew-attach.js\";\nimport { crewChatCommand } from \"./crew-chat.js\";\n\nconst SOCK = join(homedir(), \".config\", \"squadrant\", \"squadrant.sock\");\n\n// Codex thread setup is async after `dispatch` returns; let startThread finish\n// before sending the first turn. Empirically codex handshake completes in well\n// under a second; 1.5s is a safe margin without blocking the spawn return for\n// long (this function is invoked fire-and-forget).\nconst CODEX_FIRST_TURN_DELAY_MS = 1500;\n\n/**\n * Send the spawn task arg to a freshly-dispatched codex interactive task as\n * the first turn — mirrors how `squadrant crew spawn --agent claude \"<task>\"`\n * sends the task arg into the claude CLI's first prompt.\n *\n * Reuses the existing attach-socket `say` op (same one used by `crew send` and\n * `crew attach` follow-ups). Opens a transient socket, attaches, sends say,\n * closes. The renderer running in the captain tab attaches independently and\n * receives the streamed reply.\n */\nexport async function sendCodexFirstTurn(taskId: string, text: string): Promise<void> {\n await new Promise((r) => setTimeout(r, CODEX_FIRST_TURN_DELAY_MS));\n await new Promise<void>((resolve, reject) => {\n const conn = createConnection(SOCK);\n conn.setEncoding(\"utf-8\");\n conn.on(\"data\", () => { /* drain attach frames; we just want to send */ });\n conn.on(\"error\", reject);\n conn.once(\"connect\", () => {\n try {\n conn.write(JSON.stringify({ op: \"attach\", taskId }) + \"\\n\");\n conn.write(JSON.stringify({ op: \"say\", taskId, text }) + \"\\n\");\n } catch (e) {\n reject(e);\n return;\n }\n // Brief flush window before close so the daemon processes both frames.\n setTimeout(() => { conn.end(); resolve(); }, 100);\n });\n });\n}\n\nexport function buildDispatchRequest(o: {\n project: string; provider: Provider; mode: Mode; task: string; budgetMs?: number; cwd?: string;\n approvalPolicy?: string; roleInstructions?: string; name?: string; serverPort?: number;\n}): { kind: \"dispatch\"; record: TaskRecord } {\n const now = Date.now();\n const attemptId = randomUUID();\n return {\n kind: \"dispatch\",\n record: {\n id: randomUUID(), project: o.project, provider: o.provider, mode: o.mode,\n state: \"submitted\", task: o.task, cwd: o.cwd, createdAt: now, lastHeartbeat: now,\n lastEvent: \"dispatch\", heartbeatBudgetMs: o.budgetMs ?? 300000,\n attempts: [{ attemptId, startedAt: now, lastHeartbeatAt: now }],\n ...(o.approvalPolicy ? { approvalPolicy: o.approvalPolicy } : {}),\n ...(o.roleInstructions ? { roleInstructions: o.roleInstructions } : {}),\n ...(o.name ? { name: o.name } : {}),\n ...(o.serverPort ? { serverPort: o.serverPort } : {}),\n },\n };\n}\n\nexport function buildStatusRequest(project: string, id: string) {\n return { kind: \"status\" as const, project, id };\n}\n\nexport function buildGateResolveRequest(o: { project: string; gateId: string; message: string }) {\n const lower = o.message.toLowerCase().trim();\n const decision = lower.startsWith(\"approve\") ? \"approve\" : lower.startsWith(\"deny\") ? \"deny\" : undefined;\n return {\n kind: \"gate-resolve\" as const,\n project: o.project,\n gateId: o.gateId,\n resolvedBy: \"captain\",\n payload: { text: o.message, ...(decision ? { decision } : {}) },\n };\n}\n\nexport async function squadrantdCall(req: unknown): Promise<unknown> {\n try {\n return await sendRequest(SOCK, req);\n } catch {\n ensureDaemon(); // resolves its own entrypoint — never pass a path here\n // kickstart→socket is racy; bounded backoff. If all attempts fail,\n // throw the last error (fail loud, no scrape fallback).\n let lastErr: unknown;\n for (let i = 0; i < 3; i++) {\n try {\n return await sendRequest(SOCK, req);\n } catch (e) {\n lastErr = e;\n await new Promise((r) => setTimeout(r, 200));\n }\n }\n throw lastErr;\n }\n}\n\n/**\n * Build an explicit terminal/blocked event request from a crew's `signal`\n * verb. Defaults to reading `SQUADRANT_CREW_TASK_ID` and `SQUADRANT_CREW_PROJECT`\n * from env so the claude/opencode crew templates can run e.g.\n * `squadrant crew signal done --message \"…\"` without knowing their own ids.\n *\n * Explicit `taskId`/`project` (from `--task-id`/`--project` flags) take\n * precedence over env. This is the codex path: a single long-lived app-server\n * child serves all codex tasks as threads, so a process-level env var is\n * unsafe (wrong for concurrent tasks). The codex crew is told its concrete ids\n * via per-thread developerInstructions and signals with the explicit flags.\n *\n * Anti-#2576 invariant lives at the OTHER end (the hook bridge in\n * `_hook`). This builder is the *explicit* path: a crew running this verb\n * has *intentionally* declared terminal state after its own settle-check.\n */\nexport function buildSignalRequest(\n signal: \"done\" | \"blocked\" | \"failed\",\n o: {\n message?: string;\n question?: string;\n error?: string;\n /** Explicit override (codex); falls back to SQUADRANT_CREW_TASK_ID env. */\n taskId?: string;\n /** Explicit override (codex); falls back to SQUADRANT_CREW_PROJECT env. */\n project?: string;\n /** Injectable for tests; defaults to writing under ~/.config/squadrant/state/_results. */\n writeResult?: (id: string, payload: string) => string;\n },\n): { kind: \"event\"; project: string; event: ControlEvent } {\n const taskId = o.taskId ?? process.env.SQUADRANT_CREW_TASK_ID;\n const project = o.project ?? process.env.SQUADRANT_CREW_PROJECT;\n if (!taskId)\n throw new Error(\"not running under a crew (SQUADRANT_CREW_TASK_ID unset)\");\n if (!project)\n throw new Error(\"not running under a crew (SQUADRANT_CREW_PROJECT unset)\");\n let event: ControlEvent;\n if (signal === \"done\") {\n const resultRef = o.writeResult ? o.writeResult(taskId, o.message ?? \"\") : \"\";\n event = {\n type: \"task.done\",\n id: taskId,\n resultRef,\n ...(o.message !== undefined ? { message: o.message } : {}),\n };\n } else if (signal === \"blocked\") {\n event = { type: \"task.blocked\", id: taskId, reason: \"crew signaled blocked\", question: o.question ?? \"\" };\n } else {\n event = { type: \"task.failed\", id: taskId, error: o.error ?? \"crew signaled failed\" };\n }\n return { kind: \"event\", project, event };\n}\n\n/** Default writer used by the `signal done` subcommand. Tests inject their own. */\nfunction defaultWriteResult(id: string, payload: string): string {\n const dir = join(homedir(), \".config\", \"squadrant\", \"state\", \"_results\");\n mkdirSync(dir, { recursive: true });\n const file = join(dir, `${id}.txt`);\n writeFileSync(file, payload);\n return file;\n}\n\n/**\n * Attach the control-plane verbs onto an existing `squadrant crew` command so\n * they coexist with the legacy cmux-scrape verbs (spawn/send/read/close/list).\n * The control-plane task listing is `tasks` (not `list`) to avoid colliding\n * with the legacy `list` that captains' playbook still uses. This is the\n * deferred-legacy coexistence state — wired so PR #85 does not break live\n * captains. Migrating captain-ops to the control-plane verbs is the deferred\n * legacy-re-pointing spec's job.\n */\nexport function addControlPlaneCrewCommands(crew: Command): void {\n crew\n .command(\"dispatch <project> <task>\")\n .description(\"Dispatch a crew task via the control-plane daemon\")\n .requiredOption(\"--provider <p>\", \"claude|opencode|codex (gemini: experimental, headless not supported)\")\n .option(\"--mode <m>\", \"headless|interactive\", \"interactive\")\n .option(\"--cwd <dir>\", \"working dir for the crew (project/worktree); required for codex to edit code\")\n .action(async (project: string, task: string, opts: { provider: Provider; mode: Mode; cwd?: string }) => {\n const req = buildDispatchRequest({ project, task, provider: opts.provider, mode: opts.mode, cwd: opts.cwd });\n const r = await squadrantdCall(req);\n process.stdout.write(JSON.stringify(r) + \"\\n\");\n });\n\n crew\n .command(\"status <project> <id>\")\n .description(\"Read a control-plane task's state\")\n .action(async (project: string, id: string) => {\n const r = await squadrantdCall(buildStatusRequest(project, id));\n process.stdout.write(JSON.stringify(r) + \"\\n\");\n });\n\n crew\n .command(\"tasks <project>\")\n .description(\"List control-plane tasks for a project (control-plane analogue of legacy `list`), or purge a task with --purge\")\n .option(\"--json\", \"Full JSON output (one or more records)\")\n .option(\"--id <taskId>\", \"Show only tasks matching this id prefix\")\n .option(\"--state <state>\", \"Filter by task state\")\n .option(\"--state-only <taskId>\", \"Print just the state string for a single task\")\n .option(\"--purge <taskId>\", \"Purge a task record from the store (default: only terminal records)\")\n .option(\"--force\", \"Force-purge a non-terminal record (use with --purge)\")\n .action(async (project: string, opts: { json?: boolean; id?: string; state?: string; stateOnly?: string; purge?: string; force?: boolean }) => {\n if (opts.purge) {\n const r = await squadrantdCall({ kind: \"purge\", project, id: opts.purge, force: opts.force ?? false }) as TaskRecord;\n console.log(`purged ${r.provider}/${r.id} (was ${r.state})`);\n return;\n }\n const raw = (await squadrantdCall({ kind: \"list\", project })) as TaskRecord[];\n let records = raw;\n if (opts.stateOnly) {\n records = filterTasks(records, { id: opts.stateOnly, stateOnly: true });\n process.stdout.write(formatCompactTasks(records, { stateOnly: true }) + \"\\n\");\n return;\n }\n records = filterTasks(records, { id: opts.id, state: opts.state });\n const compact = opts.json !== true;\n process.stdout.write(formatCompactTasks(records, { compact }) + \"\\n\");\n });\n\n // TODO(downstream interactive-wiring spec): deliverReply is not yet wired in\n // squadrantd, so this transitions task state but never reaches the agent. Deferred.\n // --gate <gateId> routes through the gate-resolve verb instead (spec §4.9).\n crew\n .command(\"reply <project> <id> <message>\")\n .description(\"Reply to a blocked control-plane task (delivery deferred), or resolve a gate via --gate\")\n .option(\"--gate <gateId>\", \"resolve a pending gate by id (codex interactive, spec §4.9)\")\n .action(async (project: string, id: string, message: string, opts: { gate?: string }) => {\n if (opts.gate) {\n const r = await squadrantdCall(buildGateResolveRequest({ project, gateId: opts.gate, message }));\n process.stdout.write(JSON.stringify(r) + \"\\n\");\n return;\n }\n process.stderr.write(\"reply delivery is not yet wired (deferred); state transitioned only\\n\");\n const r = await squadrantdCall({ kind: \"reply\", project, id, message });\n process.stdout.write(JSON.stringify(r) + \"\\n\");\n });\n\n // Bridge from Claude's native Stop/SubagentStop/SessionEnd hooks to the\n // squadrant control plane. Reads hook payload JSON on stdin (Claude hook\n // contract); env-gated on SQUADRANT_CREW_TASK_ID/SQUADRANT_CREW_PROJECT so the\n // hook is a no-op outside spawned crews. Anti-#2576: maps only to\n // task.progress (liveness), never task.done — terminal state comes from\n // `squadrant crew signal` (explicit, post-settle-check).\n crew\n .command(\"_hook <event>\", { hidden: true })\n .description(\"internal: bridge from claude Stop/SubagentStop/SessionEnd hooks to squadrantd\")\n .action(async (event: string) => {\n const taskId = process.env.SQUADRANT_CREW_TASK_ID;\n const project = process.env.SQUADRANT_CREW_PROJECT;\n if (!taskId || !project) { process.exit(0); }\n // Drain stdin (Claude posts hook JSON there). Tolerate missing/malformed.\n let stdin = \"\";\n try {\n for await (const chunk of process.stdin) stdin += chunk;\n } catch { /* ignore */ }\n let payload: unknown = undefined;\n if (stdin.trim()) {\n try { payload = JSON.parse(stdin); } catch { /* ignore malformed */ }\n }\n const ev = mapClaudeHookToEvent(event, payload, taskId);\n if (!ev) { process.exit(0); }\n try {\n await squadrantdCall({ kind: \"event\", project, event: ev });\n } catch {\n // Daemon down: do NOT block Claude. Hook contract requires exit 0;\n // a non-zero exit would block the conversation.\n }\n process.exit(0);\n });\n\n // The explicit done/blocked/failed signal — the anti-#2576 escape from\n // liveness-only Stop hooks. The crew runs this AFTER its own settle-check\n // (git status clean, etc.) to declare terminal state to the captain.\n crew\n .command(\"signal <state>\")\n .description(\"Emit explicit terminal signal from a crew session: done|blocked|failed (reads SQUADRANT_CREW_* env, or --task-id/--project for codex)\")\n .option(\"--message <m>\", \"Summary written to resultRef (done)\")\n .option(\"--question <q>\", \"Question to surface to captain (blocked)\")\n .option(\"--error <e>\", \"Error message (failed)\")\n .option(\"--task-id <id>\", \"Explicit task id (codex; overrides SQUADRANT_CREW_TASK_ID env)\")\n .option(\"--project <p>\", \"Explicit project (codex; overrides SQUADRANT_CREW_PROJECT env)\")\n .action(async (state: string, opts: { message?: string; question?: string; error?: string; taskId?: string; project?: string }) => {\n if (state !== \"done\" && state !== \"blocked\" && state !== \"failed\") {\n process.stderr.write(`unknown signal '${state}' (expected: done|blocked|failed)\\n`);\n process.exit(2);\n }\n try {\n const req = buildSignalRequest(state as \"done\" | \"blocked\" | \"failed\", {\n ...(opts.message !== undefined ? { message: opts.message } : {}),\n ...(opts.question !== undefined ? { question: opts.question } : {}),\n ...(opts.error !== undefined ? { error: opts.error } : {}),\n ...(opts.taskId !== undefined ? { taskId: opts.taskId } : {}),\n ...(opts.project !== undefined ? { project: opts.project } : {}),\n writeResult: defaultWriteResult,\n });\n await squadrantdCall(req);\n process.exit(0);\n } catch (e) {\n process.stderr.write(`${(e as Error).message}\\n`);\n process.exit(1);\n }\n });\n\n crew.addCommand(crewAttachCommand);\n crew.addCommand(crewChatCommand);\n}\n\n// Standalone control-plane-only command (kept for back-compat / direct use;\n// the CLI composes these onto the legacy `crew` command via the function above).\nexport const crewControlCommand = new Command(\"crew\")\n .description(\"Dispatch and track crew via the squadrant control plane\");\naddControlPlaneCrewCommands(crewControlCommand);\n","import type { TaskRecord } from \"@squadrant/shared\";\n\nexport function tailLines(\n text: string,\n maxLines = 40,\n maxBytes = 4096,\n): string {\n if (!text) return \"\";\n const lines = text.split(\"\\n\");\n if (lines.at(-1) === \"\") lines.pop();\n const kept = lines.slice(-maxLines);\n let result = kept.join(\"\\n\");\n if (Buffer.byteLength(result, \"utf-8\") > maxBytes) {\n const truncated: string[] = [];\n let bytes = 0;\n for (const line of kept) {\n const lineBytes = Buffer.byteLength(line, \"utf-8\") + 1;\n if (bytes + lineBytes > maxBytes) break;\n truncated.push(line);\n bytes += lineBytes;\n }\n result = truncated.join(\"\\n\");\n }\n return result;\n}\n\nfunction shortId(id: string): string {\n return id.slice(0, 8);\n}\n\nexport function formatTaskLine(record: TaskRecord): string {\n const sid = shortId(record.id);\n const title = record.task\n .split(\"\\n\")[0]\n .slice(0, 60);\n return `${sid} ${record.provider} ${record.state} ${record.lastEvent} ${title}`;\n}\n\nexport function filterTasks(\n records: TaskRecord[],\n opts: { id?: string; state?: string; stateOnly?: boolean },\n): TaskRecord[] {\n let filtered = records;\n if (opts.id) {\n filtered = filtered.filter((r) => r.id.startsWith(opts.id!));\n }\n if (opts.state) {\n filtered = filtered.filter((r) => r.state === opts.state);\n }\n return filtered;\n}\n\nexport function formatCompactTasks(\n records: TaskRecord[],\n opts: { compact?: boolean; stateOnly?: boolean },\n): string {\n if (records.length === 0) {\n return \"(no tasks match filter)\";\n }\n if (opts.stateOnly) {\n return records[0].state;\n }\n if (opts.compact === false) {\n return JSON.stringify(records, null, 2);\n }\n return records.map(formatTaskLine).join(\"\\n\");\n}\n","// src/commands/crew-attach.ts\nimport { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport { createConnection } from \"node:net\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { createInterface } from \"node:readline\";\nimport { decodeFrames, type AttachFrame, type AttachInbound } from \"@squadrant/core\";\n\nfunction socketPath(): string {\n return process.env.SQUADRANTD_SOCK ?? join(homedir(), \".config\", \"squadrant\", \"squadrant.sock\");\n}\n\n// --- Pure formatters (exported for tests) ---\n\nconst ANSI_RE = /\\x1b\\[[0-9;]*m/g;\n\nexport function stripAnsi(s: string): string {\n return s.replace(ANSI_RE, \"\");\n}\n\nfunction rule(width: number, ch = \"─\"): string {\n return ch.repeat(Math.max(0, width));\n}\n\nexport function formatTurnHeader(turn: number, width = 60): string {\n const label = ` codex · turn ${turn} `;\n const remaining = Math.max(2, width - label.length - 2);\n const left = \"╭─\";\n const right = rule(remaining) + \"╮\";\n return chalk.cyan.bold(left) + chalk.cyan.bold(label) + chalk.cyan(right);\n}\n\nexport function formatTurnFooter(elapsedMs: number, width = 60): string {\n const secs = (elapsedMs / 1000).toFixed(1);\n const label = ` done · ${secs}s `;\n const remaining = Math.max(2, width - label.length - 2);\n const left = \"╰─\";\n const right = rule(remaining) + \"╯\";\n return chalk.dim(left + label + right);\n}\n\nexport type RendererState = \"idle\" | \"working\" | \"awaiting-input\" | \"blocked\";\n\nexport function formatStatus(state: RendererState, turn: number, elapsedMs: number): string {\n const secs = (elapsedMs / 1000).toFixed(1);\n return chalk.dim(` · state=${state} turn=${turn} elapsed=${secs}s`);\n}\n\nexport function formatApproval(kind: string, question: string): string {\n return chalk.yellow.bold(`[approval] ${kind}`) + chalk.yellow(`: ${question}`);\n}\n\nexport function formatApprovalPrompt(): string {\n return chalk.yellow(\"[approve/deny]> \");\n}\n\nexport function formatInputQuestion(question: string): string {\n return chalk.cyan.bold(\"[codex asks] \") + question;\n}\n\nexport function formatInputPrompt(): string {\n return chalk.cyan(\"[answer]> \");\n}\n\nexport function formatDoneFollowup(): string {\n return chalk.dim(\"[done — type a follow-up or Ctrl-C]\");\n}\n\nexport function formatAttached(): string {\n return chalk.dim(\"(attached)\");\n}\n\nexport function formatReattached(): string {\n return chalk.dim(\"(reattached)\");\n}\n\nexport function formatClosed(reason: string): string {\n return chalk.dim(`(closed: ${reason})`);\n}\n\nexport function formatConnectionClosed(): string {\n return chalk.dim(\"(connection closed)\");\n}\n\nexport function formatConnectionLost(): string {\n return chalk.dim(\"(connection lost — retrying...)\");\n}\n\nexport function formatReattachFailed(taskId: string): string {\n return chalk.red(`(reattach failed — re-run: squadrant crew attach ${taskId})`);\n}\n\nexport function formatGatePromoted(gateId: string): string {\n return chalk.dim(`(no client was attached; question promoted to gate ${gateId})`);\n}\n\n// --- Retry/backoff pure logic (exported for tests) ---\n\n/** Minimum elapsed ms on a connection before it's considered stable (no-frame path). */\nexport const STABLE_MS = 5_000;\n\n/** Total retry budget per disconnect episode before giving up. */\nexport const RETRY_BUDGET_MS = 60_000;\n\n/**\n * Exponential backoff delay for reconnect attempt N (0-indexed).\n * Caps at 16s to bound the per-attempt wait.\n */\nexport function computeBackoffDelay(attempt: number): number {\n return Math.min(1000 * Math.pow(2, attempt), 16_000);\n}\n\n/**\n * Returns true if the connection should be considered \"stable\" —\n * meaning backoff should reset on the next disconnect.\n * Stable = received >=1 real frame OR survived >= STABLE_MS.\n */\nexport function isConnectionStable(\n connectTimeMs: number,\n framesReceived: number,\n nowMs: number\n): boolean {\n return connectTimeMs > 0 && (framesReceived > 0 || nowMs - connectTimeMs >= STABLE_MS);\n}\n\n// --- CLI command ---\n\nexport const crewAttachCommand = new Command(\"attach\")\n .description(\"Attach to a live interactive task (renders deltas; takes follow-ups). Spec §4.6.\")\n .argument(\"<taskId>\", \"task id to attach to\")\n .action((taskId: string) => {\n // --- Retry state (persists across reconnects) ---\n let attempt = 0; // 0-indexed; grows on unstable disconnect, resets on stable\n let totalSpentMs = 0; // cumulative backoff spent this episode; resets on stable\n let retryLogged = false; // dedup: print \"connection lost\" once per episode\n\n // --- Per-connection state (reset each connect()) ---\n let connectTimeMs = 0;\n let framesReceived = 0;\n let taskClosed = false;\n let disconnecting = false;\n\n // Mutable send ref — updated on each new connection so readline/SIGINT always\n // writes to the current socket. Noop during backoff gaps.\n let send: (m: AttachInbound) => void = () => {};\n\n // --- Renderer state (persists across reconnects) ---\n let pendingRequestId: number | undefined;\n let turnCount = 0;\n let turnStartMs = 0;\n let inTurn = false;\n let state: RendererState = \"idle\";\n let attachedOnce = false;\n\n const elapsed = () => (turnStartMs ? Date.now() - turnStartMs : 0);\n const writeStatus = () => process.stdout.write(formatStatus(state, turnCount, elapsed()) + \"\\n\");\n\n let buf = \"\";\n\n function handleDisconnect(errorMsg?: string): void {\n if (disconnecting) return; // guard: error fires before close in Node.js\n disconnecting = true;\n send = () => {}; // noop until next connect()\n\n if (errorMsg) {\n process.stderr.write(`\\n${chalk.red(`(socket error: ${errorMsg})`)}\\n`);\n }\n\n if (taskClosed) {\n // Task ended cleanly via \"closed\" frame — no retry needed.\n process.stderr.write(\"\\n\" + formatConnectionClosed() + \"\\n\");\n process.exit(0);\n return;\n }\n\n const stable = isConnectionStable(connectTimeMs, framesReceived, Date.now());\n\n if (stable) {\n // New episode: the lost connection was healthy, so reset budget and backoff.\n attempt = 0;\n totalSpentMs = 0;\n retryLogged = false;\n }\n\n if (!retryLogged) {\n process.stderr.write(\"\\n\" + formatConnectionLost() + \"\\n\");\n retryLogged = true;\n }\n\n const delay = computeBackoffDelay(attempt);\n if (!stable) attempt += 1; // grow backoff only on unstable; stable already reset to 0\n\n totalSpentMs += delay;\n if (totalSpentMs > RETRY_BUDGET_MS) {\n process.stderr.write(formatReattachFailed(taskId) + \"\\n\");\n process.exit(1);\n return;\n }\n\n setTimeout(connect, delay);\n }\n\n function connect(): void {\n connectTimeMs = 0;\n framesReceived = 0;\n taskClosed = false;\n disconnecting = false;\n buf = \"\";\n\n const conn = createConnection(socketPath());\n send = (m: AttachInbound) => conn.write(JSON.stringify(m) + \"\\n\");\n\n conn.on(\"connect\", () => {\n connectTimeMs = Date.now();\n send({ op: \"attach\", taskId });\n });\n\n conn.on(\"data\", (chunk) => {\n buf += chunk.toString();\n const lastNl = buf.lastIndexOf(\"\\n\");\n if (lastNl < 0) return;\n const consumable = buf.slice(0, lastNl + 1);\n buf = buf.slice(lastNl + 1);\n for (const f of decodeFrames(consumable)) render(f);\n });\n\n conn.on(\"close\", () => handleDisconnect());\n conn.on(\"error\", (e) => handleDisconnect(e.message));\n }\n\n function render(f: AttachFrame): void {\n switch (f.type) {\n case \"delta\":\n framesReceived += 1;\n process.stdout.write(f.text);\n break;\n case \"turn-started\":\n framesReceived += 1;\n turnCount += 1;\n turnStartMs = Date.now();\n inTurn = true;\n state = \"working\";\n process.stdout.write(\"\\n\" + formatTurnHeader(turnCount) + \"\\n\");\n writeStatus();\n break;\n case \"turn-completed\":\n framesReceived += 1;\n process.stdout.write(\"\\n\" + formatTurnFooter(elapsed()) + \"\\n\");\n state = \"idle\";\n inTurn = false;\n process.stdout.write(formatDoneFollowup() + \"\\n> \");\n break;\n case \"input-requested\":\n framesReceived += 1;\n pendingRequestId = f.requestId;\n state = \"awaiting-input\";\n process.stdout.write(\"\\n\" + formatInputQuestion(f.question) + \"\\n\" + formatInputPrompt());\n break;\n case \"approval-requested\":\n framesReceived += 1;\n pendingRequestId = f.requestId;\n state = \"blocked\";\n process.stdout.write(\"\\n\" + formatApproval(f.kind, f.question) + \"\\n\" + formatApprovalPrompt());\n break;\n case \"gate-promoted\":\n framesReceived += 1;\n process.stdout.write(\"\\n\" + formatGatePromoted(f.gateId) + \"\\n> \");\n break;\n case \"reattached\":\n framesReceived += 1;\n process.stdout.write(\"\\n\" + (attachedOnce ? formatReattached() : formatAttached()) + \"\\n> \");\n attachedOnce = true;\n break;\n case \"closed\":\n taskClosed = true;\n process.stdout.write(\"\\n\" + formatClosed(f.reason) + \"\\n\");\n break;\n case \"_keepalive\":\n break;\n }\n }\n\n connect();\n\n const rl = createInterface({ input: process.stdin, terminal: false });\n rl.on(\"line\", (text) => {\n if (pendingRequestId != null) {\n const lower = text.toLowerCase();\n const decision = lower.startsWith(\"approve\") ? \"approve\" : lower.startsWith(\"deny\") ? \"deny\" : undefined;\n send({ op: \"answer\", taskId, requestId: pendingRequestId, payload: { text, decision } });\n pendingRequestId = undefined;\n if (state === \"awaiting-input\" || state === \"blocked\") state = \"working\";\n } else {\n send({ op: \"say\", taskId, text });\n }\n });\n process.on(\"SIGINT\", () => send({ op: \"interrupt\", taskId }));\n });\n","// src/commands/crew-chat.ts\n// DEPRECATED alias for `squadrant crew spawn --agent codex`. Kept so external\n// callers don't break; prints a warning and delegates to runCrewSpawn so the\n// session opens as a tab in the captain (same UX as `--agent claude`).\nimport { Command } from \"commander\";\nimport { runCrewSpawn } from \"./crew.js\";\n\nexport const crewChatCommand = new Command(\"chat\")\n .description(\"[DEPRECATED] alias for `squadrant crew spawn <project> '(interactive)' --agent codex`.\")\n .requiredOption(\"--provider <p>\", \"provider (codex only today)\")\n .requiredOption(\"--project <name>\", \"project name\")\n .option(\"--cwd <dir>\", \"(ignored; project cwd is used)\", process.cwd())\n .option(\"--model <m>\", \"(unused; reserved for future codex model routing)\")\n .option(\n \"--approval\",\n \"force codex approvalPolicy='untrusted' so tool/shell calls request approval\",\n false\n )\n .action(async (opts: { provider: string; project: string; cwd: string; model?: string; approval: boolean }) => {\n process.stderr.write(\n \"⚠️ `squadrant crew chat --provider codex` is deprecated. \" +\n \"Use: squadrant crew spawn <project> '(interactive)' --agent codex\" +\n (opts.approval ? \" --approval\" : \"\") +\n \"\\n\"\n );\n if (opts.provider !== \"codex\") {\n throw new Error(`crew chat is implemented for provider=codex only (got '${opts.provider}')`);\n }\n const pane = await runCrewSpawn({\n project: opts.project,\n task: \"(interactive)\",\n agent: \"codex\",\n ...(opts.approval ? { approvalPolicy: \"untrusted\" } : {}),\n });\n process.stdout.write(`Crew '${pane.title}' spawned (${pane.surfaceId})\\n`);\n });\n","import { mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { mergeClaudeHooks } from \"@squadrant/agents\";\n\n/**\n * Bash permission allowlist for crews running under `--permission-mode\n * acceptEdits` (Phase 2a). acceptEdits auto-accepts file edits but still\n * prompts on EVERY shell command. Without this, the Phase 2b pane probe fires\n * CREW BLOCKED on every commit/install/test/grep = notification spam.\n *\n * Conservative by design: two tiers —\n * 1. Read-only inspection (ps, ls, grep, jq, …) — never mutates anything.\n * 2. Safe-but-mutating dev ops (git commit, npm install, vitest, …) — needed\n * for normal crew work; scoped to safe subcommands.\n * Genuinely risky ops (`git reset --hard`, `git config`, `rm`, `curl`, `wget`,\n * `sudo`, `kill`, unknown binaries, out-of-workspace writes) STILL prompt and\n * surface as CREW BLOCKED. No blanket `Bash(*)`.\n *\n * Syntax: `Bash(<prefix>:*)` allows any command whose text starts with\n * <prefix>. Patterns match the raw command string — NOT the resolved binary.\n *\n * Known limitation: commands with a leading env-var assignment\n * (e.g. `SQUADRANT_CREW_TASK_ID=x sleep 5`) still prompt because the line\n * starts with the variable name, not the command. This is rare and acceptable;\n * it's not a bug.\n */\nexport const CREW_PERMISSION_ALLOWLIST: readonly string[] = [\n // git — read + safe mutations (reset/clean/config intentionally excluded)\n \"Bash(git status:*)\",\n \"Bash(git add:*)\",\n \"Bash(git commit:*)\",\n \"Bash(git push:*)\",\n \"Bash(git pull:*)\",\n \"Bash(git fetch:*)\",\n \"Bash(git checkout:*)\",\n \"Bash(git branch:*)\",\n \"Bash(git diff:*)\",\n \"Bash(git log:*)\",\n \"Bash(git stash:*)\",\n \"Bash(git restore:*)\",\n // git — read-only queries (no-mutation subcommands)\n \"Bash(git show:*)\",\n \"Bash(git rev-parse:*)\",\n \"Bash(git remote -v:*)\",\n \"Bash(git stash list:*)\",\n // npm / npx — installs + script/test/build runners\n \"Bash(npm install:*)\",\n \"Bash(npm ci:*)\",\n \"Bash(npm run:*)\",\n \"Bash(npm test:*)\",\n \"Bash(npm ls:*)\",\n \"Bash(npm view:*)\",\n \"Bash(npx vitest:*)\",\n \"Bash(npx tsc:*)\",\n // direct runners\n \"Bash(node:*)\",\n \"Bash(node --version:*)\",\n \"Bash(vitest:*)\",\n \"Bash(tsc:*)\",\n // pnpm\n \"Bash(pnpm ls:*)\",\n // process / system read — non-interactive, read-only\n \"Bash(ps:*)\",\n \"Bash(pgrep:*)\",\n \"Bash(lsof:*)\",\n \"Bash(top -l:*)\",\n \"Bash(uptime:*)\",\n \"Bash(whoami:*)\",\n \"Bash(uname:*)\",\n \"Bash(date:*)\",\n \"Bash(env:*)\",\n \"Bash(sysctl:*)\",\n // file read / navigation\n \"Bash(ls:*)\",\n \"Bash(cat:*)\",\n \"Bash(head:*)\",\n \"Bash(tail:*)\",\n \"Bash(wc:*)\",\n \"Bash(grep:*)\",\n \"Bash(rg:*)\",\n \"Bash(find:*)\",\n \"Bash(pwd:*)\",\n \"Bash(stat:*)\",\n \"Bash(file:*)\",\n \"Bash(realpath:*)\",\n \"Bash(basename:*)\",\n \"Bash(dirname:*)\",\n \"Bash(du:*)\",\n \"Bash(df:*)\",\n \"Bash(tree:*)\",\n // read-only text processing\n \"Bash(sort:*)\",\n \"Bash(uniq:*)\",\n \"Bash(cut:*)\",\n \"Bash(tr:*)\",\n \"Bash(jq:*)\",\n \"Bash(diff:*)\",\n \"Bash(column:*)\",\n // harmless utilities\n \"Bash(echo:*)\",\n \"Bash(which:*)\",\n \"Bash(true:*)\",\n \"Bash(sleep:*)\",\n \"Bash(printf:*)\",\n];\n\n/**\n * Pure: merge the crew permission allowlist into a settings object's\n * `permissions.allow`, de-duplicating and preserving any existing entries and\n * sibling permission keys (deny/ask). Never mutates the input.\n */\nexport function mergeCrewPermissions(settings: Record<string, unknown>): Record<string, unknown> {\n const next = structuredClone(settings ?? {});\n const permissions = (next.permissions ??= {}) as { allow?: unknown };\n const existing = Array.isArray(permissions.allow) ? (permissions.allow as string[]) : [];\n permissions.allow = [...new Set([...existing, ...CREW_PERMISSION_ALLOWLIST])];\n return next;\n}\n\n/**\n * Write a Claude `--settings`-compatible JSON file containing the squadrant\n * Stop/SubagentStop/SessionEnd hooks merged onto an empty base. Per-crew\n * scoping (one file per spawned task) keeps the hook out of the user's\n * global `~/.claude/settings.json` — captain/command Claude sessions are\n * untouched. Returns the absolute path to the written file.\n */\nexport function writePerCrewSettings(o: {\n stateRoot: string;\n project: string;\n taskId: string;\n hookCmd?: string;\n}): string {\n const dir = join(o.stateRoot, o.project, o.taskId);\n mkdirSync(dir, { recursive: true });\n const file = join(dir, \"settings.json\");\n const merged = mergeClaudeHooks({}, o.hookCmd ?? \"squadrant crew _hook\");\n writeFileSync(file, JSON.stringify(merged, null, 2));\n return file;\n}\n\n/**\n * Write squadrant hooks into `<projectCwd>/.claude/settings.local.json` so they\n * are auto-loaded by Claude Code as a project-local settings source (level 3\n * in the precedence hierarchy). Unlike the per-crew settings.json passed via\n * `--settings` (level 2), this auto-loaded file merges with the cmux wrapper's\n * `--settings` hooks rather than being overwritten by them (#134).\n *\n * Merges with any existing `.claude/settings.local.json` — does not clobber\n * the user's own personal hooks or permissions. Returns the absolute path.\n */\nexport function writePerCrewSettingsLocal(o: {\n projectCwd: string;\n hookCmd?: string;\n}): string {\n const dir = join(o.projectCwd, \".claude\");\n mkdirSync(dir, { recursive: true });\n const file = join(dir, \"settings.local.json\");\n let existing: Record<string, unknown> = {};\n try {\n const raw = readFileSync(file, \"utf-8\");\n existing = JSON.parse(raw);\n } catch {\n // File doesn't exist or isn't valid JSON — start fresh\n }\n const withHooks = mergeClaudeHooks(existing, o.hookCmd ?? \"squadrant crew _hook\");\n const merged = mergeCrewPermissions(withHooks);\n writeFileSync(file, JSON.stringify(merged, null, 2));\n return file;\n}\n\n/**\n * Write an opencode config file that auto-approves edit/bash/webfetch so\n * squadrant-spawned opencode crews never block on a manual permission prompt.\n * OPENCODE_CONFIG merges with (does not replace) the global config, so only\n * the permission block is needed — model/plugin/mcp flow through from\n * ~/.config/opencode/opencode.json automatically.\n *\n * Returns the absolute path to the written file.\n *\n * CP3 opt-in: with `gateBash`, bash flips to \"ask\" so the captain approves\n * shell commands (opencode emits `permission.asked` → daemon surfaces CREW\n * BLOCKED → captain's decision is POSTed back). Default (no flag) keeps bash\n * \"allow\" — opencode crews stay fully autonomous unless `--approval` is passed.\n */\nexport function writePerCrewOpencodeConfig(o: {\n stateRoot: string;\n project: string;\n taskId: string;\n gateBash?: boolean;\n}): string {\n const dir = join(o.stateRoot, o.project, o.taskId);\n mkdirSync(dir, { recursive: true });\n const file = join(dir, \"opencode.json\");\n const config = {\n permission: {\n read: \"allow\",\n edit: \"allow\",\n glob: \"allow\",\n grep: \"allow\",\n bash: o.gateBash ? \"ask\" : \"allow\",\n webfetch: \"allow\",\n websearch: \"allow\",\n task: \"allow\",\n lsp: \"allow\",\n external_directory: { \"**\": \"allow\" },\n },\n };\n writeFileSync(file, JSON.stringify(config, null, 2));\n return file;\n}\n","import { Command } from \"commander\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport os from \"node:os\";\nimport chalk from \"chalk\";\nimport { loadConfig } from \"@squadrant/shared\";\nimport { createCmuxDriver, RuntimeRegistry } from \"@squadrant/workspaces\";\nimport type { PaneRef, PanePlacement } from \"@squadrant/workspaces\";\nimport {\n createClaudeDriver,\n createCodexDriver,\n createGeminiDriver,\n createOpencodeDriver,\n CapabilityRegistry,\n} from \"@squadrant/agents\";\nimport { resolveCaptainWorkspace, sendFirstTurnWhenReady } from \"@squadrant/workspaces\";\nimport { resolveTextInput } from \"@squadrant/shared\";\nimport { addWorktree, removeWorktree, worktreePath, resolveWorktreeBase } from \"@squadrant/shared\";\n\nconst TEMPLATES_DIR = path.join(os.homedir(), \".config\", \"squadrant\", \"templates\");\n\n// Base branch derived at spawn time from origin/HEAD (#359).\n\nconst SIDE_ROLES = [\"research\", \"debug\"] as const;\ntype SideRole = (typeof SIDE_ROLES)[number];\n\n// POSIX single-quote a path so it is safe to embed in a shell command even\n// when the path contains spaces or special characters.\nfunction shellQuote(p: string): string {\n return \"'\" + p.replace(/'/g, \"'\\\\''\") + \"'\";\n}\n\nfunction titleFor(project: string, name: string): string {\n return `🗒 ${project}:${name}`;\n}\n\nfunction isSideTitle(project: string, title: string): boolean {\n return title.startsWith(`🗒 ${project}:`);\n}\n\nfunction nameFromTitle(project: string, title: string): string {\n return title.slice(`🗒 ${project}:`.length);\n}\n\nfunction nextAutoName(existingTitles: string[], project: string): string {\n const used = new Set<number>();\n for (const title of existingTitles) {\n const n = nameFromTitle(project, title).match(/^side-(\\d+)$/);\n if (n) used.add(Number(n[1]));\n }\n let i = 1;\n while (used.has(i)) i++;\n return `side-${i}`;\n}\n\n/** Builds the first-turn message: topic + injected context the agent needs\n * for handoff (spokeVault, project, role). For debug sessions, scratchWorktree\n * is the isolated worktree path the session is running in. */\nexport function buildSideFirstTurn(\n topic: string,\n project: string,\n role: string,\n spokeVault: string,\n scratchWorktree?: string,\n): string {\n const lines = [\n topic,\n \"\",\n \"---\",\n \"Side-session context (for handoff use):\",\n `Project: ${project}`,\n `Role: ${role}`,\n `Spoke vault: ${spokeVault}`,\n ];\n if (scratchWorktree) {\n lines.push(`Scratch worktree: ${scratchWorktree}`);\n }\n return lines.join(\"\\n\");\n}\n\nexport interface SideSpawnInput {\n project: string;\n topic: string;\n role: string;\n name?: string;\n direction?: PanePlacement;\n agent?: string;\n}\n\nexport async function runSideSpawn(input: SideSpawnInput): Promise<PaneRef> {\n const config = loadConfig();\n const proj = config.projects[input.project];\n if (!proj) {\n throw new Error(`Project '${input.project}' not found. Run 'squadrant projects list'.`);\n }\n\n if (!SIDE_ROLES.includes(input.role as SideRole)) {\n throw new Error(\n `Unknown side role '${input.role}'. Valid roles: ${SIDE_ROLES.join(\", \")}.`,\n );\n }\n\n const runtime = new RuntimeRegistry({ cmux: createCmuxDriver() }).forProject(\n input.project,\n config,\n );\n const captain = await runtime.status(proj.captainName);\n if (!captain) {\n throw new Error(\n `Captain workspace '${proj.captainName}' is not running. Run 'squadrant launch ${input.project}' first.`,\n );\n }\n\n const existing = await runtime.listSurfaces(captain.id);\n const existingTitles = existing\n .filter((s) => s.title && isSideTitle(input.project, s.title))\n .map((s) => s.title!);\n\n if (input.name) {\n const wantTitle = titleFor(input.project, input.name);\n if (existingTitles.includes(wantTitle)) {\n throw new Error(\n `Side session '${input.name}' already exists for ${input.project}.`,\n );\n }\n }\n const name = input.name ?? nextAutoName(existingTitles, input.project);\n\n // Debug sessions run in an isolated scratch git worktree so instrumentation\n // edits never touch the captain's checkout. Research sessions share the root\n // checkout. The #279 fix (cd into spawnCwd before launching CLI) applies to both.\n const spawnCwd = input.role === \"debug\"\n ? addWorktree({\n repoRoot: proj.path,\n worktreeDir: config.defaults.worktreeDir ?? \".worktrees\",\n project: input.project,\n name,\n base: resolveWorktreeBase(proj.path),\n })\n : proj.path;\n\n const agents = new CapabilityRegistry({\n claude: createClaudeDriver(),\n codex: createCodexDriver(),\n gemini: createGeminiDriver(),\n opencode: createOpencodeDriver(),\n });\n const sideRole = config.defaults.roles?.side;\n const agentName = input.agent ?? sideRole?.agent ?? \"claude\";\n const agent = agents.get(agentName);\n if (!agent) {\n throw new Error(`Unknown agent '${agentName}'. Known: claude, codex, gemini, opencode.`);\n }\n\n const sideModel = sideRole?.model;\n const promptFile = path.join(\n TEMPLATES_DIR,\n `side.${input.role}.${agent.templateSuffix}.md`,\n );\n\n const direction: PanePlacement = input.direction ?? \"tab\";\n const title = titleFor(input.project, name);\n const pane = await runtime.newPane({ workspaceId: captain.id, direction, title });\n\n const cliCommand = agent.buildCommand({\n prompt: input.topic,\n workdir: spawnCwd,\n role: \"side\",\n promptFile: fs.existsSync(promptFile) ? promptFile : undefined,\n interactive: true,\n permissionMode: config.defaults.permissions?.crew ?? \"auto\",\n ...(sideModel ? { model: sideModel } : {}),\n });\n\n await runtime.sendToPane(pane, `cd ${shellQuote(spawnCwd)} && ${cliCommand}`);\n const preLaunchScreen = (await runtime.readPaneScreen(pane)) ?? \"\";\n\n const firstTurn = buildSideFirstTurn(\n input.topic,\n input.project,\n input.role,\n proj.spokeVault ?? \"\",\n input.role === \"debug\" ? spawnCwd : undefined,\n );\n await sendFirstTurnWhenReady(runtime, pane, firstTurn, preLaunchScreen);\n\n return { ...pane, title };\n}\n\nexport async function runSideSend(\n project: string,\n name: string,\n message: string,\n): Promise<void> {\n const { runtime, workspaceId } = await resolveCaptainWorkspace(project);\n const want = titleFor(project, name);\n const surfaces = await runtime.listSurfaces(workspaceId);\n const pane = surfaces.find((s) => s.title === want) ?? null;\n if (!pane) {\n throw new Error(\n `Side session '${name}' not found for ${project}. Run 'squadrant side list ${project}'.`,\n );\n }\n await runtime.sendToPane(pane, message);\n}\n\nexport async function runSideList(\n project: string,\n): Promise<Array<{ name: string; surfaceId: string }>> {\n const { runtime, workspaceId } = await resolveCaptainWorkspace(project);\n const surfaces = await runtime.listSurfaces(workspaceId);\n return surfaces\n .filter((s) => s.title && isSideTitle(project, s.title))\n .map((s) => ({\n name: nameFromTitle(project, s.title!),\n surfaceId: s.surfaceId,\n }));\n}\n\nexport async function runSideClose(project: string, name: string): Promise<void> {\n const config = loadConfig();\n const proj = config.projects[project];\n const { runtime, workspaceId } = await resolveCaptainWorkspace(project);\n const want = titleFor(project, name);\n const surfaces = await runtime.listSurfaces(workspaceId);\n const pane = surfaces.find((s) => s.title === want) ?? null;\n if (!pane) {\n throw new Error(\n `Side session '${name}' not found for ${project}. Run 'squadrant side list ${project}'.`,\n );\n }\n await runtime.closePane(pane);\n // Prune the scratch worktree if this was a debug session. Detection is\n // filesystem-based: debug spawns create a worktree at the deterministic path;\n // research spawns do not. If the path exists, remove it (best-effort).\n if (proj) {\n const wtPath = worktreePath(\n proj.path,\n config.defaults.worktreeDir ?? \".worktrees\",\n project,\n name,\n );\n if (fs.existsSync(wtPath)) {\n try {\n removeWorktree(proj.path, wtPath);\n } catch (e) {\n process.stderr.write(`(worktree remove failed: ${(e as Error).message})\\n`);\n }\n }\n }\n}\n\nexport const sideCommand = new Command(\"side\").description(\n \"Spawn and manage side-sessions (research/debug) — fresh-context tabs off the daemon lifecycle\",\n);\n\nsideCommand\n .command(\"spawn\")\n .description(\n \"Spawn a fresh-context side-session tab for research or debug (--role required)\",\n )\n .argument(\"<project>\", \"Project name (must be registered)\")\n .argument(\"[topic]\", \"Topic or question for the session (omit with --topic-file)\")\n .requiredOption(\"--role <role>\", \"Session role: research | debug\")\n .option(\"--name <name>\", \"Session name (default: auto-generated side-N)\")\n .option(\n \"--direction <dir>\",\n \"Placement: tab (default) or split direction (right|left|up|down)\",\n \"tab\",\n )\n .option(\"--agent <name>\", \"Agent CLI to use (claude|opencode)\", \"claude\")\n .option(\"--topic-file <path>\", \"Read topic from file instead of positional arg ('-' for stdin)\")\n .action(\n async (\n project: string,\n topic: string | undefined,\n opts: { role: string; name?: string; direction: PanePlacement; agent: string; topicFile?: string },\n ) => {\n try {\n const resolvedTopic = await resolveTextInput({\n positional: topic,\n filePath: opts.topicFile,\n label: \"topic\",\n });\n const pane = await runSideSpawn({\n project,\n topic: resolvedTopic,\n role: opts.role,\n name: opts.name,\n direction: opts.direction,\n agent: opts.agent,\n });\n console.log(chalk.green(`✔ Side session '${pane.title}' spawned (${pane.surfaceId})`));\n } catch (err) {\n console.error(chalk.red((err as Error).message));\n process.exit(1);\n }\n },\n );\n\nsideCommand\n .command(\"list\")\n .description(\"List live side-sessions for a project\")\n .argument(\"<project>\", \"Project name\")\n .action(async (project: string) => {\n try {\n const sessions = await runSideList(project);\n if (sessions.length === 0) {\n console.log(chalk.yellow(`No live side-sessions for ${project}.`));\n return;\n }\n for (const s of sessions) {\n console.log(` ${s.name} (${s.surfaceId})`);\n }\n } catch (err) {\n console.error(chalk.red((err as Error).message));\n process.exit(1);\n }\n });\n\nsideCommand\n .command(\"send\")\n .description(\"Send a follow-up message to an existing side-session\")\n .argument(\"<project>\", \"Project name\")\n .argument(\"<name>\", \"Session name (e.g. side-1)\")\n .argument(\"[message]\", \"Message to send (omit with --message-file)\")\n .option(\"--message-file <path>\", \"Read message from file ('-' for stdin)\")\n .action(\n async (\n project: string,\n name: string,\n message: string | undefined,\n opts: { messageFile?: string },\n ) => {\n try {\n const resolvedMessage = await resolveTextInput({\n positional: message,\n filePath: opts.messageFile,\n label: \"message\",\n });\n await runSideSend(project, name, resolvedMessage);\n console.log(chalk.green(`✔ Sent to ${project}:${name}`));\n } catch (err) {\n console.error(chalk.red((err as Error).message));\n process.exit(1);\n }\n },\n );\n\nsideCommand\n .command(\"close\")\n .description(\"Close a side-session (closes its tab)\")\n .argument(\"<project>\", \"Project name\")\n .argument(\"<name>\", \"Session name\")\n .action(async (project: string, name: string) => {\n try {\n await runSideClose(project, name);\n console.log(chalk.green(`✔ Closed ${project}:${name}`));\n } catch (err) {\n console.error(chalk.red((err as Error).message));\n process.exit(1);\n }\n });\n","import { Command } from \"commander\";\nimport { execSync } from \"node:child_process\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport chalk from \"chalk\";\nimport { loadConfig } from \"@squadrant/shared\";\nimport { createCmuxDriver, RuntimeRegistry } from \"@squadrant/workspaces\";\nimport type { PaneRef } from \"@squadrant/workspaces\";\nimport {\n readAllStatuses,\n renderDashboard,\n syncHub,\n startWebServer,\n defaultProbeRunners,\n} from \"@squadrant/web\";\nimport type { SyncHubResult } from \"@squadrant/web\";\nimport { squadrantdCall } from \"./crew-control.js\";\nimport { resolveCmuxBin } from \"@squadrant/shared\";\n\nconst SOCK = join(homedir(), \".config\", \"squadrant\", \"squadrant.sock\");\n\nfunction detectCurrentWorkspace(): string {\n const out = execSync(`\"${resolveCmuxBin()}\" current-workspace`, { encoding: \"utf-8\" }).trim();\n const match = out.match(/workspace:\\d+/);\n if (!match) {\n throw new Error(\"Could not detect current cmux workspace. Run `squadrant dashboard --pane` from inside a cmux workspace.\");\n }\n return match[0];\n}\n\nexport interface DashboardOnceDeps {\n now?: () => string;\n write?: (s: string) => void;\n}\n\nexport async function runDashboardOnce(deps: DashboardOnceDeps = {}): Promise<void> {\n const config = loadConfig();\n const now = (deps.now ?? (() => new Date().toISOString()))();\n const write = deps.write ?? ((s) => process.stdout.write(s));\n\n const statuses = await readAllStatuses({ config, call: squadrantdCall });\n const width = process.stdout.columns ?? 100;\n write(renderDashboard(statuses, { now, width }));\n write(\"\\n\");\n}\n\nexport interface SyncHubCliDeps {\n writeFile?: (path: string, content: string) => void;\n mkdir?: (path: string) => void;\n}\n\nexport async function runSyncHub(deps: SyncHubCliDeps = {}): Promise<SyncHubResult[]> {\n const config = loadConfig();\n const statuses = await readAllStatuses({ config, call: squadrantdCall });\n return syncHub({ config, statuses, writeFile: deps.writeFile, mkdir: deps.mkdir });\n}\n\nexport interface DashboardPaneInput {\n direction?: \"right\" | \"left\" | \"up\" | \"down\";\n interval?: number;\n}\n\nexport async function runDashboardPane(input: DashboardPaneInput): Promise<PaneRef> {\n const config = loadConfig();\n const runtime = new RuntimeRegistry({ cmux: createCmuxDriver() }).global(config);\n const workspaceId = detectCurrentWorkspace();\n\n const interval = input.interval ?? 10;\n const direction = input.direction ?? \"right\";\n const title = \"📊 dashboard\";\n\n // Portable refresh loop — no `watch` install dependency.\n // FORCE_COLOR=1 makes chalk emit ANSI even when run through the loop.\n const loop = `clear; while true; do clear; FORCE_COLOR=1 squadrant dashboard --once; sleep ${interval}; done`;\n\n const pane = await runtime.newPane({ workspaceId, direction, title });\n await runtime.sendToPane(pane, loop);\n return pane;\n}\n\nexport interface DashboardWebInput {\n port: number;\n interval: number; // seconds\n}\n\n/**\n * Start the localhost-only observability web dashboard. Separate process from\n * the daemon (crash-isolated, read-only socket client). Keeps running until the\n * process is killed; the HTTP server + tick loop hold the event loop open.\n */\nexport async function runDashboardWeb(input: DashboardWebInput): Promise<void> {\n const handle = await startWebServer({\n port: input.port,\n intervalMs: input.interval * 1000,\n sockPath: SOCK,\n runners: defaultProbeRunners(),\n });\n console.log(chalk.green(`✔ Squadrant system dashboard → http://127.0.0.1:${handle.port}`));\n console.log(chalk.dim(` polling the daemon every ${input.interval}s · localhost only · read-only · Ctrl-C to stop`));\n}\n\nexport const dashboardCommand = new Command(\"dashboard\")\n .description(\"Live status grid of all projects (derived from daemon task state)\")\n .option(\"--once\", \"Print one snapshot and exit (used by --pane's refresh loop)\")\n .option(\"--pane\", \"Open a refreshing sidebar pane in the current cmux workspace\")\n .option(\"--web\", \"Serve the live system-health web dashboard on 127.0.0.1 (HTTP + SSE)\")\n .option(\"--port <port>\", \"Port for --web (default 7878)\", (v) => parseInt(v, 10), 7878)\n .option(\"--direction <dir>\", \"Pane split direction (right|left|up|down)\", \"right\")\n .option(\"--interval <seconds>\", \"Daemon poll interval for --web (default 5); refresh interval for --pane (default 10)\", (v) => parseInt(v, 10))\n .action(async (opts: { once?: boolean; pane?: boolean; web?: boolean; port: number; direction: \"right\" | \"left\" | \"up\" | \"down\"; interval?: number }) => {\n try {\n if (opts.web) {\n await runDashboardWeb({ port: opts.port, interval: opts.interval ?? 5 });\n return;\n }\n if (opts.pane) {\n const pane = await runDashboardPane({ direction: opts.direction, interval: opts.interval ?? 10 });\n console.log(chalk.green(`✔ Dashboard pane opened in ${pane.workspaceId} ${pane.surfaceId}`));\n return;\n }\n // Default behaviour: --once. (Bare `squadrant dashboard` prints once and exits.)\n await runDashboardOnce();\n } catch (err) {\n console.error(chalk.red((err as Error).message));\n process.exit(1);\n }\n });\n\ndashboardCommand\n .command(\"sync-hub\")\n .description(\"Mirror each spoke status.md into {hubVault}/projects/<name>.md for Obsidian Dataview\")\n .option(\"--json\", \"Emit results as JSON\")\n .action(async (opts: { json?: boolean }) => {\n const results = await runSyncHub();\n if (opts.json) {\n console.log(JSON.stringify(results, null, 2));\n return;\n }\n if (results.length === 0) {\n console.log(chalk.dim(\"\\n No mirrors written (no projects with usable status.md, or hubVault unset).\\n\"));\n return;\n }\n console.log(chalk.bold(\"\\n 📊 Hub mirror sync\\n\"));\n for (const r of results) {\n console.log(` ${chalk.green(\"✔\")} ${chalk.cyan(r.project.padEnd(16))} → ${chalk.dim(r.hubPath)}`);\n }\n console.log(\"\");\n });\n","import type { SquadrantConfig } from \"@squadrant/shared\";\nimport type { TaskRecord } from \"@squadrant/shared\";\n\nexport type SquadrantdCall = (req: unknown) => Promise<unknown>;\n\nexport type DashboardState = \"idle\" | \"busy\" | \"blocked\" | \"errored\" | \"offline\" | \"unknown\";\n\nexport interface ProjectStatus {\n project: string;\n state: DashboardState;\n lastChecked: string;\n captainWorkspace: string;\n excerpt: string;\n}\n\nexport interface ReadStatusDeps {\n config: SquadrantConfig;\n call?: SquadrantdCall;\n listTasks?: (project: string) => Promise<TaskRecord[]>;\n}\n\nfunction deriveState(tasks: TaskRecord[]): DashboardState {\n if (tasks.some(t => t.state === \"blocked\" || t.state === \"awaiting-input\")) return \"blocked\";\n if (tasks.some(t => t.state === \"failed\" || t.state === \"stalled\")) return \"errored\";\n if (tasks.some(t => t.state === \"working\")) return \"busy\";\n return \"idle\";\n}\n\nfunction buildExcerpt(tasks: TaskRecord[]): string {\n const working = tasks.filter(t => t.state === \"working\").length;\n const blocked = tasks.filter(t => t.state === \"blocked\" || t.state === \"awaiting-input\").length;\n const parts: string[] = [];\n if (working > 0) parts.push(`${working} working`);\n if (blocked > 0) parts.push(`${blocked} blocked`);\n const summary = parts.length > 0 ? parts.join(\", \") : \"idle\";\n\n const active = tasks.filter(t =>\n [\"working\", \"blocked\", \"awaiting-input\", \"submitted\"].includes(t.state)\n );\n const titles = active.slice(0, 3).map(t => {\n const firstLine = t.task ? t.task.split(\"\\n\")[0] : \"\";\n return t.name ?? (firstLine || t.id.slice(0, 8));\n }).join(\"; \");\n\n return titles ? `${summary} — ${titles}` : summary;\n}\n\nexport async function readAllStatuses(deps: ReadStatusDeps): Promise<ProjectStatus[]> {\n const listTasks = deps.listTasks ?? (async (project: string) => {\n if (!deps.call) throw new Error(\"ReadStatusDeps: call is required when listTasks is not provided\");\n const result = await deps.call({ kind: \"list\", project });\n return result as TaskRecord[];\n });\n\n const rows: ProjectStatus[] = [];\n for (const [name, project] of Object.entries(deps.config.projects)) {\n try {\n const tasks = await listTasks(name);\n rows.push({\n project: name,\n state: deriveState(tasks),\n lastChecked: new Date().toISOString(),\n captainWorkspace: project.captainName,\n excerpt: buildExcerpt(tasks),\n });\n } catch {\n rows.push({\n project: name,\n state: \"offline\",\n lastChecked: new Date().toISOString(),\n captainWorkspace: project.captainName,\n excerpt: \"\",\n });\n }\n }\n return rows;\n}\n","import chalk from \"chalk\";\nimport type { ProjectStatus, DashboardState } from \"./read-status.js\";\n\nexport interface RenderOptions {\n now: string; // ISO-8601 string, used for age calc + footer\n width?: number; // terminal width (defaults to process.stdout.columns or 100)\n}\n\nconst ICON: Record<DashboardState, (s: string) => string> = {\n idle: chalk.green,\n busy: chalk.cyan,\n blocked: chalk.yellow,\n errored: chalk.red,\n offline: chalk.dim,\n unknown: chalk.gray,\n};\n\nconst ICON_CHAR: Record<DashboardState, string> = {\n idle: \"●\",\n busy: \"◐\",\n blocked: \"⏸\",\n errored: \"✗\",\n offline: \"○\",\n unknown: \"·\",\n};\n\nexport function formatAge(lastChecked: string, now: string): string {\n if (!lastChecked) return \"?\";\n const t = Date.parse(lastChecked);\n const n = Date.parse(now);\n if (Number.isNaN(t) || Number.isNaN(n)) return \"?\";\n const sec = Math.max(0, Math.floor((n - t) / 1000));\n if (sec < 60) return `${sec}s`;\n if (sec < 60 * 60) return `${Math.floor(sec / 60)}m`;\n if (sec < 60 * 60 * 24) return `${Math.floor(sec / 3600)}h`;\n return \"stale\";\n}\n\nfunction firstLine(s: string): string {\n for (const line of s.split(/\\r?\\n/)) {\n if (line.trim().length > 0) return line.trim();\n }\n return \"\";\n}\n\nfunction pad(s: string, n: number): string {\n return s.length >= n ? s.slice(0, n) : s + \" \".repeat(n - s.length);\n}\n\nfunction truncate(s: string, n: number): string {\n return s.length <= n ? s : s.slice(0, Math.max(0, n - 1)) + \"…\";\n}\n\nexport function renderDashboard(rows: ProjectStatus[], opts: RenderOptions): string {\n const width = opts.width ?? 100;\n const lines: string[] = [];\n\n lines.push(\"\");\n lines.push(\" \" + chalk.bold(\"📊 Squadrant Dashboard\") + \" \" + chalk.dim(opts.now));\n lines.push(\"\");\n\n if (rows.length === 0) {\n lines.push(\" \" + chalk.yellow(\"No projects registered. Add one with: squadrant projects add <name> <path>\"));\n lines.push(\"\");\n return lines.join(\"\\n\");\n }\n\n // Column widths — fixed for the left side, excerpt fills the remainder.\n const NAME_W = 16;\n const STATE_W = 8;\n const AGE_W = 6;\n const FIXED = 2 /*indent*/ + 1 /*icon*/ + 1 + NAME_W + 1 + STATE_W + 1 + AGE_W + 3 /*│ */;\n const excerptW = Math.max(20, width - FIXED);\n\n for (const r of rows) {\n const icon = ICON[r.state](ICON_CHAR[r.state]);\n const name = chalk.cyan(pad(r.project, NAME_W));\n const state = ICON[r.state](pad(r.state, STATE_W));\n const age = pad(formatAge(r.lastChecked, opts.now), AGE_W);\n const excerpt = chalk.dim(truncate(firstLine(r.excerpt), excerptW));\n lines.push(` ${icon} ${name} ${state} ${age} │ ${excerpt}`);\n }\n\n lines.push(\"\");\n lines.push(chalk.dim(\" Refreshes every 10s · Ctrl+C to exit\"));\n lines.push(\"\");\n return lines.join(\"\\n\");\n}\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport type { SquadrantConfig } from \"@squadrant/shared\";\nimport { resolveHome } from \"@squadrant/shared\";\nimport type { ProjectStatus } from \"./read-status.js\";\n\nexport interface SyncHubResult {\n project: string;\n hubPath: string;\n}\n\nexport interface SyncHubDeps {\n config: SquadrantConfig;\n statuses: ProjectStatus[];\n writeFile?: (path: string, content: string) => void;\n mkdir?: (dirPath: string) => void;\n}\n\nexport function buildMirrorMarkdown(s: ProjectStatus): string {\n const fenced = \"```\";\n return [\n \"---\",\n `project: ${s.project}`,\n `auto_state: ${s.state}`,\n `auto_last_checked: \"${s.lastChecked}\"`,\n `captain_workspace: ${s.captainWorkspace}`,\n \"---\",\n \"\",\n `# ${s.project}`,\n \"\",\n \"> Mirror of `{spokeVault}/status.md`. Updated by `squadrant dashboard sync-hub` (#44).\",\n \"\",\n \"## Last activity excerpt\",\n \"\",\n fenced,\n s.excerpt,\n fenced,\n \"\",\n ].join(\"\\n\");\n}\n\nexport function syncHub(deps: SyncHubDeps): SyncHubResult[] {\n if (!deps.config.hubVault) return [];\n\n const writeFile = deps.writeFile ?? ((p, c) => fs.writeFileSync(p, c));\n const mkdir = deps.mkdir ?? ((p) => fs.mkdirSync(p, { recursive: true }));\n\n const projectsDir = path.join(resolveHome(deps.config.hubVault), \"projects\");\n mkdir(projectsDir);\n\n const out: SyncHubResult[] = [];\n for (const s of deps.statuses) {\n if (s.state === \"unknown\") continue;\n const hubPath = path.join(projectsDir, `${s.project}.md`);\n try {\n writeFile(hubPath, buildMirrorMarkdown(s));\n out.push({ project: s.project, hubPath });\n } catch { /* best-effort */ }\n }\n return out;\n}\n","// src/dashboard/web-server.ts\n//\n// The `squadrant dashboard --web` process: a localhost-only HTTP + SSE server that,\n// on each tick, queries the daemon's read-only `snapshot` verb, runs the Tier 3/4\n// external probes (which the daemon cannot — lineage wall), merges them, and\n// pushes the result to every connected browser. Crash-isolated from the daemon\n// (separate PID, read-only socket client) and bound to 127.0.0.1 with no auth.\n// Zero new deps: Node's built-in `http` + `EventSource` on the client.\nimport { createServer, type Server, type ServerResponse } from \"node:http\";\nimport { sendRequest } from \"@squadrant/core\";\nimport type { DaemonSnapshot } from \"@squadrant/core\";\nimport { mergeSnapshot, type FullSnapshot } from \"./snapshot-merge.js\";\nimport { runExternalProbes, type ProbeRunners } from \"./probes.js\";\nimport { renderHtml, renderTickJson } from \"./web-render.js\";\n\n/**\n * Query the daemon's read-only snapshot verb. Returns \"unreachable\" when the\n * daemon socket can't be reached — the page degrades (banner + Tier 3/4) rather\n * than blanking. Mirrors queryHealth() in health-view.ts.\n */\nexport async function querySnapshot(sockPath: string): Promise<DaemonSnapshot | \"unreachable\"> {\n try {\n const reply = await sendRequest(sockPath, { kind: \"snapshot\" });\n return reply as DaemonSnapshot;\n } catch {\n return \"unreachable\";\n }\n}\n\nexport interface WebServerOpts {\n port: number;\n intervalMs: number;\n sockPath: string;\n runners: ProbeRunners;\n host?: string;\n now?: () => number;\n probeTimeoutMs?: number;\n}\n\nexport interface WebServerHandle {\n /** The actually-bound port (useful when port 0 was requested in tests). */\n port: number;\n close: () => Promise<void>;\n}\n\n/**\n * Start the dashboard web server. Binds 127.0.0.1 only, serves the static page on\n * GET /, an SSE stream on GET /events, and pushes a fresh snapshot every\n * intervalMs. Returns a handle whose close() stops the tick loop and the server.\n */\nexport async function startWebServer(opts: WebServerOpts): Promise<WebServerHandle> {\n const host = opts.host ?? \"127.0.0.1\";\n const now = opts.now ?? (() => Date.now());\n const clients = new Set<ServerResponse>();\n let latest: FullSnapshot | null = null;\n\n async function tick(): Promise<void> {\n const daemon = await querySnapshot(opts.sockPath);\n const external = await runExternalProbes(opts.runners, opts.probeTimeoutMs);\n latest = mergeSnapshot(daemon, external, now());\n const payload = `data: ${renderTickJson(latest)}\\n\\n`;\n for (const res of clients) {\n try { res.write(payload); } catch { /* client gone; pruned on close */ }\n }\n }\n\n const server: Server = createServer((req, res) => {\n if (req.method !== \"GET\") { res.writeHead(405).end(); return; }\n if (req.url === \"/\" || req.url === \"/index.html\") {\n res.writeHead(200, { \"Content-Type\": \"text/html; charset=utf-8\" });\n res.end(latest ? renderHtml(latest, { port: opts.port }) : \"<!DOCTYPE html><body>starting…</body>\");\n return;\n }\n if (req.url === \"/events\") {\n res.writeHead(200, {\n \"Content-Type\": \"text/event-stream\",\n \"Cache-Control\": \"no-cache\",\n Connection: \"keep-alive\",\n });\n res.write(\"retry: 3000\\n\\n\");\n if (latest) res.write(`data: ${renderTickJson(latest)}\\n\\n`);\n clients.add(res);\n req.on(\"close\", () => clients.delete(res));\n return;\n }\n res.writeHead(404).end();\n });\n\n await new Promise<void>((resolve, reject) => {\n server.once(\"error\", reject);\n server.listen(opts.port, host, resolve);\n });\n const addr = server.address();\n const boundPort = typeof addr === \"object\" && addr ? addr.port : opts.port;\n\n // Prime `latest` before the first request lands, then start the loop.\n await tick();\n const timer = setInterval(() => { void tick().catch(() => { /* a tick must never crash the loop */ }); }, opts.intervalMs);\n timer.unref?.();\n\n return {\n port: boundPort,\n close: () =>\n new Promise<void>((resolve) => {\n clearInterval(timer);\n for (const res of clients) { try { res.end(); } catch { /* already closed */ } }\n clients.clear();\n server.close(() => resolve());\n }),\n };\n}\n","// src/dashboard/snapshot-merge.ts\n//\n// PURE merge of the two data sources behind the dashboard: the daemon's\n// Tier 0/1/2 `DaemonSnapshot` (or \"unreachable\") and the dashboard process's\n// Tier 3/4 `ExternalProbes`. The whole point of keeping this separate and pure\n// is the degrade-never-blank guarantee: when the daemon is unreachable the\n// external tiers still render, so a daemon outage never blanks the page.\nimport type { DaemonSnapshot } from \"@squadrant/core\";\nimport type { ExternalProbes } from \"./probes.js\";\n\nexport interface FullSnapshot {\n /** epoch ms this snapshot was assembled (drives \"updated Ns ago\"). */\n generatedAt: number;\n /** \"unreachable\" when the daemon socket query failed — Tier 0/1/2 are dark. */\n daemon: DaemonSnapshot | \"unreachable\";\n external: ExternalProbes;\n}\n\n/** Pure. Stamp the two sources into one FullSnapshot. */\nexport function mergeSnapshot(\n daemon: DaemonSnapshot | \"unreachable\",\n external: ExternalProbes,\n now: number,\n): FullSnapshot {\n return { generatedAt: now, daemon, external };\n}\n","// src/dashboard/probes.ts\n//\n// Tier 3 (external dependencies) + Tier 4 (config integrity) probes for the web\n// dashboard. These live in the DASHBOARD process, never the daemon: the daemon\n// runs under launchd and is outside cmux's process lineage, so it cannot probe\n// cmux (the \"lineage wall\"). Every probe is behind an injectable runner and is\n// independently try/caught with a short timeout — a thrown or hung probe yields\n// `unknown` and NEVER propagates, so one bad probe can never crash a tick.\nimport { join } from \"node:path\";\nimport { homedir } from \"node:os\";\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { execFile } from \"node:child_process\";\nimport type { SquadrantConfig } from \"@squadrant/shared\";\nimport { loadConfig } from \"@squadrant/shared\";\nimport { resolveCmuxBin } from \"@squadrant/shared\";\n\nexport type ProbeState = \"alive\" | \"stale\" | \"gone\" | \"unknown\";\n\nexport interface Probe {\n state: ProbeState;\n /** Human-facing context for a degraded/unknown cell. */\n detail?: string;\n}\n\nexport interface ExternalProbes {\n cmux: Probe;\n agentClis: Array<{ cli: string } & Probe>;\n vaults: {\n hub: { path: string } & Probe;\n spokes: Array<{ project: string; path: string } & Probe>;\n };\n config: {\n parseable: Probe;\n projectPaths: Array<{ project: string; path: string } & Probe>;\n sessions: Probe;\n };\n}\n\n/** Low-level I/O the probes depend on. Tests inject fakes; the dashboard process\n * injects {@link defaultProbeRunners}. */\nexport interface ProbeRunners {\n /** cmux reachable (e.g. `cmux --version` exited 0). */\n probeCmuxBin: () => Promise<boolean>;\n /** an agent CLI resolves on PATH. */\n probeOnPath: (cli: string) => Promise<boolean>;\n /** a directory/file exists (sync stat). */\n pathExists: (p: string) => boolean;\n /** load + parse config.json; throws when unparseable. */\n loadConfig: () => SquadrantConfig;\n /** distinct templateHash values recorded in sessions.json; throws when unreadable. */\n loadSessionsHashes: () => string[];\n}\n\nconst DEFAULT_TIMEOUT_MS = 2000;\nconst AGENT_CLIS = [\"claude\", \"codex\", \"gemini\", \"opencode\"] as const;\n\n/** Reject a promise that outlives `ms`, clearing the timer either way. */\nfunction withTimeout<T>(p: Promise<T>, ms: number): Promise<T> {\n let timer: ReturnType<typeof setTimeout>;\n const timeout = new Promise<never>((_, reject) => {\n timer = setTimeout(() => reject(new Error(\"probe timeout\")), ms);\n timer.unref?.();\n });\n return Promise.race([p.finally(() => clearTimeout(timer)), timeout]);\n}\n\n// ── Tier 3 — external dependencies ────────────────────────────────────────────\n\nexport async function probeCmux(run: ProbeRunners, timeoutMs = DEFAULT_TIMEOUT_MS): Promise<Probe> {\n try {\n const ok = await withTimeout(run.probeCmuxBin(), timeoutMs);\n return ok ? { state: \"alive\" } : { state: \"gone\", detail: \"cmux not reachable\" };\n } catch {\n return { state: \"unknown\" };\n }\n}\n\nexport async function probeAgentClis(\n run: ProbeRunners,\n timeoutMs = DEFAULT_TIMEOUT_MS,\n): Promise<Array<{ cli: string } & Probe>> {\n return Promise.all(\n AGENT_CLIS.map(async (cli) => {\n try {\n const ok = await withTimeout(run.probeOnPath(cli), timeoutMs);\n return ok ? { cli, state: \"alive\" as const } : { cli, state: \"gone\" as const, detail: `${cli} not on PATH` };\n } catch {\n return { cli, state: \"unknown\" as const };\n }\n }),\n );\n}\n\n/** Hub vault is alive only when its directory AND its `.obsidian/` both exist. */\nfunction vaultProbe(run: ProbeRunners, dir: string): Probe {\n try {\n if (!dir) return { state: \"unknown\", detail: \"no vault configured\" };\n if (!run.pathExists(dir)) return { state: \"gone\", detail: \"vault directory missing\" };\n if (!run.pathExists(join(dir, \".obsidian\"))) return { state: \"gone\", detail: \"no .obsidian/ (not a vault)\" };\n return { state: \"alive\" };\n } catch {\n return { state: \"unknown\" };\n }\n}\n\n/** Spoke vault directories live INSIDE the hub vault and correctly have no\n * `.obsidian/` of their own. Alive = directory exists; gone = directory missing. */\nfunction spokeProbe(run: ProbeRunners, dir: string): Probe {\n try {\n if (!dir) return { state: \"unknown\", detail: \"no vault configured\" };\n if (!run.pathExists(dir)) return { state: \"gone\", detail: \"spoke directory missing\" };\n return { state: \"alive\" };\n } catch {\n return { state: \"unknown\" };\n }\n}\n\nexport function probeVaults(run: ProbeRunners, config: SquadrantConfig): ExternalProbes[\"vaults\"] {\n return {\n hub: { path: config.hubVault, ...vaultProbe(run, config.hubVault) },\n spokes: Object.entries(config.projects).map(([project, p]) => ({\n project,\n path: p.spokeVault,\n ...spokeProbe(run, p.spokeVault),\n })),\n };\n}\n\n// ── Tier 4 — config integrity ─────────────────────────────────────────────────\n\nexport function probeProjectPaths(\n run: ProbeRunners,\n config: SquadrantConfig,\n): Array<{ project: string; path: string } & Probe> {\n return Object.entries(config.projects).map(([project, p]) => {\n try {\n const ok = run.pathExists(p.path);\n return ok\n ? { project, path: p.path, state: \"alive\" as const }\n : { project, path: p.path, state: \"gone\" as const, detail: \"project path missing\" };\n } catch {\n return { project, path: p.path, state: \"unknown\" as const };\n }\n });\n}\n\n/**\n * sessions.json template-drift signal. Re-deriving the exact \"current\" template\n * hash would couple the dashboard to the launcher's hashing internals + the\n * installed templates dir; instead we surface the honest, dependency-free signal\n * that the recorded sessions disagree: more than one distinct templateHash means\n * some workspaces are running against an older template (drift). One hash =\n * consistent; none recorded = unknown.\n */\nexport function probeSessions(run: ProbeRunners): Probe {\n try {\n const hashes = run.loadSessionsHashes();\n if (hashes.length === 0) return { state: \"unknown\", detail: \"no sessions recorded\" };\n if (hashes.length === 1) return { state: \"alive\" };\n return { state: \"stale\", detail: `template drift: ${hashes.length} distinct hashes` };\n } catch {\n return { state: \"unknown\" };\n }\n}\n\n// ── Top-level assembly ────────────────────────────────────────────────────────\n\n/**\n * Run every Tier 3/4 probe and assemble {@link ExternalProbes}. config.json is\n * loaded once (shared by vaults + project-path checks); if it fails to parse the\n * config tier degrades but cmux/CLI probes still run.\n */\nexport async function runExternalProbes(\n run: ProbeRunners,\n timeoutMs = DEFAULT_TIMEOUT_MS,\n): Promise<ExternalProbes> {\n const [cmux, agentClis] = await Promise.all([\n probeCmux(run, timeoutMs),\n probeAgentClis(run, timeoutMs),\n ]);\n\n let config: SquadrantConfig | null = null;\n let parseable: Probe;\n try {\n config = run.loadConfig();\n parseable = { state: \"alive\" };\n } catch {\n parseable = { state: \"gone\", detail: \"config.json unparseable\" };\n }\n\n const vaults = config\n ? probeVaults(run, config)\n : { hub: { path: \"\", state: \"unknown\" as const }, spokes: [] };\n const projectPaths = config ? probeProjectPaths(run, config) : [];\n const sessions = probeSessions(run);\n\n return { cmux, agentClis, vaults, config: { parseable, projectPaths, sessions } };\n}\n\n// ── Default real-I/O runners (dashboard process; not unit-tested) ──────────────\n\nconst SESSIONS_PATH = join(homedir(), \".config\", \"squadrant\", \"sessions.json\");\n\n/** Resolve a bare binary name against the PATH dirs (dependency-free `which`). */\nfunction onPath(cli: string): boolean {\n const dirs = (process.env.PATH ?? \"\").split(\":\").filter(Boolean);\n return dirs.some((d) => existsSync(join(d, cli)));\n}\n\n/** Distinct templateHash values recorded across all workspaces in sessions.json. */\nfunction readSessionsHashes(): string[] {\n const raw = JSON.parse(readFileSync(SESSIONS_PATH, \"utf-8\")) as {\n workspaces?: Record<string, { templateHash?: string }>;\n };\n const hashes = Object.values(raw.workspaces ?? {})\n .map((w) => w.templateHash)\n .filter((h): h is string => typeof h === \"string\" && h.length > 0);\n return [...new Set(hashes)];\n}\n\n/** The real runners used by `squadrant dashboard --web`. */\nexport function defaultProbeRunners(): ProbeRunners {\n return {\n probeCmuxBin: () =>\n new Promise<boolean>((resolve) => {\n try {\n execFile(resolveCmuxBin(), [\"--version\"], { timeout: 1500 }, (err) => resolve(!err));\n } catch {\n resolve(false);\n }\n }),\n probeOnPath: async (cli) => onPath(cli),\n pathExists: (p) => existsSync(p),\n loadConfig: () => loadConfig(),\n loadSessionsHashes: () => readSessionsHashes(),\n };\n}\n","// src/dashboard/web-render.ts\n//\n// PURE render of a FullSnapshot to (a) a complete HTML document for the initial\n// GET / load and (b) a per-tick JSON payload pushed over SSE. No I/O, no clock —\n// every age is derived from snapshot-time deltas or `snap.generatedAt`, so the\n// render is deterministic and unit-tested.\n//\n// Visual language: a glass-squadrant flight deck. A master-status ANNUNCIATOR and\n// an inline-SVG health DONUT read the fleet at a glance; OVERVIEW / PROJECTS /\n// DAEMON / ENVIRONMENT tabs (vanilla-JS, one SSE stream) hold the detail. Charts\n// are inline SVG only (donut server-rendered; sparklines drawn client-side from a\n// rolling history of successive SSE frames). Severity rolls UP (a `gone` bubbles a\n// red rollup to its project header); the stale-build / link-lost banners render\n// only when applicable; remediation is COPY-ABLE TEXT (never buttons — read-only\n// beta). Zero new deps: vanilla JS + modern CSS + inline SVG.\nimport type { HealthState, ComponentHealth, DaemonSnapshot } from \"@squadrant/core\";\nimport { healCmdFor, ageText } from \"@squadrant/core\";\nimport type { FullSnapshot } from \"./snapshot-merge.js\";\nimport type { ExternalProbes, Probe, ProbeState } from \"./probes.js\";\n\ntype AnyState = HealthState | ProbeState;\n\nconst ICON: Record<AnyState, string> = { alive: \"✔\", stale: \"•\", gone: \"✘\", stopped: \"⏻\", unknown: \"○\" };\n// Rollup ordering: gone (fault) is worst. `stopped` is an intentional shutdown —\n// it out-ranks a stale caution (it is the headline state of an offline project)\n// but never a genuine fault. unknown never out-ranks a real degradation.\nconst SEV: Record<AnyState, number> = { alive: 0, unknown: 1, stale: 2, stopped: 3, gone: 4 };\n// Squadrant annunciator vernacular for each state.\nconst STATE_WORD: Record<AnyState, string> = { alive: \"nominal\", stale: \"caution\", gone: \"fault\", stopped: \"stopped\", unknown: \"unknown\" };\n\nfunction esc(s: string): string {\n return s\n .replace(/&/g, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\")\n .replace(/\"/g, \"&quot;\");\n}\n\nfunction fmtBytes(n: number): string {\n if (n < 1024) return `${n}B`;\n if (n < 1024 ** 2) return `${(n / 1024).toFixed(1)}KB`;\n if (n < 1024 ** 3) return `${(n / 1024 ** 2).toFixed(1)}MB`;\n return `${(n / 1024 ** 3).toFixed(1)}GB`;\n}\n\nfunction fmtDur(ms: number): string {\n const s = Math.max(0, Math.round(ms / 1000));\n if (s < 60) return `${s}s`;\n const m = Math.round(s / 60);\n if (m < 60) return `${m}m`;\n const h = Math.floor(m / 60);\n return `${h}h${m % 60}m`;\n}\n\nfunction fmtAge(ms: number | null): string {\n return ms == null ? \"—\" : `${fmtDur(ms)} ago`;\n}\n\nfunction worst(states: AnyState[]): AnyState {\n let w: AnyState = \"alive\";\n for (const s of states) if (SEV[s] > SEV[w]) w = s;\n return w;\n}\n\n// ── Health tallies ────────────────────────────────────────────────────────────\ninterface Tally { alive: number; stale: number; gone: number; stopped: number; unknown: number; total: number }\n\nfunction tally(states: AnyState[]): Tally {\n const t: Tally = { alive: 0, stale: 0, gone: 0, stopped: 0, unknown: 0, total: states.length };\n for (const s of states) t[s]++;\n return t;\n}\n\n/** Master flight-status from an aggregate tally. gone → critical (red); stale →\n * degraded (amber); else nominal (green). Log errors map to `stale`, never gone,\n * so a noisy log can caution but never trips a CRITICAL master alarm. */\nfunction masterClass(t: Tally): \"ok\" | \"warn\" | \"crit\" {\n if (t.gone > 0) return \"crit\";\n if (t.stale > 0) return \"warn\";\n return \"ok\";\n}\nconst MASTER_WORD: Record<\"ok\" | \"warn\" | \"crit\", string> = { ok: \"NOMINAL\", warn: \"DEGRADED\", crit: \"CRITICAL\" };\n\n// ── Small presentational atoms ──────────────────────────────────────────────────\nfunction pill(state: AnyState, label: string): string {\n return `<span class=\"pill s-${state}\"><span class=\"pdot\"></span>${esc(label)}</span>`;\n}\n\n/** Status pill carrying the glyph + state word — used in component tables. */\nfunction statePill(state: AnyState): string {\n return pill(state, `${ICON[state]} ${STATE_WORD[state]}`);\n}\n\nfunction banner(kind: \"err\" | \"warn\", text: string): string {\n return `<div class=\"banner ${kind}\">${esc(text)}</div>`;\n}\n\nfunction remediation(text: string): string {\n // Copy-able text, NOT a button — read-only beta surface.\n return `<div class=\"rem\">remediation <code>${esc(text)}</code></div>`;\n}\n\nfunction probeCell(label: string, p: Probe): string {\n const detail = p.detail ? ` · ${esc(p.detail)}` : \"\";\n return `${pill(p.state, label)}<span class=\"cell-detail\">${detail}</span>`;\n}\n\n// ── Donut gauge (inline SVG) ────────────────────────────────────────────────────\nconst DONUT_ORDER: AnyState[] = [\"alive\", \"stale\", \"stopped\", \"gone\", \"unknown\"];\n\n/** The signature element: a four-segment health ring. Segment arc lengths are\n * proportional to the tally; everything is plain SVG math so it is deterministic\n * and testable. An empty tally shows a faint full track. */\nfunction donut(t: Tally): string {\n const cx = 64, cy = 64, r = 52, w = 14;\n const C = 2 * Math.PI * r;\n let acc = 0;\n const segs = DONUT_ORDER.map((k) => {\n const v = t[k];\n if (v <= 0) return \"\";\n const len = t.total ? (v / t.total) * C : 0;\n const rot = t.total ? (acc / t.total) * 360 : 0;\n acc += v;\n return `<circle class=\"seg s-${k}\" cx=\"${cx}\" cy=\"${cy}\" r=\"${r}\" fill=\"none\" stroke-width=\"${w}\" stroke-dasharray=\"${len.toFixed(2)} ${(C - len).toFixed(2)}\" transform=\"rotate(${(rot - 90).toFixed(2)} ${cx} ${cy})\"></circle>`;\n }).join(\"\");\n const track = `<circle class=\"donut-track\" cx=\"${cx}\" cy=\"${cy}\" r=\"${r}\" fill=\"none\" stroke-width=\"${w}\"></circle>`;\n return `<svg class=\"donut\" viewBox=\"0 0 128 128\" role=\"img\" aria-label=\"fleet health distribution\">${track}${segs}</svg>`;\n}\n\nfunction legendRow(state: AnyState, count: number): string {\n return `<div class=\"leg s-${state}\"><span class=\"pdot\"></span><span class=\"leg-n\" data-countup=\"leg-${state}\" data-value=\"${count}\">${count}</span><span class=\"leg-l\">${STATE_WORD[state]}</span></div>`;\n}\n\n/** A trend card: a label + a big readout value + an empty sparkline svg the\n * client fills from rolling history (data-spark key). */\nfunction trendCard(key: string, label: string, value: string, sub: string): string {\n return [\n `<div class=\"trend\">`,\n `<div class=\"trend-head\"><span class=\"trend-l\">${esc(label)}</span><span class=\"trend-v\">${esc(value)}</span></div>`,\n `<svg class=\"spark\" data-spark=\"${key}\" viewBox=\"0 0 100 28\" preserveAspectRatio=\"none\" aria-hidden=\"true\"></svg>`,\n `<div class=\"trend-sub\">${esc(sub)}</div>`,\n `</div>`,\n ].join(\"\");\n}\n\n/** Sum delivery lag across projects whose captain is alive (online only).\n * A captain that is offline with unread mail is not a live delivery problem. */\nfunction liveDeliveryBehind(d: DaemonSnapshot): number {\n return d.tier2.projects.reduce((sum, p) => {\n const captain = d.tier1.find((c) => c.kind === \"captain\" && c.project === p.project);\n const captainState = captain?.state ?? \"unknown\";\n return captainState === \"alive\" ? sum + p.delivery.behind : sum;\n }, 0);\n}\n\n// ── Aggregate collection (pure) ─────────────────────────────────────────────────\ninterface Collected {\n now: number;\n daemonT: Tally; projT: Tally; envT: Tally; overall: Tally;\n errors: number; behind: number; crewAgeMs: number;\n}\n\nfunction collect(snap: FullSnapshot): Collected {\n const now = snap.generatedAt;\n const env = snap.external;\n const envStates: AnyState[] = [\n env.cmux.state,\n ...env.agentClis.map((c) => c.state),\n env.vaults.hub.state,\n ...env.vaults.spokes.map((s) => s.state),\n env.config.parseable.state,\n env.config.sessions.state,\n ...env.config.projectPaths.map((p) => p.state),\n ];\n const daemonStates: AnyState[] = [];\n const projStates: AnyState[] = [];\n let errors = 0, behind = 0, crewAgeMs = 0;\n if (snap.daemon !== \"unreachable\") {\n const t0 = snap.daemon.tier0;\n daemonStates.push(\"alive\"); // the daemon process itself is up\n daemonStates.push(t0.build.state === \"fresh\" ? \"alive\" : \"stale\");\n daemonStates.push(t0.log.errorCount > 0 ? \"stale\" : \"alive\");\n errors = t0.log.errorCount;\n for (const c of snap.daemon.tier1) {\n projStates.push(c.state);\n if (c.kind === \"crew\" && c.lastSeenMs != null) crewAgeMs = Math.max(crewAgeMs, now - c.lastSeenMs);\n }\n for (const p of snap.daemon.tier2.projects) {\n if (p.delivery.behind > 0) projStates.push(\"stale\");\n if (p.store.corruptCount > 0) projStates.push(\"gone\");\n }\n behind = liveDeliveryBehind(snap.daemon);\n }\n return {\n now,\n daemonT: tally(daemonStates),\n projT: tally(projStates),\n envT: tally(envStates),\n overall: tally([...daemonStates, ...projStates, ...envStates]),\n errors, behind, crewAgeMs,\n };\n}\n\n// ── Tab: OVERVIEW ───────────────────────────────────────────────────────────────\n/** A titled section header: a short heading + a one-line plain-language caption,\n * so a first-time viewer knows what each block of widgets is showing. */\nfunction sectionHead(title: string, sub: string): string {\n return `<div class=\"section-head\"><h2 class=\"section-title\">${esc(title)}</h2><p class=\"section-sub\">${esc(sub)}</p></div>`;\n}\n\nfunction tierCard(name: string, t: Tally, desc: string): string {\n const w = t.total ? worst(([] as AnyState[]).concat(\n ...Array.from({ length: t.gone }, () => \"gone\" as AnyState),\n ...Array.from({ length: t.stopped }, () => \"stopped\" as AnyState),\n ...Array.from({ length: t.stale }, () => \"stale\" as AnyState),\n ...Array.from({ length: t.unknown }, () => \"unknown\" as AnyState),\n ...Array.from({ length: t.alive }, () => \"alive\" as AnyState),\n )) : \"unknown\";\n return [\n `<div class=\"tier-card\">`,\n `<div class=\"tier-top\"><span class=\"tier-name\">${esc(name)}</span>${statePill(w)}</div>`,\n `<p class=\"tier-desc\">${esc(desc)}</p>`,\n `<div class=\"tier-counts\">`,\n `<span class=\"tc s-alive\">${t.alive}<i>ok</i></span>`,\n `<span class=\"tc s-stale\">${t.stale}<i>caution</i></span>`,\n `<span class=\"tc s-gone\">${t.gone}<i>fault</i></span>`,\n ...(t.stopped > 0 ? [`<span class=\"tc s-stopped\">${t.stopped}<i>stopped</i></span>`] : []),\n `<span class=\"tc s-unknown\">${t.unknown}<i>unknown</i></span>`,\n `</div></div>`,\n ].join(\"\");\n}\n\nfunction renderOverview(snap: FullSnapshot, col: Collected): string {\n const linkLost = snap.daemon === \"unreachable\";\n const mc = linkLost ? \"crit\" : masterClass(col.overall);\n const word = linkLost ? \"LINK LOST\" : MASTER_WORD[mc];\n const out: string[] = [`<section class=\"panel\" data-panel=\"overview\" role=\"tabpanel\" aria-label=\"Overview\">`];\n\n out.push(sectionHead(\n \"System Health\",\n `${col.overall.alive} of ${col.overall.total} monitored components are alive — the ring shows the full breakdown by state.`,\n ));\n out.push(\n `<div class=\"hero a-${mc}\">`,\n `<div class=\"gauge\">`,\n donut(col.overall),\n `<div class=\"gauge-core\"><span class=\"gauge-n\" data-countup=\"monitored\" data-value=\"${col.overall.total}\">${col.overall.total}</span><span class=\"gauge-word\">${esc(word)}</span><span class=\"gauge-cap\">monitored</span></div>`,\n `</div>`,\n `<div class=\"legend\">`,\n legendRow(\"alive\", col.overall.alive),\n legendRow(\"stale\", col.overall.stale),\n legendRow(\"gone\", col.overall.gone),\n ...(col.overall.stopped > 0 ? [legendRow(\"stopped\", col.overall.stopped)] : []),\n legendRow(\"unknown\", col.overall.unknown),\n `</div>`,\n `</div>`,\n );\n\n out.push(sectionHead(\"Health by Tier\", \"How many components are healthy in each layer of the stack.\"));\n out.push(\n `<div class=\"tier-grid\">`,\n tierCard(\"Daemon\", col.daemonT, \"squadrantd process, build freshness & log volume (Tier 0)\"),\n tierCard(\"Projects\", col.projT, \"captains, crews & message data plane (Tier 1/2)\"),\n tierCard(\"Environment\", col.envT, \"agent CLIs, vaults & config integrity (Tier 3/4)\"),\n `</div>`,\n );\n\n out.push(sectionHead(\"Live Trends\", \"Magnitudes tracked over time — each sparkline builds as new updates arrive.\"));\n out.push(\n `<div class=\"trend-grid\">`,\n trendCard(\"errors\", \"Daemon log\", `${col.errors}`, \"errors the daemon logged in the last window\"),\n trendCard(\"behind\", \"Delivery lag\", `${col.behind}`, \"messages captains have not read yet\"),\n trendCard(\"crewAge\", \"Crew heartbeat\", linkLost ? \"—\" : fmtDur(col.crewAgeMs), \"time since the quietest crew was last seen\"),\n `</div>`,\n );\n\n out.push(`</section>`);\n return out.join(\"\");\n}\n\n// ── Tab: PROJECTS ───────────────────────────────────────────────────────────────\nfunction componentRow(c: ComponentHealth, now: number): string {\n const detail = c.detail ? esc(c.detail) : \"\";\n const row =\n `<tr>` +\n `<td>${statePill(c.state)}</td>` +\n `<td class=\"mono\">${esc(c.kind)}</td>` +\n `<td class=\"mono\">${esc(c.ref)}</td>` +\n `<td class=\"mono dim\">${esc(ageText(c.lastSeenMs, now))}</td>` +\n `<td class=\"dim\">${detail}</td>` +\n `</tr>`;\n const heal = healCmdFor(c);\n return heal ? row + `<tr class=\"rem-row\"><td colspan=\"5\">${remediation(heal)}</td></tr>` : row;\n}\n\nfunction deliveryBar(behind: number, maxSeq: number): string {\n const acked = Math.max(0, maxSeq - behind);\n const ackedPct = maxSeq > 0 ? (acked / maxSeq) * 100 : 100;\n const behindPct = maxSeq > 0 ? (behind / maxSeq) * 100 : 0;\n return [\n `<div class=\"dbar\" role=\"img\" aria-label=\"${acked} of ${maxSeq} delivered, ${behind} behind\">`,\n `<span class=\"dbar-acked\" style=\"width:${ackedPct.toFixed(1)}%\"></span>`,\n `<span class=\"dbar-behind\" style=\"width:${behindPct.toFixed(1)}%\"></span>`,\n `</div>`,\n ].join(\"\");\n}\n\nfunction renderProjects(snap: FullSnapshot, now: number): string {\n const out: string[] = [`<section class=\"panel\" data-panel=\"projects\" role=\"tabpanel\" aria-label=\"Projects\">`];\n out.push(sectionHead(\"Projects\", \"Per-project captains and crews, plus each project's mailbox delivery and task store.\"));\n if (snap.daemon === \"unreachable\") {\n out.push(`<div class=\"empty\">Telemetry link lost — per-project data is served by the daemon. Start it to restore: <code>squadrant heal daemon</code></div></section>`);\n return out.join(\"\");\n }\n const d = snap.daemon;\n const projects = new Set<string>([...d.tier1.map((c) => c.project), ...d.tier2.projects.map((p) => p.project)]);\n if (projects.size === 0) out.push(`<div class=\"empty\">No projects registered yet.</div>`);\n for (const project of projects) {\n const comps = d.tier1.filter((c) => c.project === project);\n const dp = d.tier2.projects.find((p) => p.project === project);\n // A stopped captain means the project is intentionally offline — its unread\n // mail is expected backlog, not a live caution, so the delivery lag does not\n // contribute a `stale` to the rollup (#324/#323). A genuine fault (corrupt\n // store) still bubbles `gone` and out-ranks the stopped headline.\n const captainStopped = comps.some((c) => c.kind === \"captain\" && c.state === \"stopped\");\n const rollupStates: AnyState[] = [\n ...comps.map((c) => c.state),\n !captainStopped && dp && dp.delivery.behind > 0 ? \"stale\" : \"alive\",\n dp && dp.store.corruptCount > 0 ? \"gone\" : \"alive\",\n ];\n const rollup = worst(rollupStates);\n out.push(`<article class=\"card\" data-rollup=\"${rollup}\">`);\n out.push(`<header class=\"card-head\"><span class=\"card-title\">${esc(project)}</span>${statePill(rollup)}</header>`);\n if (comps.length) {\n out.push(\n `<table class=\"grid\"><thead><tr><th>status</th><th>kind</th><th>ref</th><th>last seen</th><th>detail</th></tr></thead><tbody>`,\n ...comps.map((c) => componentRow(c, now)),\n `</tbody></table>`,\n );\n } else {\n out.push(`<div class=\"dim small\">no live components reported</div>`);\n }\n if (dp) {\n const counts = Object.entries(dp.store.byState).map(([s, n]) => pill(\"unknown\", `${n} ${s}`)).join(\"\");\n out.push(\n `<div class=\"dp-grid\">`,\n `<div class=\"dp-block\"><span class=\"dp-l\">mailbox</span><span class=\"dp-v\"><span class=\"mono\">${dp.mailbox.maxSeq}</span> entries · ${fmtBytes(dp.mailbox.sizeBytes)} · rotated ${dp.mailbox.rotationCount} · oldest ${fmtAge(dp.mailbox.oldestEntryAgeMs)}</span></div>`,\n `<div class=\"dp-block\"><span class=\"dp-l\">captain delivery</span>${deliveryBar(dp.delivery.behind, dp.mailbox.maxSeq)}<span class=\"dp-v\"><span class=\"mono\">${dp.delivery.behind}</span> behind</span></div>`,\n `<div class=\"dp-block\"><span class=\"dp-l\">task store</span><span class=\"chips\">${counts || `<span class=\"dim small\">no tasks</span>`}${dp.store.corruptCount > 0 ? pill(\"gone\", `${dp.store.corruptCount} corrupt`) : \"\"}</span></div>`,\n `</div>`,\n );\n }\n out.push(`</article>`);\n }\n out.push(`</section>`);\n return out.join(\"\");\n}\n\n// ── Tab: DAEMON ─────────────────────────────────────────────────────────────────\nfunction instr(label: string, value: string, extra = \"\"): string {\n return `<div class=\"instr\"><span class=\"instr-l\">${esc(label)}</span><span class=\"instr-v\">${value}</span>${extra}</div>`;\n}\n\nfunction renderDaemon(snap: FullSnapshot): string {\n const out: string[] = [`<section class=\"panel\" data-panel=\"daemon\" role=\"tabpanel\" aria-label=\"Daemon\">`];\n out.push(sectionHead(\"Daemon · Tier 0\", \"The squadrantd process at the root of everything — uptime, build freshness, sweep cadence, and log volume.\"));\n if (snap.daemon === \"unreachable\") {\n out.push(`<div class=\"empty\">Daemon unreachable — no Tier 0 telemetry. ${remediation(\"squadrant heal daemon\")}</div></section>`);\n return out.join(\"\");\n }\n const t0 = snap.daemon.tier0;\n const buildState: HealthState = t0.build.state === \"fresh\" ? \"alive\" : \"gone\";\n // #fix(a): a fresh daemon that has not run a sweep yet is \"awaiting first\n // sweep\" — not \"never swept\". A null age means the loop simply hasn't ticked.\n const sweep = t0.sweep.ageMs == null\n ? \"awaiting first sweep\"\n : `last ${fmtAge(t0.sweep.ageMs)} · ${fmtDur(t0.sweep.cadenceMs)} cadence`;\n const sweepState: AnyState = t0.sweep.ageMs == null ? \"unknown\" : \"alive\";\n // #fix(b): present the log error count as a calm, non-alarming metric — a\n // caution at most, with a trend sparkline, never a red master alarm.\n const logState: AnyState = t0.log.errorCount > 0 ? \"stale\" : \"alive\";\n\n out.push(\n `<div class=\"instr-grid\">`,\n instr(\"process\", `<span class=\"mono\">squadrantd</span> ${statePill(\"alive\")}`, `<span class=\"instr-sub\">pid ${t0.pid} · v${esc(t0.version)}</span>`),\n instr(\"uptime\", `<span class=\"mono\">${fmtDur(t0.uptimeMs)}</span>`),\n instr(\"build\", `${pill(buildState, t0.build.state)}`, t0.build.state === \"stale\" ? remediation(\"npm run build && squadrant heal daemon\") : \"\"),\n instr(\"sweep\", `${pill(sweepState, sweep)}`),\n `</div>`,\n );\n\n out.push(\n `<div class=\"trend-grid\">`,\n [\n `<div class=\"trend\">`,\n `<div class=\"trend-head\"><span class=\"trend-l\">Log errors</span><span class=\"trend-v\">${pill(logState, `${t0.log.errorCount}`)}</span></div>`,\n `<svg class=\"spark\" data-spark=\"errors\" viewBox=\"0 0 100 28\" preserveAspectRatio=\"none\" aria-hidden=\"true\"></svg>`,\n `<div class=\"trend-sub\">${t0.log.errorCount === 0 ? \"clean over the last\" : `over the last`} ${fmtDur(t0.log.windowMs)} · log ${fmtBytes(t0.log.sizeBytes)}</div>`,\n `</div>`,\n ].join(\"\"),\n trendCard(\"behind\", \"Delivery lag\", `${liveDeliveryBehind(snap.daemon)}`, \"summed across online projects only (offline excluded)\"),\n `</div>`,\n );\n\n out.push(`<div class=\"results\">global results · <span class=\"mono\">${snap.daemon.tier2.results.fileCount}</span> files · ${fmtBytes(snap.daemon.tier2.results.totalBytes)}</div>`);\n out.push(`</section>`);\n return out.join(\"\");\n}\n\n// ── Tab: ENVIRONMENT ────────────────────────────────────────────────────────────\nfunction probeTable(rows: Array<[string, Probe]>): string {\n return [\n `<table class=\"grid\"><thead><tr><th>status</th><th>component</th><th>detail</th></tr></thead><tbody>`,\n ...rows.map(([label, p]) =>\n `<tr><td>${statePill(p.state)}</td><td class=\"mono\">${esc(label)}</td><td class=\"dim\">${p.detail ? esc(p.detail) : \"\"}</td></tr>`,\n ),\n `</tbody></table>`,\n ].join(\"\");\n}\n\nfunction renderEnv(ext: ExternalProbes): string {\n const out: string[] = [`<section class=\"panel\" data-panel=\"environment\" role=\"tabpanel\" aria-label=\"Environment\">`];\n out.push(sectionHead(\"Environment · Tier 3 / 4\", \"External tools and on-disk state the squadrant depends on but does not own — agent CLIs, vaults, and config.\"));\n\n out.push(`<article class=\"card\"><header class=\"card-head\"><span class=\"card-title\">Runtime & CLIs</span></header>`);\n out.push(probeTable([\n [\"cmux\", ext.cmux],\n ...ext.agentClis.map((c) => [c.cli, c] as [string, Probe]),\n ]));\n out.push(`</article>`);\n\n out.push(`<article class=\"card\"><header class=\"card-head\"><span class=\"card-title\">Vaults</span></header>`);\n out.push(probeTable([\n [\"hub\", ext.vaults.hub],\n ...ext.vaults.spokes.map((s) => [`spoke · ${s.project}`, s] as [string, Probe]),\n ]));\n out.push(`</article>`);\n\n out.push(`<article class=\"card\"><header class=\"card-head\"><span class=\"card-title\">Config integrity</span></header>`);\n out.push(probeTable([\n [\"config.json\", ext.config.parseable],\n [\"sessions\", ext.config.sessions],\n ...ext.config.projectPaths.map((p) => [`path · ${p.project}`, p] as [string, Probe]),\n ]));\n out.push(`</article>`);\n\n out.push(`</section>`);\n return out.join(\"\");\n}\n\n// ── Tab nav + content assembly ──────────────────────────────────────────────────\nconst TABS: Array<[string, string]> = [\n [\"overview\", \"Overview\"],\n [\"projects\", \"Projects\"],\n [\"daemon\", \"Daemon\"],\n [\"environment\", \"Environment\"],\n];\n\nfunction tabNav(): string {\n const btns = TABS.map(([id, label], i) =>\n `<button class=\"tab${i === 0 ? \" on\" : \"\"}\" data-tab=\"${id}\" role=\"tab\" aria-selected=\"${i === 0 ? \"true\" : \"false\"}\">${esc(label)}</button>`,\n ).join(\"\");\n return `<nav class=\"tabs\" role=\"tablist\">${btns}</nav>`;\n}\n\nfunction metricsBlob(col: Collected, linkLost: boolean): string {\n const m = {\n t: col.now,\n errors: linkLost ? 0 : col.errors,\n behind: linkLost ? 0 : col.behind,\n crewAgeMs: linkLost ? 0 : col.crewAgeMs,\n alive: col.overall.alive, stale: col.overall.stale, gone: col.overall.gone, stopped: col.overall.stopped, unknown: col.overall.unknown,\n };\n // Escape `</` defensively so the JSON can never close the <script> early.\n const json = JSON.stringify(m).replace(/</g, \"\\\\u003c\");\n return `<script type=\"application/json\" id=\"squadrant-metrics\">${json}</script>`;\n}\n\n/** Pure. The live inner content (everything inside #content), re-pushed each tick. */\nexport function renderContent(snap: FullSnapshot): string {\n const col = collect(snap);\n const linkLost = snap.daemon === \"unreachable\";\n const mc = linkLost ? \"crit\" : masterClass(col.overall);\n const word = linkLost ? \"LINK LOST\" : MASTER_WORD[mc];\n\n const out: string[] = [\n `<header class=\"page-head\">`,\n `<h1 class=\"page-title\">SQUADRANT SYSTEM HEALTH</h1>`,\n `<p class=\"page-sub\">Live health of the squadrant daemon, sessions, message data plane, and environment — refreshed automatically every few seconds.</p>`,\n `</header>`,\n ];\n\n // Master annunciator (status summary) — glanceable on every tab.\n const stoppedPart = col.overall.stopped > 0 ? ` · ${col.overall.stopped} stopped` : \"\";\n const sumLine = `${col.overall.alive} nominal · ${col.overall.stale} caution · ${col.overall.gone} fault${stoppedPart} · ${col.overall.unknown} unknown`;\n out.push(\n `<section class=\"annunciator a-${mc}\" role=\"status\" aria-label=\"Status summary\">`,\n `<div class=\"ann-main\"><span class=\"ann-eyebrow\">Status summary</span><span class=\"ann-word\">${esc(word)}</span></div>`,\n `<div class=\"ann-meta\"><span class=\"ann-sum\">${sumLine}</span><span class=\"ann-cap\">worst current state across all ${col.overall.total} monitored components</span></div>`,\n `</section>`,\n );\n\n // Caution banners (loud, only when applicable).\n if (snap.daemon === \"unreachable\") {\n out.push(banner(\"err\", \"✘ DAEMON UNREACHABLE — start it: squadrant heal daemon (external checks below still live)\"));\n } else if (snap.daemon.tier0.build.state === \"stale\") {\n out.push(banner(\"warn\", \"⚠ DAEMON RUNNING STALE CODE — process started before the current dist build\"));\n out.push(remediation(\"npm run build && squadrant heal daemon\"));\n }\n\n out.push(tabNav());\n out.push(`<div class=\"panels\">`);\n out.push(renderOverview(snap, col));\n out.push(renderProjects(snap, col.now));\n out.push(renderDaemon(snap));\n out.push(renderEnv(snap.external));\n out.push(`</div>`);\n\n out.push(metricsBlob(col, linkLost));\n return out.join(\"\\n\");\n}\n\n/** Pure. The per-tick SSE payload: re-rendered content + the snapshot timestamp. */\nexport function renderTickJson(snap: FullSnapshot): string {\n return JSON.stringify({ contentHtml: renderContent(snap), generatedAt: snap.generatedAt });\n}\n\nconst STYLE = `\n:root{\n --bg:#f6f7f9;--panel:#ffffff;--panel-2:#eef1f6;--bezel:#e3e7ef;--track:#e9ecf2;\n --ink:#1b2333;--ink-dim:#5b6678;--hud:#0b6fc2;--hud-deep:#0b6fc2;\n --ok:#157f3c;--warn:#b45309;--crit:#c01f2e;--unk:#5f6b7d;--stopped:#7c5cbf;\n --shadow:0 1px 2px rgba(16,24,40,.05),0 4px 14px rgba(16,24,40,.06);\n}\n*{box-sizing:border-box}\nbody{margin:0;min-height:100vh;background:radial-gradient(1200px 760px at 50% -260px,#eaf1fb 0%,var(--bg) 58%);color:var(--ink);\n font:13px/1.55 ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;-webkit-font-smoothing:antialiased}\n\n/* Flight deck header (persistent shell) */\n.deck{display:flex;align-items:center;gap:18px;padding:14px 22px;border-bottom:1px solid var(--bezel);\n background:linear-gradient(180deg,rgba(255,255,255,.92),rgba(255,255,255,.62));position:sticky;top:0;z-index:5;backdrop-filter:blur(8px)}\n.brand{display:flex;align-items:center;gap:11px}\n.led{width:10px;height:10px;border-radius:50%;background:var(--unk);box-shadow:0 0 0 0 rgba(55,198,238,.5)}\n.led.live{background:var(--ok);animation:beat 2.2s ease-in-out infinite}\n.led.down{background:var(--crit);animation:blink 1s steps(2) infinite}\n.wordmark{font-family:system-ui,-apple-system,\"Segoe UI\",sans-serif;font-weight:800;letter-spacing:.34em;font-size:15px;text-transform:uppercase}\n.tagline{font-family:system-ui,sans-serif;text-transform:uppercase;letter-spacing:.26em;font-size:9.5px;color:var(--hud)}\n.deck-spacer{flex:1}\n.readout{display:flex;align-items:center;gap:16px;font-size:11px}\n.conn{font-family:system-ui,sans-serif;letter-spacing:.16em;text-transform:uppercase;color:var(--ink-dim)}\n.conn.live{color:var(--ok)}.conn.down{color:var(--crit)}\n.updated{color:var(--ink-dim)}\n.port{color:var(--hud)}\n\n#content{max-width:1080px;margin:0 auto;padding:18px 22px 64px;transition:opacity .18s ease}\n#content.swap{animation:fade .26s ease}\n\n/* Page heading + section headings */\n.page-head{margin:2px 0 16px}\n.page-title{margin:0;font-family:system-ui,-apple-system,\"Segoe UI\",sans-serif;font-weight:800;font-size:20px;letter-spacing:.06em;color:var(--ink)}\n.page-sub{margin:5px 0 0;color:var(--ink-dim);font-size:13px;max-width:74ch}\n.section-head{margin:20px 0 10px}\n.section-title{margin:0;font-family:system-ui,sans-serif;text-transform:uppercase;letter-spacing:.1em;font-size:12px;font-weight:700;color:var(--ink)}\n.section-sub{margin:3px 0 0;color:var(--ink-dim);font-size:12px}\n\n/* Annunciator */\n.annunciator{display:flex;align-items:center;justify-content:space-between;gap:18px;flex-wrap:wrap;padding:14px 18px;border-radius:12px;margin-bottom:6px;\n border:1px solid var(--bezel);background:var(--panel);box-shadow:var(--shadow);position:relative;overflow:hidden}\n.annunciator::before{content:\"\";position:absolute;inset:0 auto 0 0;width:4px}\n.ann-main{display:flex;flex-direction:column;gap:2px}\n.ann-eyebrow{font-family:system-ui,sans-serif;text-transform:uppercase;letter-spacing:.16em;font-size:9px;color:var(--ink-dim)}\n.ann-meta{display:flex;flex-direction:column;gap:2px;text-align:right;min-width:0}\n.ann-word{font-family:system-ui,sans-serif;font-weight:800;letter-spacing:.2em;font-size:21px}\n.ann-sum{color:var(--ink);letter-spacing:.04em;font-size:12px}\n.ann-cap{color:var(--ink-dim);font-size:11px}\n@media (max-width:560px){.ann-meta{text-align:left}}\n.a-ok .ann-word{color:var(--ok)}.a-ok::before{background:var(--ok);box-shadow:0 0 18px var(--ok)}\n.a-warn .ann-word{color:var(--warn)}.a-warn::before{background:var(--warn);box-shadow:0 0 18px var(--warn)}\n.a-crit .ann-word{color:var(--crit)}.a-crit::before{background:var(--crit);box-shadow:0 0 18px var(--crit);animation:pulseBar 1.4s ease-in-out infinite}\n\n/* Banners */\n.banner{padding:10px 14px;border-radius:10px;margin:10px 0;font-weight:700;letter-spacing:.02em;border:1px solid transparent}\n.banner.err{background:#fdecee;color:#b21f2c;border-color:#f3c3c9}\n.banner.warn{background:#fff5e1;color:#8a5806;border-color:#f0d8a4}\n.rem{color:var(--ink-dim);margin:6px 0;font-size:12px}\n.rem code,.empty code{background:var(--panel-2);padding:2px 7px;border-radius:5px;color:var(--hud);user-select:all;border:1px solid var(--bezel)}\n\n/* Tabs */\n.tabs{display:flex;gap:4px;margin:6px 0 16px;border-bottom:1px solid var(--bezel);flex-wrap:wrap}\n.tab{appearance:none;background:none;border:0;color:var(--ink-dim);cursor:pointer;padding:9px 16px;\n font-family:system-ui,sans-serif;text-transform:uppercase;letter-spacing:.16em;font-size:11px;font-weight:600;\n border-bottom:2px solid transparent;margin-bottom:-1px;transition:color .15s ease,border-color .15s ease}\n.tab:hover{color:var(--ink)}\n.tab.on{color:var(--hud);border-bottom-color:var(--hud)}\n.panel{animation:none}\n.panel.fade{animation:fade .28s ease}\n\n/* Overview hero */\n.hero{display:flex;gap:30px;align-items:center;flex-wrap:wrap;padding:22px;border-radius:14px;\n border:1px solid var(--bezel);background:linear-gradient(180deg,var(--panel-2),var(--panel));box-shadow:var(--shadow);margin-bottom:16px}\n.gauge{position:relative;width:172px;height:172px;flex:none}\n.donut{width:172px;height:172px;animation:rise .55s ease}\n.donut-track{stroke:var(--track)}\n.seg{transition:stroke-dasharray .5s ease}\n.seg.s-alive{stroke:var(--ok)}.seg.s-stale{stroke:var(--warn)}.seg.s-gone{stroke:var(--crit)}.seg.s-stopped{stroke:var(--stopped)}.seg.s-unknown{stroke:var(--unk)}\n.a-ok .seg.s-alive{filter:drop-shadow(0 0 4px var(--ok))}\n.gauge-core{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;gap:1px}\n.gauge-n{font-size:38px;font-weight:800;font-family:system-ui,sans-serif;line-height:1}\n.gauge-word{font-family:system-ui,sans-serif;text-transform:uppercase;letter-spacing:.14em;font-size:11px;color:var(--ink-dim)}\n.a-ok .gauge-word{color:var(--ok)}.a-warn .gauge-word{color:var(--warn)}.a-crit .gauge-word{color:var(--crit)}\n.gauge-cap{font-size:9px;letter-spacing:.2em;text-transform:uppercase;color:var(--ink-dim)}\n.legend{display:grid;grid-template-columns:1fr 1fr;gap:10px 22px;flex:1;min-width:200px}\n.leg{display:flex;align-items:center;gap:9px}\n.leg-n{font-size:20px;font-weight:700;font-family:system-ui,sans-serif;min-width:1.4em;text-align:right}\n.leg-l{color:var(--ink-dim);text-transform:uppercase;letter-spacing:.1em;font-size:10px;font-family:system-ui,sans-serif}\n.leg.s-alive .pdot{background:var(--ok)}.leg.s-stale .pdot{background:var(--warn)}\n.leg.s-gone .pdot{background:var(--crit)}.leg.s-stopped .pdot{background:var(--stopped)}.leg.s-unknown .pdot{background:var(--unk)}\n\n/* Tier + trend cards */\n.tier-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:12px;margin-bottom:16px}\n.tier-card{border:1px solid var(--bezel);border-radius:12px;background:var(--panel);padding:14px 16px;box-shadow:var(--shadow)}\n.tier-top{display:flex;align-items:center;justify-content:space-between;margin-bottom:6px}\n.tier-name{font-family:system-ui,sans-serif;text-transform:uppercase;letter-spacing:.12em;font-size:11px;color:var(--ink)}\n.tier-desc{margin:0 0 12px;color:var(--ink-dim);font-size:11px;min-height:2.2em}\n.tier-counts{display:flex;gap:14px}\n.tc{display:flex;flex-direction:column;font-size:21px;font-weight:700;font-family:system-ui,sans-serif;line-height:1.1}\n.tc i{font-size:9px;font-weight:600;font-style:normal;letter-spacing:.1em;text-transform:uppercase;color:var(--ink-dim)}\n.tc.s-alive{color:var(--ok)}.tc.s-stale{color:var(--warn)}.tc.s-gone{color:var(--crit)}.tc.s-stopped{color:var(--stopped)}.tc.s-unknown{color:var(--unk)}\n\n.trend-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));gap:12px;margin-bottom:16px}\n.trend{border:1px solid var(--bezel);border-radius:12px;background:var(--panel);padding:13px 15px;box-shadow:var(--shadow)}\n.trend-head{display:flex;align-items:center;justify-content:space-between;margin-bottom:8px}\n.trend-l{font-family:system-ui,sans-serif;text-transform:uppercase;letter-spacing:.12em;font-size:10px;color:var(--ink-dim)}\n.trend-v{font-size:18px;font-weight:700;font-family:system-ui,sans-serif;color:var(--hud)}\n.trend-sub{color:var(--ink-dim);font-size:11px;margin-top:7px}\n.spark{width:100%;height:34px;display:block}\n.spark-line{fill:none;stroke:var(--hud);stroke-width:1.6;vector-effect:non-scaling-stroke;stroke-linejoin:round}\n.spark-area{fill:var(--hud);opacity:.1}\n.spark-dot{fill:var(--hud)}\n\n/* Cards / tables */\n.card{border:1px solid var(--bezel);border-radius:12px;background:var(--panel);box-shadow:var(--shadow);padding:14px 16px;margin-bottom:14px;border-left:3px solid var(--bezel)}\n.card[data-rollup=\"gone\"]{border-left-color:var(--crit)}\n.card[data-rollup=\"stale\"]{border-left-color:var(--warn)}\n.card[data-rollup=\"stopped\"]{border-left-color:var(--stopped)}\n.card[data-rollup=\"alive\"]{border-left-color:var(--ok)}\n.card[data-rollup=\"unknown\"]{border-left-color:var(--unk)}\n.card-head{display:flex;align-items:center;justify-content:space-between;margin-bottom:12px}\n.card-title{font-family:system-ui,sans-serif;text-transform:uppercase;letter-spacing:.1em;font-size:12px;font-weight:600}\n.grid{width:100%;border-collapse:collapse;font-size:12px}\n.grid th{text-align:left;font-family:system-ui,sans-serif;text-transform:uppercase;letter-spacing:.1em;font-size:9px;\n color:var(--ink-dim);font-weight:600;padding:4px 10px 8px;border-bottom:1px solid var(--bezel)}\n.grid td{padding:6px 10px;border-bottom:1px solid var(--track);vertical-align:middle}\n.grid tr:last-child td{border-bottom:0}\n.rem-row td{padding-top:0;border-bottom:0}\n.mono{font-family:ui-monospace,monospace}\n.dim{color:var(--ink-dim)}.small{font-size:11px}\n\n/* Pills */\n.pill{display:inline-flex;align-items:center;gap:6px;padding:2px 9px;border-radius:999px;font-size:11px;\n border:1px solid var(--bezel);background:var(--panel-2);white-space:nowrap}\n.pdot{width:7px;height:7px;border-radius:50%;flex:none;background:var(--unk)}\n.pill.s-alive{color:var(--ok)}.pill.s-alive .pdot{background:var(--ok);box-shadow:0 0 6px var(--ok)}\n.pill.s-stale{color:var(--warn)}.pill.s-stale .pdot{background:var(--warn);box-shadow:0 0 6px var(--warn)}\n.pill.s-gone{color:var(--crit)}.pill.s-gone .pdot{background:var(--crit);box-shadow:0 0 6px var(--crit)}\n.pill.s-stopped{color:var(--stopped)}.pill.s-stopped .pdot{background:var(--stopped);box-shadow:0 0 6px var(--stopped)}\n.pill.s-unknown{color:var(--unk)}.pill.s-unknown .pdot{background:var(--unk)}\n.cell-detail{color:var(--ink-dim)}\n\n/* Project data-plane */\n.dp-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:12px;margin-top:14px;\n padding-top:13px;border-top:1px solid var(--bezel)}\n.dp-block{display:flex;flex-direction:column;gap:6px}\n.dp-l{font-family:system-ui,sans-serif;text-transform:uppercase;letter-spacing:.1em;font-size:9px;color:var(--ink-dim)}\n.dp-v{font-size:12px}\n.chips{display:flex;flex-wrap:wrap;gap:5px}\n.dbar{display:flex;height:9px;border-radius:5px;overflow:hidden;background:var(--track);border:1px solid var(--bezel)}\n.dbar-acked{background:var(--ok);transition:width .5s ease}\n.dbar-behind{background:var(--warn);transition:width .5s ease}\n.results{color:var(--ink-dim);font-size:12px;margin-top:8px}\n\n/* Daemon instruments */\n.instr-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:12px;margin-bottom:16px}\n.instr{border:1px solid var(--bezel);border-radius:12px;background:var(--panel);padding:13px 15px;box-shadow:var(--shadow);display:flex;flex-direction:column;gap:7px}\n.instr-l{font-family:system-ui,sans-serif;text-transform:uppercase;letter-spacing:.12em;font-size:9px;color:var(--ink-dim)}\n.instr-v{font-size:15px;display:flex;align-items:center;gap:9px;flex-wrap:wrap}\n.instr-sub{color:var(--ink-dim);font-size:11px}\n\n.empty{border:1px dashed var(--bezel);border-radius:12px;padding:24px;color:var(--ink-dim);text-align:center;background:var(--panel)}\n\n:focus-visible{outline:2px solid var(--hud);outline-offset:2px;border-radius:4px}\n\n@keyframes beat{0%,100%{box-shadow:0 0 0 0 rgba(58,210,159,.45)}50%{box-shadow:0 0 0 6px rgba(58,210,159,0)}}\n@keyframes blink{50%{opacity:.35}}\n@keyframes pulseBar{0%,100%{opacity:1}50%{opacity:.4}}\n@keyframes fade{from{opacity:0;transform:translateY(4px)}to{opacity:1;transform:none}}\n@keyframes rise{from{opacity:0;transform:scale(.92)}to{opacity:1;transform:none}}\n@media (prefers-reduced-motion:reduce){*{animation:none!important;transition:none!important}}\n@media (max-width:640px){.hero{gap:18px}.deck{padding:12px 14px;gap:10px}.tagline{display:none}#content{padding:14px}}\n`.trim();\n\n// Persistent client controller: tab switching (event-delegated), rolling history\n// for sparklines, count-ups, and the SSE wiring. Lives in the shell so it is set\n// up ONCE and survives every #content swap; `refresh()` reapplies tab + redraws\n// charts after each frame.\nconst CLIENT_JS = `\n(function(){\n var activeTab='overview';var hist={};var prev={};\n function pushHist(k,v,t){var a=hist[k]||(hist[k]=[]);if(a.length&&a[a.length-1].t===t)return;a.push({t:t,v:v});if(a.length>48)a.shift();}\n function ingest(){var el=document.getElementById('squadrant-metrics');if(!el)return;var m;try{m=JSON.parse(el.textContent);}catch(e){return;}pushHist('errors',m.errors,m.t);pushHist('behind',m.behind,m.t);pushHist('crewAge',Math.round(m.crewAgeMs/1000),m.t);}\n function sparkSVG(a){var W=100,H=28,p=2;if(!a.length)return'';var vs=a.map(function(x){return x.v;});var mx=Math.max.apply(null,vs),mn=Math.min.apply(null,vs);if(mx===mn)mx=mn+1;var n=a.length;var pts=a.map(function(x,i){var px=n>1?p+i/(n-1)*(W-2*p):W/2;var py=H-p-(x.v-mn)/(mx-mn)*(H-2*p);return[px,py];});var d=pts.map(function(pt,i){return(i?'L':'M')+pt[0].toFixed(1)+' '+pt[1].toFixed(1);}).join(' ');var last=pts[pts.length-1];var area=d+' L'+last[0].toFixed(1)+' '+H+' L'+pts[0][0].toFixed(1)+' '+H+' Z';return'<path class=\"spark-area\" d=\"'+area+'\"/><path class=\"spark-line\" d=\"'+d+'\"/><circle class=\"spark-dot\" cx=\"'+last[0].toFixed(1)+'\" cy=\"'+last[1].toFixed(1)+'\" r=\"2\"/>';}\n function drawSparks(){var ns=document.querySelectorAll('[data-spark]');for(var i=0;i<ns.length;i++){ns[i].innerHTML=sparkSVG(hist[ns[i].getAttribute('data-spark')]||[]);}}\n function applyTab(){var ts=document.querySelectorAll('[data-tab]');for(var i=0;i<ts.length;i++){var on=ts[i].getAttribute('data-tab')===activeTab;ts[i].setAttribute('aria-selected',on?'true':'false');ts[i].classList.toggle('on',on);}var ps=document.querySelectorAll('[data-panel]');for(var j=0;j<ps.length;j++){var on2=ps[j].getAttribute('data-panel')===activeTab;ps[j].hidden=!on2;}}\n function ease(k){return k<.5?2*k*k:1-Math.pow(-2*k+2,2)/2;}\n function countUps(){var ns=document.querySelectorAll('[data-countup]');for(var i=0;i<ns.length;i++){(function(el){var key=el.getAttribute('data-countup');var to=parseFloat(el.getAttribute('data-value'))||0;var from=prev[key]!=null?prev[key]:0;prev[key]=to;if(from===to){el.textContent=to;return;}var s=null;function step(ts){if(s===null)s=ts;var k=Math.min(1,(ts-s)/600);el.textContent=Math.round(from+(to-from)*ease(k));if(k<1)requestAnimationFrame(step);}requestAnimationFrame(step);})(ns[i]);}}\n function refresh(){ingest();applyTab();drawSparks();countUps();}\n document.addEventListener('click',function(e){var t=e.target&&e.target.closest?e.target.closest('[data-tab]'):null;if(t){activeTab=t.getAttribute('data-tab');applyTab();var c=document.getElementById('content');if(c){c.classList.remove('swap');void c.offsetWidth;c.classList.add('swap');}}});\n document.addEventListener('keydown',function(e){var ae=document.activeElement;if((e.key==='ArrowRight'||e.key==='ArrowLeft')&&ae&&ae.getAttribute&&ae.getAttribute('data-tab')){var o=['overview','projects','daemon','environment'];var i=o.indexOf(activeTab);i=(i+(e.key==='ArrowRight'?1:o.length-1))%o.length;activeTab=o[i];applyTab();var nt=document.querySelector('[data-tab=\"'+activeTab+'\"]');if(nt)nt.focus();e.preventDefault();}});\n var led=document.getElementById('led');var conn=document.getElementById('conn');var updated=document.getElementById('updated');\n function tickAge(){if(!generatedAt)return;var s=Math.max(0,Math.round((Date.now()-generatedAt)/1000));updated.textContent='updated '+s+'s ago';}\n setInterval(tickAge,1000);\n var es=new EventSource('/events');\n es.onopen=function(){conn.textContent='live';conn.className='conn live';led.className='led live';};\n es.onerror=function(){conn.textContent='reconnecting';conn.className='conn down';led.className='led down';};\n es.onmessage=function(e){try{var d=JSON.parse(e.data);document.getElementById('content').innerHTML=d.contentHtml;generatedAt=d.generatedAt;tickAge();refresh();}catch(_){}};\n refresh();tickAge();\n})();\n`.trim();\n\n/** Pure. The full HTML document for the initial GET / load (shell + content + SSE JS). */\nexport function renderHtml(snap: FullSnapshot, opts: { port?: number } = {}): string {\n const port = opts.port ? `:${opts.port}` : \"\";\n return [\n \"<!DOCTYPE html>\",\n '<html lang=\"en\"><head><meta charset=\"utf-8\">',\n '<meta name=\"viewport\" content=\"width=device-width,initial-scale=1\">',\n \"<title>squadrant · system health</title>\",\n `<style>${STYLE}</style></head><body class=\"theme-light\">`,\n `<header class=\"deck\">`,\n `<div class=\"brand\"><span class=\"led\" id=\"led\"></span><span class=\"wordmark\">Squadrant</span><span class=\"tagline\">Mission Control</span></div>`,\n `<span class=\"deck-spacer\"></span>`,\n `<div class=\"readout\"><span class=\"conn\" id=\"conn\">connecting</span><span class=\"updated\" id=\"updated\"></span><span class=\"port\">${esc(port)}</span></div>`,\n `</header>`,\n `<main id=\"content\">${renderContent(snap)}</main>`,\n `<script>let generatedAt=${snap.generatedAt};${CLIENT_JS}</script>`,\n \"</body></html>\",\n ].join(\"\");\n}\n","import { Command } from \"commander\";\nimport { execSync } from \"node:child_process\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport os from \"node:os\";\nimport chalk from \"chalk\";\nimport { loadConfig, resolveHome } from \"@squadrant/shared\";\nimport type { ModelRoutingConfig } from \"@squadrant/shared\";\nimport { createClaudeDriver, createCodexDriver, createGeminiDriver, createOpencodeDriver, CapabilityRegistry, buildAgentCmd } from \"@squadrant/agents\";\nimport type { AgentDriver } from \"@squadrant/agents\";\nimport { RuntimeRegistry, createCmuxDriver, createObsidianDriver, WorkspaceRegistry, isInsideCmux, cmuxLocal } from \"@squadrant/workspaces\";\nimport type { RuntimeDriver } from \"@squadrant/workspaces\";\nimport { ensureSpokeLayout } from \"@squadrant/shared\";\nimport { classifyStartupSurface } from \"@squadrant/workspaces\";\nimport { shouldStartFresh, recordSession } from \"@squadrant/core\";\n\nconst CMUX_APP = \"/Applications/cmux.app\";\nconst TEMPLATES_DIR = path.join(os.homedir(), \".config\", \"squadrant\", \"templates\");\nconst SESSIONS_PATH = path.join(os.homedir(), \".config\", \"squadrant\", \"sessions.json\");\n\nfunction ensureCmuxReady(): void {\n if (isInsideCmux()) return;\n\n console.log(chalk.yellow(\"\\n Not running inside cmux. Opening cmux app...\\n\"));\n execSync(`open \"${CMUX_APP}\"`, { stdio: \"inherit\" });\n console.log(chalk.bold(\" Run `squadrant launch` from inside a cmux workspace.\\n\"));\n process.exit(0);\n}\n\nexport interface StartupDeliveryOptions {\n /** Max time to wait for the surface to leave the cold-init splash. */\n readyTimeoutMs?: number;\n /** Pause after a send before checking whether the turn started. */\n settleMs?: number;\n /** Poll cadence while waiting for readiness. */\n pollMs?: number;\n /** Hard cap on (re)send attempts. */\n maxAttempts?: number;\n}\n\n/**\n * #292: deliver the captain/command startup prompt deterministically instead of\n * on a fixed 8s timer. CC cold-init takes 5–15s, so a fixed delay either wastes\n * boot time or — on a slow boot — drops the prompt on the splash screen (#235),\n * leaving the captain idle and the relay unbooted.\n *\n * The loop, per attempt: (1) poll until the surface is past the splash; (2) if a\n * turn is already running, stop — never queue a duplicate startup run; (3) send;\n * (4) after a short settle, re-check — a real submit flips the surface to\n * \"working\", so we re-send ONLY while it's still \"idle\" (keystrokes were dropped).\n * Re-sending strictly on observed-still-idle is what guards against duplicate\n * runs: a prompt that landed is never sent twice. Best-effort and never throws.\n */\nexport async function deliverStartupPrompt(\n runtime: Pick<RuntimeDriver, \"readScreen\" | \"send\">,\n refId: string,\n prompt: string,\n opts: StartupDeliveryOptions = {},\n): Promise<void> {\n const readyTimeoutMs = opts.readyTimeoutMs ?? 30_000;\n const settleMs = opts.settleMs ?? 2_500;\n const pollMs = opts.pollMs ?? 1_000;\n const maxAttempts = opts.maxAttempts ?? 3;\n const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms));\n const read = async () => runtime.readScreen(refId).catch(() => \"\");\n\n for (let attempt = 0; attempt < maxAttempts; attempt++) {\n // Phase 1 — wait out cold init (poll, don't guess with a fixed delay).\n // Keep the last-read screen as the pre-send baseline for the Phase-3 check.\n const deadline = Date.now() + readyTimeoutMs;\n let preSend = await read();\n let state = classifyStartupSurface(preSend);\n while (state === \"loading\" && Date.now() < deadline) {\n await sleep(pollMs);\n preSend = await read();\n state = classifyStartupSurface(preSend);\n }\n\n // A turn is already in flight (a prior attempt landed, or a resumed session\n // auto-continued). Never keystroke into it — that would queue a duplicate run.\n if (state === \"working\") return;\n\n // Phase 2 — deliver. We send on \"idle\" (input-ready) and, as a non-hanging\n // fallback, on a \"loading\" timeout (e.g. a non-Claude agent whose chrome we\n // don't recognize) so a launch is never left silently without its prompt.\n await runtime.send(refId, prompt).catch(() => { /* best-effort */ });\n\n // Timed out waiting for chrome — sent blind once; nothing to confirm, stop.\n if (state === \"loading\") return;\n\n // Phase 3 — confirm by whether the surface CHANGED, not by re-matching a\n // working-spinner. The old guard re-sent \"while still idle\", relying on\n // classifyStartupSurface → CC_WORKING_RE matching the live spinner. The newer\n // CC renders the early turn as a bare \"✽ Synthesizing…\" (no timer/token/shell\n // marker) and streams \"⏺ Thinking…\" with no spinner line at all — none of\n // which CC_WORKING_RE matches — so a captain that ALREADY accepted the prompt\n // and is busy thinking reads as \"idle\" at the +settleMs sample, and the loop\n // re-sends → duplicate startup run (cmux/CC render drift, audit A3; the code\n // is unchanged since v0.6.2). A LANDED prompt always mutates the surface (the\n // submitted message echoes into the transcript and the turn begins); DROPPED\n // keystrokes (#235) leave the surface byte-identical to the pre-send baseline.\n // Re-send only on no-change — robust to whatever the spinner renders as.\n await sleep(settleMs);\n const after = await read();\n if (after !== preSend) return;\n }\n}\n\nasync function launchWorkspace(\n runtime: RuntimeDriver,\n name: string,\n agentCmd: string,\n cwd?: string,\n navigate = false,\n forceFresh = false,\n pinToTop = false,\n initialPrompt?: string,\n): Promise<void> {\n ensureCmuxReady();\n\n const existing = await runtime.status(name);\n if (existing && forceFresh) {\n console.log(chalk.yellow(` Closing stale workspace '${name}' for fresh start`));\n await runtime.stop(existing.id);\n } else if (existing) {\n console.log(chalk.yellow(` Workspace '${name}' already exists — switching to it`));\n // TODO(runtime): select/focus not yet abstracted; direct cmux call retained intentionally\n cmuxLocal([\"select-workspace\", \"--workspace\", existing.id]);\n return;\n }\n\n let currentRef: string | undefined;\n try {\n // TODO(runtime): current-workspace not yet abstracted\n const cur = cmuxLocal([\"current-workspace\"]);\n currentRef = cur.match(/workspace:\\d+/)?.[0];\n } catch { /* ignore */ }\n\n const ref = await runtime.spawn({\n name,\n workdir: cwd ?? process.cwd(),\n command: agentCmd,\n pinToTop,\n });\n\n if (initialPrompt) {\n // #292: deterministic delivery — poll for input-readiness, send, and bounded\n // re-send if the first turn was dropped (replaces the racy fixed 8s delay\n // that dropped the prompt on slow 5–15s cold boots). Fire-and-forget, as the\n // old setTimeout was, so launch stays non-blocking and `--all` dispatches\n // captains in parallel; the loop's pending poll timers keep the CLI process\n // alive until delivery completes.\n void deliverStartupPrompt(runtime, ref.id, initialPrompt);\n }\n\n if (navigate) {\n // TODO(runtime): select not yet abstracted\n cmuxLocal([\"select-workspace\", \"--workspace\", ref.id]);\n } else if (currentRef) {\n // TODO(runtime): select not yet abstracted\n cmuxLocal([\"select-workspace\", \"--workspace\", currentRef]);\n }\n\n console.log(chalk.green(` ✔ Workspace '${name}' created`));\n}\n\nexport const launchCommand = new Command(\"launch\")\n .description(\n \"Launch a project captain (with project arg) or all captains (--all). Use `squadrant command` for one-shot Command tasks.\",\n )\n .argument(\"[project]\", \"Project name to launch captain for\")\n .option(\"--fresh\", \"Start a new session instead of resuming the last one\")\n .option(\"--all\", \"Launch all captain workspaces\")\n .action(async (project: string | undefined, opts: { fresh?: boolean; all?: boolean }) => {\n const config = loadConfig();\n\n // Build agent driver registry\n const drivers: Record<string, AgentDriver> = {\n claude: createClaudeDriver(),\n codex: createCodexDriver(),\n gemini: createGeminiDriver(),\n opencode: createOpencodeDriver(),\n };\n const registry = new CapabilityRegistry(drivers);\n\n // Build runtime driver registry\n const runtimes = new RuntimeRegistry({ cmux: createCmuxDriver() });\n\n async function launchOne(\n workspaceName: string,\n role: string,\n cwd: string,\n permissionMode: string,\n navigate: boolean,\n pinToTop = false,\n projectName?: string,\n ): Promise<void> {\n let forceFresh = !!opts.fresh;\n if (!forceFresh) {\n const auto = shouldStartFresh(workspaceName, role, { sessionsPath: SESSIONS_PATH, templatesDir: TEMPLATES_DIR });\n if (auto.fresh) {\n console.log(chalk.cyan(` ↻ ${auto.reason}`));\n forceFresh = true;\n }\n }\n\n const roleConfig = config.defaults.roles?.[role as keyof NonNullable<typeof config.defaults.roles>];\n const agentName = roleConfig?.agent || \"claude\";\n const model = roleConfig?.model || config.defaults.models?.[role as keyof ModelRoutingConfig];\n const agentCmd = buildAgentCmd(agentName, registry, role, forceFresh, permissionMode, model, TEMPLATES_DIR);\n recordSession(workspaceName, role, { sessionsPath: SESSIONS_PATH, templatesDir: TEMPLATES_DIR });\n\n // Auto-trigger startup checklist\n let initialPrompt: string | undefined;\n if (role === \"captain\") {\n initialPrompt = \"Run your startup checklist: use the squadrant:captain-ops skill, complete all startup steps, then report ready.\";\n } else if (role === \"command\") {\n initialPrompt = \"Run your startup checklist: use the squadrant:command-ops skill, complete your daily briefing, then report ready.\";\n }\n\n const runtime = projectName\n ? runtimes.forProject(projectName, config)\n : runtimes.global(config);\n\n try {\n await launchWorkspace(runtime, workspaceName, agentCmd, cwd, navigate, forceFresh, pinToTop, initialPrompt);\n } catch (err) {\n console.error(chalk.red(` ✘ Failed: ${(err as Error).message}`));\n }\n }\n\n if (opts.all) {\n // Launch all captains. Command is no longer auto-launched (#42).\n const hubPath = resolveHome(config.hubVault);\n fs.mkdirSync(hubPath, { recursive: true });\n\n console.log(chalk.bold(\"\\nLaunching all captain workspaces\\n\"));\n\n for (const [name, proj] of Object.entries(config.projects)) {\n const projPath = resolveHome(proj.path);\n const spokePath = resolveHome(proj.spokeVault);\n if (!fs.existsSync(spokePath)) {\n const spokeDriver = new WorkspaceRegistry({ obsidian: createObsidianDriver }).forProject(name, config);\n await ensureSpokeLayout(spokeDriver);\n console.log(chalk.cyan(` ✔ Created spoke vault at ${spokePath}`));\n }\n console.log(chalk.bold(`\\n Captain: ${proj.captainName} (${name})`));\n await launchOne(proj.captainName, \"captain\", projPath, config.defaults.permissions?.captain || \"auto\", false, true, name);\n }\n console.log(\"\");\n } else if (!project) {\n console.error(\n chalk.red(\n \"\\n ✘ Specify a project name, or pass --all to launch every captain.\\n\" +\n \" For one-shot Command tasks, use `squadrant command --task <briefing|learnings-review|wiki-aggregate>`.\\n\",\n ),\n );\n process.exit(1);\n } else {\n // Launch captain workspace for a project\n if (!config.projects[project]) {\n console.error(\n chalk.red(\n `\\n ✘ Project '${project}' not found. Run 'squadrant projects list' to see registered projects.\\n`,\n ),\n );\n process.exit(1);\n }\n\n const proj = config.projects[project];\n const projPath = resolveHome(proj.path);\n\n // Ensure spoke vault exists\n const spokePath = resolveHome(proj.spokeVault);\n if (!fs.existsSync(spokePath)) {\n const spokeDriver = new WorkspaceRegistry({ obsidian: createObsidianDriver }).forProject(project, config);\n await ensureSpokeLayout(spokeDriver);\n console.log(chalk.cyan(` ✔ Created spoke vault at ${spokePath}`));\n }\n\n console.log(\n chalk.bold(\n `\\nLaunching captain workspace for '${project}' (${proj.captainName})\\n`,\n ),\n );\n await launchOne(proj.captainName, \"captain\", projPath, config.defaults.permissions?.captain || \"auto\", false, true, project);\n }\n });\n","import { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport { loadConfig } from \"@squadrant/shared\";\nimport { createCmuxDriver, RuntimeRegistry } from \"@squadrant/workspaces\";\nimport type { RuntimeDriver } from \"@squadrant/workspaces\";\nimport { squadrantdCall } from \"./crew-control.js\";\nimport type { TaskRecord } from \"@squadrant/shared\";\nimport { TERMINAL_STATES } from \"@squadrant/shared\";\n\n// Captain workspaces gained the leading \"⚓ \" prefix partway through squadrant's\n// life. Workspaces created before that convention persist with the un-prefixed\n// name and shutdown needs to match both shapes.\nfunction nameVariants(name: string): string[] {\n const stripped = name.replace(/^⚓\\s+/, \"\").trim();\n return stripped === name ? [name] : [name, stripped];\n}\n\nasync function closeMatching(\n runtime: RuntimeDriver,\n variants: string[],\n label: string,\n): Promise<{ closed: string[]; failed: string[] }> {\n const workspaces = await runtime.list();\n const matches = workspaces.filter((w) => variants.includes(w.name));\n const closed: string[] = [];\n const failed: string[] = [];\n if (matches.length === 0) {\n console.log(\n chalk.yellow(` ⚠ Workspace '${label}' not found — already closed?`),\n );\n return { closed, failed };\n }\n for (const ws of matches) {\n try {\n await runtime.stop(ws.id);\n console.log(chalk.green(` ✔ Closed: ${ws.name}`));\n closed.push(ws.name);\n } catch {\n console.log(chalk.red(` ✘ Failed to close: ${ws.name}`));\n failed.push(ws.name);\n }\n }\n return { closed, failed };\n}\n\nexport const shutdownCommand = new Command(\"shutdown\")\n .description(\n \"Shutdown command + all captain workspaces (no args) or one captain workspace\",\n )\n .argument(\"[project]\", \"Project name to shut down captain for\")\n .action(async (project: string | undefined) => {\n const config = loadConfig();\n const runtimes = new RuntimeRegistry({ cmux: createCmuxDriver() });\n\n if (!project) {\n const globalRuntime = runtimes.global(config);\n const workspaces = await globalRuntime.list();\n const captainVariants = Object.values(config.projects).flatMap((p) =>\n nameVariants(p.captainName),\n );\n const commandName = config.commandName || \"command\";\n const commandVariants = nameVariants(commandName);\n const allVariants = new Set([...captainVariants, ...commandVariants]);\n const squadrantWorkspaces = workspaces.filter((w) => allVariants.has(w.name));\n\n if (squadrantWorkspaces.length === 0) {\n console.log(chalk.yellow(\"\\nNo squadrant workspaces found to close.\\n\"));\n return;\n }\n\n console.log(\n chalk.bold(\n `\\nShutting down ${squadrantWorkspaces.length} workspace(s)...\\n`,\n ),\n );\n // Terminalize all non-terminal crew tasks across every project before\n // closing workspaces — prevents ghost records from flooding on restart.\n for (const proj of Object.keys(config.projects)) {\n try {\n const tasks = (await squadrantdCall({ kind: \"list\", project: proj })) as TaskRecord[];\n for (const task of tasks) {\n if (!TERMINAL_STATES.has(task.state)) {\n await squadrantdCall({ kind: \"event\", project: proj, event: { type: \"task.cancelled\", id: task.id, reason: \"captain shutdown\" } });\n }\n }\n } catch { /* best-effort — daemon miss must not block workspace close */ }\n }\n for (const ws of squadrantWorkspaces) {\n try {\n await globalRuntime.stop(ws.id);\n console.log(chalk.green(` ✔ Closed: ${ws.name}`));\n } catch {\n console.log(chalk.red(` ✘ Failed to close: ${ws.name}`));\n }\n }\n console.log(\"\");\n return;\n }\n\n if (!config.projects[project]) {\n console.error(\n chalk.red(\n `\\n ✘ Project '${project}' not found. Run 'squadrant projects list' to see registered projects.\\n`,\n ),\n );\n process.exit(1);\n }\n\n const captainName = config.projects[project].captainName;\n const runtime = runtimes.forProject(project, config);\n console.log(\n chalk.bold(`\\nShutting down captain workspace for '${project}'...\\n`),\n );\n\n // Terminalize non-terminal crew tasks for this project before closing the\n // captain workspace — prevents ghost records from flooding on restart (#225).\n try {\n const tasks = (await squadrantdCall({ kind: \"list\", project })) as TaskRecord[];\n for (const task of tasks) {\n if (!TERMINAL_STATES.has(task.state)) {\n await squadrantdCall({ kind: \"event\", project, event: { type: \"task.cancelled\", id: task.id, reason: \"captain shutdown\" } });\n }\n }\n } catch { /* best-effort — daemon miss must not block workspace close */ }\n\n const { failed } = await closeMatching(\n runtime,\n nameVariants(captainName),\n captainName,\n );\n console.log(\"\");\n if (failed.length > 0) process.exit(1);\n });\n","import { Command } from \"commander\";\nimport fs from \"node:fs\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { execSync } from \"node:child_process\";\nimport chalk from \"chalk\";\nimport { loadConfig, readStamp } from \"@squadrant/shared\";\n\nconst REPO_URL = \"https://github.com/tu11aa/squadrant\";\n\n// Real running version. Path math is dist-relative and invariant to source\n// moves: the bundle lives at dist/index.js, so \"../package.json\" is the root\n// package.json (mirrors readPkgVersion in config.ts and index.ts).\nfunction readPkgVersion(): string {\n try {\n const pkgPath = path.join(path.dirname(fileURLToPath(import.meta.url)), \"..\", \"package.json\");\n return (JSON.parse(fs.readFileSync(pkgPath, \"utf-8\")).version as string) ?? \"unknown\";\n } catch {\n return \"unknown\";\n }\n}\n\ninterface Metrics {\n projects?: number;\n launches?: number;\n shutdowns?: number;\n lastUsed?: string;\n [key: string]: unknown;\n}\n\nfunction readMetrics(metricsPath: string): Metrics {\n try {\n return JSON.parse(fs.readFileSync(metricsPath, \"utf-8\")) as Metrics;\n } catch {\n return {};\n }\n}\n\nexport function buildIssueUrl(metrics: Metrics, squadrantVersion: string): string {\n const nodeVersion = process.versions.node;\n const platform = process.platform;\n\n const body = [\n \"## Feedback / Bug Report\",\n \"\",\n \"**Describe your feedback or issue:**\",\n \"\",\n \"<!-- Please describe what happened or what you'd like to see -->\",\n \"\",\n \"## Environment\",\n \"\",\n \"```\",\n `squadrant: ${squadrantVersion}`,\n `node: ${nodeVersion}`,\n `platform: ${platform}`,\n \"```\",\n \"\",\n \"## Usage Metrics\",\n \"\",\n \"```json\",\n JSON.stringify(metrics, null, 2),\n \"```\",\n ].join(\"\\n\");\n\n const params = new URLSearchParams({\n template: \"feedback.md\",\n title: \"[feedback] \",\n body,\n });\n\n return `${REPO_URL}/issues/new?${params.toString()}`;\n}\n\nexport const feedbackCommand = new Command(\"feedback\")\n .description(\"Open a pre-filled GitHub issue for feedback or bug reports\")\n .action(() => {\n const config = loadConfig();\n const metricsPath = config.metrics?.path || path.join(os.homedir(), \".config\", \"squadrant\", \"metrics.json\");\n const metrics = readMetrics(metricsPath);\n\n const version = readStamp(config) ?? readPkgVersion();\n const issueUrl = buildIssueUrl(metrics, version);\n\n console.log(chalk.bold(\"\\nOpening feedback issue in browser...\\n\"));\n console.log(chalk.dim(` URL: ${issueUrl.substring(0, 80)}...\\n`));\n\n try {\n execSync(`open \"${issueUrl}\"`, { stdio: \"ignore\" });\n console.log(chalk.green(\" ✔ Browser opened\\n\"));\n } catch {\n console.log(chalk.yellow(\" ⚠ Could not open browser automatically.\"));\n console.log(` Open manually: ${chalk.cyan(issueUrl)}\\n`);\n }\n });\n","import { Command } from \"commander\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport chalk from \"chalk\";\nimport matter from \"gray-matter\";\nimport { loadConfig, resolveHome, type ProjectConfig, type SquadrantConfig } from \"@squadrant/shared\";\nimport { readDailyLog, getGitCommits, iso, daysAgo } from \"@squadrant/shared\";\nimport { createObsidianDriver, WorkspaceRegistry } from \"@squadrant/workspaces\";\n\ninterface StatusFrontmatter {\n project?: string;\n captain_session?: string;\n last_updated?: string;\n active_crew?: number;\n tasks_total?: number;\n tasks_completed?: number;\n tasks_in_progress?: number;\n tasks_pending?: number;\n}\n\ninterface ProjectStandup {\n name: string;\n status: StatusFrontmatter;\n dailyLog: string | null;\n gitCommits: string[];\n blockers: string[];\n}\n\nfunction getDateStr(yesterday: boolean): string {\n return iso(daysAgo(yesterday ? 1 : 0));\n}\n\nasync function getProjectStandup(\n name: string,\n project: ProjectConfig,\n dateStr: string,\n registry: WorkspaceRegistry,\n config: SquadrantConfig,\n): Promise<ProjectStandup> {\n const workspace = registry.forProject(name, config);\n // TODO(workspace): status.md still read via raw fs — migrate to workspace driver (see #24)\n const spokeVault = resolveHome(project.spokeVault);\n const statusFile = path.join(spokeVault, \"status.md\");\n\n let status: StatusFrontmatter = {};\n if (fs.existsSync(statusFile)) {\n try {\n status = matter(fs.readFileSync(statusFile, \"utf-8\")).data as StatusFrontmatter;\n } catch { /* empty */ }\n }\n\n const log = await readDailyLog(workspace, dateStr);\n const gitCommits = getGitCommits(project.path, dateStr);\n\n return {\n name,\n status,\n dailyLog: log?.content ?? null,\n gitCommits,\n blockers: log?.blockers ?? [],\n };\n}\n\nfunction formatStandup(standups: ProjectStandup[], dateStr: string, raw: boolean): string {\n const lines: string[] = [];\n const header = `Standup — ${dateStr}`;\n\n if (!raw) {\n lines.push(chalk.bold(`\\n${header}\\n`));\n } else {\n lines.push(`# ${header}\\n`);\n }\n\n let hasBlockers = false;\n\n for (const s of standups) {\n const tasksDone = s.status.tasks_completed ?? 0;\n const tasksTotal = s.status.tasks_total ?? 0;\n const tasksInProgress = s.status.tasks_in_progress ?? 0;\n\n if (!raw) {\n lines.push(chalk.cyan.bold(`## ${s.name}`));\n } else {\n lines.push(`## ${s.name}`);\n }\n\n // What was done\n if (s.gitCommits.length > 0 || tasksDone > 0) {\n lines.push(!raw ? chalk.green(\"Done:\") : \"**Done:**\");\n for (const commit of s.gitCommits) {\n lines.push(` - ${commit}`);\n }\n if (tasksDone > 0 && s.gitCommits.length === 0) {\n lines.push(` - ${tasksDone}/${tasksTotal} tasks completed`);\n }\n }\n\n // In progress\n if (tasksInProgress > 0) {\n lines.push(!raw ? chalk.yellow(\"In Progress:\") : \"**In Progress:**\");\n lines.push(` - ${tasksInProgress} task(s) active`);\n }\n\n // Extract sections from daily log\n if (s.dailyLog) {\n const sections = [\"Completed\", \"In Progress\", \"Tomorrow\"];\n for (const section of sections) {\n const match = s.dailyLog.match(new RegExp(`## ${section}\\\\n([\\\\s\\\\S]*?)(?=\\\\n##|$)`));\n if (match) {\n const items = match[1].trim().split(\"\\n\").filter((l) => l.trim().startsWith(\"-\"));\n if (items.length > 0 && section === \"Tomorrow\") {\n lines.push(!raw ? chalk.blue(\"Next:\") : \"**Next:**\");\n for (const item of items) lines.push(` ${item.trim()}`);\n }\n }\n }\n }\n\n // Blockers\n if (s.blockers.length > 0) {\n hasBlockers = true;\n lines.push(!raw ? chalk.red(\"Blocked:\") : \"**Blocked:**\");\n for (const b of s.blockers) {\n lines.push(` - ${b}`);\n }\n }\n\n // No activity\n if (s.gitCommits.length === 0 && tasksDone === 0 && !s.dailyLog) {\n lines.push(!raw ? chalk.dim(\" (no activity)\") : \" (no activity)\");\n }\n\n lines.push(\"\");\n }\n\n // Summary line\n const totalCommits = standups.reduce((sum, s) => sum + s.gitCommits.length, 0);\n const totalDone = standups.reduce((sum, s) => sum + (s.status.tasks_completed ?? 0), 0);\n\n if (!raw) {\n lines.push(chalk.dim(`--- ${totalCommits} commits, ${totalDone} tasks done${hasBlockers ? \", HAS BLOCKERS\" : \"\"} ---\\n`));\n } else {\n lines.push(`---\\n*${totalCommits} commits, ${totalDone} tasks done${hasBlockers ? \", HAS BLOCKERS\" : \"\"}*\\n`);\n }\n\n return lines.join(\"\\n\");\n}\n\nexport const standupCommand = new Command(\"standup\")\n .description(\"Generate daily standup report from spoke vault data and git logs (zero tokens)\")\n .option(\"-p, --project <name>\", \"Show standup for a specific project only\")\n .option(\"-a, --all\", \"Show all projects (default)\")\n .option(\"-y, --yesterday\", \"Show yesterday's standup instead of today\")\n .option(\"-r, --raw\", \"Output raw markdown (for pasting into Slack/chat)\")\n .action(async (opts) => {\n const config = loadConfig();\n const registry = new WorkspaceRegistry({ obsidian: createObsidianDriver });\n const projects = Object.entries(config.projects);\n\n if (projects.length === 0) {\n console.log(chalk.yellow(\"\\nNo projects registered. Use: squadrant projects add <name> <path>\\n\"));\n return;\n }\n\n const dateStr = getDateStr(!!opts.yesterday);\n const raw = !!opts.raw;\n\n let targets: [string, ProjectConfig][];\n if (opts.project) {\n const match = projects.find(([name]) => name === opts.project);\n if (!match) {\n console.error(chalk.red(`Project \"${opts.project}\" not found.`));\n process.exit(1);\n }\n targets = [match];\n } else {\n targets = projects;\n }\n\n const standups = await Promise.all(\n targets.map(([name, proj]) => getProjectStandup(name, proj, dateStr, registry, config)),\n );\n const output = formatStandup(standups, dateStr, raw);\n console.log(output);\n });\n","import { Command } from \"commander\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport chalk from \"chalk\";\nimport matter from \"gray-matter\";\nimport { loadConfig, resolveHome, type ProjectConfig, type SquadrantConfig } from \"@squadrant/shared\";\nimport {\n readDailyLog,\n parseSection,\n getGitCommitsInRange,\n getMergedPRsInRange,\n enumerateDays,\n iso,\n daysAgo,\n} from \"@squadrant/shared\";\nimport { createObsidianDriver, WorkspaceRegistry } from \"@squadrant/workspaces\";\n\ninterface StatusFrontmatter {\n tasks_total?: number;\n tasks_completed?: number;\n tasks_in_progress?: number;\n}\n\ninterface ProjectRetro {\n name: string;\n shipped: string[];\n inProgress: string[];\n blocked: string[];\n decisions: string[];\n commits: string[];\n mergedPRs: string[];\n tasksCompletedNow: number;\n tasksInProgressNow: number;\n}\n\n// TODO(workspace): status.md still read via raw fs — migrate to workspace driver (see #24)\nfunction readStatus(spokeVault: string): StatusFrontmatter {\n const statusFile = path.join(spokeVault, \"status.md\");\n if (!fs.existsSync(statusFile)) return {};\n try {\n return matter(fs.readFileSync(statusFile, \"utf-8\")).data as StatusFrontmatter;\n } catch {\n return {};\n }\n}\n\nfunction dedupe(items: string[]): string[] {\n const seen = new Set<string>();\n const out: string[] = [];\n for (const it of items) {\n const key = it.toLowerCase();\n if (!seen.has(key)) {\n seen.add(key);\n out.push(it);\n }\n }\n return out;\n}\n\nasync function getProjectRetro(\n name: string,\n project: ProjectConfig,\n fromStr: string,\n toStr: string,\n registry: WorkspaceRegistry,\n config: SquadrantConfig,\n): Promise<ProjectRetro> {\n const workspace = registry.forProject(name, config);\n const spokeVault = resolveHome(project.spokeVault);\n const status = readStatus(spokeVault);\n\n const shipped: string[] = [];\n const inProgress: string[] = [];\n const blocked: string[] = [];\n const decisions: string[] = [];\n\n for (const day of enumerateDays(new Date(fromStr), new Date(toStr))) {\n const log = await readDailyLog(workspace, day);\n if (!log) continue;\n shipped.push(...parseSection(log.content, \"Completed\"));\n inProgress.push(...parseSection(log.content, \"In Progress\"));\n blocked.push(...log.blockers);\n decisions.push(...parseSection(log.content, \"Decisions\"));\n }\n\n const commits = getGitCommitsInRange(\n project.path,\n `${fromStr} 00:00:00`,\n `${toStr} 23:59:59`,\n );\n const mergedPRs = getMergedPRsInRange(\n project.path,\n `${fromStr} 00:00:00`,\n `${toStr} 23:59:59`,\n );\n\n return {\n name,\n shipped: dedupe(shipped),\n inProgress: dedupe(inProgress),\n blocked: dedupe(blocked),\n decisions: dedupe(decisions),\n commits,\n mergedPRs,\n tasksCompletedNow: status.tasks_completed ?? 0,\n tasksInProgressNow: status.tasks_in_progress ?? 0,\n };\n}\n\nfunction renderList(lines: string[], items: string[], raw: boolean, label: string, color: (s: string) => string) {\n if (items.length === 0) return;\n lines.push(raw ? `**${label}:**` : color(`${label}:`));\n for (const it of items) lines.push(` - ${it}`);\n}\n\nfunction formatRetro(retros: ProjectRetro[], fromStr: string, toStr: string, raw: boolean): string {\n const lines: string[] = [];\n const header = `Retro — ${fromStr} → ${toStr}`;\n lines.push(raw ? `# ${header}\\n` : chalk.bold(`\\n${header}\\n`));\n\n let totalCommits = 0;\n let totalPRs = 0;\n let totalShipped = 0;\n\n for (const r of retros) {\n totalCommits += r.commits.length;\n totalPRs += r.mergedPRs.length;\n totalShipped += r.shipped.length;\n\n lines.push(raw ? `## ${r.name}` : chalk.cyan.bold(`## ${r.name}`));\n\n renderList(lines, r.shipped, raw, \"Shipped\", chalk.green);\n if (r.mergedPRs.length > 0) {\n lines.push(raw ? `**PRs merged:**` : chalk.green(\"PRs merged:\"));\n for (const pr of r.mergedPRs) lines.push(` - ${pr}`);\n }\n renderList(lines, r.inProgress, raw, \"In Progress\", chalk.yellow);\n renderList(lines, r.blocked, raw, \"Blocked\", chalk.red);\n renderList(lines, r.decisions, raw, \"Key Decisions\", chalk.magenta);\n\n const metricBits = [\n `${r.commits.length} commits`,\n `${r.mergedPRs.length} PRs merged`,\n `${r.shipped.length} shipped`,\n ];\n lines.push(raw ? `*${metricBits.join(\" · \")}*` : chalk.dim(` ${metricBits.join(\" · \")}`));\n\n if (\n r.shipped.length === 0 &&\n r.commits.length === 0 &&\n r.mergedPRs.length === 0 &&\n r.inProgress.length === 0 &&\n r.blocked.length === 0\n ) {\n lines.push(raw ? \"_(no activity in this window)_\" : chalk.dim(\" (no activity in this window)\"));\n }\n\n lines.push(\"\");\n }\n\n const summary = `${totalShipped} items shipped · ${totalCommits} commits · ${totalPRs} PRs merged`;\n lines.push(raw ? `---\\n*${summary}*\\n` : chalk.dim(`--- ${summary} ---\\n`));\n\n return lines.join(\"\\n\");\n}\n\nexport const retroCommand = new Command(\"retro\")\n .description(\"Generate a retro (weekly/sprint summary) from daily logs and git (zero tokens)\")\n .option(\"-w, --week\", \"Trailing 7 days (default)\")\n .option(\"-s, --sprint [days]\", \"Custom window of N days (default 14 if N omitted)\")\n .option(\"-p, --project <name>\", \"Retro for a single project\")\n .option(\"-a, --all\", \"All projects (default)\")\n .option(\"-r, --raw\", \"Raw markdown output (for pasting into Slack/Obsidian)\")\n .action(async (opts) => {\n const config = loadConfig();\n const registry = new WorkspaceRegistry({ obsidian: createObsidianDriver });\n const projects = Object.entries(config.projects);\n\n if (projects.length === 0) {\n console.log(chalk.yellow(\"\\nNo projects registered. Use: squadrant projects add <name> <path>\\n\"));\n return;\n }\n\n let windowDays = 7;\n if (opts.sprint !== undefined) {\n const parsed = typeof opts.sprint === \"string\" ? parseInt(opts.sprint, 10) : NaN;\n windowDays = Number.isFinite(parsed) && parsed > 0 ? parsed : 14;\n } else if (opts.week) {\n windowDays = 7;\n }\n\n const toStr = iso(new Date());\n const fromStr = iso(daysAgo(windowDays - 1));\n const raw = !!opts.raw;\n\n let targets: [string, ProjectConfig][];\n if (opts.project) {\n const match = projects.find(([name]) => name === opts.project);\n if (!match) {\n console.error(chalk.red(`Project \"${opts.project}\" not found.`));\n process.exit(1);\n }\n targets = [match];\n } else {\n targets = projects;\n }\n\n const retros = await Promise.all(\n targets.map(([name, proj]) => getProjectRetro(name, proj, fromStr, toStr, registry, config)),\n );\n console.log(formatRetro(retros, fromStr, toStr, raw));\n });\n","import { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport { loadConfig } from \"@squadrant/shared\";\nimport { createCmuxDriver, RuntimeRegistry } from \"@squadrant/workspaces\";\nimport type { RuntimeDriver } from \"@squadrant/workspaces\";\nimport type { SquadrantConfig } from \"@squadrant/shared\";\n\nfunction buildRegistry(): RuntimeRegistry {\n return new RuntimeRegistry({\n cmux: createCmuxDriver(),\n });\n}\n\ninterface ResolvedTarget {\n driver: RuntimeDriver;\n workspaceName: string;\n}\n\nfunction resolveTarget(\n registry: RuntimeRegistry,\n config: SquadrantConfig,\n target: string | undefined,\n useCommand: boolean,\n): ResolvedTarget {\n if (useCommand) {\n return {\n driver: registry.global(config),\n workspaceName: config.commandName,\n };\n }\n if (!target) {\n throw new Error(\"Missing target: pass a project name or use --command\");\n }\n const proj = config.projects[target];\n if (!proj) {\n throw new Error(`Project '${target}' not found. Run 'squadrant projects list'.`);\n }\n return {\n driver: registry.forProject(target, config),\n workspaceName: proj.captainName,\n };\n}\n\nasync function needRef(resolved: ResolvedTarget): Promise<string> {\n const ref = await resolved.driver.status(resolved.workspaceName);\n if (!ref) {\n throw new Error(`Workspace '${resolved.workspaceName}' is not running`);\n }\n return ref.id;\n}\n\nexport const runtimeCommand = new Command(\"runtime\")\n .description(\"Interact with the runtime layer (workspaces). Bridges bash scripts to the RuntimeDriver.\");\n\nruntimeCommand\n .command(\"status\")\n .description(\"Print 'running' or 'stopped' for a target; exit 0 if running, 1 if not\")\n .argument(\"[target]\", \"Project name\")\n .option(\"--command\", \"Target the command workspace instead of a project captain\")\n .action(async (target: string | undefined, opts: { command?: boolean }) => {\n const config = loadConfig();\n const registry = buildRegistry();\n try {\n const resolved = resolveTarget(registry, config, target, !!opts.command);\n const ref = await resolved.driver.status(resolved.workspaceName);\n if (ref) {\n console.log(\"running\");\n process.exit(0);\n } else {\n console.log(\"stopped\");\n process.exit(1);\n }\n } catch (err) {\n console.error(chalk.red((err as Error).message));\n process.exit(2);\n }\n });\n\nruntimeCommand\n .command(\"send\")\n .description(\"Send a message to a target workspace AND commit with Enter. With --command, the first positional is the message.\")\n .argument(\"<arg1>\", \"Project name, or the message when --command is used\")\n .argument(\"[arg2]\", \"Message (when target is a project). Omit when using --command.\")\n .option(\"--command\", \"Target the command workspace\")\n .action(async (arg1: string, arg2: string | undefined, opts: { command?: boolean }) => {\n const config = loadConfig();\n const registry = buildRegistry();\n try {\n if (opts.command && arg2 !== undefined) {\n throw new Error(\"With --command, pass only the message (not a project name)\");\n }\n const target = opts.command ? undefined : arg1;\n const message = opts.command ? arg1 : arg2;\n if (!message) throw new Error(\"Message is required\");\n const resolved = resolveTarget(registry, config, target, !!opts.command);\n const ref = await needRef(resolved);\n await resolved.driver.send(ref, message);\n } catch (err) {\n console.error(chalk.red((err as Error).message));\n process.exit(1);\n }\n });\n\nruntimeCommand\n .command(\"send-key\")\n .description(\"Send a literal key press (e.g. Enter, Escape) to a target workspace. With --command, the first positional is the key.\")\n .argument(\"<arg1>\", \"Project name, or the key when --command is used\")\n .argument(\"[arg2]\", \"Key name (when target is a project). Omit when using --command.\")\n .option(\"--command\", \"Target the command workspace\")\n .action(async (arg1: string, arg2: string | undefined, opts: { command?: boolean }) => {\n const config = loadConfig();\n const registry = buildRegistry();\n try {\n if (opts.command && arg2 !== undefined) {\n throw new Error(\"With --command, pass only the key (not a project name)\");\n }\n const target = opts.command ? undefined : arg1;\n const key = opts.command ? arg1 : arg2;\n if (!key) throw new Error(\"Key is required\");\n const resolved = resolveTarget(registry, config, target, !!opts.command);\n const ref = await needRef(resolved);\n await resolved.driver.sendKey(ref, key);\n } catch (err) {\n console.error(chalk.red((err as Error).message));\n process.exit(1);\n }\n });\n\nruntimeCommand\n .command(\"list\")\n .description(\"List all workspaces from the global runtime\")\n .option(\"-j, --json\", \"Output as JSON\")\n .action(async (opts: { json?: boolean }) => {\n const config = loadConfig();\n const registry = buildRegistry();\n const driver = registry.global(config);\n const refs = await driver.list();\n if (opts.json) {\n console.log(JSON.stringify(refs, null, 2));\n } else {\n for (const r of refs) {\n console.log(`${r.id}\\t${r.name}\\t${r.status}`);\n }\n }\n });\n\nruntimeCommand\n .command(\"read-screen\")\n .description(\"Print a terminal snapshot of a target workspace\")\n .argument(\"[target]\", \"Project name\")\n .option(\"--command\", \"Target the command workspace\")\n .action(async (target: string | undefined, opts: { command?: boolean }) => {\n const config = loadConfig();\n const registry = buildRegistry();\n try {\n const resolved = resolveTarget(registry, config, target, !!opts.command);\n const ref = await needRef(resolved);\n const screen = await resolved.driver.readScreen(ref);\n process.stdout.write(screen);\n } catch (err) {\n console.error(chalk.red((err as Error).message));\n process.exit(1);\n }\n });\n\nruntimeCommand\n .command(\"stop\")\n .description(\"Stop a target workspace\")\n .argument(\"[target]\", \"Project name\")\n .option(\"--command\", \"Target the command workspace\")\n .action(async (target: string | undefined, opts: { command?: boolean }) => {\n const config = loadConfig();\n const registry = buildRegistry();\n try {\n const resolved = resolveTarget(registry, config, target, !!opts.command);\n const ref = await resolved.driver.status(resolved.workspaceName);\n if (!ref) {\n console.log(chalk.yellow(`Workspace '${resolved.workspaceName}' already stopped`));\n return;\n }\n await resolved.driver.stop(ref.id);\n console.log(chalk.green(`✔ Stopped ${resolved.workspaceName}`));\n } catch (err) {\n console.error(chalk.red((err as Error).message));\n process.exit(1);\n }\n });\n","import { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport { loadConfig, type SquadrantConfig } from \"@squadrant/shared\";\nimport { createObsidianDriver, WorkspaceRegistry } from \"@squadrant/workspaces\";\nimport type { WorkspaceDriver } from \"@squadrant/shared\";\n\nfunction buildRegistry(): WorkspaceRegistry {\n return new WorkspaceRegistry({\n obsidian: createObsidianDriver,\n });\n}\n\nfunction resolveDriver(\n registry: WorkspaceRegistry,\n config: SquadrantConfig,\n projectTarget: string | undefined,\n useHub: boolean,\n): WorkspaceDriver {\n if (useHub) return registry.hub(config);\n if (!projectTarget) throw new Error(\"Missing target: pass a project name or use --hub\");\n return registry.forProject(projectTarget, config);\n}\n\nasync function readStdin(): Promise<string> {\n const chunks: Buffer[] = [];\n for await (const chunk of process.stdin) {\n chunks.push(chunk as Buffer);\n }\n return Buffer.concat(chunks).toString(\"utf-8\");\n}\n\nexport const workspaceCommand = new Command(\"workspace\")\n .description(\"Interact with the workspace layer (vault storage). Bridges bash scripts to the WorkspaceDriver.\");\n\n// Reusable positional parser. The CLI convention:\n// <target> <path> → project workspace\n// --hub <path> → hub workspace\n// With commander we declare <arg1> [arg2] and in the action:\n// if --hub: arg1 is the path (target is implicit).\n// else: arg1 is the target, arg2 is the path.\nfunction resolveTargetAndPath(\n arg1: string,\n arg2: string | undefined,\n useHub: boolean,\n): { projectTarget: string | undefined; path: string } {\n if (useHub) {\n if (arg2 !== undefined) {\n throw new Error(\"With --hub, pass only the path (not a project name)\");\n }\n return { projectTarget: undefined, path: arg1 };\n }\n if (arg2 === undefined) {\n throw new Error(\"Missing path — usage: <project> <path> (or: --hub <path>)\");\n }\n return { projectTarget: arg1, path: arg2 };\n}\n\nworkspaceCommand\n .command(\"read\")\n .description(\"Print the contents of a scope-relative path to stdout\")\n .argument(\"<arg1>\", \"Project name, or the path when --hub is used\")\n .argument(\"[arg2]\", \"Scope-relative path (omit when using --hub)\")\n .option(\"--hub\", \"Target the hub workspace instead of a project spoke\")\n .action(async (arg1: string, arg2: string | undefined, opts: { hub?: boolean }) => {\n const config = loadConfig();\n const registry = buildRegistry();\n try {\n const { projectTarget, path } = resolveTargetAndPath(arg1, arg2, !!opts.hub);\n const driver = resolveDriver(registry, config, projectTarget, !!opts.hub);\n const content = await driver.read(path);\n process.stdout.write(content);\n } catch (err) {\n console.error(chalk.red((err as Error).message));\n process.exit(1);\n }\n });\n\nworkspaceCommand\n .command(\"write\")\n .description(\"Write content to a scope-relative path. Pass '-' as content to read from stdin.\")\n .argument(\"<arg1>\", \"Project name, or the path when --hub is used\")\n .argument(\"<arg2>\", \"Scope-relative path, or content when --hub is used\")\n .argument(\"[arg3]\", \"Content (omit when using --hub). Use '-' for stdin.\")\n .option(\"--hub\", \"Target the hub workspace\")\n .action(async (arg1: string, arg2: string, arg3: string | undefined, opts: { hub?: boolean }) => {\n const config = loadConfig();\n const registry = buildRegistry();\n try {\n let projectTarget: string | undefined;\n let path: string;\n let rawContent: string;\n if (opts.hub) {\n if (arg3 !== undefined) {\n throw new Error(\"With --hub, pass only the path and content\");\n }\n projectTarget = undefined;\n path = arg1;\n rawContent = arg2;\n } else {\n if (arg3 === undefined) {\n throw new Error(\"Missing content — usage: <project> <path> <content>\");\n }\n projectTarget = arg1;\n path = arg2;\n rawContent = arg3;\n }\n const driver = resolveDriver(registry, config, projectTarget, !!opts.hub);\n const payload = rawContent === \"-\" ? await readStdin() : rawContent;\n await driver.write(path, payload);\n } catch (err) {\n console.error(chalk.red((err as Error).message));\n process.exit(1);\n }\n });\n\nworkspaceCommand\n .command(\"list\")\n .description(\"List entries in a scope-relative directory\")\n .argument(\"<arg1>\", \"Project name, or the directory when --hub is used\")\n .argument(\"[arg2]\", \"Scope-relative directory (omit when using --hub)\")\n .option(\"--hub\", \"Target the hub workspace\")\n .action(async (arg1: string, arg2: string | undefined, opts: { hub?: boolean }) => {\n const config = loadConfig();\n const registry = buildRegistry();\n try {\n const { projectTarget, path } = resolveTargetAndPath(arg1, arg2, !!opts.hub);\n const driver = resolveDriver(registry, config, projectTarget, !!opts.hub);\n const entries = await driver.list(path);\n for (const entry of entries) console.log(entry);\n } catch (err) {\n console.error(chalk.red((err as Error).message));\n process.exit(1);\n }\n });\n\nworkspaceCommand\n .command(\"exists\")\n .description(\"Exit 0 if path exists, 1 if not\")\n .argument(\"<arg1>\", \"Project name, or the path when --hub is used\")\n .argument(\"[arg2]\", \"Scope-relative path (omit when using --hub)\")\n .option(\"--hub\", \"Target the hub workspace\")\n .action(async (arg1: string, arg2: string | undefined, opts: { hub?: boolean }) => {\n const config = loadConfig();\n const registry = buildRegistry();\n try {\n const { projectTarget, path } = resolveTargetAndPath(arg1, arg2, !!opts.hub);\n const driver = resolveDriver(registry, config, projectTarget, !!opts.hub);\n const ok = await driver.exists(path);\n process.exit(ok ? 0 : 1);\n } catch (err) {\n console.error(chalk.red((err as Error).message));\n process.exit(2);\n }\n });\n\nworkspaceCommand\n .command(\"mkdir\")\n .description(\"Recursively create a scope-relative directory\")\n .argument(\"<arg1>\", \"Project name, or the path when --hub is used\")\n .argument(\"[arg2]\", \"Scope-relative path (omit when using --hub)\")\n .option(\"--hub\", \"Target the hub workspace\")\n .action(async (arg1: string, arg2: string | undefined, opts: { hub?: boolean }) => {\n const config = loadConfig();\n const registry = buildRegistry();\n try {\n const { projectTarget, path } = resolveTargetAndPath(arg1, arg2, !!opts.hub);\n const driver = resolveDriver(registry, config, projectTarget, !!opts.hub);\n await driver.mkdir(path);\n } catch (err) {\n console.error(chalk.red((err as Error).message));\n process.exit(1);\n }\n });\n","import { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport { loadConfig } from \"@squadrant/shared\";\nimport { createCmuxNotifier, NotifierRegistry } from \"@squadrant/workspaces\";\n\nasync function readStdin(): Promise<string> {\n const chunks: Buffer[] = [];\n for await (const chunk of process.stdin) {\n chunks.push(chunk as Buffer);\n }\n return Buffer.concat(chunks).toString(\"utf-8\");\n}\n\nexport const notifyCommand = new Command(\"notify\")\n .description(\"Send a message to the user via the configured notifier\")\n .argument(\"<message>\", \"Message to send (use '-' to read from stdin)\")\n .action(async (message: string) => {\n const config = loadConfig();\n const registry = new NotifierRegistry({ cmux: createCmuxNotifier });\n try {\n const payload = message === \"-\" ? await readStdin() : message;\n if (!payload) throw new Error(\"Empty message\");\n await registry.get(config).notify(payload);\n } catch (err) {\n console.error(chalk.red((err as Error).message));\n process.exit(1);\n }\n });\n","import { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { loadConfig } from \"@squadrant/shared\";\nimport {\n createCursorEmitter,\n createCodexEmitter,\n createGeminiEmitter,\n createOpencodeEmitter,\n ProjectionRegistry,\n type ProjectionEmitter,\n type ProjectionSource,\n} from \"@squadrant/agents\";\nimport { createObsidianDriver } from \"@squadrant/workspaces\";\nimport type { WorkspaceDriver } from \"@squadrant/shared\";\nimport {\n readUserLevelSource,\n readProjectLevelSource,\n} from \"@squadrant/shared\";\n\ntype Opts = {\n scope?: \"user\" | \"project\";\n project?: string;\n target?: string;\n all?: boolean;\n};\n\nfunction parseScope(v: string): \"user\" | \"project\" {\n if (v !== \"user\" && v !== \"project\") {\n throw new Error(\"--scope must be 'user' or 'project'\");\n }\n return v;\n}\n\nfunction findPackageRoot(): string {\n let dir = path.dirname(fileURLToPath(import.meta.url));\n while (dir !== \"/\" && dir !== \"\") {\n if (fs.existsSync(path.join(dir, \"package.json\"))) return dir;\n dir = path.dirname(dir);\n }\n return process.cwd();\n}\n\nfunction buildRegistry(): ProjectionRegistry {\n return new ProjectionRegistry({\n cursor: createCursorEmitter,\n codex: createCodexEmitter,\n gemini: createGeminiEmitter,\n opencode: createOpencodeEmitter,\n });\n}\n\nfunction resolveTargets(cfg: ReturnType<typeof loadConfig>, opts: Opts): string[] {\n if (opts.target) return [opts.target];\n return cfg.projection?.targets ?? [\"cursor\", \"codex\", \"gemini\"];\n}\n\nasync function runEmit(opts: Opts & { dryRun?: boolean }) {\n if (opts.scope === \"user\" && opts.project) {\n throw new Error(\"--scope user cannot be combined with --project\");\n }\n if (opts.all && (opts.scope || opts.project)) {\n throw new Error(\"--all cannot be combined with --scope or --project\");\n }\n\n const cfg = loadConfig();\n const registry = buildRegistry();\n const workspace: WorkspaceDriver = createObsidianDriver({ root: process.cwd() });\n const targets = resolveTargets(cfg, opts);\n for (const name of targets) registry.get(name); // throws on unknown target\n\n const emittedCount = { written: 0, skipped: 0 };\n\n async function emitForTarget(\n emitter: ProjectionEmitter,\n scope: \"user\" | \"project\",\n source: ProjectionSource,\n projectRoot?: string,\n ) {\n for (const dest of emitter.destinations(scope, projectRoot)) {\n const result = await emitter.emit(source, dest, { dryRun: opts.dryRun });\n if (opts.dryRun) {\n console.log(chalk.cyan(`[${emitter.name}] ${dest.path}`));\n console.log(result.diff ?? \"(no diff)\");\n } else if (result.written) {\n console.log(\n chalk.green(\n `✔ ${emitter.name} → ${dest.path} (${result.bytesWritten} bytes)`,\n ),\n );\n emittedCount.written++;\n } else {\n console.log(chalk.gray(`- ${emitter.name} → ${dest.path} (skipped)`));\n emittedCount.skipped++;\n }\n }\n }\n\n const wantUser =\n opts.scope === \"user\" || opts.all || (!opts.project && !opts.scope);\n const wantProject = opts.scope === \"project\" || opts.all || !!opts.project;\n\n if (wantUser) {\n const source = await readUserLevelSource(workspace, { pkgRoot: findPackageRoot() });\n for (const name of targets) {\n await emitForTarget(registry.get(name), \"user\", source);\n }\n }\n\n if (wantProject) {\n const projectNames = opts.project ? [opts.project] : Object.keys(cfg.projects);\n for (const projectName of projectNames) {\n const proj = cfg.projects[projectName];\n if (!proj) {\n if (opts.project) {\n throw new Error(\n `Unknown project '${projectName}'. Available: ${Object.keys(cfg.projects).join(\", \") || \"(none)\"}`,\n );\n }\n console.error(chalk.yellow(`⚠ unknown project: ${projectName}`));\n continue;\n }\n const source = await readProjectLevelSource(\n createObsidianDriver({ root: proj.path }),\n );\n if (!source) {\n console.log(chalk.gray(`- ${projectName}: no AGENTS.md, skipping`));\n continue;\n }\n for (const name of targets) {\n await emitForTarget(registry.get(name), \"project\", source, proj.path);\n }\n }\n }\n\n if (!opts.dryRun) {\n console.log(\n chalk.bold(\n `\\nProjection complete — ${emittedCount.written} written, ${emittedCount.skipped} skipped.`,\n ),\n );\n }\n}\n\nexport const projectionCommand = new Command(\"projection\").description(\n \"Project squadrant instructions and skills to supported agent formats\",\n);\n\nprojectionCommand\n .command(\"emit\")\n .description(\"Emit projections to disk\")\n .option(\"--scope <scope>\", \"user or project\", parseScope)\n .option(\"--project <name>\", \"managed project name\")\n .option(\"--target <name>\", \"single target (cursor, codex, gemini, opencode)\")\n .option(\"--all\", \"emit user-level + every managed project\")\n .action(async (opts: Opts) => {\n try {\n await runEmit({ ...opts, dryRun: false });\n } catch (err) {\n console.error(chalk.red((err as Error).message));\n process.exit(1);\n }\n });\n\nprojectionCommand\n .command(\"diff\")\n .description(\"Preview changes without writing\")\n .option(\"--scope <scope>\", \"user or project\", parseScope)\n .option(\"--project <name>\", \"managed project name\")\n .option(\"--target <name>\", \"single target (cursor, codex, gemini, opencode)\")\n .option(\"--all\", \"dry-run across user-level + every managed project\")\n .action(async (opts: Opts) => {\n try {\n await runEmit({ ...opts, dryRun: true });\n } catch (err) {\n console.error(chalk.red((err as Error).message));\n process.exit(1);\n }\n });\n\nprojectionCommand\n .command(\"list\")\n .description(\"List registered projection targets\")\n .action(() => {\n const registry = buildRegistry();\n for (const name of registry.list()) {\n const emitter = registry.get(name);\n const userDests = emitter.destinations(\"user\").map((d) => d.path);\n const projectDests = emitter\n .destinations(\"project\", \"<project>\")\n .map((d) => d.path);\n console.log(chalk.bold(name));\n console.log(` user: ${userDests.join(\", \") || \"(none)\"}`);\n console.log(` project: ${projectDests.join(\", \") || \"(none)\"}`);\n }\n });\n","import { Command } from \"commander\";\nimport { AppServerClient } from \"@squadrant/agents\";\nimport { resolve } from \"node:path\";\n\nexport const codexChatSmokeCommand = new Command(\"codex-chat-smoke\")\n .description(\"Phase 1 gate: prove the codex app-server JSON-RPC path works end-to-end.\")\n .option(\"--cwd <dir>\", \"working dir for the codex thread\", process.cwd())\n .option(\"--model <m>\", \"model id (optional)\")\n .option(\n \"--approval\",\n \"include the approval round-trip (Phase 1 PASS requires this)\",\n false\n )\n .action(async (opts: { cwd: string; model?: string; approval: boolean }) => {\n const c = new AppServerClient({ clientInfo: { name: \"squadrant\", version: \"smoke\" } });\n const transcript: string[] = [];\n c.on(\"notification\", (n) =>\n transcript.push(`> ${n.method} ${JSON.stringify(n.params).slice(0, 200)}`)\n );\n c.on(\"stderr\", (s) => transcript.push(`[stderr] ${s.trim()}`));\n try {\n c.start();\n await c.initialize();\n const { threadId } = await c.startThread({\n cwd: resolve(opts.cwd),\n model: opts.model,\n sandbox: \"workspace-write\",\n // With --approval, force untrusted policy so codex requests approval\n // for any tool/shell invocation — proves the round-trip.\n ...(opts.approval ? { approvalPolicy: \"untrusted\" } : {}),\n });\n await c.sendTurn(threadId, \"Reply with exactly: PING-OK\");\n await assertSawText(transcript, \"PING-OK\");\n await c.sendTurn(threadId, \"Now reply with: PONG-OK\");\n await assertSawText(transcript, \"PONG-OK\");\n process.stdout.write(\"smoke: BASIC ok\\n\");\n if (!opts.approval) {\n c.kill();\n return;\n }\n\n // Approval round-trip — Phase-1 GATE.\n const pendingApprovals: Array<{ id: number; method: string }> = [];\n c.on(\"serverRequest\", (r) => {\n pendingApprovals.push({ id: r.id, method: r.method });\n // Approve every approval-shaped request automatically (PASS-by-affirm).\n c.respondToServerRequest(r.id, { decision: \"approve\" });\n });\n // Ask codex to do something that needs approval (writing a file).\n await c.sendTurn(threadId, `Write the text \"approval-ok\" to a file at ${resolve(opts.cwd)}/.squadrant-smoke.txt`);\n if (pendingApprovals.length === 0) {\n throw new Error(\"approval gate: expected at least one server-request (approval/input) during the turn\");\n }\n process.stdout.write(`smoke: APPROVAL ok (${pendingApprovals.length} request(s) handled)\\n`);\n c.kill();\n } catch (e) {\n process.stderr.write(\n `smoke FAIL: ${(e as Error).message}\\n${transcript.join(\"\\n\")}\\n`\n );\n c.kill();\n process.exit(1);\n }\n });\n\nasync function assertSawText(transcript: string[], needle: string): Promise<void> {\n const hit = transcript.some((l) => l.includes(needle));\n if (!hit)\n throw new Error(\n `expected to see '${needle}' in delta stream\\nTranscript:\\n${transcript.join(\"\\n\")}`\n );\n}\n","import { Command } from \"commander\";\nimport fs from \"node:fs\";\nimport { fileURLToPath } from \"node:url\";\nimport { dirname, join } from \"node:path\";\nimport chalk from \"chalk\";\nimport { DEFAULT_CONFIG_PATH, getDefaultConfig, loadConfig, saveConfig, type SquadrantConfig } from \"@squadrant/shared\";\nimport { detectDrift, applySafeFixes, type DriftItem } from \"@squadrant/shared\";\nimport { withStamp } from \"@squadrant/shared\";\n\nexport interface ConfigCheckOptions {\n configPath: string;\n pkgVersion: string;\n fix: boolean;\n accept: boolean;\n}\n\nexport interface ConfigCheckResult {\n items: DriftItem[];\n applied: string[];\n remaining: DriftItem[];\n stamped: boolean;\n}\n\nexport function runConfigCheck(opts: ConfigCheckOptions): ConfigCheckResult {\n const raw = JSON.parse(fs.readFileSync(opts.configPath, \"utf-8\")) as SquadrantConfig;\n const def = getDefaultConfig();\n const items = detectDrift(raw, def);\n\n let working = raw;\n let applied: string[] = [];\n\n if (opts.fix) {\n const r = applySafeFixes(raw, items, def);\n working = r.config;\n applied = r.applied;\n }\n\n const remaining = detectDrift(working, def);\n\n let stamped = false;\n if (opts.accept || remaining.length === 0) {\n working = withStamp(working, opts.pkgVersion);\n stamped = true;\n }\n\n if (opts.fix || opts.accept || stamped) {\n fs.writeFileSync(opts.configPath, JSON.stringify(working, null, 2) + \"\\n\");\n }\n\n return { items, applied, remaining, stamped };\n}\n\n/** Read a value at a dotted path (e.g. \"defaults.effort\"). Throws if the path\n * does not resolve. Returns the raw value (stringified by the caller for display). */\nexport function runConfigGet(key: string, configPath = DEFAULT_CONFIG_PATH): unknown {\n const config = loadConfig(configPath);\n const parts = key.split(\".\");\n let node: unknown = config;\n for (const p of parts) {\n if (node === null || typeof node !== \"object\" || !(p in (node as Record<string, unknown>))) {\n throw new Error(`config key not found: ${key}`);\n }\n node = (node as Record<string, unknown>)[p];\n }\n return node;\n}\n\n/** Write a value at a dotted path, creating intermediate objects as needed.\n * The value is JSON-parsed when it parses (numbers/bools/arrays); otherwise the\n * raw string is kept (so `low` stays \"low\", not a parse error). Persists to disk.\n * NOTE: this is a generic local CLI surface; the Telegram channel restricts which\n * keys may be set via WRITABLE_CONFIG_KEYS, so secrets can't be written remotely. */\nexport function runConfigSet(key: string, value: string, configPath = DEFAULT_CONFIG_PATH): void {\n let parsed: unknown;\n try { parsed = JSON.parse(value); } catch { parsed = value; }\n const config = loadConfig(configPath) as unknown as Record<string, unknown>;\n const parts = key.split(\".\");\n let node = config;\n for (let i = 0; i < parts.length - 1; i++) {\n const p = parts[i];\n if (node[p] === null || typeof node[p] !== \"object\") node[p] = {};\n node = node[p] as Record<string, unknown>;\n }\n node[parts[parts.length - 1]] = parsed;\n saveConfig(config as unknown as SquadrantConfig, configPath);\n}\n\nconst SEV_COLOR: Record<string, (s: string) => string> = {\n info: chalk.green,\n advisory: chalk.yellow,\n warn: chalk.red,\n};\nconst KIND_GLYPH: Record<string, string> = {\n missing: \"+\",\n deprecated: \"-\",\n \"changed-default\": \"~\",\n invalid: \"\\u2717\",\n};\n\nfunction printItems(items: DriftItem[]): void {\n for (const i of items) {\n const color = SEV_COLOR[i.severity] ?? ((s: string) => s);\n const detail = i.note ? ` (${i.note})` : i.suggested !== undefined ? ` \\u2192 ${JSON.stringify(i.suggested)}` : \"\";\n console.log(\" \" + color(`${KIND_GLYPH[i.kind]} ${i.kind}: ${i.path}`) + chalk.dim(detail));\n }\n}\n\nexport const configCommand = new Command(\"config\").description(\"Inspect and reconcile squadrant config\");\n\nconfigCommand\n .command(\"check\")\n .description(\"Detect config drift vs the current default schema\")\n .option(\"--fix\", \"Apply the safe tier (add missing, remove deprecated)\", false)\n .option(\"--accept\", \"Stamp the current version without changing config (dismiss advisories)\", false)\n .option(\"--json\", \"Output drift items as JSON\", false)\n .action((opts: { fix: boolean; accept: boolean; json: boolean }) => {\n const pkgVersion = readPkgVersion();\n if (!fs.existsSync(DEFAULT_CONFIG_PATH)) {\n console.log(chalk.yellow(\"No config found \\u2014 run `squadrant init` first.\"));\n return;\n }\n const res = runConfigCheck({ configPath: DEFAULT_CONFIG_PATH, pkgVersion, fix: opts.fix, accept: opts.accept });\n\n if (opts.json) {\n console.log(JSON.stringify(res.items, null, 2));\n return;\n }\n\n if (res.items.length === 0) {\n console.log(chalk.green(\"\\u2714 Config is in sync with the current schema.\"));\n return;\n }\n\n console.log(chalk.bold(\"\\nConfig drift:\\n\"));\n printItems(res.items);\n\n if (opts.fix && res.applied.length) {\n console.log(chalk.green(`\\n\\u2714 Applied ${res.applied.length} safe item(s): ${res.applied.join(\", \")}`));\n }\n const judgment = res.remaining.filter((i) => i.kind === \"changed-default\" || i.kind === \"invalid\");\n if (judgment.length) {\n console.log(chalk.yellow(`\\n${judgment.length} item(s) need review \\u2014 run the config-doctor skill, or \\`squadrant config check --accept\\` to keep your values.`));\n } else if (res.stamped) {\n console.log(chalk.green(\"\\n\\u2714 Config reconciled and stamped.\"));\n }\n });\n\nconfigCommand\n .command(\"get\")\n .description(\"Read a config value by dotted key (e.g. defaults.effort)\")\n .argument(\"<key>\", \"dotted config key\")\n .action((key: string) => {\n try {\n const value = runConfigGet(key);\n console.log(typeof value === \"string\" ? value : JSON.stringify(value));\n } catch (e) {\n console.error(chalk.red((e as Error).message));\n process.exit(1);\n }\n });\n\nconfigCommand\n .command(\"set\")\n .description(\"Write a config value by dotted key (e.g. defaults.effort low)\")\n .argument(\"<key>\", \"dotted config key\")\n .argument(\"<value>\", \"value (JSON-parsed when possible, else a bare string)\")\n .action((key: string, value: string) => {\n try {\n runConfigSet(key, value);\n console.log(chalk.green(`✔ set ${key} = ${value}`));\n } catch (e) {\n console.error(chalk.red((e as Error).message));\n process.exit(1);\n }\n });\n\nfunction readPkgVersion(): string {\n const pkgPath = join(dirname(fileURLToPath(import.meta.url)), \"..\", \"package.json\");\n return JSON.parse(fs.readFileSync(pkgPath, \"utf-8\")).version as string;\n}\n","// src/commands/heal.ts\n//\n// squadrant heal <component> — targeted, idempotent, machine-readable remediation\n// surface for the detect → notify → remediate loop (#234).\n//\n// Subcommands:\n// heal status — dry-run: print unhealthy components + the exact heal command\n// heal daemon — restart squadrantd via the existing launchd kickstart path\n//\n// DEFERRED: heal crew <id> — re-attach a stuck crew task (overlaps #100, more\n// complex; explicitly out of MVP scope).\nimport { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport { queryHealth } from \"./health-view.js\";\nimport { healCmdFor } from \"@squadrant/core\";\nimport { ensureDaemon as _ensureDaemon } from \"@squadrant/core\";\nimport type { ComponentHealth, HealthState } from \"@squadrant/core\";\n\n// ── pure helpers (fully unit-testable, no I/O) ────────────────────────────────\n\n// Re-exported so existing consumers (tests + external code) that import from\n// this module continue to work without changes.\nexport { healCmdFor };\n\nexport interface HealComponent {\n kind: ComponentHealth[\"kind\"];\n project: string;\n ref: string;\n state: HealthState;\n healCmd: string | null;\n}\n\nexport interface HealStatusResult {\n healthy: boolean;\n daemonUnreachable?: boolean;\n components: HealComponent[];\n}\n\n/**\n * Pure. Assemble the HealStatusResult from a raw liveness snapshot.\n * null input = daemon unreachable.\n */\nexport function buildHealStatus(components: ComponentHealth[] | null): HealStatusResult {\n if (components === null) {\n return { healthy: false, daemonUnreachable: true, components: [] };\n }\n const out: HealComponent[] = components.map((c) => ({\n kind: c.kind,\n project: c.project,\n ref: c.ref,\n state: c.state,\n healCmd: healCmdFor(c),\n }));\n const healthy = out.every((c) => c.healCmd === null);\n return { healthy, components: out };\n}\n\n// ── injectable runners (used by Commander actions + tests) ────────────────────\n\nexport interface HealStatusOpts {\n project: string | undefined;\n json: boolean;\n queryHealth: typeof queryHealth;\n stdout: NodeJS.WritableStream;\n stderr: NodeJS.WritableStream;\n}\n\n/** Returns exit code: 0=all healthy, 1=error/daemon-unreachable, 2=unhealthy */\nexport async function runHealStatus(opts: HealStatusOpts): Promise<number> {\n const { project, json, stdout, stderr } = opts;\n let rows: ComponentHealth[] | null;\n try {\n rows = await opts.queryHealth(project);\n } catch (e) {\n stderr.write(`heal status: ${(e as Error).message}\\n`);\n return 1;\n }\n\n const result = buildHealStatus(rows);\n\n if (result.daemonUnreachable) {\n if (json) {\n stdout.write(JSON.stringify({ healthy: false, daemonUnreachable: true, components: [] }) + \"\\n\");\n } else {\n stderr.write(\"daemon unreachable — start the daemon first (squadrant heal daemon)\\n\");\n }\n return 1;\n }\n\n if (json) {\n stdout.write(JSON.stringify(result) + \"\\n\");\n return result.healthy ? 0 : 2;\n }\n\n if (result.healthy) {\n stdout.write(chalk.green(\"✔ all components healthy\\n\"));\n return 0;\n }\n\n stdout.write(chalk.bold(\"Unhealthy components:\\n\\n\"));\n for (const c of result.components) {\n if (c.healCmd) {\n stdout.write(` ${chalk.red(\"✘\")} ${c.kind.padEnd(8)} ${c.ref.padEnd(16)} ${chalk.red(c.state.padEnd(8))} ${c.project}\\n`);\n stdout.write(` heal: ${chalk.cyan(c.healCmd)}\\n`);\n }\n }\n return 2;\n}\n\nexport interface HealDaemonOpts {\n ensureDaemon: () => void;\n stdout: NodeJS.WritableStream;\n stderr: NodeJS.WritableStream;\n}\n\n/** Returns exit code: 0=success, 1=error */\nexport async function runHealDaemon(opts: HealDaemonOpts): Promise<number> {\n const { stdout, stderr } = opts;\n stdout.write(\"restarting squadrantd via launchd kickstart...\\n\");\n try {\n opts.ensureDaemon();\n stdout.write(chalk.green(\"✔ daemon kickstart complete\\n\"));\n return 0;\n } catch (e) {\n stderr.write(`heal daemon failed: ${(e as Error).message}\\n`);\n return 1;\n }\n}\n\n// ── Commander command tree ────────────────────────────────────────────────────\n\nexport const healCommand = new Command(\"heal\")\n .description(\"Targeted, idempotent remediation for squadrant components (daemon, health)\")\n .addHelpText(\"after\", \"\\nDeferred: 'squadrant heal crew <id>' (re-attach) — see issue #100.\")\n .addCommand(\n new Command(\"status\")\n .description(\"Dry-run: print unhealthy components and the exact heal command for each\")\n .option(\"-p, --project <project>\", \"scope to one project\")\n .option(\"--json\", \"output machine-readable JSON (exit 0=healthy, 1=error, 2=unhealthy)\")\n .action(async (opts: { project?: string; json?: boolean }) => {\n const code = await runHealStatus({\n project: opts.project,\n json: opts.json ?? false,\n queryHealth,\n stdout: process.stdout,\n stderr: process.stderr,\n });\n process.exit(code);\n }),\n )\n .addCommand(\n new Command(\"daemon\")\n .description(\"Restart squadrantd via the idempotent launchd kickstart path\")\n .action(async () => {\n const code = await runHealDaemon({\n ensureDaemon: _ensureDaemon,\n stdout: process.stdout,\n stderr: process.stderr,\n });\n process.exit(code);\n }),\n );\n","// src/commands/group.ts\n//\n// #246: cross-project intra-group delegation. `squadrant group dispatch`\n// sends a task to a sibling project in the same group. The target's captain\n// is woken via the existing mailbox/relay path. A dispatches-and-yields;\n// the origin captain is auto-woken when the task settles (report-back).\n\nimport { Command } from \"commander\";\nimport { execSync } from \"node:child_process\";\nimport { randomUUID } from \"node:crypto\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport chalk from \"chalk\";\nimport { loadConfig, resolveHome, type SquadrantConfig } from \"@squadrant/shared\";\nimport { sendRequest } from \"@squadrant/core\";\nimport type { TaskRecord, Provider, Mode } from \"@squadrant/shared\";\n\nconst SOCK = join(homedir(), \".config\", \"squadrant\", \"squadrant.sock\");\n// #288: 30s was too short — cold captain boot + relay supervisor startup takes\n// 45-90s. 120s gives the full chain (Claude init + checklist + relay register)\n// comfortable headroom while still failing fast on a genuinely broken launch.\nconst WARMUP_TIMEOUT_MS = 120_000;\nconst WARMUP_POLL_MS = 1_000;\n\n/** Resolve the current project name by matching cwd against config paths. */\nexport function resolveCurrentProject(config: SquadrantConfig): string | null {\n const cwd = process.cwd();\n for (const [name, proj] of Object.entries(config.projects)) {\n const resolvedPath = resolveHome(proj.path);\n if (cwd.startsWith(resolvedPath)) return name;\n }\n return null;\n}\n\n/** Check via the daemon health endpoint whether a project's captain is up. */\nasync function isCaptainAlive(project: string): Promise<boolean> {\n try {\n const health = (await sendRequest(SOCK, { kind: \"health\", project }, 5000)) as Array<{\n kind: string; project: string; state: string;\n }>;\n const captain = health?.find((h) => h.kind === \"captain\" && h.project === project);\n return captain != null && captain.state !== \"gone\" && captain.state !== \"unknown\";\n } catch {\n return false;\n }\n}\n\n/** Poll the daemon health endpoint until the target project's captain is up,\n * or the hard timeout expires. Returns true if warmup succeeded. */\nexport async function waitForWarmup(\n project: string,\n timeoutMs = WARMUP_TIMEOUT_MS,\n pollMs = WARMUP_POLL_MS,\n): Promise<boolean> {\n const deadline = Date.now() + timeoutMs;\n while (Date.now() < deadline) {\n if (await isCaptainAlive(project)) return true;\n await new Promise((r) => setTimeout(r, pollMs));\n }\n return false;\n}\n\nexport interface GroupDispatchOpts {\n fromProject: string;\n toProject: string;\n task: string;\n provider?: Provider;\n mode?: Mode;\n warmupTimeoutMs?: number;\n warmupPollMs?: number;\n}\n\n/** Pure-ish dispatch function (extracted for testability). */\nexport async function runGroupDispatch(opts: GroupDispatchOpts): Promise<TaskRecord> {\n const config = loadConfig();\n const fromCfg = config.projects[opts.fromProject];\n const toCfg = config.projects[opts.toProject];\n\n if (!toCfg) {\n throw new Error(`target project '${opts.toProject}' not found in config`);\n }\n\n // #246: same-group gate — hard boundary\n if (!fromCfg.group || !toCfg.group || fromCfg.group !== toCfg.group) {\n throw new Error(\n `cannot dispatch: '${opts.toProject}' (group: ${toCfg.group ?? \"none\"}) ` +\n `is not in the same group as '${opts.fromProject}' (group: ${fromCfg.group ?? \"none\"})`,\n );\n }\n\n // #246: acceptDelegations check\n if (toCfg.acceptDelegations === false) {\n throw new Error(\n `cannot dispatch to '${opts.toProject}': project has acceptDelegations set to false`,\n );\n }\n\n // Ensure B's captain is up\n const alive = await isCaptainAlive(opts.toProject);\n if (!alive) {\n try {\n execSync(`squadrant launch ${opts.toProject}`, { stdio: \"ignore\", timeout: 15_000 });\n } catch {\n throw new Error(`failed to launch captain for '${opts.toProject}' — is squadrant installed?`);\n }\n\n const warmed = await waitForWarmup(opts.toProject, opts.warmupTimeoutMs, opts.warmupPollMs);\n if (!warmed) {\n throw new Error(\n `dispatch to '${opts.toProject}' timed out waiting for captain warmup ` +\n `(>${(opts.warmupTimeoutMs ?? WARMUP_TIMEOUT_MS) / 1000}s)`,\n );\n }\n }\n\n // Record the task via the daemon\n const now = Date.now();\n const attemptId = randomUUID();\n const record: TaskRecord = {\n id: randomUUID(),\n project: opts.toProject,\n originProject: opts.fromProject,\n provider: opts.provider ?? \"claude\",\n mode: opts.mode ?? \"headless\",\n state: \"submitted\",\n task: opts.task,\n createdAt: now,\n lastHeartbeat: now,\n lastEvent: \"dispatch\",\n heartbeatBudgetMs: 300000,\n attempts: [{ attemptId, startedAt: now, lastHeartbeatAt: now }],\n };\n\n const result = await sendRequest(SOCK, { kind: \"dispatch\", record }) as TaskRecord;\n return result;\n}\n\n// ── CLI command ──────────────────────────────────────────────────────────────\n\nexport const groupCommand = new Command(\"group\")\n .description(\"Cross-project intra-group operations (Phase 1: dispatch)\")\n .addCommand(\n new Command(\"dispatch\")\n .description(\"Dispatch a task to a sibling project in the same group\")\n .argument(\"<to-project>\", \"Target project name (must be in the same group)\")\n .argument(\"<task>\", \"Task description to dispatch\")\n .option(\"--provider <p>\", \"claude|opencode|codex\", \"claude\")\n .option(\"--mode <m>\", \"headless|interactive\", \"headless\")\n .option(\"--warmup-timeout <s>\", \"seconds to wait for target captain relay to boot (default: 120)\", (v) => parseInt(v, 10) * 1000)\n .action(async (toProject: string, task: string, opts: { provider?: Provider; mode?: Mode; warmupTimeout?: number }) => {\n const fromProject = resolveCurrentProject(loadConfig());\n if (!fromProject) {\n console.error(chalk.red(\"Could not determine current project from cwd. Run from inside a registered project directory.\"));\n process.exit(1);\n }\n\n try {\n const result = await runGroupDispatch({\n fromProject,\n toProject,\n task,\n provider: opts.provider,\n mode: opts.mode,\n warmupTimeoutMs: opts.warmupTimeout,\n });\n console.log(chalk.green(`✔ Dispatched to '${toProject}' (task ${result.id.slice(0, 8)})`));\n console.log(chalk.dim(` originProject: ${result.originProject ?? \"none\"}`));\n console.log(chalk.dim(\" You will be notified when the task settles (done/blocked/failed).\"));\n } catch (e) {\n console.error(chalk.red(`✘ ${(e as Error).message}`));\n process.exit(1);\n }\n }),\n );\n","// src/commands/cmux.ts\n//\n// squadrant cmux autoconfig — #348 (part of #332). User-facing surface for the\n// cmux socket auto-config: write the comment-preserving automation config, probe\n// the live socket from a non-cmux process, and tell the user whether a cmux\n// restart is needed to enable daemon-direct delivery.\n//\n// See docs/specs/2026-06-16-cmux-socket-auth-daemon-direct-design.md §4.\nimport { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport { ensureCmuxAutoConfig, type AutoConfigResult } from \"@squadrant/shared\";\n\nexport interface CmuxAutoconfigOpts {\n json: boolean;\n stdout: NodeJS.WritableStream;\n stderr: NodeJS.WritableStream;\n /** Injectable for tests. Default = ensureCmuxAutoConfig (real I/O). */\n run?: () => Promise<AutoConfigResult>;\n}\n\n/** Returns exit code: 0=reachable, 1=unknown/error, 2=restart needed. */\nexport async function runCmuxAutoconfig(opts: CmuxAutoconfigOpts): Promise<number> {\n const { json, stdout, stderr } = opts;\n let r: AutoConfigResult;\n try {\n r = await (opts.run ?? ensureCmuxAutoConfig)();\n } catch (e) {\n stderr.write(`cmux autoconfig failed: ${(e as Error).message}\\n`);\n return 1;\n }\n\n if (json) {\n stdout.write(JSON.stringify(r) + \"\\n\");\n return r.verdict === \"reachable\" ? 0 : r.needsRestart ? 2 : 1;\n }\n\n if (r.configChanged) {\n stdout.write(`wrote cmux automation config → ${r.configPath}\\n`);\n } else {\n stdout.write(chalk.dim(`cmux automation config already in place (${r.configPath})\\n`));\n }\n\n if (r.verdict === \"reachable\") {\n stdout.write(chalk.green(\"✔ daemon-direct delivery is reachable — cmux control socket accepts the daemon\\n\"));\n return 0;\n }\n\n if (r.needsRestart) {\n stdout.write(\n chalk.yellow(\"⚠ cmux is still on the old socket mode — restart cmux to enable daemon-direct delivery.\\n\"),\n );\n if (r.promptedThisRun) {\n stdout.write(chalk.dim(\" (one-time prompt — you won't be nagged again)\\n\"));\n }\n return 2;\n }\n\n // unknown — fail soft.\n stderr.write(\n \"could not reach the cmux control socket (is cmux installed and running?) — staying on the relay.\\n\",\n );\n return 1;\n}\n\nexport const cmuxCommand = new Command(\"cmux\")\n .description(\"cmux integration helpers\")\n .addCommand(\n new Command(\"autoconfig\")\n .description(\n \"Write the cmux automation socket config and probe whether daemon-direct\\n\" +\n \"delivery is reachable. Idempotent; prompts once if a cmux restart is needed.\",\n )\n .option(\"--json\", \"output machine-readable JSON (exit 0=reachable, 1=unknown, 2=restart-needed)\")\n .action(async (opts: { json?: boolean }) => {\n const code = await runCmuxAutoconfig({\n json: opts.json ?? false,\n stdout: process.stdout,\n stderr: process.stderr,\n });\n process.exit(code);\n }),\n );\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport { loadConfig, saveConfig, resolveEffort, DEFAULT_CONFIG_PATH } from \"@squadrant/shared\";\nimport type { SquadrantConfig, Effort } from \"@squadrant/shared\";\n\nconst VALID_EFFORTS: Effort[] = [\"max\", \"balance\", \"low\"];\n\nconst EFFORT_MEANING: Record<Effort, string> = {\n max: \"tokens are plentiful — bias crew spawns toward claude/opus\",\n balance: \"normal routing — use default crew routing rules unchanged\",\n low: \"conserve tokens — bias crew spawns toward opencode/sonnet; reserve opus for work that genuinely needs it\",\n};\n\nexport interface EffortGetResult {\n effort: Effort;\n description: string;\n}\n\nexport function runEffortGet(configPath = DEFAULT_CONFIG_PATH): EffortGetResult {\n const config = loadConfig(configPath);\n const effort = resolveEffort(config);\n const description = `${effort}: ${EFFORT_MEANING[effort]}`;\n return { effort, description };\n}\n\nexport function runEffortSet(value: string, configPath = DEFAULT_CONFIG_PATH): void {\n if (!(VALID_EFFORTS as string[]).includes(value)) {\n throw new Error(\n `Invalid effort '${value}'. Valid values: ${VALID_EFFORTS.join(\" | \")}`,\n );\n }\n const config = loadConfig(configPath);\n config.defaults.effort = value as Effort;\n saveConfig(config, configPath);\n}\n\n/** Minimal slice of RuntimeDriver used to notify a captain. */\ninterface EffortNotifyDriver {\n status(nameOrId: string): Promise<{ id: string } | null>;\n send(ref: string, message: string): Promise<void>;\n}\n\n/** Resolve a path through symlinks; fall back to a plain resolve if it\n * doesn't exist on disk (e.g. a stale/unmounted project entry). */\nfunction canonical(p: string): string {\n try {\n return fs.realpathSync(p);\n } catch {\n return path.resolve(p);\n }\n}\n\n/**\n * Send the effort-change notice to every running captain EXCEPT the one in the\n * current working directory. The captain that ran `squadrant effort` already saw\n * the stdout '✔ effort → ...' confirmation, so injecting the notice into its own\n * pane is a duplicate self-notification. Other running captains still get it.\n */\nexport async function notifyCaptainsOfEffort(\n effort: Effort,\n config: SquadrantConfig,\n driver: EffortNotifyDriver,\n cwd: string = process.cwd(),\n): Promise<void> {\n const here = canonical(cwd);\n const notice = `🎚️ effort → ${effort}: ${EFFORT_MEANING[effort]}`;\n for (const [, proj] of Object.entries(config.projects)) {\n // Skip the captain running in this same directory — it already saw stdout.\n if (canonical(proj.path) === here) continue;\n try {\n const ref = await driver.status(proj.captainName);\n if (ref) {\n await driver.send(ref.id, notice);\n }\n } catch {\n // individual project captain unreachable — skip\n }\n }\n}\n\nexport const effortCommand = new Command(\"effort\")\n .description(\"Get or set the global crew tokenomics dial (max | balance | low)\")\n .argument(\"[value]\", \"effort level to set: max | balance | low\")\n .action(async (value: string | undefined) => {\n if (value === undefined) {\n const { effort, description } = runEffortGet();\n console.log(chalk.bold(\"Current effort:\"), chalk.cyan(effort));\n console.log(chalk.dim(EFFORT_MEANING[effort]));\n return;\n }\n\n try {\n runEffortSet(value);\n } catch (err) {\n console.error(chalk.red((err as Error).message));\n process.exit(1);\n }\n\n const effort = value as Effort;\n console.log(chalk.green(`✔ effort → ${effort}`));\n console.log(chalk.dim(EFFORT_MEANING[effort]));\n\n // Best-effort active notify: send a one-line notice to any running captain.\n // Never hard-fails — config is already written above.\n try {\n const { createCmuxDriver, RuntimeRegistry } = await import(\"@squadrant/workspaces\");\n const config = loadConfig();\n const registry = new RuntimeRegistry({ cmux: createCmuxDriver() });\n const driver = registry.global(config);\n await notifyCaptainsOfEffort(effort, config, driver);\n } catch {\n // runtime unavailable — config already written, change applies on next launch\n console.log(chalk.dim(\"(no running captain detected — change applies on next launch)\"));\n }\n });\n","import { join, dirname } from \"node:path\";\nimport { emitKeypressEvents } from \"node:readline\";\nimport { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport { loadConfig, DEFAULT_CONFIG_PATH } from \"@squadrant/shared\";\nimport type { SquadrantConfig, TelegramConfig } from \"@squadrant/shared\";\nimport { createTelegramClient, loadState, setTopic, topicKey, topicName, detectGroupAndUser, writeTelegramConfig, maskToken } from \"@squadrant/core\";\nimport type { TelegramClient } from \"@squadrant/core\";\n\n/** Daemon state root (mirrors buildContext): ~/.config/squadrant/state. */\nfunction defaultStateRoot(): string {\n return join(dirname(DEFAULT_CONFIG_PATH), \"state\");\n}\n\nexport interface TelegramStatusResult {\n tokenSet: boolean;\n supergroupId: number | null;\n links: Array<{ project: string; scope: string; topicId: number }>;\n}\n\nexport function runTelegramStatus(opts: {\n config: SquadrantConfig;\n stateRoot: string;\n env?: NodeJS.ProcessEnv;\n}): TelegramStatusResult {\n const tg = opts.config.telegram;\n const env = opts.env ?? process.env;\n const tokenSet = !!(tg?.botToken ?? env.TELEGRAM_BOT_TOKEN);\n const links = Object.entries(loadState(opts.stateRoot).topics).map(([key, topicId]) => {\n const sep = key.indexOf(\"::\");\n return { project: key.slice(0, sep), scope: key.slice(sep + 2), topicId };\n });\n return { tokenSet, supergroupId: tg?.supergroupId ?? null, links };\n}\n\n/** Send a message to a project's linked Telegram topic. */\nexport async function runTelegramSend(opts: {\n project: string;\n message: string;\n cfg: TelegramConfig;\n client: TelegramClient;\n stateRoot: string;\n}): Promise<{ chatId: number; topicId: number }> {\n const topicId = loadState(opts.stateRoot).topics[topicKey(opts.project)];\n if (topicId === undefined) {\n throw new Error(`project \"${opts.project}\" is not linked — run: squadrant telegram link ${opts.project}`);\n }\n await opts.client.sendMessage(opts.cfg.supergroupId, topicId, opts.message);\n return { chatId: opts.cfg.supergroupId, topicId };\n}\n\n/** Bind a project to a forum topic, creating it on first link. Idempotent. */\nexport async function runTelegramLink(opts: {\n project: string;\n cfg: TelegramConfig;\n client: TelegramClient;\n stateRoot: string;\n}): Promise<{ topicId: number; created: boolean }> {\n const existing = loadState(opts.stateRoot).topics[topicKey(opts.project)];\n if (existing !== undefined) return { topicId: existing, created: false };\n const topicId = await opts.client.createForumTopic(opts.cfg.supergroupId, topicName(opts.project));\n setTopic(opts.stateRoot, opts.project, topicId);\n return { topicId, created: true };\n}\n\n// Reads a secret from stdin, printing \"*\" per character. The caller must print\n// the visible label before calling this — raw mode is active only during input.\nexport async function questionMasked(): Promise<string> {\n return new Promise<string>((resolve) => {\n emitKeypressEvents(process.stdin);\n process.stdin.setRawMode(true);\n process.stdin.resume();\n\n let answer = \"\";\n\n const onKeypress = (_str: string | undefined, key: { name: string; ctrl: boolean; meta: boolean; sequence: string }) => {\n if (key.ctrl && key.name === \"c\") {\n process.stdin.removeListener(\"keypress\", onKeypress as any);\n process.stdin.setRawMode(false);\n process.stdin.pause();\n process.stdout.write(\"\\n\");\n process.exit(130);\n } else if (key.name === \"return\" || key.name === \"enter\") {\n process.stdin.removeListener(\"keypress\", onKeypress as any);\n process.stdin.setRawMode(false);\n process.stdin.pause();\n process.stdout.write(\"\\n\");\n resolve(answer);\n } else if (key.name === \"backspace\") {\n if (answer.length > 0) {\n answer = answer.slice(0, -1);\n process.stdout.write(\"\\b \\b\");\n }\n } else if (!key.ctrl && !key.meta && key.sequence) {\n answer += key.sequence;\n process.stdout.write(\"*\");\n }\n };\n\n process.stdin.on(\"keypress\", onKeypress as any);\n });\n}\n\n// Visible yes/no prompt (default No). Used for opt-ins where masking is wrong.\n// Pauses stdin afterward so the process can exit cleanly (prior wizard-hang fix).\nasync function questionYesNo(prompt: string): Promise<boolean> {\n const { createInterface } = await import(\"node:readline\");\n const rl = createInterface({ input: process.stdin, output: process.stdout });\n return new Promise<boolean>((resolve) => {\n rl.question(prompt, (ans) => {\n rl.close();\n process.stdin.pause();\n resolve(/^y(es)?$/i.test(ans.trim()));\n });\n });\n}\n\nexport const telegramCommand = new Command(\"telegram\")\n .description(\"Two-way Telegram integration: push crew events to a topic and reply into the captain pane\");\n\ntelegramCommand\n .command(\"status\")\n .description(\"Show Telegram config and linked projects\")\n .action(() => {\n const { tokenSet, supergroupId, links } = runTelegramStatus({ config: loadConfig(), stateRoot: defaultStateRoot() });\n console.log(`token: ${tokenSet ? chalk.green(\"set\") : chalk.yellow(\"unset\")}`);\n console.log(`supergroup: ${supergroupId ?? chalk.yellow(\"unset\")}`);\n if (links.length === 0) {\n console.log(\"no projects linked\");\n return;\n }\n for (const l of links) console.log(` ${l.project} (${l.scope}) → topic ${l.topicId}`);\n });\n\ntelegramCommand\n .command(\"link\")\n .argument(\"<project>\", \"project to bind to a Telegram topic\")\n .description(\"Create (or reuse) a forum topic for a project and bind it\")\n .action(async (project: string) => {\n const cfg = loadConfig().telegram;\n if (!cfg) {\n console.error(chalk.red(\"telegram config absent — add a `telegram` block to ~/.config/squadrant/config.json\"));\n process.exit(1);\n }\n const token = cfg.botToken ?? process.env.TELEGRAM_BOT_TOKEN;\n if (!token) {\n console.error(chalk.red(\"no botToken in config and TELEGRAM_BOT_TOKEN is unset\"));\n process.exit(1);\n }\n const client = createTelegramClient({ token });\n const { topicId, created } = await runTelegramLink({ project, cfg, client, stateRoot: defaultStateRoot() });\n console.log(chalk.green(`${created ? \"linked\" : \"already linked\"}: ${project} → topic ${topicId}`));\n });\n\ntelegramCommand\n .command(\"setup\")\n .description(\"Interactive wizard — bot token, validate, auto-detect supergroup, write config\")\n .action(async () => {\n if (!process.stdin.isTTY) {\n console.error(chalk.red(\"setup requires a TTY — pipe input is not supported\"));\n process.exit(1);\n }\n\n // Banner\n console.log();\n console.log(chalk.bold(\"Telegram setup\") + \" — connect squadrant to a Telegram bot for notifications + remote control\");\n console.log();\n console.log(\"Before you start you need:\");\n console.log(\" 1. A bot token from @BotFather (send /newbot)\");\n console.log(\" 2. A forum supergroup with the bot added as an admin (Topics enabled)\");\n console.log(\" 3. Bot privacy mode set to OFF (@BotFather → /setprivacy → Disable)\");\n console.log();\n\n // Step 1/3 — Bot token\n console.log(chalk.bold(\"Step 1/3 — Bot token\"));\n console.log(\"Paste your bot token then press Enter (input is hidden):\");\n const token = await questionMasked();\n if (!token) {\n console.error(chalk.red(\"token required\"));\n process.exit(1);\n }\n\n const client = createTelegramClient({ token });\n let botUser: { id: number; username: string };\n try {\n botUser = await client.getMe();\n } catch (e) {\n console.error(chalk.red(`token rejected: ${(e as Error).message}`));\n process.exit(1);\n }\n console.log(chalk.green(`Connected as @${botUser.username}`));\n console.log();\n\n // Step 2/3 — Find group\n console.log(chalk.bold(\"Step 2/3 — Find your group\"));\n console.log(\"Add the bot to your forum supergroup, then send any message in it.\");\n console.log(chalk.dim(\"Waiting for a message (up to 60s)…\"));\n let supergroupId: number;\n let userId: number | undefined;\n try {\n ({ supergroupId, userId } = await detectGroupAndUser(client, { timeoutMs: 60_000 }));\n } catch {\n console.error(chalk.red(\"Timed out — no supergroup message received within 60s.\"));\n console.error(chalk.yellow(\"Check: bot is an admin in the group · privacy mode is OFF · Topics enabled\"));\n process.exit(1);\n }\n console.log(chalk.green(`Found group: ${supergroupId}`));\n console.log();\n\n // Step 3/3 — Remote control (opt-in, #321) + Save\n console.log(chalk.bold(\"Step 3/3 — Remote control + Save\"));\n console.log(chalk.dim(\"Remote control enables auto-launching captains and the General command channel\"));\n console.log(chalk.dim(\"from your phone — gated to your Telegram user-id only (fail-closed).\"));\n let users: number[] | undefined;\n let remoteControl: boolean | undefined;\n if (userId === undefined) {\n console.log(chalk.yellow(\"Could not read your user-id from that message — skipping remote control.\"));\n console.log(chalk.yellow(\"Re-run setup once it's available, or edit telegram.users in config manually.\"));\n } else {\n const enable = await questionYesNo(\n `Enable remote control for your user-id ${userId}? [y/N] `,\n );\n if (enable) {\n users = [userId];\n remoteControl = true;\n }\n }\n\n writeTelegramConfig(DEFAULT_CONFIG_PATH, { token, supergroupId, users, remoteControl });\n console.log(chalk.green(`Wrote telegram config — token: ${maskToken(token)} group: ${supergroupId}`));\n if (remoteControl) {\n console.log(chalk.green(`Remote control: ON (allowlisted user-id ${users?.[0]})`));\n } else {\n console.log(chalk.dim(\"Remote control: off (default). Re-run setup to enable later.\"));\n }\n console.log();\n console.log(`Next: ${chalk.cyan(\"squadrant telegram link <project>\")}`);\n });\n\ntelegramCommand\n .command(\"send\")\n .argument(\"<project>\", \"project whose topic receives the message\")\n .argument(\"[message...]\", \"message text (omit to read from stdin)\")\n .description(\"Send a message to a project's linked Telegram topic\")\n .action(async (project: string, messageParts: string[]) => {\n const cfg = loadConfig().telegram;\n if (!cfg) {\n console.error(chalk.red(\"telegram config absent — add a `telegram` block to ~/.config/squadrant/config.json\"));\n process.exit(1);\n }\n const token = cfg.botToken ?? process.env.TELEGRAM_BOT_TOKEN;\n if (!token) {\n console.error(chalk.red(\"no botToken in config and TELEGRAM_BOT_TOKEN is unset\"));\n process.exit(1);\n }\n\n let message: string;\n if (messageParts.length > 0) {\n message = messageParts.join(\" \");\n } else if (!process.stdin.isTTY) {\n const { createInterface } = await import(\"node:readline\");\n const lines: string[] = [];\n const rl = createInterface({ input: process.stdin });\n for await (const line of rl) lines.push(line);\n message = lines.join(\"\\n\").trimEnd();\n if (!message) {\n console.error(chalk.red(\"no message provided (stdin was empty)\"));\n process.exit(1);\n }\n } else {\n console.error(chalk.red(\"message required — pass as argument or pipe via stdin\"));\n process.exit(1);\n }\n\n const client = createTelegramClient({ token });\n try {\n const { chatId, topicId } = await runTelegramSend({ project, message, cfg, client, stateRoot: defaultStateRoot() });\n console.log(chalk.green(`sent to group ${chatId} topic ${topicId}`));\n } catch (e) {\n console.error(chalk.red((e as Error).message));\n process.exit(1);\n }\n });\n"],"mappings":"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","names":["path","existsSync","readFileSync","homedir","join","existsSync","readFileSync","writeFileSync","join","existsSync","readFileSync","writeFileSync","mkdirSync","rmSync","homedir","dirname","join","path","statePath","execFileSync","path","fs","readFile","readStdin","fs","path","fs","path","fs","path","fs","join","existsSync","resolve","mkdirSync","readFileSync","writeFileSync","existsSync","rmSync","join","execFileSync","mkdirSync","writeFileSync","readFileSync","existsSync","unlinkSync","homedir","dirname","join","path","homedir","join","writeFileSync","mkdirSync","randomUUID","fileURLToPath","join","statSync","openSync","closeSync","readdirSync","readFileSync","join","dirname","fs","path","resolve","fs","path","fs","sleep","init_dist","execFileSync","resolve","init_dist","execFileSync","execSync","init_cmux","init_registry","init_cmux","init_registry","fs","existsSync","path","init_registry","init_workspaces","init_registry","bin","args","sleep","resolve","resolve","init_dist","init_dist","init_workspaces","execSync","execSync","execSync","execSync","init_registry","fs","path","roleFile","init_registry","path","os","sep","mkdir","readFile","writeFile","path","os","readExisting","init_codex","mkdir","readFile","writeFile","path","os","renderMarkdown","readExisting","init_gemini","mkdir","readFile","writeFile","path","os","renderMarkdown","readExisting","init_opencode","init_registry","init_projection","init_codex","init_gemini","init_opencode","init_registry","nodeSpawn","resolve","readFile","homedir","join","init_config","resolve","init_config","sleep","execSync","readFileSync","homedir","join","path","init_claude","init_claude","init_registry","init_claude","init_types","init_types","init_claude","init_types","init_opencode","init_types","init_codex","init_types","ADAPTERS","init_registry","init_claude","init_opencode","init_codex","resolve","init_registry","dist_exports","init_dist","init_projection","init_claude","init_registry","init_types","init_dist","Command","readFileSync","existsSync","writeFileSync","fileURLToPath","dirname","join","homedir","init_dist","execSync","fs","path","chalk","init_dist","homedir","join","chalk","init_dist","execSync","fs","chalk","path","createClaudeDriver","createCodexDriver","createGeminiDriver","createOpencodeDriver","CapabilityRegistry","init_dist","Command","fs","path","os","chalk","Command","fs","path","chalk","findPackageRoot","copyDirRecursive","init_dist","Command","chalk","matter","chalk","Command","matter","init_dist","Command","execSync","path","os","chalk","Command","fs","path","os","chalk","rule","init_dist","init_dist","Command","createConnection","randomUUID","homedir","join","mkdirSync","writeFileSync","init_dist","Command","chalk","createConnection","homedir","join","chalk","Command","createConnection","Command","Command","SOCK","join","homedir","resolve","createConnection","randomUUID","mkdirSync","writeFileSync","r","Command","init_dist","mkdirSync","readFileSync","writeFileSync","join","join","mkdirSync","readFileSync","writeFileSync","init_dist","TEMPLATES_DIR","path","os","chalk","fs","cliCommand","direction","title","pane","Command","init_dist","Command","fs","path","os","chalk","TEMPLATES_DIR","shellQuote","titleFor","nameFromTitle","nextAutoName","init_dist","Command","execSync","homedir","join","chalk","firstLine","chalk","fs","path","writeFile","mkdir","init_dist","createServer","join","homedir","existsSync","readFileSync","execFile","withTimeout","cmux","resolve","init_dist","ICON","createServer","resolve","SOCK","join","homedir","detectCurrentWorkspace","execSync","chalk","Command","init_dist","Command","execSync","fs","path","os","chalk","TEMPLATES_DIR","SESSIONS_PATH","sleep","init_dist","Command","chalk","chalk","Command","Command","fs","os","path","fileURLToPath","execSync","chalk","init_dist","Command","fs","path","chalk","matter","init_dist","Command","fs","path","chalk","matter","init_dist","Command","chalk","init_dist","Command","chalk","buildRegistry","path","init_dist","Command","chalk","readStdin","init_dist","Command","chalk","fs","path","fileURLToPath","findPackageRoot","buildRegistry","init_dist","Command","resolve","Command","fs","fileURLToPath","dirname","join","chalk","readPkgVersion","Command","chalk","init_dist","chalk","Command","init_dist","Command","execSync","randomUUID","homedir","join","chalk","SOCK","Command","chalk","fs","path","Command","chalk","effort","createCmuxDriver","RuntimeRegistry","init_dist","join","dirname","Command","chalk","sep","resolve","createInterface","dirname","fileURLToPath","readFileSync","join","homedir","existsSync","writeFileSync","Command"]}
1
+ {"version":3,"sources":["../packages/shared/src/config.ts","../packages/shared/src/project-config.ts","../packages/shared/src/effort.ts","../packages/shared/dist/types/runtime.js","../packages/shared/src/types/control.ts","../packages/shared/dist/types/projection.js","../packages/shared/dist/types/workspaces.js","../packages/shared/src/lib/cmux-config.ts","../packages/shared/src/lib/cmux-bin.ts","../packages/shared/src/lib/cmux-probe.ts","../packages/shared/src/lib/cmux-autoconfig.ts","../packages/shared/src/lib/compat-manifest.ts","../packages/shared/src/lib/config-drift.ts","../packages/shared/src/lib/config-version.ts","../packages/shared/src/lib/git-worktree.ts","../packages/shared/src/lib/resolve-text-input.ts","../packages/shared/src/lib/runtime-sync.ts","../packages/shared/src/lib/tool-compat.ts","../packages/shared/src/lib/canonical-source.ts","../packages/shared/src/lib/daily-logs.ts","../packages/shared/src/lib/vault-layout.ts","../packages/shared/src/daemon-keys.ts","../packages/shared/src/index.ts","../packages/core/src/state-machine.ts","../packages/core/src/watchdog.ts","../packages/core/src/daemon.ts","../packages/core/src/mailbox.ts","../packages/core/src/protocol.ts","../packages/core/src/liveness.ts","../packages/core/src/store.ts","../packages/core/src/snapshot.ts","../packages/core/src/launchd.ts","../packages/core/src/crew-pane-reader.ts","../packages/core/dist/interfaces.js","../packages/core/src/gate.ts","../packages/core/src/daemon/context.ts","../packages/core/src/daemon/attach.ts","../packages/core/src/daemon/interactive-probe.ts","../packages/core/src/daemon/probes.ts","../packages/core/src/delivery/defer-delivery.ts","../packages/core/src/delivery/captain-delivery.ts","../packages/core/src/daemon/delivery.ts","../packages/core/src/daemon/gates.ts","../packages/core/src/daemon/server.ts","../packages/core/src/daemon/snapshot-gather.ts","../packages/core/src/daemon/start.ts","../packages/core/src/session-freshness.ts","../packages/core/src/crew-protocol.ts","../packages/core/src/crew-lifecycle.ts","../packages/core/src/telegram/bot-commands.ts","../packages/core/src/telegram/auth.ts","../packages/core/src/telegram/commands.ts","../packages/core/src/telegram/ensure-captain.ts","../packages/core/src/telegram/format.ts","../packages/core/src/telegram/state.ts","../packages/core/src/telegram/client.ts","../packages/core/src/telegram/panels.ts","../packages/core/src/telegram/tiers.ts","../packages/core/src/telegram/bridge.ts","../packages/core/src/telegram/setup.ts","../packages/core/src/telegram/index.ts","../packages/core/src/index.ts","../packages/workspaces/src/runtimes/cmux.ts","../packages/workspaces/src/runtimes/registry.ts","../packages/workspaces/src/runtimes/index.ts","../packages/workspaces/src/notifiers/cmux.ts","../packages/workspaces/src/notifiers/registry.ts","../packages/workspaces/src/notifiers/index.ts","../packages/workspaces/src/workspaces/obsidian.ts","../packages/workspaces/src/workspaces/registry.ts","../packages/workspaces/src/workspaces/index.ts","../packages/workspaces/src/cmux/events-bridge.ts","../packages/workspaces/src/cmux/daemon-cmux.ts","../packages/workspaces/src/crew-pane.ts","../packages/workspaces/src/index.ts","../packages/agents/src/drivers/claude.ts","../packages/agents/src/drivers/codex.ts","../packages/agents/src/drivers/gemini.ts","../packages/agents/src/drivers/opencode.ts","../packages/agents/src/drivers/types.ts","../packages/agents/src/drivers/registry.ts","../packages/agents/src/drivers/launch-cmd.ts","../packages/agents/src/drivers/index.ts","../packages/agents/src/projection/cursor.ts","../packages/agents/src/projection/marker.ts","../packages/agents/src/projection/codex.ts","../packages/agents/src/projection/gemini.ts","../packages/agents/src/projection/opencode.ts","../packages/agents/src/projection/registry.ts","../packages/agents/src/projection/index.ts","../packages/agents/src/codex/app-server-client.ts","../packages/agents/src/codex/config.ts","../packages/agents/src/codex/normalize.ts","../packages/agents/src/codex/driver.ts","../packages/agents/src/opencode/sse-bridge.ts","../packages/agents/src/interactive/claude.ts","../packages/agents/src/interactive/pane-classifier.ts","../packages/agents/src/interactive/registry.ts","../packages/agents/dist/interactive/types.js","../packages/agents/src/headless/types.ts","../packages/agents/src/headless/claude.ts","../packages/agents/src/headless/opencode.ts","../packages/agents/src/headless/codex.ts","../packages/agents/src/headless/registry.ts","../packages/agents/src/headless-launcher.ts","../packages/agents/src/index.ts","../packages/cli/src/index.ts","../packages/cli/src/commands/doctor.ts","../packages/cli/src/commands/health-view.ts","../packages/cli/src/commands/init.ts","../packages/cli/src/commands/projects.ts","../packages/cli/src/control/restart-daemon.ts","../packages/cli/src/commands/status.ts","../packages/cli/src/commands/command.ts","../packages/cli/src/commands/crew.ts","../packages/cli/src/control/crew-routing.ts","../packages/cli/src/commands/crew-control.ts","../packages/cli/src/commands/crew-output.ts","../packages/cli/src/commands/crew-attach.ts","../packages/cli/src/commands/crew-chat.ts","../packages/cli/src/lib/per-crew-settings.ts","../packages/cli/src/commands/side.ts","../packages/cli/src/commands/dashboard.ts","../packages/web/src/read-status.ts","../packages/web/src/render.ts","../packages/web/src/sync-hub.ts","../packages/web/src/web-server.ts","../packages/web/src/snapshot-merge.ts","../packages/web/src/probes.ts","../packages/web/src/web-render.ts","../packages/cli/src/commands/launch.ts","../packages/cli/src/commands/shutdown.ts","../packages/cli/src/commands/feedback.ts","../packages/cli/src/commands/standup.ts","../packages/cli/src/commands/retro.ts","../packages/cli/src/commands/runtime.ts","../packages/cli/src/commands/workspace.ts","../packages/cli/src/commands/notify.ts","../packages/cli/src/commands/projection.ts","../packages/cli/src/commands/codex-chat-smoke.ts","../packages/cli/src/commands/config.ts","../packages/cli/src/commands/heal.ts","../packages/cli/src/commands/group.ts","../packages/cli/src/commands/cmux.ts","../packages/cli/src/commands/effort.ts","../packages/cli/src/commands/telegram.ts"],"sourcesContent":["// src/config.ts\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport os from \"node:os\";\nimport chalk from \"chalk\";\n\nexport interface ProjectConfig {\n path: string;\n captainName: string;\n spokeVault: string;\n host: string;\n group?: string;\n groupRole?: string;\n runtime?: string;\n workspace?: string;\n /** #246: when false, `squadrant group dispatch` rejects delegations to this\n * project. Defaults to true when absent. */\n acceptDelegations?: boolean;\n}\n\nexport interface PermissionConfig {\n command: string; // permission mode for the command session\n captain: string; // permission mode for captain sessions\n crew?: string; // permission mode for crew sessions (default: acceptEdits)\n // Flexible role->mode map so future roles don't need a type change.\n [role: string]: string | undefined;\n}\n\nexport type ModelAlias = \"opus\" | \"sonnet\" | \"haiku\";\n\nexport interface CrewRoutingRule {\n tier: string;\n match: string;\n agent: string;\n model?: string;\n}\n\nexport interface CrewRoutingConfig {\n rules: CrewRoutingRule[];\n}\n\nexport interface TelegramConfig {\n botToken?: string; // falls back to env TELEGRAM_BOT_TOKEN at read time\n supergroupId: number; // forum supergroup hosting per-project topics\n chats: number[]; // chat_id allowlist (inbound honored only from these)\n users?: number[]; // user-id allowlist for CONTROL actions (#321); empty ⇒ control disabled\n remoteControl?: boolean; // opt-in master switch for auto-launch + general commands (default false)\n pollMs?: number; // getUpdates long-poll cadence (default 1000)\n /** Global notification defaults (per-project override lives in projects/<name>.json). */\n notify?: { active?: boolean; cap?: boolean; crew?: \"all\" | \"alert_only\" | \"done_only\" | \"none\" };\n}\n\nexport interface ModelRoutingConfig {\n command: ModelAlias;\n captain: ModelAlias;\n crew: ModelAlias;\n exploration: ModelAlias;\n review: ModelAlias;\n}\n\nexport interface AgentEntry {\n cli: string;\n driver: string;\n}\n\nexport interface RoleAssignment {\n agent: string;\n model?: string;\n}\n\nexport type RoleConfig = Partial<Record<\"command\" | \"captain\" | \"crew\" | \"exploration\" | \"side\", RoleAssignment>>;\n\nexport interface SquadrantConfig {\n /** Package version that last reconciled this config. Absent on legacy/fresh configs. */\n _squadrantVersion?: string;\n commandName: string;\n hubVault: string;\n projects: Record<string, ProjectConfig>;\n agents?: Record<string, AgentEntry>;\n runtime?: string;\n workspace?: string;\n notifier?: string;\n /** Optional Telegram bridge config. Absent ⇒ the bridge is never constructed\n * (zero behavior change). See docs/superpowers/specs/2026-06-22-telegram-integration-v1-design.md. */\n telegram?: TelegramConfig;\n projection?: {\n targets?: string[];\n };\n delivery?: {\n /** Max consecutive defers before force-delivering a message (~1s poll cadence). Default: 300 (~5min). */\n maxDeferDeliveries?: number;\n /** Consecutive stable-content polls before probing early to avoid a stall (#302). Default: 3 (~3s). */\n stableProbePolls?: number;\n };\n defaults: {\n maxCrew: number;\n worktreeDir: string;\n teammateMode: string;\n permissions: PermissionConfig;\n models?: ModelRoutingConfig;\n roles?: RoleConfig;\n /** #225 hard crew task-timeout ceiling (ms). Default: 8h. */\n taskTimeoutMs?: number;\n /** #275 rule-based crew routing: keyword rules map task text to {agent, model}. Optional — absent = fall through to defaults.roles.crew. */\n crewRouting?: CrewRoutingConfig;\n /** B1: consume cmux's native event stream for crew turn-end (idle) detection\n * alongside the scrape fallback. Default true; set false for scrape-only. */\n cmuxEventsBridge?: boolean;\n /**\n * Audit C2 — agent hibernation (reclaim idle-crew RAM). INTENTIONALLY OFF and\n * INERT: cmux 0.64.16's `cmux agent-hibernation <on|off>` is GLOBAL (app-wide,\n * no per-session/per-workspace scope), so enabling it would also hibernate the\n * CAPTAIN — which must stay responsive for daemon-direct delivery —\n * breaking orchestration. We do NOT call `agent-hibernation on`\n * anywhere; this flag is a documented decision record + a forward hook for when\n * cmux gains crew-only scoping. Until then leave false.\n * See docs/research/2026-06-16-cmux-events-stream.md (C2 finding).\n */\n cmuxAgentHibernation?: boolean;\n /** #317 global crew tokenomics dial. Absent ⇒ \"balance\" (today's behavior).\n * Biases the captain toward stronger (\"max\") or cheaper (\"low\") crew models. */\n effort?: \"max\" | \"balance\" | \"low\";\n };\n metrics: {\n enabled: boolean;\n path: string;\n };\n}\n\nconst CONFIG_DIR = path.join(os.homedir(), \".config\", \"squadrant\");\nexport const DEFAULT_CONFIG_PATH = path.join(CONFIG_DIR, \"config.json\");\n\nexport function getDefaultConfig(): SquadrantConfig {\n return {\n commandName: \"\\u{1F3DB}\\u{FE0F} command\",\n hubVault: path.join(os.homedir(), \"squadrant-hub\"),\n projects: {},\n agents: {\n claude: { cli: \"claude\", driver: \"claude\" },\n },\n defaults: {\n maxCrew: 5,\n worktreeDir: \".worktrees\",\n teammateMode: \"in-process\",\n permissions: {\n command: \"auto\",\n captain: \"auto\",\n crew: \"auto\",\n },\n models: {\n command: \"opus\",\n captain: \"opus\",\n crew: \"opus\",\n exploration: \"haiku\",\n review: \"opus\",\n },\n roles: {\n command: { agent: \"claude\", model: \"opus\" },\n captain: { agent: \"claude\", model: \"opus\" },\n crew: { agent: \"claude\", model: \"opus\" },\n exploration: { agent: \"claude\", model: \"haiku\" },\n side: { agent: \"claude\", model: \"opus\" },\n },\n taskTimeoutMs: 8 * 60 * 60 * 1000,\n cmuxEventsBridge: true,\n // Audit C2: OFF by design — cmux hibernation is global-only and would\n // hibernate the captain. See the field doc above.\n cmuxAgentHibernation: false,\n crewRouting: {\n rules: [\n { tier: \"extreme\", match: \"redesign|architect|rewrite|from scratch|deep reasoning\", agent: \"claude\", model: \"opus\" },\n { tier: \"hard\", match: \"refactor|migrate|implement|feature|daemon|control-plane\", agent: \"claude\", model: \"sonnet\" },\n { tier: \"mobile\", match: \"mobile|ios|swift|android|kotlin|react native\", agent: \"codex\" },\n { tier: \"daily\", match: \"typo|rename|bump|docs|comment|lint|format\", agent: \"opencode\" },\n ],\n },\n },\n metrics: {\n enabled: true,\n path: path.join(CONFIG_DIR, \"metrics.json\"),\n },\n };\n}\n\nexport function loadConfig(configPath = DEFAULT_CONFIG_PATH): SquadrantConfig {\n try {\n const raw = fs.readFileSync(configPath, \"utf-8\");\n const config = JSON.parse(raw) as SquadrantConfig;\n\n // Backward compat: migrate models → roles if roles not set\n if (config.defaults.models && !config.defaults.roles) {\n const m = config.defaults.models;\n config.defaults.roles = {\n command: { agent: \"claude\", model: m.command },\n captain: { agent: \"claude\", model: m.captain },\n crew: { agent: \"claude\", model: m.crew },\n exploration: { agent: \"claude\", model: m.exploration },\n };\n }\n\n // Ensure agents has at least claude\n if (!config.agents) {\n config.agents = { claude: { cli: \"claude\", driver: \"claude\" } };\n }\n\n // #286: backfill crewRouting for configs written before routing existed\n if (!config.defaults.crewRouting) {\n config.defaults.crewRouting = getDefaultConfig().defaults.crewRouting;\n saveConfig(config, configPath);\n console.error(\n chalk.cyan(\n \"⬆ squadrant upgrade: added default crew routing rules to your config (leveled routing now active). \" +\n \"Edit defaults.crewRouting in ~/.config/squadrant/config.json or use the squadrant:add-pick-crew-rule skill.\",\n ),\n );\n }\n\n return config;\n } catch {\n return getDefaultConfig();\n }\n}\n\nexport function saveConfig(\n config: SquadrantConfig,\n configPath = DEFAULT_CONFIG_PATH,\n): void {\n const dir = path.dirname(configPath);\n fs.mkdirSync(dir, { recursive: true });\n fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + \"\\n\");\n}\n\nexport function resolveHome(p: string): string {\n return p.startsWith(\"~\") ? p.replace(\"~\", os.homedir()) : p;\n}\n","// Per-project layered config override file. Pure, file-backed, no daemon\n// knowledge. Resolved as built-in → global config.json → projects/<name>.json.\n// See docs/superpowers/specs/2026-06-23-per-project-layered-config-design.md.\nimport fs from \"node:fs\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport type { ModelRoutingConfig } from \"./config.js\";\n\nexport type CrewTier = \"all\" | \"alert_only\" | \"done_only\" | \"none\";\n\nexport interface NotifyConfig {\n active: boolean;\n cap: boolean;\n crew: CrewTier;\n}\n\n/** Per-project override layer. Every key optional; mirrors the global settings. */\nexport interface ProjectOverrideConfig {\n telegram?: { notify?: Partial<NotifyConfig> };\n // Reserved future tenants (resolver is already generic; consumers not yet wired):\n effort?: \"max\" | \"balance\" | \"low\";\n models?: Partial<ModelRoutingConfig>;\n}\n\nfunction defaultRoot(): string {\n return path.join(os.homedir(), \".config\", \"squadrant\");\n}\n\nexport function projectConfigPath(name: string, root = defaultRoot()): string {\n return path.join(root, \"projects\", `${name}.json`);\n}\n\nexport function loadProjectOverride(name: string, root = defaultRoot()): ProjectOverrideConfig {\n try {\n return JSON.parse(fs.readFileSync(projectConfigPath(name, root), \"utf-8\")) as ProjectOverrideConfig;\n } catch {\n return {};\n }\n}\n\n/** Deep-merge a generic plain-object tree. Arrays/primitives in `patch` replace. */\nexport function deepMerge<T>(base: T, patch: unknown): T {\n if (patch === null || typeof patch !== \"object\" || Array.isArray(patch)) return (patch as T) ?? base;\n const out: Record<string, unknown> = { ...(base as Record<string, unknown>) };\n for (const [k, v] of Object.entries(patch as Record<string, unknown>)) {\n out[k] = deepMerge(out[k], v);\n }\n return out as T;\n}\n\nexport function saveProjectOverride(name: string, patch: ProjectOverrideConfig, root = defaultRoot()): void {\n const merged = deepMerge(loadProjectOverride(name, root), patch);\n const file = projectConfigPath(name, root);\n fs.mkdirSync(path.dirname(file), { recursive: true });\n fs.writeFileSync(file, JSON.stringify(merged, null, 2) + \"\\n\");\n}\n\nexport const DEFAULT_NOTIFY: NotifyConfig = { active: false, cap: true, crew: \"alert_only\" };\n\nconst CREW_RANK: Record<CrewTier, number> = { none: 0, done_only: 1, alert_only: 2, all: 3 };\nexport function crewRank(tier: CrewTier): number {\n return CREW_RANK[tier];\n}\n\nexport function isQuieter(\n before: NotifyConfig,\n after: NotifyConfig,\n): { quieter: boolean; dim: \"active\" | \"cap\" | \"crew\" | null } {\n if (before.active && !after.active) return { quieter: true, dim: \"active\" };\n if (before.cap && !after.cap) return { quieter: true, dim: \"cap\" };\n if (crewRank(after.crew) < crewRank(before.crew)) return { quieter: true, dim: \"crew\" };\n return { quieter: false, dim: null };\n}\n\n/** Built-in → global → project, per-key. Does NOT apply live state (bridge's job). */\nexport function resolveNotify(\n globalNotify: Partial<NotifyConfig> | undefined,\n override: ProjectOverrideConfig,\n): NotifyConfig {\n let n: NotifyConfig = { ...DEFAULT_NOTIFY };\n if (globalNotify) n = deepMerge(n, globalNotify);\n if (override.telegram?.notify) n = deepMerge(n, override.telegram.notify);\n return n;\n}\n","import type { SquadrantConfig } from \"./config.js\";\n\nexport type Effort = \"max\" | \"balance\" | \"low\";\n\nexport function resolveEffort(config: SquadrantConfig): Effort {\n return config.defaults.effort ?? \"balance\";\n}\n","export {};\n//# sourceMappingURL=runtime.js.map","// src/control/types.ts\nexport type Provider = \"claude\" | \"opencode\" | \"codex\" | \"gemini\";\nexport type Mode = \"headless\" | \"interactive\";\n\nexport type TaskState =\n | \"submitted\"\n | \"working\"\n | \"blocked\"\n | \"done\"\n | \"failed\"\n | \"stalled\"\n | \"awaiting-input\"\n | \"cancelled\";\n\nexport interface DispatchAttempt {\n attemptId: string;\n startedAt: number;\n pid?: number;\n resumeRef?: string; // opaque, hashed-treated, NEVER parsed (orca #1148)\n lastHeartbeatAt: number;\n error?: string;\n exitCode?: number;\n circuitBroken?: boolean;\n}\n\nexport interface Gate {\n gateId: string;\n taskId: string;\n kind: \"input\" | \"approval\";\n question: string;\n state: \"pending\" | \"resolved\" | \"timeout\";\n createdAt: number;\n resolvedBy?: string;\n resolution?: unknown;\n}\n\nexport interface TaskRecord {\n id: string;\n /** Human-readable crew name (e.g. the `--name` arg to `squadrant crew spawn`).\n * Optional for backward-compat with records written before this field\n * existed; relay/daemon fall back to the short id when absent. */\n name?: string;\n project: string;\n provider: Provider;\n mode: Mode;\n state: TaskState;\n task: string; // the dispatched instruction\n sessionId?: string; // provider session id for resume (blocked→reply)\n cwd?: string; // working dir for the spawned headless child (project/worktree); unset → daemon cwd\n pid?: number; // headless child pid (daemon-owned)\n question?: string; // populated when state === \"blocked\"\n error?: string; // populated when state === \"failed\"\n exitCode?: number;\n resultRef?: string; // filesystem path to captured output/artifact\n parseWarning?: boolean; // headless exit 0 but unparseable result\n createdAt: number; // epoch ms\n lastHeartbeat: number; // epoch ms\n lastEvent: string; // last event type applied\n heartbeatBudgetMs: number; // per-task stall threshold\n /** Append-only dispatch attempt history. Current attempt = at(-1). */\n attempts: DispatchAttempt[];\n /** Interactive-codex HITL slice (spec §4.9). */\n gates?: Gate[];\n /** Codex AskForApproval policy forwarded to startThread (interactive only).\n * When set to \"untrusted\", codex requests approval for tool/shell calls,\n * exercising the gate-promotion flow end-to-end. */\n approvalPolicy?: string;\n /** Role-priming content forwarded to startThread's developerInstructions\n * (interactive only). Parity with claude's --append-system-prompt-file:\n * injects crew rules / Karpathy discipline before the first user turn. */\n roleInstructions?: string;\n /** TCP port of an interactive opencode crew's embedded HTTP server\n * (`opencode --port <N>`). The daemon's SSE bridge subscribes to\n * http://127.0.0.1:<serverPort>/event for reliable turn-end detection. */\n serverPort?: number;\n /** #246: cross-project intra-group delegation — set to the origin project's\n * name when this task was dispatched by a sibling captain. When the task\n * settles, the daemon fans the outcome back to originProject's mailbox. */\n originProject?: string;\n /** #354: the tool call currently in flight, if any. Set when a PreToolUse\n * liveness signal arrives (cmux events-bridge carries the tool name); cleared\n * the moment its PostToolUse / next turn boundary arrives. A `working` crew\n * whose pendingTool has been outstanding past TOOL_STALL_BUDGET_MS is treated\n * as hung-on-a-tool (CREW STALLED warn) — distinct from a quiet thinking turn\n * (no pendingTool → CREW QUIET). Auto-clears: the next PostToolUse recovers\n * the record to `working` (state-machine + recoverStall). */\n pendingTool?: { name: string; since: number };\n}\n\nexport type ControlEvent =\n | { type: \"task.started\"; id: string; pid?: number; sessionId?: string }\n | { type: \"task.progress\"; id: string; note?: string; tool?: string }\n | { type: \"heartbeat\"; id: string }\n | { type: \"task.blocked\"; id: string; reason: string; question: string }\n | { type: \"task.done\"; id: string; resultRef: string; message?: string; parseWarning?: boolean }\n | { type: \"task.failed\"; id: string; error: string; exitCode?: number }\n | { type: \"task.session\"; id: string; resumeRef: string }\n | { type: \"task.turn.started\"; id: string; turnId: string }\n | { type: \"task.turn.completed\"; id: string; turnId: string }\n | { type: \"task.delta\"; id: string; turnId: string; chunk: string }\n | { type: \"task.input.requested\"; id: string; requestId: number; question: string }\n | { type: \"task.approval.requested\"; id: string; requestId: number; question: string; kind: string }\n | { type: \"task.reattached\"; id: string }\n // Reopen: the only event allowed to revive a terminal task. Emitted by\n // `squadrant crew send` when the target crew's daemon task is in a terminal\n // state, allowing the next `signal done` to be a real transition.\n | { type: \"task.reopened\"; id: string }\n // Synthetic events: emitted by the daemon (watchdog / reconcile) purely as\n // notify payloads. They are never sent over the wire and the reducer treats\n // them as no-ops; the watchdog has already updated state directly.\n // #354: `tool`/`elapsedMs` are set when the stall is a hung interactive tool\n // call (PreToolUse with no matching PostToolUse past TOOL_STALL_BUDGET_MS),\n // letting the notifier render \"still running {tool} ~{N}min\" instead of the\n // generic headless \"no heartbeat\" message.\n | { type: \"task.stalled\"; id: string; heartbeatBudgetMs: number; tool?: string; elapsedMs?: number }\n // task.idle is the interactive analogue of task.stalled: the watchdog has\n // already moved an idle interactive task to 'awaiting-input', and this carries\n // the accurate (non-alarming) notify payload to the captain.\n | { type: \"task.idle\"; id: string; heartbeatBudgetMs: number }\n // #354: a `working` interactive crew that has been quiet past its heartbeat\n // budget with NO tool in flight — alive but deep-thinking (no hook fires\n // during pure model thinking). Notify-only (reducer no-op): the crew stays\n // `working`, NOT awaiting-input. Real CREW IDLE still comes only from the Stop\n // hook (a genuine turn-end). `quietMs` = how long it has been silent.\n | { type: \"task.quiet\"; id: string; quietMs: number }\n // #225: emitted by the sweep when a task's wall-clock age exceeds the ceiling.\n // Notify-only (detect-first, #77); reducer is a no-op.\n | { type: \"task.timeout\"; id: string; taskTimeoutMs: number }\n | { type: \"task.reconcile-failed\"; id: string; reason: string }\n // Emitted by runCrewClose before closing the pane; transitions a non-terminal\n // task to the absorbing 'cancelled' state. Silent: captain initiated the close\n // so no CREW CANCELLED push is fired (not in ATTENTION_STATES).\n | { type: \"task.cancelled\"; id: string; reason?: string }\n // #139: a claude crew's SessionEnd hook fired — the session is GONE. Unlike\n // the other turn-boundary hooks (PostToolUse/SubagentStop = liveness), a dead\n // session must NOT resume 'working' (nothing heartbeats → false CREW STALLED\n // ~budget later). Terminalizes the record to the absorbing 'cancelled' state.\n // Silent (not in ATTENTION_STATES), like task.cancelled.\n | { type: \"task.session.ended\"; id: string };\n\n// 'stalled' is intentionally excluded — recoverable by the watchdog.\n// 'cancelled' is terminal and silent (captain-initiated close).\nexport const TERMINAL_STATES: ReadonlySet<TaskState> = new Set([\n \"done\",\n \"failed\",\n \"cancelled\",\n]);\n","export {};\n//# sourceMappingURL=projection.js.map","export {};\n//# sourceMappingURL=workspaces.js.map","// src/lib/cmux-config.ts\n//\n// #348 (part of #332): comment-preserving JSONC merge for the cmux control\n// socket auth mode. Writes ONLY `automation.socketControlMode = \"automation\"`\n// into ~/.config/cmux/cmux.json so the launchd squadrant daemon (NOT a cmux\n// descendant) may connect to the cmux control socket for daemon-direct delivery.\n//\n// See docs/specs/2026-06-16-cmux-socket-auth-daemon-direct-design.md §2–§4.1.\n//\n// We use jsonc-parser (modify + applyEdits) rather than JSON.parse/stringify so\n// every existing comment and key in the user's cmux.json survives — cmux itself\n// preserves comments and we must not clobber them.\nimport { existsSync, readFileSync, writeFileSync, mkdirSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { dirname, join } from \"node:path\";\nimport { parse, modify, applyEdits } from \"jsonc-parser\";\n\n/** Canonical cmux config path. cmux watches this file live (§3.2). */\nexport function defaultCmuxConfigPath(): string {\n return join(homedir(), \".config\", \"cmux\", \"cmux.json\");\n}\n\nexport const SOCKET_CONTROL_MODE_PATH = [\"automation\", \"socketControlMode\"] as const;\nexport const AUTOMATION_MODE = \"automation\";\n\nexport interface EnsureSocketAutomationResult {\n /** Absolute path written/inspected. */\n path: string;\n /** True when the file was written this call. */\n changed: boolean;\n /** True when socketControlMode was ALREADY \"automation\" (no write needed). */\n alreadySet: boolean;\n}\n\n// Minimal squadrant-managed template used only when cmux.json does not yet exist\n// (clean install before cmux has created its own template). It is a strict\n// subset of cmux's schema, so cmux merges its full template keys on next launch\n// without conflict.\nconst MINIMAL_TEMPLATE = [\n `{`,\n ` // [squadrant] file-managed: allow the launchd squadrant daemon to reach the cmux`,\n ` // control socket for daemon-direct notification delivery (#348/#332).`,\n ` \"automation\": {`,\n ` \"socketControlMode\": \"${AUTOMATION_MODE}\"`,\n ` }`,\n `}`,\n ``,\n].join(\"\\n\");\n\n/**\n * Ensure `automation.socketControlMode = \"automation\"` in the cmux config.\n *\n * Idempotent: a no-op (changed=false) when already set. Comment- and\n * formatting-preserving when adding/overwriting an existing file. Creates a\n * minimal squadrant-managed file when none exists.\n */\nexport function ensureSocketAutomation(\n opts: { path?: string } = {},\n): EnsureSocketAutomationResult {\n const path = opts.path ?? defaultCmuxConfigPath();\n\n if (!existsSync(path)) {\n mkdirSync(dirname(path), { recursive: true });\n writeFileSync(path, MINIMAL_TEMPLATE);\n return { path, changed: true, alreadySet: false };\n }\n\n const text = readFileSync(path, \"utf-8\");\n const current = parse(text)?.automation?.socketControlMode;\n if (current === AUTOMATION_MODE) {\n return { path, changed: false, alreadySet: true };\n }\n\n const edits = modify(text, [...SOCKET_CONTROL_MODE_PATH], AUTOMATION_MODE, {\n formattingOptions: { insertSpaces: true, tabSize: 2 },\n });\n writeFileSync(path, applyEdits(text, edits));\n return { path, changed: true, alreadySet: false };\n}\n","import { execFileSync } from \"node:child_process\";\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\n\nlet _cached: string | undefined;\n\nfunction resolveBin(): string {\n // 1. Env var override\n const envBin = process.env.SQUADRANT_CMUX_BIN;\n if (envBin && existsSync(envBin)) return envBin;\n\n // 2. Optional cmuxBin field in config.json\n try {\n const configPath = join(homedir(), \".config\", \"squadrant\", \"config.json\");\n if (existsSync(configPath)) {\n const cfg = JSON.parse(readFileSync(configPath, \"utf-8\"));\n const cfgBin: unknown = cfg.cmuxBin;\n if (typeof cfgBin === \"string\" && existsSync(cfgBin)) return cfgBin;\n }\n } catch { /* config read is best-effort */ }\n\n // 3. PATH lookup\n try {\n const which = execFileSync(\"which\", [\"cmux\"], { encoding: \"utf-8\" }).trim();\n if (which && existsSync(which)) return which;\n } catch { /* not on PATH */ }\n\n // 4. Fallback (backward compat for macOS .app install)\n return \"/Applications/cmux.app/Contents/Resources/bin/cmux\";\n}\n\nexport function resolveCmuxBin(): string {\n return _cached ??= resolveBin();\n}\n\nexport function resetCmuxBinCache(): void {\n _cached = undefined;\n}\n","// src/lib/cmux-probe.ts\n//\n// #348 (part of #332): the hybrid gate. Answer \"can a NON-cmux process reach the\n// cmux control socket right now?\" — i.e. is daemon-direct delivery viable?\n//\n// See docs/specs/2026-06-16-cmux-socket-auth-daemon-direct-design.md §4.2.\n//\n// FAITHFULNESS: cmuxOnly mode checks the connecting process's parent chain and\n// rejects anything not descended from the cmux app. Prior research was\n// CONTAMINATED because it ran inside a cmux pane and kept cmux ancestry even\n// under `env -i`. A faithful probe MUST run from a process reparented to launchd\n// (PPID ⇒ 1). We achieve that with a launcher→worker double-fork: the launcher\n// exits immediately, orphaning the worker, which waits until process.ppid === 1\n// before touching the socket.\nimport { spawn } from \"node:child_process\";\nimport { mkdtempSync, rmSync, existsSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { tmpdir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { resolveCmuxBin } from \"./cmux-bin.js\";\n\nexport type ProbeVerdict = \"reachable\" | \"denied\" | \"unknown\";\n\nexport interface ProbeRawResult {\n ok: boolean;\n stderr?: string;\n}\n\n// cmux's parentage rejection message (and generic socket permission errors).\nconst DENIED_RE = /access denied|only processes started inside cmux|permission denied/i;\n\n/**\n * Pure. Map a raw probe result to a verdict.\n * - ok ⇒ reachable (daemon-direct viable)\n * - access-denied stderr ⇒ denied (socket still cmuxOnly — restart needed)\n * - anything else ⇒ unknown (fail soft → stay on relay)\n */\nexport function classifyProbe(r: ProbeRawResult): ProbeVerdict {\n if (r.ok) return \"reachable\";\n if (r.stderr && DENIED_RE.test(r.stderr)) return \"denied\";\n return \"unknown\";\n}\n\nexport interface ProbeOpts {\n /** Injectable runner (tests). Default = orphan-escape spawn of a cmux read. */\n run?: () => Promise<ProbeRawResult>;\n /** Overall budget for the orphan probe (default 8s). */\n timeoutMs?: number;\n}\n\n/**\n * Probe whether a non-cmux process can reach the cmux control socket. Never\n * throws — a failed/timed-out probe degrades to \"unknown\" so the caller stays on\n * the zero-setup relay.\n */\nexport async function probeCmuxDaemonDirect(opts: ProbeOpts = {}): Promise<ProbeVerdict> {\n const run = opts.run ?? (() => orphanProbe(opts.timeoutMs ?? 8000));\n try {\n return classifyProbe(await run());\n } catch {\n return \"unknown\";\n }\n}\n\n// The worker script, run via `node`. Two modes in one file:\n// launch: spawn the worker detached, then exit → worker is orphaned to launchd\n// work: wait until PPID===1 (no cmux ancestor), run the cmux read, write JSON\n// argv: [node, script, mode, resultFile, cmuxBin]\nconst WORKER_SRC = `\nimport { spawn, execFileSync } from \"node:child_process\";\nimport { writeFileSync } from \"node:fs\";\nconst [mode, resultFile, cmuxBin] = process.argv.slice(2);\nif (mode === \"launch\") {\n const child = spawn(process.execPath, [process.argv[1], \"work\", resultFile, cmuxBin], {\n detached: true, stdio: \"ignore\",\n });\n child.unref();\n process.exit(0);\n}\n// work mode: wait to be reparented to launchd (PPID 1), then probe.\nconst deadline = Date.now() + 3000;\nwhile (process.ppid !== 1 && Date.now() < deadline) {\n const until = Date.now() + 25;\n while (Date.now() < until) { /* tiny busy wait — no timers in a dying orphan */ }\n}\nlet result;\nif (process.ppid !== 1) {\n result = { ok: false, stderr: \"orphan-timeout\" };\n} else {\n try {\n execFileSync(cmuxBin, [\"workspace\", \"list\", \"--json\"], {\n encoding: \"utf-8\", timeout: 10000, env: { ...process.env, CMUX_QUIET: \"1\" },\n });\n result = { ok: true };\n } catch (e) {\n const stderr = (e && (e.stderr?.toString?.() || e.message)) || \"probe failed\";\n result = { ok: false, stderr };\n }\n}\nwriteFileSync(resultFile, JSON.stringify(result));\n`;\n\n// Default runner: double-fork to a launchd-reparented worker, poll its result.\nasync function orphanProbe(timeoutMs: number): Promise<ProbeRawResult> {\n const dir = mkdtempSync(join(tmpdir(), \"cmux-probe-\"));\n const scriptFile = join(dir, \"probe-worker.mjs\");\n const resultFile = join(dir, \"result.json\");\n writeFileSync(scriptFile, WORKER_SRC);\n\n try {\n const launcher = spawn(\n process.execPath,\n [scriptFile, \"launch\", resultFile, resolveCmuxBin()],\n { detached: true, stdio: \"ignore\" },\n );\n launcher.unref();\n\n const deadline = Date.now() + timeoutMs;\n while (Date.now() < deadline) {\n if (existsSync(resultFile)) {\n try {\n return JSON.parse(readFileSync(resultFile, \"utf-8\")) as ProbeRawResult;\n } catch {\n // partial write — fall through and retry\n }\n }\n await sleep(100);\n }\n return { ok: false, stderr: \"probe-timeout\" };\n } finally {\n rmSync(dir, { recursive: true, force: true });\n }\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((r) => setTimeout(r, ms));\n}\n","// src/lib/cmux-autoconfig.ts\n//\n// #348 (part of #332): orchestrator for cmux socket auto-config. Ties together\n// the comment-preserving config write, the non-cmux probe, and a SEMI-AUTOMATIC,\n// one-time restart prompt.\n//\n// See docs/specs/2026-06-16-cmux-socket-auth-daemon-direct-design.md §4.3–§4.4.\n//\n// This module decides WHAT to surface (configChanged / verdict / one-time\n// prompt); it does not print or log. The caller — the `squadrant cmux autoconfig`\n// CLI or the daemon-start re-check — renders the result. squadrant NEVER restarts\n// cmux for the user (that disrupts live sessions); we write config and prompt.\nimport { existsSync, readFileSync, writeFileSync, mkdirSync, rmSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { dirname, join } from \"node:path\";\nimport { ensureSocketAutomation } from \"./cmux-config.js\";\nimport { probeCmuxDaemonDirect, type ProbeVerdict } from \"./cmux-probe.js\";\n\n/** One-time prompt marker, alongside the daemon state. */\nexport function defaultStatePath(): string {\n return join(homedir(), \".config\", \"squadrant\", \"state\", \"cmux-autoconfig.json\");\n}\n\nexport interface AutoConfigResult {\n /** Path of the cmux config inspected/written. */\n configPath: string;\n /** True when the cmux config was written this run. */\n configChanged: boolean;\n /** True when socketControlMode was already \"automation\". */\n configAlreadySet: boolean;\n /** Live socket reachability from a non-cmux process. */\n verdict: ProbeVerdict;\n /** Config is in place but the live socket still rejects (cmux restart needed). */\n needsRestart: boolean;\n /** The one-time restart prompt fired this run (false on repeats — no nag). */\n promptedThisRun: boolean;\n}\n\nexport interface AutoConfigOpts {\n configPath?: string;\n statePath?: string;\n /** Injectable for tests. Default = ensureSocketAutomation. */\n ensureConfig?: typeof ensureSocketAutomation;\n /** Injectable for tests. Default = the real orphan probe. */\n probe?: () => Promise<ProbeVerdict>;\n}\n\ninterface PromptState {\n promptedRestart?: boolean;\n}\n\nfunction readState(path: string): PromptState {\n try {\n return JSON.parse(readFileSync(path, \"utf-8\")) as PromptState;\n } catch {\n return {};\n }\n}\n\n/**\n * Idempotent: write the cmux automation config (if needed), probe the live\n * socket, and fire a one-time restart prompt when the socket still rejects.\n *\n * Safe to call on every daemon start — it recovers the \"cmux not running at\n * first write\" edge case (§3.4): the value is already file-managed, so the next\n * start re-probes and daemon-direct activates once cmux is (re)launched.\n */\nexport async function ensureCmuxAutoConfig(opts: AutoConfigOpts = {}): Promise<AutoConfigResult> {\n const statePath = opts.statePath ?? defaultStatePath();\n const ensureConfig = opts.ensureConfig ?? ensureSocketAutomation;\n const probe = opts.probe ?? probeCmuxDaemonDirect;\n\n const cfg = ensureConfig({ path: opts.configPath });\n const verdict = await probe();\n const needsRestart = verdict === \"denied\";\n\n let promptedThisRun = false;\n if (needsRestart) {\n const already = readState(statePath).promptedRestart === true;\n if (!already) {\n mkdirSync(dirname(statePath), { recursive: true });\n writeFileSync(statePath, JSON.stringify({ promptedRestart: true }));\n promptedThisRun = true;\n }\n } else if (verdict === \"reachable\") {\n // Reset the marker so a future regression (e.g. cmux config wiped) re-prompts.\n if (existsSync(statePath)) rmSync(statePath, { force: true });\n }\n\n return {\n configPath: cfg.path,\n configChanged: cfg.changed,\n configAlreadySet: cfg.alreadySet,\n verdict,\n needsRestart,\n promptedThisRun,\n };\n}\n","export type ToolEntry = { min?: string; lastVerified?: string };\n\nexport const compatManifest = {\n tools: {\n cmux: { min: \"0.64.0\", lastVerified: \"0.64.16\" } satisfies ToolEntry,\n claude: { min: \"2.1.32\" } satisfies ToolEntry,\n node: { min: \"18.0.0\", lastVerified: \"24.6.0\" } satisfies ToolEntry,\n // presence-checked; no floor enforced yet\n codex: { lastVerified: \"0.139.0\" } satisfies ToolEntry,\n gemini: { lastVerified: \"0.38.2\" } satisfies ToolEntry,\n opencode: { lastVerified: \"1.17.4\" } satisfies ToolEntry,\n },\n} as const;\n","import type { SquadrantConfig } from \"../config.js\";\n\nexport type DriftKind = \"missing\" | \"deprecated\" | \"changed-default\" | \"invalid\";\nexport type DriftSeverity = \"info\" | \"advisory\" | \"warn\";\n\nexport interface DriftItem {\n path: string;\n kind: DriftKind;\n severity: DriftSeverity;\n current?: unknown;\n suggested?: unknown;\n note?: string;\n}\n\nexport const SAFE_KINDS: DriftKind[] = [\"missing\", \"deprecated\"];\n\nconst MANAGED_PATHS: string[] = [\n \"defaults.maxCrew\",\n \"defaults.worktreeDir\",\n \"defaults.teammateMode\",\n \"defaults.permissions.*\",\n \"defaults.roles.*\",\n \"agents.*\",\n \"workspace\",\n \"notifier\",\n \"runtime\",\n];\n\nconst KNOWN_DEPRECATED: Array<{ path: string; when?: (u: SquadrantConfig) => boolean; note: string }> = [\n {\n path: \"defaults.models\",\n when: (u) => u.defaults?.roles !== undefined,\n note: \"superseded by defaults.roles\",\n },\n];\n\nconst KNOWN_DEFAULT_HISTORY: Array<{ path: string; oldDefaults: unknown[] }> = [\n { path: \"defaults.roles.crew.model\", oldDefaults: [\"sonnet\"] },\n { path: \"defaults.roles.captain.model\", oldDefaults: [\"sonnet\"] },\n];\n\nconst KNOWN_DRIVERS = new Set([\"claude\", \"codex\", \"gemini\", \"opencode\"]);\n\nfunction getPath(obj: unknown, dotted: string): unknown {\n return dotted.split(\".\").reduce<unknown>((acc, k) => (acc && typeof acc === \"object\" ? (acc as Record<string, unknown>)[k] : undefined), obj);\n}\n\nfunction hasPath(obj: unknown, dotted: string): boolean {\n const parts = dotted.split(\".\");\n let cur: unknown = obj;\n for (const k of parts) {\n if (!cur || typeof cur !== \"object\" || !(k in (cur as Record<string, unknown>))) return false;\n cur = (cur as Record<string, unknown>)[k];\n }\n return true;\n}\n\nfunction expandManaged(managed: string, def: SquadrantConfig): string[] {\n if (!managed.endsWith(\".*\")) return [managed];\n const parent = managed.slice(0, -2);\n const node = getPath(def, parent);\n if (!node || typeof node !== \"object\") return [];\n return Object.keys(node as Record<string, unknown>).map((k) => `${parent}.${k}`);\n}\n\nexport function detectDrift(user: SquadrantConfig, def: SquadrantConfig): DriftItem[] {\n const items: DriftItem[] = [];\n\n for (const managed of MANAGED_PATHS) {\n for (const leaf of expandManaged(managed, def)) {\n const inDefault = hasPath(def, leaf);\n if (inDefault && !hasPath(user, leaf)) {\n items.push({ path: leaf, kind: \"missing\", severity: \"info\", suggested: getPath(def, leaf) });\n }\n }\n }\n\n for (const dep of KNOWN_DEPRECATED) {\n if (hasPath(user, dep.path) && (dep.when ? dep.when(user) : true)) {\n items.push({ path: dep.path, kind: \"deprecated\", severity: \"info\", current: getPath(user, dep.path), note: dep.note });\n }\n }\n\n for (const hist of KNOWN_DEFAULT_HISTORY) {\n if (!hasPath(user, hist.path) || !hasPath(def, hist.path)) continue;\n const cur = getPath(user, hist.path);\n const nowDefault = getPath(def, hist.path);\n if (cur !== nowDefault && hist.oldDefaults.includes(cur)) {\n items.push({\n path: hist.path,\n kind: \"changed-default\",\n severity: \"advisory\",\n current: cur,\n suggested: nowDefault,\n note: `default changed from ${JSON.stringify(cur)} to ${JSON.stringify(nowDefault)}`,\n });\n }\n }\n\n const agents = (user.agents ?? {}) as Record<string, { driver?: string }>;\n for (const [name, entry] of Object.entries(agents)) {\n if (entry?.driver && !KNOWN_DRIVERS.has(entry.driver)) {\n items.push({\n path: `agents.${name}.driver`,\n kind: \"invalid\",\n severity: \"warn\",\n current: entry.driver,\n note: `unknown driver '${entry.driver}'; known: ${[...KNOWN_DRIVERS].join(\", \")}`,\n });\n }\n }\n const roles = (user.defaults?.roles ?? {}) as Record<string, { agent?: string }>;\n for (const [role, asn] of Object.entries(roles)) {\n if (asn?.agent && !(asn.agent in agents)) {\n items.push({\n path: `defaults.roles.${role}.agent`,\n kind: \"invalid\",\n severity: \"warn\",\n current: asn.agent,\n note: `references agent '${asn.agent}' which is not defined in agents`,\n });\n }\n }\n\n return items;\n}\n\nfunction setPath(obj: Record<string, unknown>, dotted: string, value: unknown): void {\n const parts = dotted.split(\".\");\n let cur = obj;\n for (let i = 0; i < parts.length - 1; i++) {\n const k = parts[i];\n if (typeof cur[k] !== \"object\" || cur[k] === null) cur[k] = {};\n cur = cur[k] as Record<string, unknown>;\n }\n cur[parts[parts.length - 1]] = value;\n}\n\nfunction deletePath(obj: Record<string, unknown>, dotted: string): void {\n const parts = dotted.split(\".\");\n let cur: Record<string, unknown> | undefined = obj;\n for (let i = 0; i < parts.length - 1; i++) {\n cur = cur[parts[i]] as Record<string, unknown> | undefined;\n if (!cur || typeof cur !== \"object\") return;\n }\n delete cur[parts[parts.length - 1]];\n}\n\nexport function applySafeFixes(\n user: SquadrantConfig,\n items: DriftItem[],\n _def: SquadrantConfig,\n): { config: SquadrantConfig; applied: string[] } {\n const config = JSON.parse(JSON.stringify(user)) as SquadrantConfig;\n const applied: string[] = [];\n const root = config as unknown as Record<string, unknown>;\n for (const item of items) {\n if (!SAFE_KINDS.includes(item.kind)) continue;\n if (item.kind === \"missing\") setPath(root, item.path, item.suggested);\n else if (item.kind === \"deprecated\") deletePath(root, item.path);\n applied.push(item.path);\n }\n return { config, applied };\n}\n","import type { SquadrantConfig } from \"../config.js\";\n\nexport function readStamp(config: SquadrantConfig): string | null {\n return config._squadrantVersion ?? null;\n}\n\nexport function needsCheck(config: SquadrantConfig, pkgVersion: string): boolean {\n return readStamp(config) !== pkgVersion;\n}\n\nexport function withStamp(config: SquadrantConfig, pkgVersion: string): SquadrantConfig {\n return { ...config, _squadrantVersion: pkgVersion };\n}\n","// src/lib/git-worktree.ts\n//\n// Per-crew git worktree isolation (#216). A FEATURE crew (spawned with\n// `--worktree`) runs in its own worktree + branch so it can switch HEAD without\n// dragging the captain's checkout. Small/one-off crews keep running on the\n// shared root checkout (unchanged default). The side-effecting `git worktree`\n// calls live here so crew.ts stays mockable and surgical — same seam pattern as\n// per-crew-settings.ts.\n//\n// Builds and the daemon still run from the MAIN checkout's `dist`; worktrees\n// edit source only (issue #216 caveat).\nimport { execFileSync } from \"node:child_process\";\nimport path from \"node:path\";\n\nexport interface WorktreeSpec {\n /** The project's root checkout (also the shared `.git` owner). */\n repoRoot: string;\n /** Config.defaults.worktreeDir, resolved relative to repoRoot (e.g. \".worktrees\"). */\n worktreeDir: string;\n project: string;\n /** Crew name (e.g. \"crew-1\" or a --name value). */\n name: string;\n /** Branch to base the new crew branch on (GitFlow: \"develop\"). */\n base: string;\n}\n\n/** Deterministic worktree path: <repoRoot>/<worktreeDir>/<project>-<name>. */\nexport function worktreePath(repoRoot: string, worktreeDir: string, project: string, name: string): string {\n return path.resolve(repoRoot, worktreeDir, `${project}-${name}`);\n}\n\n/** Crew branch name for a worktree crew. */\nexport function crewBranch(name: string): string {\n return `crew/${name}`;\n}\n\n// #359: derive the branch a new worktree should be based on. Reads origin/HEAD\n// so main-based repos work without a hand-created `develop`. Falls back to\n// `fallback` (default \"develop\") when origin/HEAD is unset.\nexport function resolveWorktreeBase(repoRoot: string, fallback = \"develop\"): string {\n try {\n const ref = execFileSync(\n \"git\",\n [\"-C\", repoRoot, \"symbolic-ref\", \"refs/remotes/origin/HEAD\"],\n { stdio: [\"ignore\", \"pipe\", \"ignore\"] },\n ).toString().trim();\n const m = ref.match(/^refs\\/remotes\\/origin\\/(.+)$/);\n if (m) return m[1];\n } catch {\n return fallback;\n }\n return fallback;\n}\n\n/**\n * Create the crew's worktree + branch and return its absolute path.\n * Fails loud (throws) if git refuses — e.g. the base branch is missing or the\n * branch/path already exists. The caller's name-uniqueness check already\n * prevents live duplicates; a re-spawned-after-close name can collide on the\n * existing branch (rare — pick a new --name).\n */\nexport function addWorktree(spec: WorktreeSpec): string {\n const wt = worktreePath(spec.repoRoot, spec.worktreeDir, spec.project, spec.name);\n execFileSync(\n \"git\",\n [\"-C\", spec.repoRoot, \"worktree\", \"add\", wt, \"-b\", crewBranch(spec.name), spec.base],\n { stdio: \"pipe\" },\n );\n return wt;\n}\n\n/**\n * Remove a crew's worktree (auto-clean on close). Tries a plain remove first;\n * a dirty/locked worktree makes git refuse, so we retry with --force. The\n * branch is left intact so the crew's commits survive the close.\n */\nexport function removeWorktree(repoRoot: string, wtPath: string): void {\n try {\n execFileSync(\"git\", [\"-C\", repoRoot, \"worktree\", \"remove\", wtPath], { stdio: \"pipe\" });\n } catch {\n execFileSync(\"git\", [\"-C\", repoRoot, \"worktree\", \"remove\", \"--force\", wtPath], { stdio: \"pipe\" });\n }\n}\n","import fs from \"node:fs\";\n\nasync function readAllStdin(): Promise<string> {\n const chunks: Buffer[] = [];\n for await (const chunk of process.stdin) {\n chunks.push(Buffer.from(chunk));\n }\n return Buffer.concat(chunks).toString(\"utf-8\");\n}\n\nfunction flagName(label: string): string {\n return label === \"task\" ? \"--task-file\" : \"--message-file\";\n}\n\nexport interface ResolveTextInputOpts {\n positional?: string;\n filePath?: string;\n label: string;\n}\n\nexport interface ResolveTextInputDeps {\n readFile?: (path: string) => string;\n readStdin?: () => Promise<string>;\n}\n\nexport async function resolveTextInput(\n opts: ResolveTextInputOpts,\n deps?: ResolveTextInputDeps,\n): Promise<string> {\n const readFile = deps?.readFile ?? ((p: string) => fs.readFileSync(p, \"utf8\"));\n const readStdin = deps?.readStdin ?? readAllStdin;\n\n if (opts.filePath) {\n if (opts.filePath === \"-\") {\n return readStdin();\n }\n try {\n return readFile(opts.filePath);\n } catch (e) {\n const err = e as NodeJS.ErrnoException;\n const flag = flagName(opts.label);\n if (err.code === \"ENOENT\") {\n throw new Error(`${flag} '${opts.filePath}': file not found`);\n }\n throw new Error(`${flag} '${opts.filePath}': ${err.message}`);\n }\n }\n\n if (opts.positional === undefined) {\n throw new Error(\n `No ${opts.label} provided. Provide a positional argument or use ${flagName(opts.label)}.`,\n );\n }\n\n return opts.positional;\n}\n","import fs from \"node:fs\";\nimport path from \"node:path\";\n\n/**\n * Copy `src` → `dest` only if `dest` is missing or its bytes differ. Content\n * comparison (not size+mtime) makes this both correct — a same-size edit is\n * always detected — and idempotent: an unchanged file is never rewritten, so\n * there is no mtime churn across runs. Managed files are small; reading them\n * per invocation is sub-millisecond. Returns true if a copy happened.\n */\nfunction copyIfDifferent(src: string, dest: string): boolean {\n if (fs.existsSync(dest)) {\n if (fs.readFileSync(src).equals(fs.readFileSync(dest))) return false;\n }\n fs.copyFileSync(src, dest);\n return true;\n}\n\n/**\n * Mirror `src` into `dest`: recursively copy new/changed files AND prune any\n * dest entry that no longer exists in src. Idempotent — unchanged files are\n * left untouched. After this returns, `dest` is a structural copy of `src`.\n * Caller is responsible for only pointing this at source-managed trees — it\n * WILL delete dest entries absent from src.\n */\nexport function mirrorDir(src: string, dest: string): void {\n fs.mkdirSync(dest, { recursive: true });\n\n const srcEntries = fs.readdirSync(src, { withFileTypes: true });\n const srcNames = new Set(srcEntries.map((e) => e.name));\n\n for (const entry of srcEntries) {\n const srcPath = path.join(src, entry.name);\n const destPath = path.join(dest, entry.name);\n if (entry.isDirectory()) {\n mirrorDir(srcPath, destPath);\n } else {\n copyIfDifferent(srcPath, destPath);\n }\n }\n\n for (const entry of fs.readdirSync(dest, { withFileTypes: true })) {\n if (!srcNames.has(entry.name)) {\n fs.rmSync(path.join(dest, entry.name), { recursive: true, force: true });\n }\n }\n}\n\n/**\n * Copy the top-level (non-recursive) files of `src` matching `match` into a\n * flat `dest`, prune dest entries no longer in the matched set, and apply\n * `chmod` to freshly copied files when given. Idempotent — unchanged files\n * are left untouched. For runtime dirs whose source is a differently-named,\n * mixed directory (templates ← templates/, scripts).\n */\nexport function mirrorFlat(\n src: string,\n dest: string,\n match: RegExp,\n chmod?: number,\n): void {\n fs.mkdirSync(dest, { recursive: true });\n\n const matched = fs\n .readdirSync(src, { withFileTypes: true })\n .filter((e) => e.isFile() && match.test(e.name))\n .map((e) => e.name);\n const matchedSet = new Set(matched);\n\n for (const name of matched) {\n const destPath = path.join(dest, name);\n const copied = copyIfDifferent(path.join(src, name), destPath);\n if (copied && chmod !== undefined) fs.chmodSync(destPath, chmod);\n }\n\n for (const entry of fs.readdirSync(dest, { withFileTypes: true })) {\n if (!matchedSet.has(entry.name)) {\n fs.rmSync(path.join(dest, entry.name), { recursive: true, force: true });\n }\n }\n}\n\n/**\n * A source-managed runtime dir. `name` is the dir under the runtime root;\n * `srcRel` is its source dir relative to the package root (note: the\n * runtime `templates/` is sourced from `templates/`).\n */\nexport type ManagedTarget =\n | { name: string; srcRel: string; mode: \"tree\" }\n | {\n name: string;\n srcRel: string;\n mode: \"flat\";\n match: RegExp;\n chmod?: number;\n };\n\nexport const MANAGED_TARGETS: ManagedTarget[] = [\n { name: \"plugin\", srcRel: \"plugin\", mode: \"tree\" },\n { name: \"scripts\", srcRel: \"scripts\", mode: \"flat\", match: /\\.sh$/, chmod: 0o755 },\n {\n name: \"templates\",\n srcRel: \"templates\",\n mode: \"flat\",\n match: /\\.(claude\\.md|generic\\.md|opencode\\.md|CLAUDE\\.md)$/,\n },\n];\n\nexport interface EnsureRuntimeSyncedOptions {\n /** Package root containing the source dirs (`plugin/`, `templates/`, …). */\n sourceRoot: string;\n /** Runtime root, normally ~/.config/squadrant. */\n runtimeRoot: string;\n /** Override the managed-target list (defaults to MANAGED_TARGETS). */\n targets?: ManagedTarget[];\n}\n\n/**\n * Self-heal the runtime copy of source-managed dirs. Every invocation\n * mirrors each managed target (mirrorDir for tree, mirrorFlat for flat) —\n * idempotent copy-if-different + prune, so the runtime is always reconciled\n * to source. There is no cached state: nothing can claim \"synced\" while the\n * dest is actually wrong. Only ever touches the runtime dirs named in the\n * target list — never user/runtime state. Never throws — a sync failure\n * degrades to a stderr warning so the CLI stays usable.\n */\nexport function ensureRuntimeSynced(opts: EnsureRuntimeSyncedOptions): void {\n const targets = opts.targets ?? MANAGED_TARGETS;\n\n for (const t of targets) {\n const srcDir = path.join(opts.sourceRoot, t.srcRel);\n try {\n if (!fs.existsSync(srcDir)) continue;\n const destDir = path.join(opts.runtimeRoot, t.name);\n if (t.mode === \"tree\") {\n mirrorDir(srcDir, destDir);\n } else {\n mirrorFlat(srcDir, destDir, t.match, t.chmod);\n }\n } catch (err) {\n process.stderr.write(\n `squadrant: runtime sync skipped for ${t.name}: ${(err as Error).message}\\n`,\n );\n }\n }\n}\n","type SemVer = [number, number, number];\n\nfunction parseSemVer(v: string): SemVer | null {\n const m = v.match(/(\\d+)\\.(\\d+)\\.(\\d+)/);\n if (!m) return null;\n return [parseInt(m[1], 10), parseInt(m[2], 10), parseInt(m[3], 10)];\n}\n\nfunction cmpSemVer(a: SemVer, b: SemVer): number {\n for (let i = 0; i < 3; i++) {\n if (a[i] !== b[i]) return a[i] - b[i];\n }\n return 0;\n}\n\n/**\n * Compare an installed tool version against the compat manifest entry.\n * Returns a warning string when the version is below min or above lastVerified,\n * or null when the version is in-range or unparseable (non-blocking).\n * `min` is optional — entries without a floor are only drift-checked against lastVerified.\n */\nexport function checkToolCompat(\n name: string,\n rawVersion: string,\n entry: { min?: string; lastVerified?: string },\n): string | null {\n const installed = parseSemVer(rawVersion);\n if (!installed) return null;\n\n const min = entry.min ? parseSemVer(entry.min) : null;\n if (min && cmpSemVer(installed, min) < 0) {\n return `${name} ${rawVersion} < min ${entry.min} — upgrade to ${entry.min}+`;\n }\n\n if (entry.lastVerified) {\n const lastVerified = parseSemVer(entry.lastVerified);\n if (lastVerified && cmpSemVer(installed, lastVerified) > 0) {\n return `${name} ${rawVersion} > last-verified ${entry.lastVerified} — re-run compat audit`;\n }\n }\n\n return null;\n}\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport type { WorkspaceDriver } from \"../types/workspaces.js\";\nimport type { ProjectionSource } from \"../types/projection.js\";\n\ninterface SkillFrontmatter {\n name: string;\n description: string;\n}\n\nfunction parseSkill(raw: string): { frontmatter: SkillFrontmatter; body: string } | null {\n const match = raw.match(/^---\\n([\\s\\S]*?)\\n---\\n?([\\s\\S]*)$/);\n if (!match) return null;\n const [, fmBlock, body] = match;\n const fm: Partial<SkillFrontmatter> = {};\n for (const line of fmBlock.split(\"\\n\")) {\n const kv = line.match(/^(\\w+):\\s*(.+)$/);\n if (kv) (fm as Record<string, string>)[kv[1]] = kv[2].trim();\n }\n if (!fm.name || !fm.description) return null;\n return { frontmatter: fm as SkillFrontmatter, body: body.trim() };\n}\n\nasync function readSkills(\n driver: WorkspaceDriver,\n skillsDir: string,\n): Promise<ProjectionSource[\"skills\"]> {\n if (!(await driver.exists(skillsDir))) return [];\n const names = await driver.list(skillsDir);\n const skills: ProjectionSource[\"skills\"] = [];\n for (const name of names) {\n const skillPath = `${skillsDir}/${name}/SKILL.md`;\n if (!(await driver.exists(skillPath))) continue;\n const raw = await driver.read(skillPath);\n const parsed = parseSkill(raw);\n if (!parsed) continue;\n skills.push({\n name: parsed.frontmatter.name,\n description: parsed.frontmatter.description,\n content: parsed.body,\n });\n }\n skills.sort((a, b) => a.name.localeCompare(b.name));\n return skills;\n}\n\nexport interface UserSourceOptions {\n pkgRoot?: string;\n readFile?: (p: string) => string;\n}\n\nconst ROLE_TEMPLATES: ReadonlyArray<{ file: string; heading: string }> = [\n { file: \"captain.generic.md\", heading: \"## Captain Role\" },\n { file: \"crew.generic.md\", heading: \"## Crew Role\" },\n];\n\nfunction readRoleTemplates(opts: UserSourceOptions): string {\n if (!opts.pkgRoot) return \"\";\n const reader = opts.readFile ?? ((p: string) => fs.readFileSync(p, \"utf-8\"));\n const sections: string[] = [];\n for (const { file, heading } of ROLE_TEMPLATES) {\n const full = path.join(opts.pkgRoot, \"templates\", file);\n let body = \"\";\n try { body = reader(full); } catch { continue; }\n sections.push(`${heading}\\n\\n${body.trim()}`);\n }\n return sections.join(\"\\n\\n\");\n}\n\nexport async function readUserLevelSource(\n driver: WorkspaceDriver,\n opts: UserSourceOptions = {},\n): Promise<ProjectionSource> {\n const skills = await readSkills(driver, \"plugin/skills\");\n const instructions = readRoleTemplates(opts);\n return { instructions, skills };\n}\n\n// `driver` must be rooted at the project directory itself (createObsidianDriver\n// with root: proj.path). Reading via a driver rooted at process.cwd() — as the\n// projection command previously did — made the sandbox guard reject every\n// managed project living outside the squadrant repo, silently skipping them.\nexport async function readProjectLevelSource(\n driver: WorkspaceDriver,\n): Promise<ProjectionSource | null> {\n if (!(await driver.exists(\"AGENTS.md\"))) return null;\n const instructions = await driver.read(\"AGENTS.md\");\n const skills = await readSkills(driver, \"plugin/skills\");\n return { instructions, skills };\n}\n","import { execSync } from \"node:child_process\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport matter from \"gray-matter\";\nimport { resolveHome } from \"../config.js\";\nimport type { WorkspaceDriver } from \"../types/workspaces.js\";\n\nexport function iso(d: Date): string {\n return d.toISOString().slice(0, 10);\n}\n\nexport function daysAgo(n: number): Date {\n const d = new Date();\n d.setDate(d.getDate() - n);\n return d;\n}\n\nexport function enumerateDays(from: Date, to: Date): string[] {\n const out: string[] = [];\n const cur = new Date(from);\n cur.setHours(0, 0, 0, 0);\n const end = new Date(to);\n end.setHours(0, 0, 0, 0);\n while (cur <= end) {\n out.push(iso(cur));\n cur.setDate(cur.getDate() + 1);\n }\n return out;\n}\n\nexport interface DailyLog {\n content: string;\n blockers: string[];\n}\n\nexport async function readDailyLog(\n workspace: WorkspaceDriver,\n dateStr: string,\n): Promise<DailyLog | null> {\n const relPath = `daily-logs/${dateStr}.md`;\n if (!(await workspace.exists(relPath))) return null;\n\n const raw = await workspace.read(relPath);\n const { content } = matter(raw);\n\n const blockers: string[] = [];\n const blockerMatch = content.match(/## Blocked\\n([\\s\\S]*?)(?=\\n##|$)/);\n if (blockerMatch) {\n const lines = blockerMatch[1].trim().split(\"\\n\");\n for (const line of lines) {\n const trimmed = line.replace(/^[-*]\\s*/, \"\").trim();\n if (trimmed && trimmed !== \"(none)\" && trimmed !== \"None\") {\n blockers.push(trimmed);\n }\n }\n }\n return { content, blockers };\n}\n\nexport function parseSection(content: string, section: string): string[] {\n const match = content.match(new RegExp(`## ${section}\\\\n([\\\\s\\\\S]*?)(?=\\\\n##|$)`));\n if (!match) return [];\n return match[1]\n .trim()\n .split(\"\\n\")\n .map((l) => l.replace(/^[-*]\\s*/, \"\").trim())\n .filter((l) => l && l !== \"(none)\" && l !== \"None\");\n}\n\nexport function getGitCommits(projectPath: string, dateStr: string): string[] {\n return getGitCommitsInRange(projectPath, `${dateStr} 00:00:00`, `${dateStr} 23:59:59`);\n}\n\nexport function getGitCommitsInRange(projectPath: string, since: string, until?: string): string[] {\n const resolved = resolveHome(projectPath);\n if (!fs.existsSync(path.join(resolved, \".git\"))) return [];\n\n const untilArg = until ? ` --until=\"${until}\"` : \"\";\n try {\n const output = execSync(\n `git -C \"${resolved}\" log --since=\"${since}\"${untilArg} --oneline --no-merges 2>/dev/null`,\n { encoding: \"utf-8\", timeout: 5000 },\n ).trim();\n if (!output) return [];\n return output.split(\"\\n\").map((l) => l.trim()).filter(Boolean);\n } catch {\n return [];\n }\n}\n\nexport function getMergedPRsInRange(projectPath: string, since: string, until?: string): string[] {\n const resolved = resolveHome(projectPath);\n if (!fs.existsSync(path.join(resolved, \".git\"))) return [];\n\n const untilArg = until ? ` --until=\"${until}\"` : \"\";\n try {\n const output = execSync(\n `git -C \"${resolved}\" log --merges --since=\"${since}\"${untilArg} --pretty=format:%s 2>/dev/null`,\n { encoding: \"utf-8\", timeout: 5000 },\n ).trim();\n if (!output) return [];\n return output.split(\"\\n\").map((l) => l.trim()).filter(Boolean);\n } catch {\n return [];\n }\n}\n","import type { WorkspaceDriver } from \"../types/workspaces.js\";\n\nexport const SPOKE_SUBDIRS = [\n \"crew\",\n \"learnings\",\n \"daily-logs\",\n \"skills\",\n \"meta\",\n \"templates\",\n \"wiki\",\n \"wiki/pages\",\n];\n\nexport async function ensureSpokeLayout(workspace: WorkspaceDriver): Promise<void> {\n for (const sub of SPOKE_SUBDIRS) {\n await workspace.mkdir(sub);\n }\n}\n","const DAEMON_CACHED_PREFIXES = [\n \"telegram.\",\n \"defaults.taskTimeoutMs\",\n \"defaults.cmuxEventsBridge\",\n \"projects.\",\n];\n\nexport function isDaemonCachedKey(dottedKey: string): boolean {\n return DAEMON_CACHED_PREFIXES.some((p) => dottedKey === p || dottedKey.startsWith(p));\n}\n","// @squadrant/shared — pure types + leaf utilities + config.\nexport * from \"./config.js\";\nexport * from \"./project-config.js\";\nexport * from \"./effort.js\";\nexport * from \"./types/runtime.js\";\nexport * from \"./types/control.js\";\nexport * from \"./types/projection.js\";\nexport * from \"./types/workspaces.js\";\nexport * from \"./lib/cmux-autoconfig.js\";\nexport * from \"./lib/cmux-bin.js\";\nexport * from \"./lib/cmux-config.js\";\nexport * from \"./lib/cmux-probe.js\";\nexport * from \"./lib/compat-manifest.js\";\nexport * from \"./lib/config-drift.js\";\nexport * from \"./lib/config-version.js\";\nexport * from \"./lib/git-worktree.js\";\nexport * from \"./lib/resolve-text-input.js\";\nexport * from \"./lib/runtime-sync.js\";\nexport * from \"./lib/tool-compat.js\";\nexport * from \"./lib/canonical-source.js\";\nexport * from \"./lib/daily-logs.js\";\nexport * from \"./lib/vault-layout.js\";\nexport * from \"./daemon-keys.js\";\n","// src/control/state-machine.ts\nimport type { ControlEvent, TaskRecord, DispatchAttempt } from \"@squadrant/shared\";\nimport { TERMINAL_STATES } from \"@squadrant/shared\";\n\n/**\n * Pure helper: merges `patch` into the last attempt and updates lastHeartbeatAt.\n * Returns a new TaskRecord; never mutates the input.\n */\nfunction stampAttempt(\n rec: TaskRecord,\n patch: Partial<DispatchAttempt>,\n now: number,\n): TaskRecord {\n const attempts = rec.attempts.slice();\n const last = attempts.at(-1) ?? { attemptId: \"a0\", startedAt: now, lastHeartbeatAt: now };\n attempts[attempts.length === 0 ? 0 : attempts.length - 1] = { ...last, ...patch, lastHeartbeatAt: now };\n if (attempts.length === 0) attempts.push(last);\n return { ...rec, attempts };\n}\n\n/**\n * #354: compute the next pendingTool marker for a task.progress liveness signal.\n * A PreToolUse (carried from the cmux events-bridge, with the tool name) opens a\n * tool-in-flight window; a PostToolUse or a new UserPromptSubmit closes it. Other\n * liveness notes (subagentstop / notification) leave the marker untouched — they\n * do not bound a tool call. The note strings match the two feeds: the events-bridge\n * emits the raw cmux hook name (\"agent.hook.PreToolUse\"); the claude hook bridge\n * emits the lower-cased event (\"posttooluse\").\n */\nfunction nextPendingTool(\n current: TaskRecord[\"pendingTool\"],\n ev: Extract<ControlEvent, { type: \"task.progress\" }>,\n now: number,\n): TaskRecord[\"pendingTool\"] {\n if (ev.note === \"agent.hook.PreToolUse\") return { name: ev.tool ?? \"tool\", since: now };\n if (ev.note === \"posttooluse\" || ev.note === \"agent.hook.UserPromptSubmit\") return undefined;\n return current;\n}\n\n/**\n * Pure transition. `now` is injected (epoch ms) so callers control time.\n * Returns a new record; never mutates the input.\n */\nexport function reduce(rec: TaskRecord, ev: ControlEvent, now: number): TaskRecord {\n // task.reopened is the ONE event allowed to escape a terminal state.\n // From ANY state (done/failed/stalled/awaiting-input/working) → working.\n // Clears question and error so the revived task looks fresh.\n if (ev.type === \"task.reopened\") {\n return { ...rec, state: \"working\", question: undefined, error: undefined, lastHeartbeat: now, lastEvent: ev.type };\n }\n\n // Terminal states are absorbing: ignore any late/duplicate event idempotently.\n if (TERMINAL_STATES.has(rec.state)) return rec;\n\n const base = { ...rec, lastHeartbeat: now, lastEvent: ev.type };\n\n switch (ev.type) {\n case \"task.started\":\n return {\n ...stampAttempt(base, { pid: ev.pid }, now),\n state: \"working\",\n pid: ev.pid ?? rec.pid,\n sessionId: ev.sessionId ?? rec.sessionId,\n question: undefined, // resuming after a blocked→reply clears the question\n pendingTool: undefined, // #354: a new turn closes any prior tool window\n };\n case \"task.progress\": {\n // task.progress is a real-activity signal (stdout chunk for headless,\n // PreToolUse/PostToolUse/SubagentStop hook for interactive). Stamp the\n // attempt so lastHeartbeatAt stays current and the watchdog stall-check\n // (#89) can key off it without false-stalling long-running headless tasks.\n // #354: also track the in-flight tool (PreToolUse opens, PostToolUse closes)\n // so a hung tool call is distinguishable from a quiet thinking turn.\n // From blocked: liveness only — do not auto-unblock (explicit reply required).\n // From awaiting-input OR stalled: resume to working — the next real activity\n // (e.g. the matching PostToolUse) auto-clears a hung-tool warn instantly.\n const pendingTool = nextPendingTool(rec.pendingTool, ev, now);\n if (rec.state === \"blocked\") return { ...rec, lastHeartbeat: now, lastEvent: ev.type, pendingTool };\n const b = { ...base, pendingTool };\n if (rec.state === \"awaiting-input\" || rec.state === \"stalled\") return { ...stampAttempt(b, {}, now), state: \"working\" };\n return stampAttempt(b, {}, now);\n }\n case \"heartbeat\":\n // Raw liveness ping — intentionally does NOT stamp the attempt so a late\n // heartbeat from a dead dispatch cannot mask stalls on the new one (#89).\n // From awaiting-input: resume to working (mirrors task.progress).\n if (rec.state === \"blocked\") return { ...rec, lastHeartbeat: now, lastEvent: ev.type };\n if (rec.state === \"awaiting-input\") return { ...base, state: \"working\" };\n return base;\n case \"task.blocked\":\n // ev.reason is protocol/logging-only and intentionally not persisted;\n // only `question` is stored on the record.\n // Idempotency (#174): the explicit `squadrant crew signal blocked` fires\n // BEFORE the turn ends; the auto-detect Stop hook may then re-emit\n // task.blocked on an already-blocked task. Treat a repeat block as a\n // no-op so the FIRST (explicit) question wins and no duplicate CREW\n // BLOCKED fires. Terminal states are already absorbed above.\n if (rec.state === \"blocked\") return { ...rec, lastHeartbeat: now, lastEvent: ev.type };\n return { ...base, state: \"blocked\", question: ev.question, pendingTool: undefined };\n case \"task.done\":\n return { ...base, state: \"done\", resultRef: ev.resultRef, parseWarning: ev.parseWarning };\n case \"task.failed\":\n return { ...base, state: \"failed\", error: ev.error, exitCode: ev.exitCode };\n case \"task.cancelled\":\n return { ...base, state: \"cancelled\" };\n case \"task.session.ended\":\n // #139: the claude crew session ended (SessionEnd hook). The process is\n // gone, so terminalize instead of resuming 'working'. Reuses the silent\n // 'cancelled' state — no alarming push, just a clean terminal record.\n return { ...base, state: \"cancelled\" };\n case \"task.session\":\n return stampAttempt(base, { resumeRef: ev.resumeRef }, now);\n case \"task.turn.started\":\n return { ...stampAttempt(base, {}, now), state: \"working\", pendingTool: undefined };\n case \"task.turn.completed\":\n // Anti-#2576 invariant: TurnCompleted is liveness, NEVER completion. Spec §4.8.\n // A turn ending while blocked must NOT unblock — only the captain's answer\n // (task.started via `crew send`) clears blocked. Mirrors task.progress: the\n // opencode SSE bridge emits task.turn.completed right after an explicit\n // `signal blocked`, and that trailing turn-end must not drop the question.\n if (rec.state === \"blocked\") return { ...rec, lastHeartbeat: now, lastEvent: ev.type };\n return { ...stampAttempt(base, {}, now), state: \"awaiting-input\", pendingTool: undefined };\n case \"task.delta\":\n return stampAttempt(base, {}, now); // heartbeat-only\n case \"task.input.requested\":\n case \"task.approval.requested\":\n return { ...stampAttempt(base, {}, now), state: \"blocked\", question: ev.question, pendingTool: undefined };\n case \"task.reattached\":\n return stampAttempt(base, {}, now);\n case \"task.stalled\":\n case \"task.idle\":\n case \"task.quiet\":\n case \"task.timeout\":\n case \"task.reconcile-failed\":\n // Synthetic notify-only events; the daemon has already updated state\n // directly via the watchdog/reconcile paths (task.quiet carries no state\n // change at all — the crew stays `working`). Reducer is a no-op.\n return rec;\n default:\n // #87: unknown/future event type from the wire — safe no-op.\n // The socket boundary (handle()) validates known types before calling\n // reduce; this default is a deep-defense fallback so reduce() can\n // never return undefined regardless of how it is called.\n return rec;\n }\n}\n","// src/control/watchdog.ts\nimport type { TaskRecord } from \"@squadrant/shared\";\n\n/**\n * #354: how long an interactive tool call may be in flight before it is treated\n * as hung. Deliberately generous (much larger than the 5-min heartbeat budget)\n * so a legitimately long tool — a multi-minute test suite, a big build, a slow\n * git/network op — does NOT trip it: those are real, recoverable work, and the\n * matching PostToolUse auto-clears the warn the instant it returns. Only a tool\n * that produces no result for this long is suspicious enough to surface as\n * \"possibly hung\". Default 10 min; tune via evaluateStall's `toolStallMs`.\n */\nexport const TOOL_STALL_BUDGET_MS = 10 * 60 * 1000;\n\n/**\n * Pure. Returns a stalled-transitioned record if a `working` task is genuinely\n * stuck at time `now` (epoch ms), else null. No I/O, no clock. #354 splits the\n * old single wall-clock timeout by what we can actually prove:\n *\n * - headless → 'stalled' once quiet past the heartbeat budget. A batch child\n * that stops emitting stdout is stuck; there is no captain turn to await.\n * - interactive WITH a tool in flight (pendingTool) → 'stalled' once that tool\n * has been outstanding past `toolStallMs`. A PreToolUse with no matching\n * PostToolUse is a hung tool call (we know which tool). Recoverable: the next\n * PostToolUse recovers it to `working` (state-machine / recoverStall).\n * - interactive with NO tool in flight → null. A quiet thinking turn is alive,\n * not stalled and NOT awaiting-input (the turn never ended — real CREW IDLE\n * comes only from the Stop hook). The daemon sweep surfaces this as a\n * distinct, non-alarming CREW QUIET notify instead (#354), keeping the crew\n * `working`. This replaces the old wall-clock → 'awaiting-input' flip, which\n * mislabeled deep-thinking crews as \"awaiting your input\".\n *\n * This function never produces `failed` or `awaiting-input` directly.\n */\nexport function evaluateStall(\n rec: TaskRecord,\n now: number,\n toolStallMs: number = TOOL_STALL_BUDGET_MS,\n): TaskRecord | null {\n if (rec.state !== \"working\") return null;\n if (rec.mode === \"interactive\") {\n // Only a hung tool call is a stall for an interactive crew; a quiet thinking\n // turn (no pendingTool) is alive and handled by the sweep's CREW QUIET path.\n if (!rec.pendingTool) return null;\n if (now - rec.pendingTool.since <= toolStallMs) return null;\n return { ...rec, state: \"stalled\", lastEvent: \"watchdog.tool-stall\" };\n }\n // headless: key off the latest attempt's lastHeartbeatAt so a stale event from\n // a dead prior attempt cannot refresh the liveness clock of the new dispatch (#89).\n const liveness = rec.attempts.at(-1)?.lastHeartbeatAt ?? rec.lastHeartbeat;\n if (now - liveness <= rec.heartbeatBudgetMs) return null;\n return { ...rec, state: \"stalled\", lastEvent: \"watchdog.stall\" };\n}\n\n/**\n * Pure. A stalled task that receives liveness returns to working.\n *\n * WARNING: this does NOT check heartbeat freshness — it returns a recovered\n * record for ANY stalled task. Callers MUST guard with\n * `now - rec.lastHeartbeat <= rec.heartbeatBudgetMs` before applying the\n * result, or a permanently-stale task will be falsely revived.\n */\nexport function recoverStall(rec: TaskRecord, now: number): TaskRecord | null {\n if (rec.state !== \"stalled\") return null;\n // #354: clear any hung-tool marker on recovery so a recovered crew never\n // carries a stale pendingTool into its next quiet window.\n return { ...rec, state: \"working\", lastHeartbeat: now, lastEvent: \"watchdog.recover\", pendingTool: undefined };\n}\n","// src/control/daemon.ts\nimport type { Store } from \"./store.js\";\nimport type { ControlEvent, TaskRecord, TaskState } from \"@squadrant/shared\";\nimport { TERMINAL_STATES } from \"@squadrant/shared\";\nimport { reduce } from \"./state-machine.js\";\nimport { evaluateStall, recoverStall } from \"./watchdog.js\";\nexport interface DaemonDeps {\n store: Store;\n now: () => number;\n /** Injected in Task 14; resumes a blocked session. Optional until then. */\n deliverReply?: (rec: TaskRecord, message: string) => Promise<void>;\n /** Defaults to a real process.kill(pid,0) check at the call site (Task 17). */\n isPidAlive?: (pid: number) => boolean;\n /**\n * #139 backstop: the interactive analogue of isPidAlive. Resolves whether an\n * interactive crew's backing cmux surface (pane/tab) still exists. Three-valued\n * so a transient cmux outage never false-reaps a live crew:\n * - \"alive\" → the crew's pane is present; keep watching.\n * - \"gone\" → cmux answered AND the pane is provably absent → terminalize.\n * - \"unknown\" → could not determine (cmux down, no captain, error) → do nothing.\n * Defaults to always-\"unknown\" (never reaps) when not wired — pure unit tests\n * and any non-cmux deployment are unaffected.\n */\n isSurfaceAlive?: (rec: TaskRecord) => Promise<\"alive\" | \"gone\" | \"unknown\">;\n /** Wired in squadrantd to runHeadless; absent in pure unit tests. */\n launchHeadless?: (rec: TaskRecord) => Promise<void>;\n /**\n * #259: true when a launchHeadless call for this task ID is currently in\n * flight (process spawned but no pid yet). reconcile() skips these so a\n * crash-restart re-run does NOT mark an actively-launching task as failed\n * and re-dispatch it, multiplying orphaned headless processes.\n * Defaults to () => false when not wired (pure unit tests, non-headless modes).\n */\n isHeadlessInFlight?: (id: string) => boolean;\n /**\n * Forward hook for the deferred interactive-wiring spec. While absent,\n * interactive dispatch fails LOUD (red-team #4) instead of silently\n * black-holing in `submitted` forever.\n */\n launchInteractive?: (rec: TaskRecord) => Promise<void>;\n /**\n * Wired in squadrantd to codexDriver.answer(). Delivers the captain's gate\n * resolution payload back to the interactive session (spec §4.9).\n */\n resolveInteractiveGate?: (taskId: string, payload: unknown) => Promise<void> | void;\n /**\n * Push notification hook (#109, refactored under mailbox-injector spec).\n * Called on every state transition into {done, blocked, failed, stalled}.\n * Implementations append to the mailbox; errors are caught + swallowed here\n * so an unhealthy notifier never breaks the event-ingest path.\n */\n notify?: (args: {\n project: string;\n message: string;\n record: TaskRecord;\n event: ControlEvent;\n }) => Promise<void> | void;\n /**\n * #225 hard crew task-timeout: wall-clock ceiling in ms. When a non-terminal\n * task's age (now - createdAt) exceeds this, the sweep fires a CREW TIMEOUT\n * escalation via the notify hook. Defaults to DEFAULT_TASK_TIMEOUT_MS (8h).\n * Distinct from the per-task heartbeat budget (stall detection).\n */\n taskTimeoutMs?: number;\n}\n\n// #225 hard crew task-timeout: default wall-clock ceiling (8h). A crew can\n// heartbeat continuously yet be stuck on one task — the stall watchdog won't\n// catch it. This ceiling does. Configurable via DaemonDeps.taskTimeoutMs.\nexport const DEFAULT_TASK_TIMEOUT_MS = 8 * 60 * 60 * 1000;\n\n// #378: GC TTL for terminal records (done/failed/cancelled). Records older\n// than this are pruned from the store during sweep().\nexport const TERMINAL_RECORD_TTL_MS = 7 * 24 * 60 * 60 * 1000;\n\n// 'awaiting-input' is an attention state: entering it (idle watchdog OR a\n// Stop-hook turn boundary) fires exactly one accurate CREW IDLE push. The\n// firePush prev===next guard keeps it from re-firing while the task sits idle.\nconst ATTENTION_STATES: ReadonlySet<TaskState> = new Set([\"done\", \"blocked\", \"failed\", \"stalled\", \"awaiting-input\"]);\n\n// #139: non-terminal, post-launch states an interactive crew can be sitting in\n// while its session has actually died. Any of these with a provably-gone surface\n// is a zombie → reap to 'cancelled'. 'submitted' is excluded: it is pre-launch\n// (no surface yet), so reaping it would race the spawn.\nconst REAPABLE_SURFACE_STATES: ReadonlySet<TaskState> = new Set([\"working\", \"stalled\", \"awaiting-input\", \"blocked\"]);\n\n// #210: CREW IDLE (awaiting-input) is debounced — suppressed when the turn-end\n// lands within this window of the captain's own last turn to the crew (a\n// `crew send`/reply emits task.started). This silences the rapid\n// send→respond→turn-end churn of an active back-and-forth while still\n// delivering a genuine self-idle (turn-end / idle-watchdog long after the\n// captain last engaged). Only awaiting-input is debounced; every other\n// attention state always delivers.\nexport const IDLE_DEBOUNCE_MS = 12_000;\n\nfunction shortId(id: string): string {\n return id.slice(0, 8);\n}\n\n/**\n * Build a disambiguated notification tag for a task record. Always appends\n * the short id so reused crew names are distinguishable across distinct ids.\n * Named: [provider/name · shortId] Unnamed: [provider/shortId]\n */\nexport function crewTag(r: TaskRecord): string {\n const suffix = shortId(r.id);\n if (r.name != null) {\n return `[${r.provider}/${r.name} · ${suffix}]`;\n }\n return `[${r.provider}/${suffix}]`;\n}\n\nfunction formatMessage(rec: TaskRecord, event?: ControlEvent): string | null {\n const tag = crewTag(rec);\n switch (rec.state) {\n case \"done\": {\n // Prefer the crew's own done message (`signal done --message`), carried on\n // the task.done event — this is what captains relied on under the old\n // relay formatter and must not regress (#214 unification). The task\n // snippet is the documented fallback when no message was provided.\n const doneMsg = event?.type === \"task.done\" ? event.message : undefined;\n const body =\n doneMsg != null && doneMsg.trim().length > 0\n ? doneMsg.split(/\\r?\\n/)[0].trim().slice(0, 200)\n : ((rec.task ?? \"\").split(/\\r?\\n/)[0]?.trim().slice(0, 120) ?? \"\");\n return `CREW DONE ${tag}: ${body}`;\n }\n case \"blocked\":\n return `CREW BLOCKED ${tag}: ${(rec.question ?? \"(no question)\").trim()}`;\n case \"failed\":\n return `CREW FAILED ${tag}: ${(rec.error ?? \"(no error)\").trim()}`;\n case \"stalled\": {\n // #354: a hung interactive tool call reads differently from a headless\n // heartbeat stall — name the tool and how long it has been outstanding,\n // and frame it as \"possibly hung\" (recoverable, auto-clears on the tool's\n // PostToolUse), NOT a death notice.\n if (event?.type === \"task.stalled\" && event.tool) {\n const mins = event.elapsedMs != null ? Math.max(1, Math.round(event.elapsedMs / 60000)) : null;\n return `CREW STALLED ${tag}: still running ${event.tool}${mins != null ? ` ~${mins}min` : \"\"} — possibly hung (no result yet).`;\n }\n return `CREW STALLED ${tag}: no heartbeat in ${rec.heartbeatBudgetMs}ms`;\n }\n case \"awaiting-input\":\n return `CREW IDLE ${tag}: turn ended / awaiting your input — review and reply or close.`;\n default:\n return null;\n }\n}\n\n/** #246: cross-project delegation report-back message. Called when a task\n * with originProject settles to a terminal state. Returns a captain-facing\n * one-liner delivered verbatim to the origin project's captain. */\nfunction formatDelegationReport(rec: TaskRecord, originProject: string, targetProject: string): string | null {\n const shortTask = (rec.task ?? \"\").split(/\\r?\\n/)[0]?.trim().slice(0, 120) ?? \"\";\n switch (rec.state) {\n case \"done\":\n return `✅ Cross-project task → ${targetProject}: done — ${shortTask}`;\n case \"blocked\":\n return `⛔ Cross-project task → ${targetProject}: blocked — ${(rec.question ?? \"(no question)\").trim()}`;\n case \"failed\":\n return `⛔ Cross-project task → ${targetProject}: failed — ${(rec.error ?? \"(no error)\").trim()}`;\n case \"stalled\":\n return `⚠️ Cross-project task → ${targetProject}: stalled (no heartbeat in ${rec.heartbeatBudgetMs}ms)`;\n default:\n return null;\n }\n}\n\nfunction firePush(\n deps: DaemonDeps,\n project: string,\n prev: TaskState,\n next: TaskRecord,\n event: ControlEvent,\n lastCaptainTurnAt?: number,\n): void {\n if (!deps.notify) return;\n if (prev === next.state) return;\n if (!ATTENTION_STATES.has(next.state)) return;\n // #210 idle debounce: a turn-end (awaiting-input) within IDLE_DEBOUNCE_MS of\n // the captain's last turn is part of an active back-and-forth — suppress the\n // CREW IDLE. All other attention states are never debounced.\n if (\n next.state === \"awaiting-input\" &&\n lastCaptainTurnAt != null &&\n deps.now() - lastCaptainTurnAt <= IDLE_DEBOUNCE_MS\n ) {\n return;\n }\n const message = formatMessage(next, event);\n if (!message) return;\n // Fire-and-forget; swallow errors so the daemon never trips on a flaky\n // notifier. Sync throws and async rejections both land here.\n try {\n const r = deps.notify({ project, message, record: next, event });\n if (r && typeof (r as Promise<void>).catch === \"function\") {\n (r as Promise<void>).catch(() => {});\n }\n } catch {\n // intentionally swallowed\n }\n // #246: cross-project delegation report-back. When a delegated task settles\n // (done/blocked/failed/stalled/cancelled), fan the outcome back to the origin\n // project's mailbox so A's relay wakes A's captain (dispatch-and-yield, never\n // poll). 'awaiting-input' is excluded — the origin doesn't need a noise push\n // every time the target crew ends a turn.\n const reportState = next.state === \"done\" || next.state === \"blocked\" || next.state === \"failed\" || next.state === \"stalled\" || next.state === \"cancelled\";\n if (next.originProject && next.originProject !== project && reportState) {\n const originMsg = formatDelegationReport(next, next.originProject, project);\n if (originMsg && deps.notify) {\n try {\n const r = deps.notify({ project: next.originProject, message: originMsg, record: next, event });\n if (r && typeof (r as Promise<void>).catch === \"function\") (r as Promise<void>).catch(() => {});\n } catch { /* swallowed */ }\n }\n }\n}\n\ntype Req =\n | { kind: \"dispatch\"; record: TaskRecord }\n | { kind: \"event\"; project: string; event: ControlEvent }\n | { kind: \"status\"; project: string; id: string }\n | { kind: \"list\"; project: string }\n | { kind: \"reply\"; project: string; id: string; message: string }\n | { kind: \"gate-resolve\"; project: string; gateId: string; resolvedBy: string; payload: unknown }\n | { kind: \"purge\"; project: string; id: string; force?: boolean };\n\n// #87: exhaustive set of known ControlEvent types for socket-boundary validation.\n// Any event.type arriving from the wire that is not in this set is rejected with\n// a clean structured error before it can reach reduce() or the store.\nconst KNOWN_EVENT_TYPES: ReadonlySet<string> = new Set([\n \"task.started\", \"task.progress\", \"heartbeat\",\n \"task.blocked\", \"task.done\", \"task.failed\",\n \"task.session\", \"task.turn.started\", \"task.turn.completed\",\n \"task.delta\", \"task.input.requested\", \"task.approval.requested\",\n \"task.reattached\", \"task.reopened\",\n \"task.stalled\", \"task.idle\", \"task.quiet\", \"task.timeout\", \"task.reconcile-failed\",\n \"task.cancelled\", \"task.session.ended\",\n]);\n\nexport function createDaemon(deps: DaemonDeps) {\n const { store, now } = deps;\n // #210: per-task timestamp of the captain's most recent turn (a `crew send`/\n // reply/answer emits task.started). Used to debounce CREW IDLE during an\n // active back-and-forth. Bounded by the live task set; never read after a\n // task terminates (terminal states don't transition to awaiting-input).\n const lastCaptainTurnAt = new Map<string, number>();\n // #354: per-task debounce for CREW QUIET. Keyed to the liveness timestamp of\n // the quiet episode so exactly one QUIET fires per episode; when the crew shows\n // activity again, liveness advances and a later quiet episode re-notifies.\n const quietNotifiedAt = new Map<string, number>();\n return {\n async handle(req: Req): Promise<TaskRecord | TaskRecord[]> {\n switch (req.kind) {\n case \"dispatch\": {\n store.put(req.record);\n // #246: cross-project delegation — notify B's mailbox so B's relay\n // wakes B's captain with the request. Skip auto-launch; B's captain\n // decides how to execute (typically spawns a crew).\n if (req.record.originProject) {\n const origin = req.record.originProject;\n const msg = `📨 Cross-project task from ${origin}: ${req.record.task}`;\n if (deps.notify) {\n try {\n const r = deps.notify({ project: req.record.project, message: msg, record: req.record, event: { type: \"task.started\", id: req.record.id } });\n if (r && typeof (r as Promise<void>).catch === \"function\") (r as Promise<void>).catch(() => {});\n } catch { /* swallowed — flaky notifier must not break dispatch */ }\n }\n return req.record;\n }\n if (req.record.mode === \"headless\" && deps.launchHeadless) {\n deps.launchHeadless(req.record).catch((e: unknown) => {\n const error = e instanceof Error ? e.message : String(e);\n store.put({ ...req.record, state: \"failed\", lastEvent: \"launch-error\", error });\n });\n return req.record;\n }\n if (req.record.mode === \"interactive\" && deps.launchInteractive) {\n deps.launchInteractive(req.record).catch((e: unknown) => {\n const error = e instanceof Error ? e.message : String(e);\n store.put({ ...req.record, state: \"failed\", lastEvent: \"launch-error\", error });\n });\n return req.record;\n }\n // No launcher for this mode → fail LOUD, never silently park in\n // `submitted` (red-team #4). Interactive launcher is the deferred\n // interactive-wiring spec; until then, say so explicitly.\n const failed: TaskRecord = {\n ...req.record,\n state: \"failed\",\n lastEvent: \"no-launcher\",\n error:\n req.record.mode === \"interactive\"\n ? \"interactive mode is not yet implemented (deferred interactive-wiring spec); use --mode headless\"\n : `no launcher available for mode '${req.record.mode}'`,\n };\n store.put(failed);\n return failed;\n }\n case \"event\": {\n // #87: validate event.type at the socket boundary before touching state.\n if (!KNOWN_EVENT_TYPES.has((req.event as any).type)) {\n throw new Error(`unknown event type '${(req.event as any).type}' — not a valid ControlEvent`);\n }\n const cur = store.get(req.project, req.event.id);\n if (!cur) throw new Error(`unknown task ${req.event.id}`);\n // A captain turn (crew send/reply) arrives as task.started → record it\n // so a quick trailing turn-end is debounced (#210).\n if (req.event.type === \"task.started\") lastCaptainTurnAt.set(req.event.id, now());\n // #227: gate SessionEnd behind surface-liveness — only terminalize\n // when the surface is provably GONE. Prevents a nested/spurious\n // SessionEnd from false-cancelling a live crew while preserving the\n // #139 dead-crew behavior. \"unknown\" never cancels (transient cmux\n // outage), identical to the sweep reaper's semantics.\n if (req.event.type === \"task.session.ended\" && !TERMINAL_STATES.has(cur.state)) {\n const liveness = deps.isSurfaceAlive ? await deps.isSurfaceAlive(cur) : \"unknown\";\n if (liveness !== \"gone\") return cur; // alive/unknown: no-op, keep current state\n }\n const next = reduce(cur, req.event, now());\n if (next !== cur) {\n store.put(next); // skip redundant write on terminal no-ops\n firePush(deps, req.project, cur.state, next, req.event, lastCaptainTurnAt.get(next.id));\n }\n return next;\n }\n case \"status\": {\n const r = store.get(req.project, req.id);\n if (!r) throw new Error(`unknown task ${req.id}`);\n return r;\n }\n case \"list\":\n return store.list(req.project);\n case \"reply\": {\n const r = store.get(req.project, req.id);\n if (!r) throw new Error(`unknown task ${req.id}`);\n if (r.state !== \"blocked\") throw new Error(`task ${req.id} is not blocked (state=${r.state})`);\n // The captain's answer is a turn to the crew (#210 debounce key).\n lastCaptainTurnAt.set(r.id, now());\n const next = reduce(r, { type: \"task.started\", id: r.id }, now());\n store.put(next); // persist the transition before delivering (durable first)\n if (deps.deliverReply) await deps.deliverReply(r, req.message);\n return next;\n }\n case \"gate-resolve\": {\n // Find the task that owns this gate.\n const owning = deps.store.listAll().find((r) => r.gates?.some((g) => g.gateId === req.gateId));\n if (!owning || !owning.gates) throw new Error(`gate ${req.gateId} not found`);\n const updatedGates = owning.gates.map((g) =>\n g.gateId === req.gateId\n ? { ...g, state: \"resolved\" as const, resolvedBy: req.resolvedBy, resolution: req.payload }\n : g,\n );\n deps.store.put({ ...owning, gates: updatedGates });\n // Driver answers via the saved requestId (it tracks it per-task internally).\n if (deps.resolveInteractiveGate) await deps.resolveInteractiveGate(owning.id, req.payload);\n return { ...owning, gates: updatedGates };\n }\n case \"purge\": {\n const r = store.get(req.project, req.id);\n if (!r) throw new Error(`unknown task ${req.id}`);\n if (!TERMINAL_STATES.has(r.state) && !req.force) {\n throw new Error(`task ${req.id} is not terminal (state=${r.state}); use --force to purge anyway`);\n }\n store.delete(req.project, req.id);\n return r;\n }\n default: { const _exhaustive: never = req; throw new Error(`unhandled request kind`); }\n }\n },\n async sweep(): Promise<void> {\n const t = now();\n const surfaceAlive = deps.isSurfaceAlive ?? (async () => \"unknown\" as const);\n for (const r of store.listAll()) {\n // #378: GC terminal records whose last heartbeat is older than the TTL.\n if (TERMINAL_STATES.has(r.state) && t - r.lastHeartbeat > TERMINAL_RECORD_TTL_MS) {\n store.delete(r.project, r.id);\n continue;\n }\n // #225 root-fix: terminate non-terminal tasks that exceeded the wall-clock\n // ceiling. Terminalization is the persistent dedup — a daemon restart sees\n // the cancelled record and the TERMINAL_STATES gate above blocks re-fire.\n // The volatile firedTimeout Set is removed; terminal state replaces it.\n if (!TERMINAL_STATES.has(r.state)) {\n const ceiling = deps.taskTimeoutMs ?? DEFAULT_TASK_TIMEOUT_MS;\n if (t - r.createdAt > ceiling) {\n const prevState = r.state; // capture BEFORE terminalization (shown in message)\n const tag = crewTag(r);\n const hrs = Math.round(ceiling / 3_600_000);\n const msg = `CREW TIMEOUT ${tag}: wall-clock exceeded ${hrs}h (id: ${r.id}, state: ${prevState})`;\n const synthEvent: ControlEvent = { type: \"task.timeout\", id: r.id, taskTimeoutMs: ceiling };\n // Terminalize first — persisted to store so any future daemon instance\n // sees a terminal record and skips it (flood-proof across restarts).\n store.put({ ...r, state: \"cancelled\", lastEvent: \"sweep.task-timeout\" });\n if (deps.notify) {\n try {\n const p = deps.notify({ project: r.project, message: msg, record: r, event: synthEvent });\n if (p && typeof (p as Promise<void>).catch === \"function\") {\n (p as Promise<void>).catch(() => {});\n }\n } catch {\n // swallowed — a flaky notifier must never trip the sweep\n }\n }\n continue; // #378: skip remaining sweep body — stale `r` must not clobber just-written terminal state\n }\n }\n // #139 backstop: reap interactive records whose backing surface is\n // PROVABLY gone (crew session died with no terminal signal — opencode has\n // no SessionEnd hook, and a hard kill can drop claude's). This is\n // liveness-based reaping, NOT a shorter timeout: the 24h heartbeat budget\n // is untouched, so a legitimately-idle LIVE crew is never reaped (its\n // surface answers \"alive\" and falls through to evaluateStall → CREW IDLE).\n // \"unknown\" (cmux down) never reaps. cancelled is silent (not in\n // ATTENTION_STATES) — no false CREW STALLED re-emitted.\n if (r.mode === \"interactive\" && REAPABLE_SURFACE_STATES.has(r.state)) {\n const liveness = await surfaceAlive(r);\n if (liveness === \"gone\") {\n store.put({ ...r, state: \"cancelled\", lastEvent: \"sweep.surface-gone\" });\n continue;\n }\n }\n // #354: evaluateStall now only stalls a HEADLESS heartbeat timeout or a\n // hung INTERACTIVE tool call (PreToolUse with no PostToolUse past the\n // tool-stall budget). A quiet interactive thinking turn no longer stalls\n // here — it is surfaced as CREW QUIET below, keeping the crew `working`.\n const idle = evaluateStall(r, t);\n if (idle) {\n store.put(idle);\n // The synth event only carries the notify payload; the reducer treats\n // it as a no-op (state already updated above). A hung-tool stall carries\n // the tool name + elapsed so the notifier renders the accurate message.\n const synthEvent: ControlEvent = idle.pendingTool\n ? { type: \"task.stalled\", id: r.id, heartbeatBudgetMs: r.heartbeatBudgetMs, tool: idle.pendingTool.name, elapsedMs: t - idle.pendingTool.since }\n : { type: \"task.stalled\", id: r.id, heartbeatBudgetMs: r.heartbeatBudgetMs };\n firePush(deps, r.project, r.state, idle, synthEvent, lastCaptainTurnAt.get(r.id));\n continue;\n }\n // #354 CREW QUIET: a `working` interactive crew quiet past its heartbeat\n // budget with NO tool in flight is alive but deep-thinking (no hook fires\n // during pure model thinking). Surface a distinct, non-alarming nudge —\n // NOT 'awaiting-input' (the turn never ended; real CREW IDLE comes only\n // from the Stop hook). State stays `working`; notify once per episode.\n if (r.mode === \"interactive\" && r.state === \"working\" && !r.pendingTool) {\n const liveness = r.attempts.at(-1)?.lastHeartbeatAt ?? r.lastHeartbeat;\n const quiet = t - liveness;\n if (quiet > r.heartbeatBudgetMs) {\n if (deps.notify && quietNotifiedAt.get(r.id) !== liveness) {\n quietNotifiedAt.set(r.id, liveness);\n const tag = crewTag(r);\n const mins = Math.max(1, Math.round(quiet / 60000));\n const message = `CREW QUIET ${tag}: working ~${mins}min with no tool activity — likely deep thinking (no reply expected yet).`;\n const synthEvent: ControlEvent = { type: \"task.quiet\", id: r.id, quietMs: quiet };\n try {\n const p = deps.notify({ project: r.project, message, record: r, event: synthEvent });\n if (p && typeof (p as Promise<void>).catch === \"function\") (p as Promise<void>).catch(() => {});\n } catch { /* swallowed — a flaky notifier must never trip the sweep */ }\n }\n continue;\n }\n }\n // Activity resumed (or never went quiet) → drop any QUIET debounce marker\n // so the next genuine quiet episode notifies again, and avoid map growth.\n if (quietNotifiedAt.has(r.id)) quietNotifiedAt.delete(r.id);\n const recovered = recoverStall(r, t);\n // recoverStall does NOT check heartbeat freshness — guard per its contract\n if (recovered && t - r.lastHeartbeat <= r.heartbeatBudgetMs) store.put(recovered);\n }\n },\n async reconcile(): Promise<void> {\n const alive = deps.isPidAlive ?? (() => true);\n const surfaceAlive = deps.isSurfaceAlive ?? (async () => \"unknown\" as const);\n for (const r of store.listAll()) {\n if (r.state !== \"working\" && r.state !== \"submitted\") continue;\n if (r.mode === \"headless\") {\n if (r.pid != null && alive(r.pid)) continue; // still running, keep watching\n if (deps.isHeadlessInFlight?.(r.id)) continue; // #259: launch in-flight, pid not yet set\n const failed: TaskRecord = {\n ...r, state: \"failed\", lastEvent: \"reconcile\",\n error: \"orphaned by daemon restart; exit unobserved (conservative fail)\",\n };\n store.put(failed);\n const synthEvent: ControlEvent = {\n type: \"task.failed\",\n id: r.id,\n error: failed.error ?? \"reconcile\",\n };\n firePush(deps, r.project, r.state, failed, synthEvent, lastCaptainTurnAt.get(r.id));\n } else {\n // #139: an interactive crew's cmux pane SURVIVES a daemon bounce, so a\n // live crew must stay 'working' for the reattach loop to re-subscribe\n // it. The old unconditional → 'stalled' both false-stalled live crews\n // AND fired CREW STALLED on every restart. Reap ONLY when the surface\n // is provably gone; alive/unknown stay working (sweep re-checks later).\n const liveness = await surfaceAlive(r);\n if (liveness === \"gone\") {\n store.put({ ...r, state: \"cancelled\", lastEvent: \"reconcile.surface-gone\" });\n // silent — the crew is gone; no alarming push (consistent with close).\n }\n }\n }\n },\n };\n}\n","import { promises as fs } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { randomUUID } from \"node:crypto\";\nimport type { TaskRecord, ControlEvent } from \"@squadrant/shared\";\n\nexport interface MailboxEntry {\n seq: number;\n ts: string;\n /** Absent on external (captain.message) entries — they have no task. */\n taskId?: string;\n /** Optional human-readable name carried from TaskRecord. Absent on legacy\n * records — readers must fall back to shortId(taskId). */\n name?: string;\n /** \"captain.message\" is an external (non-ControlEvent) message injected for the\n * captain — e.g. an inbound Telegram reply. */\n kind: ControlEvent[\"type\"] | \"captain.message\";\n /** Absent on external entries — no originating agent provider. */\n provider?: TaskRecord[\"provider\"];\n /** Absent/free-form on external entries. */\n payload?: Record<string, unknown>;\n /** Daemon-rendered captain-facing message (unified-formatter, #214/#210).\n * The daemon's formatMessage is the single source of truth; the relay\n * delivers this verbatim and skips entries where it is null/empty.\n * `null` on entries the daemon chose not to surface (and legacy records). */\n message?: string | null;\n}\n\ninterface AppendOpts {\n stateRoot: string;\n project: string;\n taskRecord: TaskRecord;\n event: ControlEvent;\n /** Captain-facing message rendered by the daemon (daemon.ts formatMessage). */\n message?: string | null;\n}\n\nfunction inboxDir(stateRoot: string): string {\n return join(stateRoot, \"inbox\");\n}\n\nfunction logPath(stateRoot: string, project: string): string {\n return join(inboxDir(stateRoot), `${project}.log`);\n}\n\nfunction extractPayload(event: ControlEvent): Record<string, unknown> {\n const { type: _type, id: _id, ...payload } = event as Record<string, unknown> & { type: string; id: string };\n return payload;\n}\n\nasync function listRotatedOldestFirst(stateRoot: string, project: string): Promise<string[]> {\n const dir = inboxDir(stateRoot);\n let entries: string[];\n try { entries = await fs.readdir(dir); }\n catch { return []; }\n const prefix = `${project}.log.`;\n return entries\n .filter((e) => e.startsWith(prefix) && /^\\d+$/.test(e.slice(prefix.length)))\n .map((e) => ({ name: e, n: Number(e.slice(prefix.length)) }))\n .sort((a, b) => b.n - a.n) // .3 first (oldest), .1 last (newest rotated)\n .map((e) => join(dir, e.name));\n}\n\nasync function readMaxSeqFromFile(file: string): Promise<number> {\n try {\n const buf = await fs.readFile(file, \"utf-8\");\n if (!buf.trim()) return 0;\n const lines = buf.trim().split(\"\\n\");\n for (let i = lines.length - 1; i >= 0; i--) {\n try {\n const obj = JSON.parse(lines[i]) as MailboxEntry;\n return obj.seq;\n } catch { continue; }\n }\n return 0;\n } catch (e) {\n if ((e as NodeJS.ErrnoException).code === \"ENOENT\") return 0;\n throw e;\n }\n}\n\nasync function readMaxSeq(stateRoot: string, project: string): Promise<number> {\n let max = 0;\n const files = [\n logPath(stateRoot, project),\n ...(await listRotatedOldestFirst(stateRoot, project)),\n ];\n for (const file of files) {\n const seq = await readMaxSeqFromFile(file);\n if (seq > max) max = seq;\n }\n return max;\n}\n\n// Per-project serial mutex. Node's event loop is single-threaded but async\n// readFile + writeFile can interleave; chaining all appends for the same\n// project through a single in-process Promise serializes them.\n//\n// For cross-process serialization (multi-daemon scenarios, e.g. launchctl\n// restart races), an OS-level flock would be needed on `<project>.log`.\n// Today squadrant runs a single daemon instance; the in-process mutex covers\n// the realistic concurrency model. flock can be added later if multi-process\n// access becomes a requirement.\nconst projectLocks = new Map<string, Promise<unknown>>();\n\nfunction withProjectLock<T>(project: string, fn: () => Promise<T>): Promise<T> {\n const prev = projectLocks.get(project) ?? Promise.resolve();\n const next = prev.catch(() => undefined).then(fn);\n // Store a tail that does not reject so the chain never breaks on caller failure\n projectLocks.set(project, next.catch(() => undefined));\n return next;\n}\n\n/** Assign a monotonic seq under the per-project lock and append the built entry. */\nfunction appendEntry(\n stateRoot: string,\n project: string,\n build: (seq: number) => MailboxEntry,\n): Promise<number> {\n return withProjectLock(project, async () => {\n const dir = inboxDir(stateRoot);\n await fs.mkdir(dir, { recursive: true });\n const file = logPath(stateRoot, project);\n const lastSeq = await readMaxSeq(stateRoot, project);\n const seq = lastSeq + 1;\n const entry = build(seq);\n await fs.appendFile(file, JSON.stringify(entry) + \"\\n\", { encoding: \"utf-8\" });\n return seq;\n });\n}\n\nexport async function appendToMailbox(opts: AppendOpts): Promise<number> {\n return appendEntry(opts.stateRoot, opts.project, (seq) => ({\n seq,\n ts: new Date().toISOString(),\n taskId: opts.taskRecord.id,\n ...(opts.taskRecord.name !== undefined ? { name: opts.taskRecord.name } : {}),\n kind: opts.event.type,\n provider: opts.taskRecord.provider,\n payload: extractPayload(opts.event),\n message: opts.message ?? null,\n }));\n}\n\n/**\n * Append an external message destined for the captain pane (#65 Telegram inbound).\n * `text` is the already-rendered captain-facing message; it is delivered verbatim\n * by the #332 delivery loop (deliverable() returns it, defer-protected). The entry\n * carries no taskId/provider — it is not tied to a crew task.\n */\nexport async function appendCaptainMessage(opts: {\n stateRoot: string;\n project: string;\n text: string;\n source: \"telegram\";\n}): Promise<void> {\n await appendEntry(opts.stateRoot, opts.project, (seq) => ({\n seq,\n ts: new Date().toISOString(),\n kind: \"captain.message\",\n payload: { source: opts.source },\n message: opts.text,\n }));\n}\n\nfunction cursorPath(stateRoot: string, project: string, subscriber: string): string {\n return join(inboxDir(stateRoot), `${project}.${subscriber}.cursor`);\n}\n\ninterface CursorOpts {\n stateRoot: string;\n project: string;\n subscriber: string;\n}\n\nexport interface CursorState {\n lastAckedSeq: number;\n subscriber: string;\n updatedAt: string;\n}\n\nexport async function readCursor(opts: CursorOpts): Promise<CursorState | null> {\n let buf: string;\n try {\n buf = await fs.readFile(cursorPath(opts.stateRoot, opts.project, opts.subscriber), \"utf-8\");\n } catch (e) {\n if ((e as NodeJS.ErrnoException).code === \"ENOENT\") return null;\n throw e;\n }\n // A 0-byte or corrupt cursor (e.g. an interrupted write) must be treated the\n // same as a missing one — return null so the caller starts fresh from seq 0\n // rather than crashing the relay boot / delivery loop (#332 storm BUG 1).\n if (!buf.trim()) return null;\n try {\n return JSON.parse(buf) as CursorState;\n } catch {\n return null;\n }\n}\n\nexport async function writeCursor(opts: CursorOpts & { lastAckedSeq: number }): Promise<void> {\n await fs.mkdir(inboxDir(opts.stateRoot), { recursive: true });\n const dest = cursorPath(opts.stateRoot, opts.project, opts.subscriber);\n // Unique tmp per call so overlapping writes never share a tmp path. A shared\n // `dest + \".tmp\"` let one rename consume the tmp the other expected → ENOENT\n // on rename, leaving a 0-byte/corrupt cursor (#332 storm BUG 2).\n const tmp = `${dest}.${process.pid}.${randomUUID()}.tmp`;\n const data: CursorState = {\n lastAckedSeq: opts.lastAckedSeq,\n subscriber: opts.subscriber,\n updatedAt: new Date().toISOString(),\n };\n const handle = await fs.open(tmp, \"w\");\n try {\n await handle.writeFile(JSON.stringify(data), { encoding: \"utf-8\" });\n await handle.sync();\n } finally {\n await handle.close();\n }\n try {\n await fs.rename(tmp, dest);\n } catch (e) {\n // Best-effort cleanup so a failed rename doesn't leave the unique tmp behind.\n await fs.unlink(tmp).catch(() => {});\n throw e;\n }\n}\n\ninterface ReadFromCursorOpts {\n stateRoot: string;\n project: string;\n fromSeq: number;\n}\n\nexport async function* readFromCursor(opts: ReadFromCursorOpts): AsyncIterable<MailboxEntry> {\n // Order: oldest rotated first (.3 → .2 → .1), then current.\n const rotated = await listRotatedOldestFirst(opts.stateRoot, opts.project);\n const files = [...rotated, logPath(opts.stateRoot, opts.project)];\n for (const file of files) {\n let buf: string;\n try {\n buf = await fs.readFile(file, \"utf-8\");\n } catch (e) {\n if ((e as NodeJS.ErrnoException).code === \"ENOENT\") continue;\n throw e;\n }\n for (const line of buf.split(\"\\n\")) {\n if (!line.trim()) continue;\n let entry: MailboxEntry;\n try {\n entry = JSON.parse(line) as MailboxEntry;\n } catch {\n continue;\n }\n if (entry.seq >= opts.fromSeq) yield entry;\n }\n }\n}\n\n/** Read-only Tier 2 observability stats for one project's mailbox (#44 dashboard). */\nexport interface MailboxStats {\n /** Highest seq across the current log + rotated segments (0 when empty). */\n maxSeq: number;\n /** Size in bytes of the current (un-rotated) log file. */\n sizeBytes: number;\n /** Age of the oldest entry in the current log (0 when empty/missing). */\n oldestEntryAgeMs: number;\n /** Number of rotated segments on disk (<project>.log.1, .2, …). */\n rotationCount: number;\n}\n\n/**\n * Read-only stats for the dashboard's Tier 2 data-plane view. Never mutates;\n * tolerates a missing inbox (returns zeros). The daemon gathers this and passes\n * it to the pure snapshot assembler.\n */\nexport async function mailboxStats(stateRoot: string, project: string): Promise<MailboxStats> {\n const file = logPath(stateRoot, project);\n let sizeBytes = 0;\n try { sizeBytes = (await fs.stat(file)).size; }\n catch (e) { if ((e as NodeJS.ErrnoException).code !== \"ENOENT\") throw e; }\n const rotated = await listRotatedOldestFirst(stateRoot, project);\n return {\n maxSeq: await readMaxSeq(stateRoot, project),\n sizeBytes,\n oldestEntryAgeMs: await oldestEntryAgeMs(file),\n rotationCount: rotated.length,\n };\n}\n\ninterface RotateOpts {\n stateRoot: string;\n project: string;\n maxBytes: number;\n maxAgeMs: number;\n keepCount: number;\n}\n\nexport interface RotateResult {\n rotated: boolean;\n from?: string;\n to?: string;\n}\n\nasync function oldestEntryAgeMs(file: string): Promise<number> {\n try {\n const buf = await fs.readFile(file, \"utf-8\");\n const firstLine = buf.split(\"\\n\").find((l) => l.trim());\n if (!firstLine) return 0;\n const entry = JSON.parse(firstLine) as MailboxEntry;\n return Date.now() - new Date(entry.ts).getTime();\n } catch {\n return 0;\n }\n}\n\nexport async function rotateIfNeeded(opts: RotateOpts): Promise<RotateResult> {\n return withProjectLock(opts.project, async () => {\n const file = logPath(opts.stateRoot, opts.project);\n let size = 0;\n try { size = (await fs.stat(file)).size; }\n catch (e) {\n if ((e as NodeJS.ErrnoException).code === \"ENOENT\") return { rotated: false };\n throw e;\n }\n const age = await oldestEntryAgeMs(file);\n if (size < opts.maxBytes && age < opts.maxAgeMs) return { rotated: false };\n\n // Shift existing .N files down (.N → .N+1), deleting anything beyond keepCount.\n // Process highest N first so we don't clobber.\n // Find the existing max N.\n const existing = await listRotatedOldestFirst(opts.stateRoot, opts.project);\n // existing is sorted by N desc (oldest first). Extract numbers.\n const nums = existing.map((p) => Number(p.slice(p.lastIndexOf(\".\") + 1))).sort((a, b) => b - a);\n for (const n of nums) {\n const src = `${file}.${n}`;\n const dst = `${file}.${n + 1}`;\n if (n + 1 > opts.keepCount) {\n try { await fs.unlink(src); } catch (e) {\n if ((e as NodeJS.ErrnoException).code !== \"ENOENT\") throw e;\n }\n } else {\n try { await fs.rename(src, dst); } catch (e) {\n if ((e as NodeJS.ErrnoException).code !== \"ENOENT\") throw e;\n }\n }\n }\n // current → .1\n await fs.rename(file, `${file}.1`);\n // create fresh empty current\n await fs.writeFile(file, \"\", { encoding: \"utf-8\" });\n return { rotated: true, from: file, to: `${file}.1` };\n });\n}\n","// src/control/protocol.ts\nimport { createServer, createConnection, type Server, type Socket } from \"node:net\";\nimport { existsSync, unlinkSync } from \"node:fs\";\n\n// Bump this on any change to the request/reply wire shape.\n// v1 is the first versioned release. Clients treat an absent _v as compatible\n// (pre-v1 rollout grace period); future bumps hard-fail on mismatch.\nexport const PROTOCOL_VERSION = 1;\n\nexport function encodeMsg(obj: unknown): string {\n return JSON.stringify(obj) + \"\\n\";\n}\n\nexport function createDecoder(onParseError?: (line: string) => void) {\n let buf = \"\";\n return {\n push(chunk: string): unknown[] {\n buf += chunk;\n const out: unknown[] = [];\n let idx: number;\n while ((idx = buf.indexOf(\"\\n\")) >= 0) {\n const line = buf.slice(0, idx);\n buf = buf.slice(idx + 1);\n if (!line.trim()) continue;\n try {\n const parsed = JSON.parse(line);\n // Silently discard keepalive frames (#94) — never surface to any consumer.\n if (typeof parsed === \"object\" && parsed !== null && (parsed as any).type === \"_keepalive\") continue;\n out.push(parsed);\n } catch {\n // #87: notify caller of malformed lines so the server can reply with a\n // structured error instead of silently dropping the frame.\n onParseError?.(line);\n }\n }\n return out;\n },\n // #87: exposes the unprocessed buffer content — bytes received but not yet\n // terminated with a newline. The server checks this on connection end to\n // detect newline-less input and reply with a fast structured error.\n remainder(): string {\n return buf;\n },\n };\n}\n\nexport type Handler = (msg: any) => Promise<unknown>;\n\n/** NetConn is the raw socket for a single client connection. */\nexport type NetConn = Socket;\n\n/** Injectable clock for startServer — lets tests drive keepalive timers without real timers. */\nexport interface ServerDeps {\n setInterval?: (fn: () => void, ms: number) => ReturnType<typeof setInterval>;\n clearInterval?: (id: ReturnType<typeof setInterval>) => void;\n}\n\n/**\n * Optional callbacks for long-lived attach connections (spec §4.5/§4.6).\n * When a connection sends {op:\"attach\",taskId} the socket is \"claimed\" by\n * the attach path and all subsequent frames on that socket are routed to\n * onAttachInbound rather than through the normal request/response handler.\n */\nexport interface ServerCallbacks {\n /** Normal request/response handler (required). */\n handler: Handler;\n /** Called once when a connection sends the {op:\"attach\",taskId} frame. */\n onAttach?: (conn: NetConn, frame: { op: \"attach\"; taskId: string }) => void;\n /** Called for every subsequent inbound frame on a claimed attach connection. */\n onAttachInbound?: (conn: NetConn, frame: AttachInbound) => void;\n /** Called when a claimed attach connection closes. */\n onAttachClose?: (conn: NetConn) => void;\n}\n\n/**\n * Red-team #2 (High): an unhandled server `error` (e.g. listen EADDRINUSE when\n * a second daemon races in) became an uncaughtException → process died →\n * launchd KeepAlive (no ThrottleInterval) tight-respawned = the crash-loop.\n * Default: log with timestamp and exit non-zero so launchd's ThrottleInterval\n * paces the restart instead of tight-looping. Tests inject a spy.\n */\nexport function defaultListenError(e: Error): void {\n process.stderr.write(`[squadrantd] ${new Date().toISOString()} server error: ${e.message}\\n`);\n process.exit(1);\n}\n\nexport function startServer(\n sockPath: string,\n handlerOrCallbacks: Handler | ServerCallbacks,\n onListenError: (e: Error) => void = defaultListenError,\n deps: ServerDeps = {},\n): Server {\n // Back-compat: accept a plain function as well as a ServerCallbacks object.\n const callbacks: ServerCallbacks =\n typeof handlerOrCallbacks === \"function\"\n ? { handler: handlerOrCallbacks }\n : handlerOrCallbacks;\n const { handler, onAttach, onAttachInbound, onAttachClose } = callbacks;\n const setIntervalFn = deps.setInterval ?? setInterval;\n const clearIntervalFn = deps.clearInterval ?? clearInterval;\n\n if (existsSync(sockPath)) {\n try { unlinkSync(sockPath); } catch { /* stale socket */ }\n }\n const server = createServer((conn) => {\n conn.setEncoding(\"utf-8\");\n let claimType: \"none\" | \"attach\" = \"none\";\n let keepaliveId: ReturnType<typeof setInterval> | undefined;\n\n // #87: reply with a structured error when a newline-terminated line fails to\n // parse as JSON, so the client gets a fast error instead of a silent drop.\n const dec = createDecoder((badLine) => {\n if (claimType !== \"attach\") {\n try {\n conn.write(encodeMsg({ ok: false, error: `malformed request: invalid JSON`, _v: PROTOCOL_VERSION }));\n } catch { /* conn already closed */ }\n }\n });\n\n conn.on(\"data\", async (chunk: string) => {\n for (const msg of dec.push(chunk)) {\n // If already claimed by attach, route all frames to the inbound handler.\n if (claimType === \"attach\") {\n onAttachInbound?.(conn, msg as AttachInbound);\n continue;\n }\n // Check for attach-claim frame BEFORE falling through to req/res.\n if (\n onAttach &&\n msg != null &&\n typeof msg === \"object\" &&\n (msg as any).op === \"attach\" &&\n typeof (msg as any).taskId === \"string\"\n ) {\n claimType = \"attach\";\n onAttach(conn, msg as { op: \"attach\"; taskId: string });\n // Start keepalive heartbeat for held-open attach connections (#94).\n keepaliveId = setIntervalFn(() => {\n try { conn.write(encodeFrame({ type: \"_keepalive\" })); } catch { /* conn closed */ }\n }, 10_000);\n continue;\n }\n // Normal request/response path.\n // #259: both writes are wrapped — a destroyed socket can throw synchronously\n // (write-after-end); that throw would escape the async data handler and become\n // an unhandled rejection, killing the daemon. Client-gone writes are silently\n // swallowed; the conn.on(\"error\") handler above covers the emitted error event.\n try {\n const reply = await handler(msg);\n try { conn.write(encodeMsg({ ok: true, reply, _v: PROTOCOL_VERSION })); } catch { /* client gone */ }\n } catch (e) {\n const errMsg = e instanceof Error ? e.message : String(e);\n try { conn.write(encodeMsg({ ok: false, error: errMsg, _v: PROTOCOL_VERSION })); } catch { /* client gone */ }\n }\n }\n });\n conn.on(\"error\", () => { /* client vanished; ignore */ });\n // #87: when the client half-closes (done sending) with bytes still in the\n // decoder buffer, the message had no newline terminator — send a fast error\n // instead of silently leaving the client to hit the 5s sendRequest timeout.\n conn.on(\"end\", () => {\n if (claimType !== \"attach\" && dec.remainder().trim()) {\n try {\n conn.write(encodeMsg({ ok: false, error: `malformed request: missing newline terminator`, _v: PROTOCOL_VERSION }));\n } catch { /* conn already closed */ }\n }\n });\n conn.on(\"close\", () => {\n if (keepaliveId !== undefined) clearIntervalFn(keepaliveId);\n if (claimType === \"attach\") onAttachClose?.(conn);\n });\n });\n server.on(\"error\", onListenError); // never let a server error become uncaughtException\n server.listen(sockPath);\n return server;\n}\n\n// #360: probe whether a live daemon owns this socket. Resolves true only when\n// a connection is accepted; false on ENOENT (no file) or ECONNREFUSED (stale\n// file / dead listener). Callers check this BEFORE startServer to avoid\n// unlink-then-bind stealing a live daemon's socket inode.\nexport function isDaemonSocketLive(sockPath: string, timeoutMs = 500): Promise<boolean> {\n return new Promise((resolve) => {\n if (!existsSync(sockPath)) { resolve(false); return; }\n const conn = createConnection(sockPath);\n const finish = (v: boolean) => { try { conn.destroy(); } catch { /* already gone */ } resolve(v); };\n const timer = setTimeout(() => finish(false), timeoutMs);\n conn.on(\"connect\", () => { clearTimeout(timer); finish(true); });\n conn.on(\"error\", () => { clearTimeout(timer); finish(false); });\n });\n}\n\nexport function sendRequest(sockPath: string, msg: unknown, timeoutMs = 5000): Promise<unknown> {\n return new Promise((resolve, reject) => {\n const conn = createConnection(sockPath);\n const dec = createDecoder();\n const timer = setTimeout(() => {\n conn.destroy();\n reject(new Error(\"control plane unavailable: request timed out\"));\n }, timeoutMs);\n conn.setEncoding(\"utf-8\");\n conn.on(\"connect\", () => conn.write(encodeMsg({ ...(msg as Record<string, unknown>), _v: PROTOCOL_VERSION })));\n conn.on(\"data\", (chunk: string) => {\n for (const m of dec.push(chunk) as any[]) {\n clearTimeout(timer);\n conn.destroy();\n if (m._v !== undefined && m._v !== PROTOCOL_VERSION) {\n reject(new Error(`squadrantd protocol v${m._v}, this client expects v${PROTOCOL_VERSION} — upgrade squadrantd or this CLI`));\n } else if (m.ok) {\n resolve(m.reply);\n } else {\n reject(new Error(m.error));\n }\n return;\n }\n });\n conn.on(\"error\", () => {\n clearTimeout(timer);\n reject(new Error(\"control plane unavailable: cannot reach squadrantd socket\"));\n });\n });\n}\n\n// ───────────────────────────────────────────────────────────────────────────\n// Streaming-subscribe frames for `squadrant crew chat / attach` (spec §4.5).\n// Additive; existing request/response verbs untouched. Cooperates with #87.\n\nexport type AttachFrame =\n | { type: \"delta\"; taskId: string; text: string }\n | { type: \"turn-started\"; taskId: string }\n | { type: \"turn-completed\"; taskId: string }\n | { type: \"input-requested\"; taskId: string; requestId: number; question: string }\n | { type: \"approval-requested\"; taskId: string; requestId: number; question: string; kind: string }\n | { type: \"gate-promoted\"; taskId: string; gateId: string }\n | { type: \"reattached\"; taskId: string }\n | { type: \"closed\"; taskId: string; reason: string }\n | { type: \"_keepalive\" };\n\nexport type AttachInbound =\n | { op: \"attach\"; taskId: string }\n | { op: \"say\"; taskId: string; text: string }\n | { op: \"steer\"; taskId: string; text: string }\n | { op: \"interrupt\"; taskId: string }\n | { op: \"answer\"; taskId: string; requestId: number; payload: unknown };\n\nexport function encodeFrame(f: AttachFrame): string {\n return JSON.stringify(f) + \"\\n\";\n}\n\nexport function decodeFrames(wire: string): AttachFrame[] {\n const out: AttachFrame[] = [];\n for (const line of wire.split(\"\\n\")) {\n if (!line.trim()) continue;\n try {\n const parsed = JSON.parse(line) as AttachFrame;\n if (parsed.type === \"_keepalive\") continue; // discard keepalive frames (#94)\n out.push(parsed);\n } catch { /* skip malformed */ }\n }\n return out;\n}\n","// src/control/liveness.ts\n//\n// PURE service-health layer (no I/O, no clock) — the #77 foundation. Mirrors\n// watchdog.ts: every function derives a verdict from records + an explicit `now`\n// so it is fully unit-testable. All runtime probing (cmux reads for captain\n// presence) is gathered by the caller (squadrantd) and passed in already-resolved;\n// this module never touches cmux.\nimport type { TaskState, Mode } from \"@squadrant/shared\";\n\nexport type ComponentKind = \"captain\" | \"crew\" | \"command\";\n\n// alive = seen within the stale window (healthy)\n// stale = quiet past stale but not yet gone (degrading)\n// gone = dark past the gone window (treat as down — a FAULT)\n// stopped = intentionally offline (user closed the captain workspace) — NOT a\n// fault. Distinct from `gone` so the surface never red-alarms an\n// expected shutdown (#324/#323).\n// unknown = no signal / not applicable (never alarms)\nexport type HealthState = \"alive\" | \"stale\" | \"gone\" | \"stopped\" | \"unknown\";\n\nexport interface ComponentHealth {\n kind: ComponentKind;\n project: string;\n /** crew name / captain name / \"command\". */\n ref: string;\n state: HealthState;\n /** epoch ms of last evidence of life, or null when there is no timestamp\n * source (captain/command presence is a boolean, not a heartbeat). */\n lastSeenMs: number | null;\n /** human-facing context — e.g. a recovery command. */\n detail?: string;\n}\n\n// Crews legitimately idle for long (24h interactive budget), so the surface uses\n// generous windows — these only flag a genuinely dark crew, and #139 already\n// reaps provably-dead ones. Display-only; does not drive any state transition.\nexport const CREW_STALE_MS = 5 * 60_000;\nexport const CREW_GONE_MS = 30 * 60_000;\n\n/**\n * Pure. Classify a last-seen timestamp into a health state.\n * null → \"unknown\"\n * age <= staleMs → \"alive\" (boundary inclusive)\n * age <= goneMs → \"stale\" (boundary inclusive)\n * else → \"gone\"\n */\nexport function classifyHealth(\n lastSeenMs: number | null,\n now: number,\n staleMs: number,\n goneMs: number,\n): HealthState {\n if (lastSeenMs == null) return \"unknown\";\n const age = now - lastSeenMs;\n if (age <= staleMs) return \"alive\";\n if (age <= goneMs) return \"stale\";\n return \"gone\";\n}\n\nconst TERMINAL: ReadonlySet<TaskState> = new Set([\"done\", \"failed\", \"cancelled\"]);\n\n/** Minimal crew shape the projection needs (subset of TaskRecord). */\nexport interface CrewLiveness {\n id: string;\n name?: string;\n state: TaskState;\n lastHeartbeat: number;\n mode: Mode;\n}\n\n/**\n * Pure. Project one project's component health from already-gathered inputs.\n * Emits: a captain row, a command row (only when applicable), and one row per\n * non-terminal crew.\n *\n * Captain liveness (#332): driven by the daemon-direct delivery loop.\n * captainStopped === false → captain surface was found on last delivery tick → ALIVE\n * captainStopped === true → surface gone for 3+ consecutive ticks → STOPPED\n * (intentional close — its crews are reaped and\n * delivery is paused; NOT a fault — #324/#323)\n * captainStopped === null → not yet checked / cmux unreachable → UNKNOWN\n */\nexport function projectHealth(input: {\n project: string;\n now: number;\n captainName: string;\n /** Delivery-loop captain surface state. See docs above. */\n captainStopped: boolean | null;\n /** true/false when a command workspace is expected; null = not applicable. */\n commandPresent: boolean | null;\n crews: CrewLiveness[];\n}): ComponentHealth[] {\n const { project, now, captainName, captainStopped, commandPresent, crews } = input;\n const out: ComponentHealth[] = [];\n\n // ── captain ────────────────────────────────────────────────────────────\n const captainState: HealthState =\n captainStopped === true ? \"stopped\" :\n captainStopped === false ? \"alive\" :\n \"unknown\";\n out.push({\n kind: \"captain\",\n project,\n ref: captainName,\n state: captainState,\n lastSeenMs: null,\n detail: captainState === \"stopped\" ? \"captain workspace closed — crews reaped; delivery paused\" : undefined,\n });\n\n // ── command (on-demand; only surfaced when applicable) ───────────────────\n if (commandPresent !== null) {\n out.push({\n kind: \"command\",\n project,\n ref: \"command\",\n state: presence(commandPresent),\n lastSeenMs: null,\n });\n }\n\n // ── crews (one row per non-terminal crew) ────────────────────────────────\n for (const c of crews) {\n if (TERMINAL.has(c.state)) continue;\n out.push({\n kind: \"crew\",\n project,\n ref: c.name ?? c.id.slice(0, 8),\n state: classifyHealth(c.lastHeartbeat, now, CREW_STALE_MS, CREW_GONE_MS),\n lastSeenMs: c.lastHeartbeat,\n detail: c.state,\n });\n }\n\n return out;\n}\n\nfunction presence(p: boolean | null): HealthState {\n if (p === null) return \"unknown\";\n return p ? \"alive\" : \"gone\";\n}\n\n/** Human-friendly age of the last-seen timestamp, or em-dash when there is none. */\nexport function ageText(lastSeenMs: number | null, now: number): string {\n if (lastSeenMs == null) return \"—\";\n const s = Math.max(0, Math.round((now - lastSeenMs) / 1000));\n if (s < 60) return `${s}s ago`;\n const m = Math.round(s / 60);\n if (m < 60) return `${m}m ago`;\n return `${Math.round(m / 60)}h ago`;\n}\n\n/**\n * Pure. Return the heal command string for a component that needs remediation,\n * or null when no action is needed (or when no heal verb exists for this kind).\n */\nexport function healCmdFor(c: ComponentHealth): string | null {\n // No heal verb for captain/crew — daemon-direct delivery handles recovery automatically.\n return null;\n}\n\n/** Per-project relay health — REMOVED (#332). No longer tracked by daemon. */\nexport type RelayHealth = never;\n","// src/control/store.ts\nimport {\n mkdirSync, readFileSync, readdirSync, renameSync, writeFileSync, existsSync,\n rmSync, statSync,\n} from \"node:fs\";\nimport { join, resolve, sep } from \"node:path\";\nimport type { TaskRecord } from \"@squadrant/shared\";\n\nexport interface Store {\n put(rec: TaskRecord): void;\n get(project: string, id: string): TaskRecord | undefined;\n list(project: string): TaskRecord[];\n listAll(): TaskRecord[];\n quarantine(project: string, id: string): void;\n delete(project: string, id: string): void;\n}\n\n/**\n * SECURITY (red-team #1, Critical): `project`/`id` arrive unsanitized from the\n * socket (dispatch + seed) and a crafted value (`..`, `/`, absolute, NUL) would\n * let a confused-deputy read/write arbitrary files as the user. A `project`/`id`\n * must be a single safe path segment — no separators, traversal, NUL, or dot\n * dirs. Enforced at the one chokepoint every fs op funnels through.\n */\nfunction safeSegment(kind: \"project\" | \"id\", s: unknown): string {\n if (typeof s !== \"string\" || s.length === 0) {\n throw new Error(`invalid ${kind}: must be a non-empty string`);\n }\n if (s.includes(\"\\0\")) throw new Error(`invalid ${kind}: NUL byte not allowed`);\n if (s === \".\" || s === \"..\" || /[/\\\\]/.test(s)) {\n throw new Error(`invalid ${kind}: '${s}' — path separators/traversal not allowed`);\n }\n return s;\n}\n\nexport function createStore(root: string): Store {\n const rootResolved = resolve(root);\n\n // Defense in depth: even after segment validation, never let a resolved\n // path escape the state root.\n const assertUnderRoot = (target: string): string => {\n const r = resolve(target);\n if (r !== rootResolved && !r.startsWith(rootResolved + sep)) {\n throw new Error(`path escapes state root: ${target}`);\n }\n return target;\n };\n\n const projDir = (p: string) => assertUnderRoot(join(root, safeSegment(\"project\", p)));\n const taskFile = (p: string, id: string) =>\n assertUnderRoot(join(projDir(p), `${safeSegment(\"id\", id)}.json`));\n\n return {\n put(rec) {\n mkdirSync(projDir(rec.project), { recursive: true });\n const dest = taskFile(rec.project, rec.id);\n const tmp = `${dest}.tmp`;\n writeFileSync(tmp, JSON.stringify(rec, null, 2));\n renameSync(tmp, dest); // atomic replace\n },\n get(project, id) {\n const f = taskFile(project, id);\n if (!existsSync(f)) return undefined;\n try {\n return JSON.parse(readFileSync(f, \"utf-8\")) as TaskRecord;\n } catch {\n return undefined; // corrupt file: caller handles (Task 6)\n }\n },\n list(project) {\n const d = projDir(project);\n if (!existsSync(d)) return [];\n return readdirSync(d)\n .filter((n) => n.endsWith(\".json\"))\n .map((n) => {\n try { return JSON.parse(readFileSync(join(d, n), \"utf-8\")) as TaskRecord; }\n catch { return undefined; }\n })\n .filter((r): r is TaskRecord => r !== undefined);\n },\n listAll() {\n if (!existsSync(root)) return [];\n return readdirSync(root)\n .filter((p) => { try { return statSync(join(root, p)).isDirectory(); } catch { return false; } })\n .flatMap((p) => this.list(p));\n },\n quarantine(project, id) {\n const f = taskFile(project, id);\n // suffix prevents clobber across process restarts\n if (existsSync(f)) renameSync(f, `${f}.corrupt.${Date.now()}`);\n },\n delete(project, id) {\n const f = taskFile(project, id);\n if (existsSync(f)) rmSync(f);\n },\n };\n}\n","// src/control/snapshot.ts\n//\n// PURE Tier 0/1/2 snapshot assembly (no I/O, no clock) for the read-only\n// `snapshot` socket verb — the observability-dashboard counterpart to\n// liveness.ts. Every derived value comes from already-gathered inputs + an\n// explicit `now`, so the whole module is trivially unit-testable. squadrantd.ts\n// performs the I/O (dist stat, log read, mailbox/store/results reads) and feeds\n// the gathered numbers in here; this module never touches the filesystem.\nimport type { ComponentHealth } from \"./liveness.js\";\nimport type { MailboxStats } from \"./mailbox.js\";\nexport type { MailboxStats };\n\nexport type BuildState = \"fresh\" | \"stale\";\n\n/**\n * Pure. The deploy-hygiene check: a daemon whose process started BEFORE the\n * current `dist/` build is running stale code (the recurring footgun). Fresh\n * requires the process to have started at or after the last build.\n * processStartedAt >= distBuiltAt → \"fresh\" (boundary inclusive)\n * else → \"stale\"\n */\nexport function buildFreshness(processStartedAt: number, distBuiltAt: number): BuildState {\n return processStartedAt >= distBuiltAt ? \"fresh\" : \"stale\";\n}\n\n// ── Tier 0: daemon root ───────────────────────────────────────────────────────\nexport interface DaemonRoot {\n pid: number;\n uptimeMs: number;\n version: string;\n build: { state: BuildState; processStartedAt: number; distBuiltAt: number };\n /** lastSweepAt/ageMs are null until the first sweep has run. */\n sweep: { lastSweepAt: number | null; ageMs: number | null; cadenceMs: number };\n log: { errorCount: number; sizeBytes: number; windowMs: number };\n}\n\n// ── Tier 2: per-project data plane + global results ───────────────────────────\n\nexport interface DeliveryLag {\n maxSeq: number;\n lastAckedSeq: number;\n /** maxSeq − lastAckedSeq, clamped at 0 — \"captain N behind\". */\n behind: number;\n}\n\nexport interface StoreStats {\n byState: Record<string, number>;\n corruptCount: number;\n}\n\nexport interface ResultArtifacts {\n fileCount: number;\n totalBytes: number;\n}\n\nexport interface ProjectDataPlane {\n project: string;\n mailbox: MailboxStats;\n delivery: DeliveryLag;\n store: StoreStats;\n}\n\nexport interface DaemonSnapshot {\n tier0: DaemonRoot;\n /** Tier 1 — per-component liveness across all projects (reuses projectHealth). */\n tier1: ComponentHealth[];\n tier2: {\n projects: ProjectDataPlane[];\n /** _results/ is a single global directory keyed by task id. */\n results: ResultArtifacts;\n };\n}\n\n/** Already-gathered (I/O-resolved) inputs the pure assembler turns into a DaemonSnapshot. */\nexport interface DaemonSnapshotInputs {\n pid: number;\n processStartedAt: number;\n version: string;\n distBuiltAt: number;\n lastSweepAt: number | null;\n sweepCadenceMs: number;\n log: { errorCount: number; sizeBytes: number; windowMs: number };\n health: ComponentHealth[];\n projects: Array<{\n project: string;\n mailbox: MailboxStats;\n lastAckedSeq: number;\n storeByState: Record<string, number>;\n corruptCount: number;\n }>;\n results: ResultArtifacts;\n}\n\n/**\n * Pure. Derive the full DaemonSnapshot from gathered inputs and an explicit now.\n */\nexport function assembleDaemonSnapshot(input: DaemonSnapshotInputs, now: number): DaemonSnapshot {\n return {\n tier0: {\n pid: input.pid,\n uptimeMs: now - input.processStartedAt,\n version: input.version,\n build: {\n state: buildFreshness(input.processStartedAt, input.distBuiltAt),\n processStartedAt: input.processStartedAt,\n distBuiltAt: input.distBuiltAt,\n },\n sweep: {\n lastSweepAt: input.lastSweepAt,\n ageMs: input.lastSweepAt == null ? null : now - input.lastSweepAt,\n cadenceMs: input.sweepCadenceMs,\n },\n log: input.log,\n },\n tier1: input.health,\n tier2: {\n projects: input.projects.map((p) => ({\n project: p.project,\n mailbox: p.mailbox,\n delivery: {\n maxSeq: p.mailbox.maxSeq,\n lastAckedSeq: p.lastAckedSeq,\n behind: Math.max(0, p.mailbox.maxSeq - p.lastAckedSeq),\n },\n store: { byState: p.storeByState, corruptCount: p.corruptCount },\n })),\n results: input.results,\n },\n };\n}\n","// src/control/launchd.ts\nimport { execFileSync } from \"node:child_process\";\nimport { mkdirSync, writeFileSync, readFileSync, existsSync, openSync, writeSync, closeSync, unlinkSync, constants } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { dirname, join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nexport const LABEL = \"com.squadrant.daemon\";\n\nexport function plistPath(): string {\n return join(homedir(), \"Library\", \"LaunchAgents\", `${LABEL}.plist`);\n}\n\n/**\n * Canonical path to the compiled daemon entrypoint, resolved relative to THIS\n * module (squadrantd.js is a sibling of the bundled entry in <dist>/). This is\n * the single source of truth — callers must NOT recompute it (a hardcoded\n * ~/.config/squadrant/dist path crash-loops the agent with MODULE_NOT_FOUND\n * because runtime-sync never mirrors compiled output there).\n */\nexport function daemonEntryPath(): string {\n const p = join(dirname(fileURLToPath(import.meta.url)), \"squadrantd.js\");\n if (!existsSync(p)) {\n throw new Error(\n `daemonEntryPath: compiled entry not found at '${p}'; ` +\n `run 'npm run build' — a src-tree or missing path in the launchd plist causes a MODULE_NOT_FOUND crash-loop (#259)`,\n );\n }\n return p;\n}\n\nfunction xmlEscape(s: string): string {\n return s.replace(/&/g, \"&amp;\").replace(/</g, \"&lt;\").replace(/>/g, \"&gt;\").replace(/\"/g, \"&quot;\");\n}\n\n/**\n * Strip per-shell ephemeral PATH entries (Claude Code plugin cache dirs) and\n * dedupe so the plist content is stable across squadrant invocations from\n * different shells. Without this, a captain shell (PATH includes\n * ~/.claude/plugins/cache/* bin dirs) vs a fresh login shell would each\n * rewrite the plist and kickstart -k the daemon, killing in-flight tasks\n * (incident 2026-05-21, observations 8704/8707/8711).\n */\nexport function sanitizePathForPlist(path: string): string {\n const seen = new Set<string>();\n const stable: string[] = [];\n for (const p of path.split(\":\")) {\n if (!p) continue;\n if (p.includes(\"/.claude/plugins/\")) continue;\n if (seen.has(p)) continue;\n seen.add(p);\n stable.push(p);\n }\n return stable.join(\":\");\n}\n\nexport const AGENT_BINS = [\"cmux\", \"claude\", \"opencode\", \"codex\", \"gemini\", \"node\"];\n\n/**\n * Resolve absolute directories for known agent + tool binaries via `which`, so\n * the launchd daemon's PATH includes them regardless of the install-time shell.\n * Missing binaries are skipped silently.\n */\nexport function resolveAgentBinDirs(): string[] {\n const dirs: string[] = [];\n for (const bin of AGENT_BINS) {\n try {\n const out = execFileSync(\"which\", [bin], { encoding: \"utf-8\", stdio: [\"ignore\", \"pipe\", \"ignore\"] });\n const resolved = out.trim();\n if (resolved) dirs.push(dirname(resolved));\n } catch {\n // binary not found on this machine — skip\n }\n }\n const seen = new Set<string>();\n return dirs.filter(d => {\n if (seen.has(d)) return false;\n seen.add(d);\n return true;\n });\n}\n\n/**\n * Compose a stable daemon PATH by prepending resolved agent bin dirs to the\n * sanitized install-shell PATH. Agent dirs take priority (prepended) and are\n * deduped against the sanitized entries so the output is deterministic.\n */\nexport function buildDaemonPath(shellPath: string): string {\n const agentDirs = resolveAgentBinDirs();\n const sanitized = sanitizePathForPlist(shellPath);\n if (agentDirs.length === 0) return sanitized;\n const parts = [...agentDirs, ...sanitized.split(\":\")];\n const seen = new Set<string>();\n return parts.filter(p => {\n if (!p || seen.has(p)) return false;\n seen.add(p);\n return true;\n }).join(\":\");\n}\n\n/**\n * Red-team #3 (High): launchd starts the daemon with a minimal PATH that does\n * NOT include where `claude`/`codex`/`opencode` live (nvm/cmux dirs), so every\n * headless `spawn` failed `ENOENT` in the real deployment (shell tests + fake\n * spawn hid it). We bake the installing process's PATH into the plist so the\n * daemon and its spawned crew children resolve the provider binaries.\n */\nexport function renderPlist(nodeBin: string, daemonEntry: string, pathEnv = \"\"): string {\n const logPath = join(homedir(), \".config\", \"squadrant\", \"squadrantd.log\");\n return `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n <key>Label</key><string>${LABEL}</string>\n <key>ProgramArguments</key>\n <array><string>${xmlEscape(nodeBin)}</string><string>${xmlEscape(daemonEntry)}</string></array>\n <key>EnvironmentVariables</key>\n <dict><key>PATH</key><string>${xmlEscape(pathEnv)}</string></dict>\n <key>RunAtLoad</key><true/>\n <key>KeepAlive</key><true/>\n <key>ThrottleInterval</key><integer>10</integer>\n <key>StandardErrorPath</key><string>${xmlEscape(logPath)}</string>\n <key>StandardOutPath</key><string>${xmlEscape(logPath)}</string>\n</dict>\n</plist>\n`;\n}\n\n/**\n * Semantic fingerprint of the <array> block inside the rendered plist. Used by\n * ensureDaemon to distinguish program-argument changes (merit a full restart)\n * from PATH-only changes (write updated plist, don't bounce the daemon).\n */\nexport function programArgsBlock(nodeBin: string, daemonEntry: string): string {\n return `<array><string>${xmlEscape(nodeBin)}</string><string>${xmlEscape(daemonEntry)}</string></array>`;\n}\n\n/**\n * Pure: which kickstart argv to use. `-k` (kill-then-restart) ONLY when the\n * plist changed. A plain `kickstart` starts a down daemon and is a no-op for a\n * healthy one — so a routine CLI call never bounces a running daemon (this was\n * a real bug: ensureDaemon ran on every `squadrant` invocation and `kickstart -k`\n * killed+restarted the daemon each time, orphaning in-flight headless crew).\n */\nexport function kickstartArgv(target: string, plistChanged: boolean): string[] {\n return plistChanged ? [\"kickstart\", \"-k\", target] : [\"kickstart\", target];\n}\n\n// In-process dedup: JS is single-threaded and ensureDaemon is synchronous, so\n// true re-entrancy is impossible; this flag prevents sequential re-calls within\n// the same process (e.g. index.ts + crew-control.ts) from re-running the\n// bootout/bootstrap pair needlessly.\nlet restartInFlight = false;\n\n/** @internal — reset only in tests; never call from production code */\nexport function _resetRestartInFlightForTest(): void {\n restartInFlight = false;\n}\n\nexport function daemonLockPath(): string {\n return join(homedir(), \".config\", \"squadrant\", \"daemon.lock\");\n}\n\n/**\n * Acquire a cross-process filesystem lock at ~/.config/squadrant/daemon.lock.\n * Uses O_EXCL for atomic, race-free creation. Cleans up stale locks (dead PID)\n * before the acquisition loop. Retries with a ~50 ms synchronous sleep up to\n * 20 times (~1 s total) before giving up.\n * Returns true on success, false if another live process holds the lock.\n */\nexport function tryAcquireDaemonLock(): boolean {\n const lp = daemonLockPath();\n\n // Stale-lock cleanup: if the owning PID is no longer alive, remove the file\n // so the next O_EXCL attempt succeeds.\n if (existsSync(lp)) {\n try {\n const pid = parseInt(readFileSync(lp, \"utf-8\").trim(), 10);\n if (!Number.isFinite(pid) || pid <= 0) {\n unlinkSync(lp);\n } else {\n try { process.kill(pid, 0); }\n catch { unlinkSync(lp); } // ESRCH → process dead, steal the lock\n }\n } catch { /* read/parse/unlink error — fall through to O_EXCL attempt */ }\n }\n\n // Atomic acquisition: O_EXCL guarantees only one process creates the file.\n for (let i = 0; i < 20; i++) {\n try {\n const fd = openSync(lp, constants.O_EXCL | constants.O_CREAT | constants.O_WRONLY);\n writeSync(fd, String(process.pid));\n closeSync(fd);\n return true;\n } catch {\n if (i < 19) {\n // Synchronous sleep: gives the lock-holder time to finish and release.\n Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, 50);\n }\n }\n }\n return false; // another live process held the lock for > ~1 s — skip restart\n}\n\n/** Release the lock written by tryAcquireDaemonLock. */\nexport function releaseDaemonLock(): void {\n try { unlinkSync(daemonLockPath()); } catch { /* already cleaned up */ }\n}\n\n/**\n * Idempotent & cheap. Never throws fatally. Writes/reloads the plist ONLY when\n * its content actually changed; Distinguishes program-argument drift (warrants\n * a full restart via bootout + bootstrap + kickstart) from PATH-only drift\n * (write the plist for the next natural restart but never bounce a healthy\n * daemon). Uses plain `kickstart` (never -k) to avoid the race between -k and\n * bootout's exit handler that produced exit-113 \"service not loaded\" errors.\n * The daemon entry is resolved internally (see daemonEntryPath) so no caller\n * can pass a wrong path.\n *\n * Concurrency guards:\n * - restartInFlight flag: prevents sequential re-calls within this process.\n * - tryAcquireDaemonLock: serialises concurrent SEPARATE squadrant processes\n * via a filesystem lock so only one runs bootout/bootstrap at a time.\n */\nexport function ensureDaemon(nodeBin: string = process.execPath): void {\n if (restartInFlight) return;\n restartInFlight = true;\n\n if (!tryAcquireDaemonLock()) {\n // Another process is handling the restart; it will be done by the time the\n // CLI tries to reach the daemon socket.\n return;\n }\n\n try {\n const p = plistPath();\n const entry = daemonEntryPath();\n const desired = renderPlist(nodeBin, entry, buildDaemonPath(process.env.PATH ?? \"\"));\n const current = existsSync(p) ? readFileSync(p, \"utf-8\") : null;\n const uid = process.getuid?.() ?? 0;\n const target = `gui/${uid}/${LABEL}`;\n\n const changed = current !== desired;\n // Semantic comparison: was the program-arg block itself different (not just\n // PATH)? Program-arg changes are rare (rebuild/reinstall) and merit a full\n // bootout+reload; PATH varies across terminals so it must NOT trigger a\n // bounce (would orphan in-flight RPCs).\n const programChanged = current !== null && changed\n && !current.includes(programArgsBlock(nodeBin, entry));\n\n if (changed) {\n mkdirSync(dirname(p), { recursive: true });\n writeFileSync(p, desired);\n }\n\n if (programChanged) {\n // unload the old instance so bootstrap picks up the new program args\n try { execFileSync(\"launchctl\", [\"bootout\", target], { stdio: \"ignore\" }); }\n catch { /* not loaded */ }\n }\n\n try { execFileSync(\"launchctl\", [\"bootstrap\", `gui/${uid}`, p], { stdio: \"ignore\" }); }\n catch { /* already bootstrapped */ }\n\n // Plain kickstart (never -k): no-op on a healthy daemon, starts one that\n // was booted-out above or that stopped for other reasons. -k is avoided\n // because it races with bootout's exit handler and produces exit-113 when\n // the service hasn't finished unloading.\n execFileSync(\"launchctl\", [\"kickstart\", target], { stdio: \"ignore\" });\n } catch (e) {\n // daemon ensure is best-effort (still don't throw); CLI fails loud on socket miss\n process.stderr.write(`[squadrant] warn: ensureDaemon failed (${e instanceof Error ? e.message : e})\\n`);\n } finally {\n releaseDaemonLock();\n }\n}\n","import { loadConfig } from \"@squadrant/shared\";\nimport type { RuntimeDriver, SquadrantConfig, TaskRecord } from \"@squadrant/shared\";\nimport type { DirectCmuxReader } from \"./interfaces.js\";\n\nconst TAIL_LINES = 25;\n\n// MUST match `titleFor` in src/commands/crew.ts — the crew tab title convention\n// the daemon uses to find a crew's pane (🔧 <project>:<name>).\nexport function crewPaneTitle(project: string, name: string): string {\n return `🔧 ${project}:${name}`;\n}\n\nexport type SurfaceLiveness = \"alive\" | \"gone\" | \"unknown\";\n\n/**\n * Pure: decide an interactive crew's surface liveness from a resolved surface\n * list (#139). Three-valued so a transient cmux outage never false-reaps a live\n * crew — \"gone\" means PROVABLY absent, not \"couldn't tell\":\n * - wantTitle null (crew has no name) → \"unknown\"\n * - surfaceTitles null (could not enumerate) → \"unknown\"\n * - title present in the list → \"alive\"\n * - title absent from an enumerated list → \"gone\"\n */\nexport function surfaceVerdict(surfaceTitles: string[] | null, wantTitle: string | null): SurfaceLiveness {\n if (!wantTitle) return \"unknown\";\n if (surfaceTitles == null) return \"unknown\";\n return surfaceTitles.includes(wantTitle) ? \"alive\" : \"gone\";\n}\n\n/**\n * I/O: enumerate the captain workspace's surface titles for a crew's project.\n * Returns null on ANY failure — surfaceVerdict maps null → \"unknown\" so we never\n * reap on an inconclusive probe. Never throws.\n */\nasync function listCaptainSurfaceTitles(\n rec: TaskRecord,\n makeRuntime: (project: string, config: SquadrantConfig) => RuntimeDriver | null,\n): Promise<string[] | null> {\n try {\n const config = loadConfig();\n const proj = config.projects[rec.project];\n if (!proj) return null;\n const runtime = makeRuntime(rec.project, config);\n if (!runtime) return null;\n const captain = await runtime.status(proj.captainName);\n if (!captain) return null;\n const surfaces = await runtime.listSurfaces(captain.id);\n return surfaces.map((s) => s.title ?? \"\");\n } catch {\n return null;\n }\n}\n\n/**\n * Build the daemon's interactive surface-liveness probe (#139 backstop).\n * @param makeRuntime Factory provided by the host (root package); omit for tests.\n */\nexport function createSurfaceLivenessProbe(\n makeRuntime?: (project: string, config: SquadrantConfig) => RuntimeDriver | null,\n): (rec: TaskRecord) => Promise<SurfaceLiveness> {\n return async (rec) => {\n if (rec.mode !== \"interactive\" || !rec.name) return \"unknown\";\n if (!makeRuntime) return \"unknown\";\n const titles = await listCaptainSurfaceTitles(rec, makeRuntime);\n return surfaceVerdict(titles, crewPaneTitle(rec.project, rec.name));\n };\n}\n\n/**\n * Build the daemon's best-effort crew-pane reader (Phase 2b).\n * @param makeRuntime Factory provided by the host; required for real pane reads.\n */\nexport function createCrewPaneReader(\n makeRuntime?: (project: string, config: SquadrantConfig) => RuntimeDriver | null,\n): (rec: TaskRecord) => Promise<string | null> {\n return async (rec) => {\n try {\n if (!rec.name || !makeRuntime) return null;\n const config = loadConfig();\n const proj = config.projects[rec.project];\n if (!proj) return null;\n const runtime = makeRuntime(rec.project, config);\n if (!runtime) return null;\n const captain = await runtime.status(proj.captainName);\n if (!captain) return null;\n const surfaces = await runtime.listSurfaces(captain.id);\n const want = crewPaneTitle(rec.project, rec.name);\n const pane = surfaces.find((s) => s.title === want);\n if (!pane) return null;\n const screen = await runtime.readPaneScreen(pane);\n if (!screen) return null;\n return screen.split(/\\r?\\n/).slice(-TAIL_LINES).join(\"\\n\");\n } catch {\n return null;\n }\n };\n}\n\n/**\n * Build a direct surface-liveness probe for daemon-direct mode (#332).\n * Uses DirectCmuxReader (seam interface implemented by DaemonCmux in root).\n */\nexport function createDirectSurfaceLivenessProbe(\n cmux: DirectCmuxReader,\n getCaptainTitle: (project: string) => string,\n): (rec: TaskRecord) => Promise<SurfaceLiveness> {\n return async (rec) => {\n try {\n if (rec.mode !== \"interactive\" || !rec.name) return \"unknown\";\n const wsId = await cmux.findWorkspaceId(getCaptainTitle(rec.project));\n if (!wsId) return \"unknown\";\n const surfaces = await cmux.listSurfaces(wsId);\n if (surfaces.length === 0) return \"unknown\";\n return surfaceVerdict(\n surfaces.map((s) => s.title ?? \"\"),\n crewPaneTitle(rec.project, rec.name),\n );\n } catch {\n return \"unknown\";\n }\n };\n}\n\n/**\n * Build a direct crew-pane reader for daemon-direct mode (#332).\n * Uses DirectCmuxReader (seam interface implemented by DaemonCmux in root).\n */\nexport function createDirectCrewPaneReader(\n cmux: DirectCmuxReader,\n getCaptainTitle: (project: string) => string,\n): (rec: TaskRecord) => Promise<string | null> {\n return async (rec) => {\n try {\n if (!rec.name) return null;\n const wsId = await cmux.findWorkspaceId(getCaptainTitle(rec.project));\n if (!wsId) return null;\n const surfaces = await cmux.listSurfaces(wsId);\n const want = crewPaneTitle(rec.project, rec.name);\n const pane = surfaces.find((s) => s.title === want);\n if (!pane) return null;\n const screen = await cmux.readPaneScreen(pane);\n if (!screen) return null;\n return screen.split(/\\r?\\n/).slice(-TAIL_LINES).join(\"\\n\");\n } catch {\n return null;\n }\n };\n}\n","export {};\n//# sourceMappingURL=interfaces.js.map","// src/control/codex/gate.ts\n// Pure helpers for the interactive-codex HITL gate primitive (spec §4.9).\nimport type { Gate } from \"@squadrant/shared\";\n\nexport function makeGate(opts: {\n taskId: string;\n kind: \"input\" | \"approval\";\n question: string;\n now: number;\n mkId: () => string;\n}): Gate {\n return {\n gateId: opts.mkId(),\n taskId: opts.taskId,\n kind: opts.kind,\n question: opts.question,\n state: \"pending\",\n createdAt: opts.now,\n };\n}\n\nexport function resolveGate(g: Gate, by: { resolvedBy: string; resolution: unknown }): Gate {\n return { ...g, state: \"resolved\", resolvedBy: by.resolvedBy, resolution: by.resolution };\n}\n\nexport function timeoutGate(g: Gate): Gate {\n return { ...g, state: \"timeout\" };\n}\n","// src/control/daemon/context.ts\n// SquadrantdOpts, defaultIsPidAlive, DaemonContext, and buildContext.\n// Kept here (not in squadrantd.ts) so daemon/* modules can import this file\n// without creating a circular dependency on the host entrypoint.\n// squadrantd.ts re-exports SquadrantdOpts and defaultIsPidAlive for backward compat.\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { spawn as realSpawn } from \"node:child_process\";\nimport { writeFileSync, mkdirSync } from \"node:fs\";\nimport { createStore } from \"../store.js\";\nimport { createDaemon } from \"../daemon.js\";\nimport { loadConfig } from \"@squadrant/shared\";\nimport type { TaskRecord, ControlEvent, Gate, AutoConfigResult } from \"@squadrant/shared\";\nimport type { Socket } from \"node:net\";\nimport type { PaneRef } from \"@squadrant/shared\";\nimport type { AgentDriver, OpencodeBridge, CmuxEventsBridge, DaemonSurfaceDriver } from \"../interfaces.js\";\nimport type { TelegramBridge } from \"../telegram/bridge.js\";\nimport type { AttachFrame } from \"../protocol.js\";\n\n// ── Public injectable options (equivalent of old squadrantd.ts SquadrantdOpts) ───\n\nexport interface SquadrantdOpts {\n stateRoot?: string;\n sockPath?: string;\n sweepMs?: number; // 0 disables the interval (tests)\n isPidAlive?: (pid: number) => boolean;\n isSurfaceAlive?: (rec: TaskRecord) => Promise<\"alive\" | \"gone\" | \"unknown\">;\n spawn?: typeof realSpawn;\n /**\n * Push-notification hook (#109). Defaults to appending a structured event\n * to the mailbox file at <stateRoot>/inbox/<project>.log; an injector\n * process inside the captain workspace tails the file and delivers entries\n * to the captain pane. Tests inject a fake to assert call shape.\n */\n notify?: (args: {\n project: string;\n message: string;\n record: TaskRecord;\n event: ControlEvent;\n }) => Promise<void> | void;\n /** Background rotation timer interval (ms). 0 disables. Default 60_000. */\n rotationIntervalMs?: number;\n /** Mailbox rotation thresholds (size/age/retention). */\n mailboxConfig?: {\n maxBytes?: number;\n maxAgeMs?: number;\n keepCount?: number;\n };\n /** Inject a fake driver for tests. Defaults to a real CodexInteractiveDriver. */\n codexDriver?: AgentDriver;\n /** Inject a fake headless launcher for tests to avoid real process spawns. */\n launchHeadless?: (rec: TaskRecord) => Promise<void>;\n /** Override which projects appear in the Tier 2 per-project snapshot. */\n registeredProjects?: string[];\n /** Inject a fake opencode SSE bridge for tests. */\n opencodeBridge?: OpencodeBridge;\n /** B1: inject a fake cmux events bridge for tests. */\n cmuxEventsBridge?: CmuxEventsBridge;\n /** Opt-in Telegram bridge (#65). Inject a fake for tests; in production the host\n * builds the real one only when config.telegram is present (and not under vitest,\n * since pushLifecycle is composed onto notify and would hit the network). */\n telegramBridge?: TelegramBridge;\n /** Inject a fake surface driver for testing daemon-direct delivery. */\n daemonCmux?: DaemonSurfaceDriver;\n /** Factory for constructing the surface driver in production. */\n makeDaemonCmux?: () => DaemonSurfaceDriver;\n /** Injected captain-surface mapping (project → PaneRef) for tests. */\n captainSurfaces?: Record<string, PaneRef>;\n /** #348: override the cmux socket auto-config re-check. */\n runCmuxAutoConfig?: () => Promise<AutoConfigResult>;\n}\n\nexport function defaultIsPidAlive(pid: number): boolean {\n try { process.kill(pid, 0); return true; }\n catch (e: any) { return e?.code === \"EPERM\"; } // EPERM = alive but not ours; ESRCH = dead\n}\n\n// ── Shared state bag ──────────────────────────────────────────────────────────\n\n/** All shared mutable state for the running daemon. Most fields are set in\n * buildContext; late-bound fields (d, notify, broadcast, etc.) are assigned\n * by start.ts after building the daemon and factories, before any event fires. */\nexport interface DaemonContext {\n opts: SquadrantdOpts;\n stateRoot: string;\n sockPath: string;\n store: ReturnType<typeof createStore>;\n bootedAt: number;\n /** Mutable box so sweep timer can update lastSweepAt without a closure rebind. */\n lastSweepAt: { value: number | null };\n taskTimeoutMs: number | undefined;\n isPidAlive: (pid: number) => boolean;\n spawn: typeof realSpawn;\n resultsDir: string;\n writeResult: (id: string, payload: string) => string;\n log: (m: string) => void;\n /** Per-task live attach connections (spec §4.5/§4.6). */\n attachConns: Map<string, Set<Socket>>;\n /** Tasks being launched headlessly with no pid yet (#259). */\n inFlightHeadlessIds: Set<string>;\n /** Cancel handles for in-flight headless runs. */\n activeHeadlessKills: Set<() => void>;\n /** #332 delivery streak counter per project for captain-absent reaping. */\n captainMissingStreak: Map<string, number>;\n /** #332 projects whose captain surface is confirmed gone. */\n stoppedProjects: Set<string>;\n\n // ── Late-bound: assigned by start.ts before any timer/server fires ──────────\n\n /** Resolved daemon instance. */\n d: ReturnType<typeof createDaemon>;\n /** Resolved notify function. */\n notify: (args: { project: string; message: string; record: TaskRecord; event: ControlEvent }) => Promise<void> | void;\n /** Resolved surface driver for daemon-direct delivery. */\n daemonCmux: DaemonSurfaceDriver | undefined;\n /** Resolved agent driver. */\n codexDriver: AgentDriver;\n /** Resolved opencode SSE bridge. */\n opencodeBridge: OpencodeBridge;\n /** Resolved cmux events bridge. */\n cmuxEventsBridge: CmuxEventsBridge;\n /** Resolved Telegram bridge — undefined when config.telegram is absent. */\n telegramBridge?: TelegramBridge;\n /** Fan-out to attach clients (set by createAttach). */\n broadcast: (taskId: string, f: AttachFrame) => void;\n /** Schedule gate promotion (set by createAttach). */\n schedulePromotion: (taskId: string, requestId: number, kind: \"input\" | \"approval\", question: string) => void;\n /** Cancel gate timers for a task (set by createAttach). */\n cancelPromotionsFor: (taskId: string) => void;\n}\n\n/** Initialize the pure-state fields of DaemonContext from opts.\n * Late-bound fields are zero-initialized and MUST be set by start.ts\n * (or squadrantd.ts for drivers) before any event, timer, or socket fires. */\nexport function buildContext(opts: SquadrantdOpts): DaemonContext {\n const stateRoot = opts.stateRoot ?? join(homedir(), \".config\", \"squadrant\", \"state\");\n const sockPath = opts.sockPath ?? join(homedir(), \".config\", \"squadrant\", \"squadrant.sock\");\n const store = createStore(stateRoot);\n const bootedAt = Date.now();\n const taskTimeoutMs = loadConfig().defaults.taskTimeoutMs;\n const isPidAlive = opts.isPidAlive ?? defaultIsPidAlive;\n const spawn = opts.spawn ?? realSpawn;\n const resultsDir = join(stateRoot, \"_results\");\n mkdirSync(resultsDir, { recursive: true });\n const writeResult = (id: string, payload: string) => {\n const p = join(resultsDir, `${id}.txt`);\n writeFileSync(p, payload);\n return p;\n };\n const log = (m: string) =>\n process.stderr.write(`[squadrantd] ${new Date().toISOString()} ${m}\\n`);\n\n return {\n opts,\n stateRoot,\n sockPath,\n store,\n bootedAt,\n lastSweepAt: { value: null },\n taskTimeoutMs,\n isPidAlive,\n spawn,\n resultsDir,\n writeResult,\n log,\n attachConns: new Map(),\n inFlightHeadlessIds: new Set(),\n activeHeadlessKills: new Set(),\n captainMissingStreak: new Map(),\n stoppedProjects: new Set(),\n // Late-bound — start.ts fills these before first use:\n d: null as unknown as ReturnType<typeof createDaemon>,\n notify: null as unknown as DaemonContext[\"notify\"],\n daemonCmux: undefined,\n codexDriver: null as unknown as AgentDriver,\n opencodeBridge: null as unknown as OpencodeBridge,\n cmuxEventsBridge: null as unknown as CmuxEventsBridge,\n telegramBridge: undefined,\n broadcast: () => {},\n schedulePromotion: () => {},\n cancelPromotionsFor: () => {},\n };\n}\n","// src/control/daemon/attach.ts\n// Attach fan-out and gate-promotion logic (spec §4.5/§4.6/§4.9).\nimport { randomUUID } from \"node:crypto\";\nimport { encodeFrame } from \"../protocol.js\";\nimport { makeGate } from \"../gate.js\";\nimport type { AttachFrame } from \"../protocol.js\";\nimport type { Gate } from \"@squadrant/shared\";\nimport type { DaemonContext } from \"./context.js\";\n\nexport interface AttachHandlers {\n broadcast: (taskId: string, f: AttachFrame) => void;\n schedulePromotion: (taskId: string, requestId: number, kind: \"input\" | \"approval\", question: string) => void;\n cancelPromotionsFor: (taskId: string) => void;\n}\n\n/** Build the attach fan-out and gate-promotion machinery. Call once in start.ts\n * immediately after buildContext; assign the returned handlers onto ctx so the\n * driver emit callbacks can reference them via the context object. */\nexport function createAttach(ctx: DaemonContext): AttachHandlers {\n const { attachConns, store, log } = ctx;\n\n function broadcast(taskId: string, f: AttachFrame): void {\n const conns = attachConns.get(taskId);\n if (!conns) return;\n const wire = encodeFrame(f);\n for (const conn of conns) {\n try { conn.write(wire); } catch { /* client gone; onAttachClose will clean up */ }\n }\n }\n\n // ── Gate promotion (spec §4.9) ─────────────────────────────────────────────\n // When a server-request event fires and no client is attached, start a 5s\n // timer. If still unattached at fire time, promote to a Gate in the store\n // and broadcast gate-promoted so any later-attaching client can offer takeover.\n const pendingGateTimers = new Map<string, { taskId: string; timer: NodeJS.Timeout }>();\n\n function schedulePromotion(\n taskId: string,\n requestId: number,\n kind: \"input\" | \"approval\",\n question: string,\n ): void {\n // If a client is already attached for this task, no promotion needed.\n const conns = attachConns.get(taskId);\n if (conns && conns.size > 0) return;\n const key = `${taskId}#${requestId}`;\n // Clear any prior timer for the same (taskId, requestId).\n const prior = pendingGateTimers.get(key);\n if (prior) clearTimeout(prior.timer);\n const timer = setTimeout(() => {\n pendingGateTimers.delete(key);\n // Re-check at fire time — a client may have attached in the 5s window.\n if (attachConns.get(taskId)?.size) return;\n const rec = store.listAll().find((r) => r.id === taskId);\n if (!rec) return;\n const gate: Gate = makeGate({ taskId, kind, question, now: Date.now(), mkId: () => randomUUID() });\n const gates = [...(rec.gates ?? []), gate];\n store.put({ ...rec, gates });\n broadcast(taskId, { type: \"gate-promoted\", taskId, gateId: gate.gateId });\n log(`gate promoted gateId=${gate.gateId} taskId=${taskId} kind=${kind}`);\n }, 5_000);\n timer.unref?.();\n pendingGateTimers.set(key, { taskId, timer });\n }\n\n function cancelPromotionsFor(taskId: string): void {\n for (const [key, slot] of pendingGateTimers.entries()) {\n if (slot.taskId === taskId) {\n clearTimeout(slot.timer);\n pendingGateTimers.delete(key);\n }\n }\n }\n\n return { broadcast, schedulePromotion, cancelPromotionsFor };\n}\n","// Daemon interactive-block probe: moved from commands/notify-relay.ts so\n// daemon/probes.ts (core) can import it without a core→commands back-edge.\nimport type { TaskRecord, ControlEvent } from \"@squadrant/shared\";\n\n// Entries older than this at session-start time are silently acked without\n// delivery — stale events from a prior session or dead crews.\nexport const STALE_THRESHOLD_MS = 5 * 60 * 1000;\n\n// A working interactive task with no heartbeat for this long is a probe\n// candidate: PostToolUse never fires while a permission prompt is up.\nexport const PROBE_QUIET_MS = 20_000;\n\n// ── Pure pane classifiers (inlined from interactive/pane-classifier.ts) ──────\n// Duplication is intentional: pane-classifier.ts stays in root for the relay\n// path; core can't import it (root → core boundary). Both copies are pure and\n// covered by pane-classifier.test.ts.\n\nfunction detectTrailingQuestion(text: string): string | null {\n if (!text) return null;\n let inFence = false;\n let lastLine: string | null = null;\n for (const raw of text.split(/\\r?\\n/)) {\n const line = raw.trim();\n if (line.startsWith(\"```\")) { inFence = !inFence; continue; }\n if (inFence || line === \"\") continue;\n lastLine = line;\n }\n if (lastLine && lastLine.endsWith(\"?\")) return lastLine;\n return null;\n}\n\nconst ERROR_BANNER_RE: RegExp[] = [\n /\\bAPI Error\\b/i,\n /\\bOverloaded\\b/,\n /\\b(?:429|500|502|503|504|529)\\b[^?]*\\b(?:overloaded|unavailable|internal server error|bad gateway|gateway timeout|too many requests|service unavailable)\\b/i,\n /\\bretr(?:y|ies)\\s+(?:exhausted|limit\\s+(?:reached|exceeded))\\b/i,\n /\\bmaximum\\s+retries\\b/i,\n];\nconst OPTION_RE = /^[❯>›]?\\s*(\\d+)\\.\\s+(.*\\S)\\s*$/;\nconst PURE_CHROME_RE = /^[\\s─━│┃╭╮╰╯┌┐└┘├┤┬┴┼═║╔╗╚╝╠╣╦╩╬▁▂▃▄▅▆▇█▔▏▕]+$/;\nconst STATUS_LINE_RE = /accept edits on|shift\\+tab|⏵⏵|\\? for shortcuts|esc to interrupt|tokens? (used|left)|context left/i;\n\nfunction stripChrome(raw: string): string | null {\n let line = raw.replace(/\\[[0-9;]*m/g, \"\");\n line = line.replace(/^[\\s│┃▏▕|]+/, \"\").replace(/[\\s│┃▏▕|]+$/, \"\");\n const trimmed = line.trim();\n if (trimmed === \"\") return null;\n if (PURE_CHROME_RE.test(trimmed)) return null;\n if (/^>\\s*$/.test(trimmed)) return null;\n if (STATUS_LINE_RE.test(trimmed)) return null;\n return trimmed;\n}\n\nfunction classifyPaneTail(\n tail: string,\n): { kind: \"approval\" | \"question\" | \"error\"; text: string } | null {\n if (!tail) return null;\n const raw = tail.split(/\\r?\\n/);\n const cleaned = raw.map(stripChrome);\n const options: { label: string; ci: number }[] = [];\n for (let i = 0; i < cleaned.length; i++) {\n const c = cleaned[i];\n if (c == null) continue;\n const m = c.match(OPTION_RE);\n if (m) options.push({ label: m[2], ci: i });\n }\n const hasYes = options.some((o) => /\\byes\\b/i.test(o.label));\n const hasNo = options.some((o) => /\\bno\\b/i.test(o.label));\n if (options.length >= 2 && hasYes && hasNo) {\n const firstOptCi = options[0].ci;\n for (let i = firstOptCi - 1; i >= 0; i--) {\n const c = cleaned[i];\n if (c == null) continue;\n if (c.endsWith(\"?\")) return { kind: \"approval\", text: c };\n }\n return { kind: \"approval\", text: \"Crew is awaiting permission approval.\" };\n }\n const region = cleaned.filter((c): c is string => c != null).join(\"\\n\");\n const q = detectTrailingQuestion(region);\n if (q) return { kind: \"question\", text: q };\n let errLine: string | null = null;\n for (const c of cleaned) {\n if (c != null && ERROR_BANNER_RE.some((re) => re.test(c))) errLine = c;\n }\n if (errLine) return { kind: \"error\", text: errLine.slice(0, 200) };\n return null;\n}\n\n// ── Interactive probe ─────────────────────────────────────────────────────────\n\ninterface InteractiveProbeDeps {\n project: string;\n listTasks: () => Promise<TaskRecord[]>;\n readPaneTail: (rec: TaskRecord) => Promise<string | null>;\n sendEvent: (event: ControlEvent) => Promise<void>;\n now: () => number;\n log: (m: string) => void;\n quietMs?: number;\n}\n\nexport function createInteractiveProbe(deps: InteractiveProbeDeps): {\n tick: () => Promise<void>;\n} {\n const quietMs = deps.quietMs ?? PROBE_QUIET_MS;\n const lastTail = new Map<string, string>();\n\n async function tick(): Promise<void> {\n let tasks: TaskRecord[];\n try {\n tasks = await deps.listTasks();\n } catch (e) {\n deps.log(`probe listTasks failed: ${(e as Error).message}`);\n return;\n }\n const now = deps.now();\n for (const rec of tasks) {\n if (rec.mode !== \"interactive\") continue;\n if (rec.state !== \"working\") continue;\n if (!rec.name) continue;\n if (now - rec.lastHeartbeat <= quietMs) continue;\n\n let tail: string | null;\n try {\n tail = await deps.readPaneTail(rec);\n } catch (e) {\n deps.log(`probe read failed for ${rec.id}: ${(e as Error).message}`);\n continue;\n }\n if (!tail) continue;\n if (lastTail.get(rec.id) === tail) continue;\n lastTail.set(rec.id, tail);\n\n const verdict = classifyPaneTail(tail);\n if (!verdict) continue;\n const event: ControlEvent =\n verdict.kind === \"error\"\n ? {\n type: \"task.failed\",\n id: rec.id,\n error: `crew session error (pane-detected): ${verdict.text}`,\n }\n : {\n type: \"task.blocked\",\n id: rec.id,\n reason:\n verdict.kind === \"approval\"\n ? \"crew awaiting permission (pane-detected)\"\n : \"crew asked a question (pane-detected)\",\n question: verdict.text,\n };\n try {\n await deps.sendEvent(event);\n const label = verdict.kind === \"error\" ? \"CREW FAILED\" : \"CREW BLOCKED\";\n deps.log(`probe -> ${label} ${rec.name} (${verdict.kind})`);\n } catch (e) {\n deps.log(`probe sendEvent failed for ${rec.id}: ${(e as Error).message}`);\n }\n }\n }\n\n return { tick };\n}\n","// src/control/daemon/probes.ts\n// Surface-liveness probe logic for the daemon-direct delivery path.\nimport { createInteractiveProbe } from \"./interactive-probe.js\";\nimport { createDirectCrewPaneReader, createDirectSurfaceLivenessProbe } from \"../crew-pane-reader.js\";\nimport { loadConfig } from \"@squadrant/shared\";\nimport type { TaskRecord } from \"@squadrant/shared\";\nimport type { DaemonSurfaceDriver } from \"../interfaces.js\";\nimport type { DaemonContext } from \"./context.js\";\n\nexport interface ProbeHandlers {\n /** Build the probe-tick function for the daemon-direct delivery loop.\n * Call once after the surface driver is resolved; returns a guarded tick. */\n buildInteractiveProbe: (deps: { cmux: DaemonSurfaceDriver }) => () => Promise<void>;\n /** Direct-cmux surface liveness probe for interactive task reaping. */\n directSurfaceProbe: (rec: TaskRecord) => Promise<\"alive\" | \"gone\" | \"unknown\">;\n}\n\n/** Resolve the captain pane name for a project from the config. */\nfunction captainNameForProject(project: string): string {\n const cfg = loadConfig();\n return cfg.projects?.[project]?.captainName ?? `${project}-captain`;\n}\n\nexport function createProbes(ctx: DaemonContext): ProbeHandlers {\n const { store, log } = ctx;\n\n // ── Daemon-direct: direct cmux surface probe ──────────────────────────────\n const directSurfaceProbe = (_rec: TaskRecord): Promise<\"alive\" | \"gone\" | \"unknown\"> => {\n return Promise.resolve(\"unknown\");\n };\n\n // ── Daemon-direct: blocked-crew detection ─────────────────────────────────\n // Reuses createInteractiveProbe with a direct cmux pane reader injected as\n // the readPaneTail dep. The returned tick must be called from the delivery\n // loop's interval.\n function buildInteractiveProbe(deps: { cmux: DaemonSurfaceDriver }): () => Promise<void> {\n const directPaneReader = createDirectCrewPaneReader(deps.cmux, captainNameForProject);\n const probe = createInteractiveProbe({\n project: \"_all_\",\n listTasks: async () => store.listAll(),\n readPaneTail: directPaneReader,\n sendEvent: async (event) => {\n const rec = store.listAll().find((r) => r.id === event.id);\n if (rec) {\n await ctx.d.handle({ kind: \"event\", project: rec.project, event });\n }\n },\n now: () => Date.now(),\n log,\n });\n let probing = false;\n return async () => {\n if (probing) return;\n probing = true;\n try { await probe.tick(); }\n finally { probing = false; }\n };\n }\n\n return { buildInteractiveProbe, directSurfaceProbe };\n}\n\n/** Build the surface-liveness probe used by createDaemon — always uses the\n * direct cmux path when a driver is available. Pure: no side effects. */\nexport function buildSurfaceProbe(\n ctx: DaemonContext,\n probes: ProbeHandlers,\n daemonCmux: DaemonSurfaceDriver | undefined,\n): (rec: TaskRecord) => Promise<\"alive\" | \"gone\" | \"unknown\"> {\n if (ctx.opts.isSurfaceAlive) return ctx.opts.isSurfaceAlive;\n if (daemonCmux) {\n return createDirectSurfaceLivenessProbe(daemonCmux, captainNameForProject);\n }\n return probes.directSurfaceProbe;\n}\n","/** Thrown by sendToSurface when the captain has a draft — delivery defers (#258/#302). */\nexport class DeferDelivery extends Error {\n constructor(public readonly draft: string | null = null) {\n super(\"deferred: captain composing\");\n this.name = \"DeferDelivery\";\n }\n}\n","import { DeferDelivery } from \"./defer-delivery.js\";\n\n/**\n * #332: extracted defer-while-typing state machine (#258/#302).\n *\n * Behaviour ported from notify-relay.ts drain() (#332):\n * - per-seq deferCounts / stableCounts / lastContent maps\n * - maxDefers / stableProbePolls thresholds\n * - stable-content probe escalation (#302)\n */\nexport interface CaptainDeliveryOptions {\n maxDefers: number;\n stableProbePolls: number;\n}\n\nexport type SendFn = (text: string, opts?: { probe?: boolean }) => Promise<void>;\nexport type DeliverResult = { delivered: true } | { deferred: true };\n\n/**\n * Unified-formatter helper (#214/#210): the daemon's formatMessage is the single\n * source of truth for the captain-facing message. Returns null for entries the\n * daemon chose not to surface (null/empty message fields).\n */\nexport function deliverable(entry: { message?: string | null }): string | null {\n const msg = entry.message;\n if (msg == null) return null;\n const trimmed = msg.trim();\n return trimmed.length > 0 ? msg : null;\n}\n\nexport class CaptainDelivery {\n private deferCounts = new Map<number, number>();\n private lastContent = new Map<number, string | null>();\n private stableCounts = new Map<number, number>();\n\n constructor(private readonly opts: CaptainDeliveryOptions) {}\n\n /**\n * Attempt to deliver one mailbox entry to the captain. Calls `send(text, opts)`\n * and, if the send throws DeferDelivery, tracks defer/stable counts for the\n * entry's seq and returns {deferred: true} (caller should NOT advance cursor).\n * On success or null message returns {delivered: true} (caller SHOULD advance).\n */\n async deliver(\n entry: { seq: number; message?: string | null },\n send: SendFn,\n ): Promise<DeliverResult> {\n const msg = deliverable(entry);\n if (!msg) return { delivered: true };\n\n const seq = entry.seq;\n const deferCount = this.deferCounts.get(seq) ?? 0;\n // #302: probe early once content has been stable for stableProbePolls\n // polls (captain not typing) — kills the ~5min stall; the 300-defer\n // backstop still guarantees delivery never hangs forever.\n const stable = (this.stableCounts.get(seq) ?? 0) >= this.opts.stableProbePolls;\n const probe = stable || deferCount >= this.opts.maxDefers;\n\n try {\n await send(msg, probe ? { probe: true } : undefined);\n this.deferCounts.delete(seq);\n this.stableCounts.delete(seq);\n this.lastContent.delete(seq);\n return { delivered: true };\n } catch (e) {\n if (e instanceof DeferDelivery) {\n this.deferCounts.set(seq, deferCount + 1);\n // Track content stability: byte-identical non-empty draft across\n // consecutive polls means the captain isn't actively typing (#302).\n const content = e.draft;\n if (content && content === this.lastContent.get(seq)) {\n this.stableCounts.set(seq, (this.stableCounts.get(seq) ?? 0) + 1);\n } else {\n this.stableCounts.set(seq, 0);\n }\n this.lastContent.set(seq, content);\n return { deferred: true };\n }\n // Non-DeferDelivery errors: don't advance cursor, retry next poll.\n return { deferred: true };\n }\n }\n}\n","// src/control/daemon/delivery.ts\n// Mailbox notification + daemon-direct captain delivery loop (#332).\nimport { appendToMailbox, readCursor, writeCursor, readFromCursor } from \"../mailbox.js\";\nimport { CaptainDelivery } from \"../delivery/captain-delivery.js\";\nimport { loadConfig, TERMINAL_STATES } from \"@squadrant/shared\";\nimport { STALE_THRESHOLD_MS } from \"./interactive-probe.js\";\nimport type { TaskRecord, ControlEvent } from \"@squadrant/shared\";\nimport type { PaneRef } from \"@squadrant/shared\";\nimport type { Store } from \"../store.js\";\nimport type { DaemonSurfaceDriver } from \"../interfaces.js\";\nimport type { DaemonContext } from \"./context.js\";\n\nconst CURSOR_SUBSCRIBER = \"captain\";\nconst CAPTAIN_GONE_STREAK_K = 3;\n\n/** Pure: find the captain surface by title in a surface list (#332). */\nexport function discoverCaptainSurface(surfaces: PaneRef[], captainTitle: string): PaneRef | null {\n return surfaces.find((s) => s.title === captainTitle) ?? null;\n}\n\n/**\n * Reap a stopped project's orphaned crews (#324). When the user closes the\n * captain workspace, its crew panes die with it — every non-terminal\n * interactive crew is orphaned. Terminalize them to 'cancelled' with a distinct\n * `captain-stopped` marker (traceable; not a fault). Silent: no push fires (the\n * captain that would receive it is gone). Returns the count reaped.\n *\n * Headless crews are excluded — they run as detached processes, not panes in the\n * captain's workspace, and are reconciled by their own pid liveness instead.\n */\nexport function reapOrphanedCrews(store: Pick<Store, \"list\" | \"put\">, project: string): number {\n let reaped = 0;\n for (const r of store.list(project)) {\n if (TERMINAL_STATES.has(r.state)) continue;\n if (r.mode !== \"interactive\") continue;\n store.put({ ...r, state: \"cancelled\", lastEvent: \"captain-stopped\" });\n reaped++;\n }\n return reaped;\n}\n\nexport interface DeliveryResult {\n defaultNotify: (args: { project: string; message: string; record: TaskRecord; event: ControlEvent }) => Promise<void>;\n /** Guarded delivery tick — undefined when daemon-direct mode is OFF. */\n deliveryTick: (() => Promise<void>) | undefined;\n}\n\nexport function createDelivery(\n ctx: DaemonContext,\n daemonCmux: DaemonSurfaceDriver | undefined,\n): DeliveryResult {\n const { stateRoot, store, log, captainMissingStreak, stoppedProjects, opts } = ctx;\n\n // ── Default push-notification wiring (mailbox-injector spec) ─────────────\n const defaultNotify = async (args: {\n project: string;\n message: string;\n record: TaskRecord;\n event: ControlEvent;\n }): Promise<void> => {\n try {\n await appendToMailbox({\n stateRoot,\n project: args.project,\n taskRecord: args.record,\n event: args.event,\n // Persist the daemon-rendered message (#214/#210): delivered verbatim\n // rather than re-derived from the raw event (which drifted).\n message: args.message,\n });\n } catch (e) {\n log(`mailbox append failed project=${args.project}: ${(e as Error).message}`);\n }\n };\n\n // ── Daemon-direct delivery loop ───────────────────────────────────────────\n if (!daemonCmux) {\n return { defaultNotify, deliveryTick: undefined };\n }\n\n const cmux = daemonCmux;\n const cfg = loadConfig();\n const deliveries = new Map<string, CaptainDelivery>();\n // Captured once at delivery-loop setup. Entries older than\n // sessionStartMs - STALE_THRESHOLD_MS are silently acked (cursor advanced)\n // without delivery. This stops a fresh/empty cursor from re-delivering the\n // entire historical backlog.\n const sessionStartMs = Date.now();\n\n // Re-entrancy guard: each tick does multiple slow cmux subprocess calls and\n // can exceed the 1s interval.\n let delivering = false;\n\n const deliveryCore = async () => {\n const injectedSurfaces = opts.captainSurfaces ?? {};\n const allProjects = [...new Set([\n ...Object.keys(cfg.projects ?? {}),\n ...Object.keys(injectedSurfaces),\n ...store.listAll().map((t) => t.project),\n ])];\n\n for (const project of allProjects) {\n const projCfg = cfg.projects?.[project];\n const captainTitle = projCfg?.captainName ?? `${project}-captain`;\n\n // Try real discovery from cmux.\n const wsId = cmux.findWorkspaceId ? await cmux.findWorkspaceId(captainTitle) : null;\n let surface: PaneRef | null = null;\n let surfacesLength = 0;\n\n if (wsId) {\n const surfaces = await cmux.listSurfaces(wsId);\n surfacesLength = surfaces.length;\n surface = discoverCaptainSurface(surfaces, captainTitle);\n }\n\n // Fall back to injected surface (tests / config-less projects).\n if (!surface) surface = injectedSurfaces[project] ?? null;\n\n if (surface) {\n // Captain found — if previously reaped, un-reap and reset streak.\n if (stoppedProjects.has(project)) {\n stoppedProjects.delete(project);\n captainMissingStreak.set(project, 0);\n }\n captainMissingStreak.set(project, 0);\n } else {\n // Streak tracking: surfaces.length > 0 means cmux is reachable but the\n // captain's pane is provably absent. surfaces.length === 0 means cmux\n // was unreachable (fail-soft → []), treat as \"unknown\" — never increment.\n if (surfacesLength > 0) {\n const streak = (captainMissingStreak.get(project) ?? 0) + 1;\n captainMissingStreak.set(project, streak);\n if (streak >= CAPTAIN_GONE_STREAK_K) {\n if (!stoppedProjects.has(project)) {\n stoppedProjects.add(project);\n const reaped = reapOrphanedCrews(store, project);\n log(`captain ${captainTitle}: surface gone for ${CAPTAIN_GONE_STREAK_K} sweeps — stopping delivery${reaped > 0 ? `, reaped ${reaped} orphaned crew(s)` : \"\"}`);\n }\n }\n }\n continue;\n }\n\n const cursor = await readCursor({ stateRoot, project, subscriber: CURSOR_SUBSCRIBER });\n const lastAcked = cursor?.lastAckedSeq ?? 0;\n let d = deliveries.get(project);\n if (!d) {\n d = new CaptainDelivery({\n maxDefers: cfg.delivery?.maxDeferDeliveries ?? 300,\n stableProbePolls: cfg.delivery?.stableProbePolls ?? 3,\n });\n deliveries.set(project, d);\n }\n for await (const entry of readFromCursor({ stateRoot, project, fromSeq: lastAcked + 1 })) {\n // #332 storm BUG 3: silently ack entries that pre-date this daemon\n // session by more than STALE_THRESHOLD_MS.\n if (new Date(entry.ts).getTime() < sessionStartMs - STALE_THRESHOLD_MS) {\n await writeCursor({ stateRoot, project, subscriber: CURSOR_SUBSCRIBER, lastAckedSeq: entry.seq });\n continue;\n }\n const result = await d.deliver(entry, (text, sendOpts) =>\n cmux.send(surface!, text, sendOpts),\n );\n if (\"delivered\" in result) {\n await writeCursor({ stateRoot, project, subscriber: CURSOR_SUBSCRIBER, lastAckedSeq: entry.seq });\n } else {\n break;\n }\n }\n }\n };\n\n const deliveryTick = async () => {\n if (delivering) return;\n delivering = true;\n try {\n await deliveryCore();\n } finally {\n delivering = false;\n }\n };\n\n return { defaultNotify, deliveryTick };\n}\n","// src/control/daemon/gates.ts\n// resolveInteractiveGate: route the captain's approve/deny to the owning driver.\n// Reads ctx.codexDriver and ctx.opencodeBridge lazily (set by squadrantd.ts before\n// any gate message can arrive on the socket).\nimport type { DaemonContext } from \"./context.js\";\n\nexport function createGateResolver(ctx: DaemonContext) {\n return async (taskId: string, payload: unknown): Promise<void> => {\n const rec = ctx.store.listAll().find((r) => r.id === taskId);\n try {\n if (rec?.provider === \"opencode\") {\n // Only an explicit \"approve\" approves; any other reply denies —\n // never auto-approve a permission gate.\n const decision = (payload as { decision?: string })?.decision === \"approve\" ? \"approve\" : \"deny\";\n await ctx.opencodeBridge.answer(taskId, decision);\n } else {\n await ctx.codexDriver.answer(taskId, payload);\n }\n } catch (e) { ctx.log(`gate-resolve answer failed: ${(e as Error).message}`); }\n };\n}\n","// src/control/daemon/server.ts\n// IPC socket server: message router + attach fan-in.\n// All state lives on DaemonContext; callbacks that can't yet be on ctx are\n// passed via ServerHandlers (built once in squadrantd.ts/start.ts).\nimport { startServer, encodeFrame } from \"../protocol.js\";\nimport type { AttachFrame, AttachInbound } from \"../protocol.js\";\nimport type { ComponentHealth } from \"../liveness.js\";\nimport type { DaemonSnapshotInputs } from \"../snapshot.js\";\nimport type { DaemonContext } from \"./context.js\";\n\nexport interface ServerHandlers {\n /** Build per-component health list (optionally filtered to one project). */\n buildHealth: (project?: string) => ComponentHealth[];\n /** Gather full snapshot inputs (all I/O). */\n gatherSnapshotInputs: (now: number) => Promise<DaemonSnapshotInputs>;\n /** Cancel pending gate-promotion timers when a client attaches. */\n cancelPromotionsFor: (taskId: string) => void;\n /** Fan-out an AttachFrame to all clients watching a task. */\n broadcast: (taskId: string, f: AttachFrame) => void;\n}\n\nexport function createServer(\n ctx: DaemonContext,\n handlers: ServerHandlers,\n) {\n const { store, log, attachConns } = ctx;\n const { buildHealth, gatherSnapshotInputs, cancelPromotionsFor, broadcast } = handlers;\n\n return startServer(ctx.sockPath, {\n handler: async (msg: any) => {\n if (msg.kind === \"seed\") { store.put(msg.record); return { ok: true }; }\n // Crew-close teardown for codex: the cmux pane only hosts the `crew attach`\n // renderer — the thread lives on the shared app-server, so closing the pane\n // doesn't reap it. `squadrant crew close` calls this to archive the thread and\n // its per-thread MCP servers (else they leak ~53MB/crew). Fires for terminal\n // and non-terminal crews alike.\n if (msg.kind === \"codex-close\") {\n await ctx.codexDriver.close(msg.taskId).catch((e: unknown) => log(`codex close err: ${e}`));\n return { ok: true };\n }\n // #77 service-health surface: per-component liveness for the queried project (or all).\n if (msg.kind === \"health\") {\n return buildHealth(msg.project as string | undefined);\n }\n // #44 dashboard: read-only full system snapshot (Tier 0/1/2).\n if (msg.kind === \"snapshot\") {\n const now = Date.now();\n const { assembleDaemonSnapshot } = await import(\"../snapshot.js\");\n return assembleDaemonSnapshot(await gatherSnapshotInputs(now), now);\n }\n if (msg.kind === \"event\") {\n return ctx.d.handle(msg);\n }\n return ctx.d.handle(msg);\n },\n onAttach: (conn, frame) => {\n let set = attachConns.get(frame.taskId);\n if (!set) { set = new Set(); attachConns.set(frame.taskId, set); }\n set.add(conn);\n // A client arriving within the 5s window defuses any pending gate timer.\n cancelPromotionsFor(frame.taskId);\n // Immediately ack the attach so the client knows it's live.\n try { conn.write(encodeFrame({ type: \"reattached\", taskId: frame.taskId })); } catch { /* ignore */ }\n },\n onAttachInbound: (_conn, frame) => {\n const f = frame as AttachInbound;\n if (f.op === \"say\")\n void ctx.codexDriver.say(f.taskId, f.text).catch((e: unknown) => log(`say err: ${e}`));\n else if (f.op === \"steer\")\n void ctx.codexDriver.steer(f.taskId, f.text).catch((e: unknown) => log(`steer err: ${e}`));\n else if (f.op === \"interrupt\")\n void ctx.codexDriver.interrupt(f.taskId).catch((e: unknown) => log(`interrupt err: ${e}`));\n else if (f.op === \"answer\")\n void ctx.codexDriver.answer(f.taskId, f.payload).catch((e: unknown) => log(`answer err: ${e}`));\n },\n onAttachClose: (conn) => {\n for (const set of attachConns.values()) set.delete(conn);\n },\n });\n}\n","// src/control/daemon/snapshot-gather.ts\n// Snapshot I/O edge: pure helpers that gather raw inputs for the snapshot verb.\n// Each tolerates missing files and never throws.\nimport { fileURLToPath } from \"node:url\";\nimport { join } from \"node:path\";\nimport {\n statSync, openSync, readSync, closeSync, readdirSync, readFileSync,\n} from \"node:fs\";\nimport type { DaemonSnapshotInputs, ResultArtifacts } from \"../snapshot.js\";\nimport type { TaskRecord } from \"@squadrant/shared\";\n\n// The compiled snapshot-gather.js shares the dist/ build time with squadrantd.js\n// (tsup compiles all entries in the same pass), so its mtime == dist build-time.\nconst SELF_PATH = fileURLToPath(import.meta.url);\n\n/** mtime (epoch ms) of the running daemon's compiled code, for build-freshness. */\nexport function distBuiltAt(): number {\n try { return statSync(SELF_PATH).mtimeMs; } catch { return 0; }\n}\n\n/** Daemon-log error count (last window) + total size. Reads only the tail so a\n * large log never makes the snapshot tick expensive. */\nexport function gatherLogStats(path: string, now: number, windowMs: number): DaemonSnapshotInputs[\"log\"] {\n let sizeBytes = 0;\n try { sizeBytes = statSync(path).size; }\n catch { return { errorCount: 0, sizeBytes: 0, windowMs }; }\n if (sizeBytes === 0) return { errorCount: 0, sizeBytes, windowMs };\n const CAP = 256 * 1024;\n const start = Math.max(0, sizeBytes - CAP);\n const len = sizeBytes - start;\n let text = \"\";\n try {\n const fd = openSync(path, \"r\");\n try {\n const buf = Buffer.alloc(len);\n readSync(fd, buf, 0, len, start);\n text = buf.toString(\"utf-8\");\n } finally { closeSync(fd); }\n } catch { return { errorCount: 0, sizeBytes, windowMs }; }\n const cutoff = now - windowMs;\n let errorCount = 0;\n for (const line of text.split(\"\\n\")) {\n if (!/error|failed/i.test(line)) continue;\n // Lines carry an ISO timestamp (\"[squadrantd] 2026-... msg\"); skip ones older\n // than the window. Lines without a parseable timestamp are counted (conservative).\n const m = line.match(/\\d{4}-\\d{2}-\\d{2}T[\\d:.]+Z/);\n if (m) { const ts = Date.parse(m[0]); if (!Number.isNaN(ts) && ts < cutoff) continue; }\n errorCount++;\n }\n return { errorCount, sizeBytes, windowMs };\n}\n\n/** Per-project store state counts + corrupt/quarantined file count. */\nexport function gatherStoreStats(\n store: { list: (p: string) => TaskRecord[] },\n stateRoot: string,\n project: string,\n): { byState: Record<string, number>; corruptCount: number } {\n const byState: Record<string, number> = {};\n for (const r of store.list(project)) byState[r.state] = (byState[r.state] ?? 0) + 1;\n let corruptCount = 0;\n const dir = join(stateRoot, project);\n try {\n for (const n of readdirSync(dir)) {\n if (n.includes(\".corrupt.\")) { corruptCount++; continue; }\n if (!n.endsWith(\".json\")) continue;\n try { JSON.parse(readFileSync(join(dir, n), \"utf-8\")); }\n catch { corruptCount++; }\n }\n } catch { /* no project dir yet */ }\n return { byState, corruptCount };\n}\n\n/** Global _results/ artifact count + total bytes (unbounded-growth watch). */\nexport function gatherResults(resultsDir: string): ResultArtifacts {\n let fileCount = 0;\n let totalBytes = 0;\n try {\n for (const n of readdirSync(resultsDir)) {\n try {\n const s = statSync(join(resultsDir, n));\n if (s.isFile()) { fileCount++; totalBytes += s.size; }\n } catch { /* vanished mid-scan */ }\n }\n } catch { /* no results dir */ }\n return { fileCount, totalBytes };\n}\n","// src/control/daemon/start.ts\n// Core daemon assembly: wires all daemon/* factories, runs boot recovery,\n// starts timers, and returns the DaemonHandle.\n// Concrete driver construction (CodexInteractiveDriver, DaemonCmux, etc.)\n// lives in the host (squadrantd.ts) — this file stays free of those imports.\nimport { join, dirname } from \"node:path\";\nimport { readdir } from \"node:fs/promises\";\nimport { createDaemon } from \"../daemon.js\";\nimport { createProbes, buildSurfaceProbe } from \"./probes.js\";\nimport { createDelivery } from \"./delivery.js\";\nimport { createGateResolver } from \"./gates.js\";\nimport { createServer } from \"./server.js\";\nimport { rotateIfNeeded, mailboxStats, readCursor } from \"../mailbox.js\";\nimport { projectHealth, type ComponentHealth } from \"../liveness.js\";\nimport type { DaemonSnapshotInputs } from \"../snapshot.js\";\nimport { loadConfig, TERMINAL_STATES, ensureCmuxAutoConfig } from \"@squadrant/shared\";\nimport { distBuiltAt, gatherLogStats, gatherStoreStats, gatherResults } from \"./snapshot-gather.js\";\nimport type { SquadrantdOpts, DaemonContext } from \"./context.js\";\n\nconst CURSOR_SUBSCRIBER = \"captain\";\nconst SNAPSHOT_LOG_WINDOW_MS = 60 * 60 * 1000;\n\nexport interface DaemonHandle {\n stop(): Promise<void>;\n tickDelivery: (() => Promise<void>) | undefined;\n tickProbe: (() => Promise<void>) | undefined;\n}\n\n/** Wire all daemon/* factories, run boot recovery, start timers.\n * ctx must already have: attach handlers, codexDriver, opencodeBridge,\n * cmuxEventsBridge, daemonCmux, daemonDirectCmux set on it by the host. */\nexport function startDaemon(ctx: DaemonContext, opts: SquadrantdOpts, pkgVersion: string): DaemonHandle {\n const {\n stateRoot, store, log, isPidAlive, resultsDir,\n taskTimeoutMs, inFlightHeadlessIds, activeHeadlessKills,\n broadcast, cancelPromotionsFor,\n } = ctx;\n const { daemonCmux } = ctx;\n\n const probes = createProbes(ctx);\n const { defaultNotify, deliveryTick: initialDeliveryTick } = createDelivery(ctx, daemonCmux);\n // Compose the Telegram outbound push onto the notify fan-out: a captain\n // notification also pushes to the project's Telegram topic. When no bridge is\n // configured, notify is the base function unchanged (zero behavior change).\n // pushLifecycle is best-effort and never throws (the bridge swallows errors),\n // so it can't delay or break captain delivery.\n const baseNotify = opts.notify ?? defaultNotify;\n const notify: DaemonContext[\"notify\"] = ctx.telegramBridge\n ? async (args) => {\n await baseNotify(args);\n ctx.telegramBridge!.pushLifecycle(args.project, args.event);\n }\n : baseNotify;\n const surfaceProbe = buildSurfaceProbe(ctx, probes, daemonCmux);\n\n const ingest = (project: string) => (e: import(\"@squadrant/shared\").ControlEvent) =>\n void ctx.d.handle({ kind: \"event\", project, event: e });\n\n const d = createDaemon({\n store, now: () => Date.now(), isPidAlive, notify, taskTimeoutMs,\n isSurfaceAlive: surfaceProbe,\n launchHeadless: opts.launchHeadless!,\n isHeadlessInFlight: (id) => inFlightHeadlessIds.has(id),\n launchInteractive: async (rec) => {\n if (rec.provider === \"codex\") {\n await ctx.codexDriver.dispatch(rec as any);\n return;\n }\n if (rec.provider === \"claude\") {\n ingest(rec.project)({ type: \"task.started\", id: rec.id });\n return;\n }\n if (rec.provider === \"opencode\") {\n ingest(rec.project)({ type: \"task.started\", id: rec.id });\n if (rec.serverPort) ctx.opencodeBridge.start({ taskId: rec.id, port: rec.serverPort });\n return;\n }\n throw new Error(\n `interactive mode is not yet implemented for provider '${rec.provider}'; only 'codex', 'claude', and 'opencode' are supported`,\n );\n },\n resolveInteractiveGate: createGateResolver(ctx),\n });\n\n ctx.d = d;\n\n // ── Health + snapshot ─────────────────────────────────────────────────────\n\n function buildHealth(only?: string): ComponentHealth[] {\n const config = loadConfig();\n const now = Date.now();\n const known = new Set<string>([\n ...Object.keys(config.projects),\n ...store.listAll().map((t) => t.project),\n ]);\n const names = only ? [only] : [...known];\n const out: ComponentHealth[] = [];\n for (const project of names) {\n const proj = config.projects[project];\n const captainName = proj?.captainName ?? `${project}-captain`;\n // Captain liveness from the delivery loop: stopped=true → gone,\n // streak===0 → alive (last tick found the surface), else unknown.\n const stopped = ctx.stoppedProjects.has(project);\n const streak = ctx.captainMissingStreak.get(project);\n const captainStopped: boolean | null = stopped ? true : streak === 0 ? false : null;\n out.push(\n ...projectHealth({\n project, now, captainName,\n captainStopped,\n commandPresent: null,\n crews: store.list(project),\n }),\n );\n }\n return out;\n }\n\n async function gatherSnapshotInputs(now: number): Promise<DaemonSnapshotInputs> {\n const logPath = join(dirname(stateRoot), \"squadrantd.log\");\n const tier2Projects = opts.registeredProjects ?? Object.keys(loadConfig().projects);\n const projects = await Promise.all(\n tier2Projects.map(async (project) => {\n const cursor = await readCursor({ stateRoot, project, subscriber: CURSOR_SUBSCRIBER });\n const storeStats = gatherStoreStats(store, stateRoot, project);\n return {\n project,\n mailbox: await mailboxStats(stateRoot, project),\n lastAckedSeq: cursor?.lastAckedSeq ?? 0,\n storeByState: storeStats.byState,\n corruptCount: storeStats.corruptCount,\n };\n }),\n );\n return {\n pid: process.pid,\n processStartedAt: ctx.bootedAt,\n version: pkgVersion,\n distBuiltAt: distBuiltAt(),\n lastSweepAt: ctx.lastSweepAt.value,\n sweepCadenceMs: opts.sweepMs ?? 30_000,\n log: gatherLogStats(logPath, now, SNAPSHOT_LOG_WINDOW_MS),\n health: buildHealth(),\n projects,\n results: gatherResults(resultsDir),\n };\n }\n\n // ── Boot recovery ─────────────────────────────────────────────────────────\n\n void (async () => {\n try { await d.reconcile(); }\n catch (e) { log(`reconcile on boot failed: ${(e as Error).message}`); }\n\n // Restart-reattach: reattach live codex crews. Guard against the storm\n // (each reattach re-spawns per-thread MCP servers). Skip terminal and stale tasks.\n // Inline predicate avoids importing from the concrete codex driver module.\n const bootNow = Date.now();\n const REATTACH_STALE_MS = 10 * 60_000;\n for (const rec of store.listAll()) {\n if (rec.provider !== \"codex\" || rec.mode !== \"interactive\") continue;\n if (TERMINAL_STATES.has(rec.state)) continue;\n // Inline of shouldReattachCodex (concrete driver module stays in host).\n const lastAttempt = rec.attempts?.at(-1);\n const last = lastAttempt?.lastHeartbeatAt ?? rec.lastHeartbeat ?? 0;\n if (bootNow - last > REATTACH_STALE_MS) continue;\n if (!lastAttempt?.resumeRef) continue;\n ctx.codexDriver.reattach(rec).catch((e: unknown) => {\n log(`reattach failed for ${rec.id}: ${(e as Error).message}`);\n });\n }\n\n // Re-subscribe opencode SSE bridge after a daemon bounce.\n for (const rec of store.listAll()) {\n if (rec.provider !== \"opencode\" || rec.mode !== \"interactive\") continue;\n if (TERMINAL_STATES.has(rec.state)) continue;\n if (!rec.serverPort) continue;\n ctx.opencodeBridge.start({ taskId: rec.id, port: rec.serverPort });\n }\n\n // B1: start cmux native-events bridge. Skipped under vitest unless injected.\n const enableCmuxEvents = loadConfig().defaults.cmuxEventsBridge !== false;\n const cmuxEventsSafe = !!opts.cmuxEventsBridge || !process.env.VITEST;\n if (enableCmuxEvents && cmuxEventsSafe) {\n try { ctx.cmuxEventsBridge.start(); }\n catch (e) { log(`cmux events bridge start failed: ${(e as Error).message}`); }\n }\n\n // Telegram inbound long-poll (opt-in). The real bridge is only constructed\n // by the host when config.telegram is present and not under vitest, so\n // ctx.telegramBridge here is either that real bridge or an injected fake.\n if (ctx.telegramBridge) {\n try { ctx.telegramBridge.start(); }\n catch (e) { log(`telegram bridge start failed: ${(e as Error).message}`); }\n }\n\n // #348: cmux socket auto-config on boot.\n const autoConfigSafe = !!opts.runCmuxAutoConfig || !process.env.VITEST;\n if (autoConfigSafe) {\n try {\n const r = await (opts.runCmuxAutoConfig ?? ensureCmuxAutoConfig)();\n if (r.configChanged) log(`cmux autoconfig: wrote automation socket mode to ${r.configPath}`);\n if (r.needsRestart && r.promptedThisRun) {\n log(\"cmux autoconfig: socket still rejects the daemon — restart cmux to enable daemon-direct delivery\");\n }\n } catch (e) {\n log(`cmux autoconfig failed: ${(e as Error).message}`);\n }\n }\n })();\n\n // ── Server + timers ───────────────────────────────────────────────────────\n\n const server = createServer(ctx, { buildHealth, gatherSnapshotInputs, cancelPromotionsFor, broadcast });\n log(`started pid=${process.pid} sock=${ctx.sockPath} stateRoot=${stateRoot}`);\n\n let deliveryTick: (() => Promise<void>) | undefined = initialDeliveryTick;\n let probeTick: (() => Promise<void>) | undefined;\n\n if (daemonCmux) {\n probeTick = probes.buildInteractiveProbe({ cmux: daemonCmux });\n }\n\n let deliveryTimer: NodeJS.Timeout | undefined;\n if (daemonCmux && opts.sweepMs && opts.sweepMs > 0) {\n deliveryTimer = setInterval(() => {\n void deliveryTick!().catch((e: unknown) => log(`delivery tick error: ${(e as Error).message}`));\n }, 1000);\n deliveryTimer.unref?.();\n }\n\n let probeTimer: NodeJS.Timeout | undefined;\n if (daemonCmux && opts.sweepMs && opts.sweepMs > 0) {\n probeTimer = setInterval(() => {\n void probeTick!().catch((e: unknown) => log(`probe tick error: ${(e as Error).message}`));\n }, 10_000);\n probeTimer.unref?.();\n }\n\n let timer: NodeJS.Timeout | undefined;\n if (opts.sweepMs && opts.sweepMs > 0) {\n let sweeping = false;\n timer = setInterval(() => {\n if (sweeping) return;\n sweeping = true;\n ctx.lastSweepAt.value = Date.now();\n void d.sweep()\n .catch((e: unknown) => log(`sweep failed: ${(e as Error).message}`))\n .finally(() => { sweeping = false; });\n }, opts.sweepMs);\n timer.unref?.();\n }\n\n const rotationInterval = opts.rotationIntervalMs ?? 60_000;\n const mboxCfg = {\n maxBytes: opts.mailboxConfig?.maxBytes ?? 5 * 1024 * 1024,\n maxAgeMs: opts.mailboxConfig?.maxAgeMs ?? 7 * 24 * 60 * 60 * 1000,\n keepCount: opts.mailboxConfig?.keepCount ?? 3,\n };\n let rotationTimer: NodeJS.Timeout | undefined;\n if (rotationInterval > 0) {\n const inboxPath = join(stateRoot, \"inbox\");\n rotationTimer = setInterval(async () => {\n try {\n let entries: string[];\n try { entries = await readdir(inboxPath); } catch { return; }\n const projects = new Set(\n entries.filter((e) => e.endsWith(\".log\")).map((e) => e.slice(0, -\".log\".length)),\n );\n for (const project of projects) await rotateIfNeeded({ stateRoot, project, ...mboxCfg });\n } catch (e) {\n log(`rotation timer error: ${(e as Error).message}`);\n }\n }, rotationInterval);\n rotationTimer.unref?.();\n }\n\n return {\n stop(): Promise<void> {\n if (deliveryTimer) clearInterval(deliveryTimer);\n if (probeTimer) clearInterval(probeTimer);\n if (timer) clearInterval(timer);\n if (rotationTimer) clearInterval(rotationTimer);\n try { ctx.cmuxEventsBridge.stop(); } catch { /* best-effort */ }\n try { ctx.telegramBridge?.stop(); } catch { /* best-effort */ }\n try { ctx.codexDriver.stop?.(); } catch { /* best-effort */ }\n for (const kill of ctx.activeHeadlessKills) kill();\n return new Promise<void>((resolve) => server.close(() => { log(\"stopped\"); resolve(); }));\n },\n tickDelivery: deliveryTick,\n tickProbe: probeTick,\n };\n}\n","// Session freshness logic — daily + templateHash rotation.\n// Extracted from packages/cli/src/commands/launch.ts so it can be\n// unit-tested without spawning real processes.\n\nimport crypto from \"node:crypto\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\n\nexport interface SessionRecord {\n lastLaunched: string; // YYYY-MM-DD\n templateHash: string;\n}\n\nexport interface SessionsFile {\n workspaces: Record<string, SessionRecord>;\n}\n\nexport function loadSessions(sessionsPath: string): SessionsFile {\n try {\n return JSON.parse(fs.readFileSync(sessionsPath, \"utf-8\")) as SessionsFile;\n } catch {\n return { workspaces: {} };\n }\n}\n\nexport function saveSessions(sessionsPath: string, sessions: SessionsFile): void {\n const dir = path.dirname(sessionsPath);\n fs.mkdirSync(dir, { recursive: true });\n fs.writeFileSync(sessionsPath, JSON.stringify(sessions, null, 2) + \"\\n\");\n}\n\nexport function computeTemplateHash(role: string, templatesDir: string): string {\n const hash = crypto.createHash(\"sha256\");\n\n const roleFile = path.join(templatesDir, `${role}.claude.md`);\n const legacyRoleFile = path.join(templatesDir, `${role}.CLAUDE.md`);\n if (fs.existsSync(roleFile)) {\n hash.update(fs.readFileSync(roleFile, \"utf-8\"));\n } else if (fs.existsSync(legacyRoleFile)) {\n hash.update(fs.readFileSync(legacyRoleFile, \"utf-8\"));\n }\n\n const pluginSkillsDir = path.join(templatesDir, \"..\", \"plugin\", \"skills\");\n if (fs.existsSync(pluginSkillsDir)) {\n for (const skill of fs.readdirSync(pluginSkillsDir).sort()) {\n const skillFile = path.join(pluginSkillsDir, skill, \"SKILL.md\");\n if (fs.existsSync(skillFile)) {\n hash.update(fs.readFileSync(skillFile, \"utf-8\"));\n }\n }\n }\n\n return hash.digest(\"hex\").slice(0, 16);\n}\n\nexport function shouldStartFresh(\n workspaceName: string,\n role: string,\n opts: { sessionsPath: string; templatesDir: string },\n): { fresh: boolean; reason?: string } {\n const sessions = loadSessions(opts.sessionsPath);\n const record = sessions.workspaces[workspaceName];\n const today = new Date().toISOString().slice(0, 10);\n const currentHash = computeTemplateHash(role, opts.templatesDir);\n\n if (!record) {\n return { fresh: true, reason: \"first launch\" };\n }\n\n if (record.lastLaunched !== today) {\n return { fresh: true, reason: \"new day — starting fresh session\" };\n }\n\n if (record.templateHash !== currentHash) {\n return { fresh: true, reason: \"template instructions updated\" };\n }\n\n return { fresh: false };\n}\n\nexport function recordSession(\n workspaceName: string,\n role: string,\n opts: { sessionsPath: string; templatesDir: string },\n): void {\n const sessions = loadSessions(opts.sessionsPath);\n sessions.workspaces[workspaceName] = {\n lastLaunched: new Date().toISOString().slice(0, 10),\n templateHash: computeTemplateHash(role, opts.templatesDir),\n };\n saveSessions(opts.sessionsPath, sessions);\n}\n","// Pure crew protocol and naming primitives — no I/O, no external-package deps.\n// Extracted from packages/cli/src/commands/crew.ts so they are unit-testable\n// and importable by packages other than cli.\n\n/** Configuration for the post-send acceptance check that replaces a naive\n * screen-changed comparison. For agents whose idle splash keeps mutating\n * (opencode's \"Ask anything…\" with blinking cursor / status line), the old\n * check would always see a different screen and never re-send a dropped turn. */\nexport interface TurnAcceptanceConfig {\n /** Text that identifies the idle splash state. When set, acceptance requires\n * this marker to be absent from the screen (e.g. \"Ask anything…\" for opencode).\n * Without it, acceptance defaults to \"screen changed\" (claude behavior). */\n splashMarker?: string;\n /** Max rounds of \"wait, check, re-send\" after the initial send. Defaults to 2\n * (initial + 1 re-send) to match the pre-retry behavior for claude. Use 3 for\n * opencode which has a wider boot-race window. */\n retryLimit?: number;\n}\n\n/** Pure-function decision: was the first turn accepted by the TUI?\n * - With splashMarker: accepted = the marker is no longer visible (the TUI left\n * its idle splash, confirming the keystroke was received).\n * - Without splashMarker (claude): accepted = the screen changed after sending. */\nexport function isTurnAccepted(\n preSendScreen: string,\n afterScreen: string,\n config?: TurnAcceptanceConfig,\n): boolean {\n if (config?.splashMarker) {\n return !afterScreen.includes(config.splashMarker);\n }\n return afterScreen !== preSendScreen;\n}\n\n/** Builds the completion-protocol suffix baked into claude + opencode first turns (#278).\n * Substituting --task-id and --project at source makes the signal robust to env-var\n * races (Mode 1) and gives the model a concrete imperative at the point of action (Mode 2).\n *\n * WARNING: The exact output text is load-bearing — a single byte change silently\n * breaks crew DONE. Any modification must be validated against the crew-lifecycle\n * checklist CP-DONE checkpoint. A snapshot test guards against drift. */\nexport function buildCompletionProtocol(taskId: string, project: string): string {\n return [\n \"---\",\n \"COMPLETION PROTOCOL (required): When this task is fully complete, your FINAL action MUST be to run exactly:\",\n ` squadrant crew signal done --task-id ${taskId} --project ${project} --message \"<one-line summary>\"`,\n \"Run it as a discrete final step AFTER you report your results. If you are blocked or need a decision, instead run:\",\n ` squadrant crew signal blocked --task-id ${taskId} --project ${project} --question \"<your question>\"`,\n \"If this task failed because of a defect in squadrant itself (not an API/infra blip, a config/user error, or an expected failure), say so in your signal done/blocked message so the captain can check tu11aa/squadrant and file it. Don't file issues from the crew.\",\n ].join(\"\\n\");\n}\n\n// POSIX single-quote a path so it is safe to embed in a shell command even\n// when the path contains spaces or special characters.\nexport function shellQuote(p: string): string {\n return \"'\" + p.replace(/'/g, \"'\\\\''\") + \"'\";\n}\n\nexport function titleFor(project: string, name: string): string {\n return `🔧 ${project}:${name}`;\n}\n\nexport function isCrewTitle(project: string, title: string): boolean {\n return title.startsWith(`🔧 ${project}:`);\n}\n\nexport function nameFromTitle(project: string, title: string): string {\n return title.slice(`🔧 ${project}:`.length);\n}\n\nexport function nextAutoName(existingTitles: string[], project: string): string {\n const used = new Set<number>();\n for (const title of existingTitles) {\n const n = nameFromTitle(project, title).match(/^crew-(\\d+)$/);\n if (n) used.add(Number(n[1]));\n }\n let i = 1;\n while (used.has(i)) i++;\n return `crew-${i}`;\n}\n","// Crew child-process lifecycle management.\n// Extracted from packages/cli/src/commands/crew.ts so it is importable from\n// packages other than cli and testable with an injected exec function.\n\nimport { exec as nodeExec } from \"node:child_process\";\n\ntype ExecFn = (\n cmd: string,\n opts: { maxBuffer: number },\n cb: (err: Error | null, stdout: string) => void,\n) => void;\n\n/** Kill every process that inherited SQUADRANT_CREW_TASK_ID=<taskId> from the\n * crew's shell env prefix. Uses `ps auxE` which exposes env vars for node\n * processes on macOS (vitest workers, the crew CLI, etc.). Best-effort:\n * swallows all errors so a childless crew still closes cleanly.\n *\n * @param graceMs - ms between SIGTERM and SIGKILL (default 2 s; pass a short\n * value in tests to avoid waiting)\n * @param execFn - injectable for testing; defaults to node:child_process.exec\n */\nexport async function reapCrewChildren(\n taskId: string,\n graceMs = 2000,\n execFn: ExecFn = nodeExec,\n): Promise<void> {\n const marker = `SQUADRANT_CREW_TASK_ID=${taskId}`;\n try {\n const stdout = await new Promise<string>((resolve, reject) => {\n // `ps auxE` dumps every process's full env, which on a busy machine far\n // exceeds exec's default 1 MB maxBuffer (~2.7 MB with ~1k procs). Without\n // a raised cap the call errors with \"maxBuffer length exceeded\", the outer\n // catch swallows it, and the reap silently no-ops — leaving crew children\n // alive. 64 MB comfortably covers thousands of processes.\n execFn(\"ps auxE\", { maxBuffer: 64 * 1024 * 1024 }, (err, out) =>\n err ? reject(err) : resolve(out),\n );\n });\n const pids: number[] = [];\n for (const line of stdout.split(\"\\n\").slice(1)) {\n if (!line.includes(marker)) continue;\n const pid = parseInt(line.trim().split(/\\s+/)[1], 10);\n if (!isNaN(pid) && pid !== process.pid) pids.push(pid);\n }\n if (pids.length === 0) return;\n for (const pid of pids) {\n try { process.kill(pid, \"SIGTERM\"); } catch { /* already gone */ }\n }\n await new Promise<void>((r) => setTimeout(r, graceMs));\n for (const pid of pids) {\n try { process.kill(pid, \"SIGKILL\"); } catch { /* already gone */ }\n }\n } catch { /* best-effort */ }\n}\n","export const BOT_COMMANDS: Array<{ command: string; description: string }> = [\n { command: \"status\", description: \"squadrant status\" },\n { command: \"projects\", description: \"list registered projects\" },\n { command: \"crews\", description: \"list crews for a project\" },\n { command: \"launch\", description: \"launch a project's captain\" },\n { command: \"effort\", description: \"set effort: max | balance | low\" },\n { command: \"spawn\", description: \"spawn a crew (guided)\" },\n { command: \"notify\", description: \"notification panel for a project topic\" },\n { command: \"mute\", description: \"mute a project's topic\" },\n { command: \"unmute\", description: \"unmute a project's topic\" },\n { command: \"help\", description: \"list commands\" },\n];\n","// Pure auth predicates for the Telegram CONTROL surfaces (auto-launch, general\n// commands). No I/O. Fail-closed: control requires both the master switch and a\n// user-id match — chat membership alone is never enough for control.\nimport type { TelegramConfig } from \"@squadrant/shared\";\n\nexport function isControlEnabled(cfg: TelegramConfig): boolean {\n return cfg.remoteControl === true;\n}\n\nexport function isAuthorized(fromId: number | undefined, cfg: TelegramConfig): boolean {\n if (fromId === undefined) return false;\n return Array.isArray(cfg.users) && cfg.users.includes(fromId);\n}\n","// Curated registry for the Telegram GENERAL command channel (#402). Pure logic:\n// parses \"/cmd args\" into a squadrant CLI argv vector — never a shell string. No\n// I/O, no execution (Task 5 wires argv → async execFile). Default-deny on\n// /config set: only WRITABLE_CONFIG_KEYS may be written over Telegram, so secrets\n// (botToken/users/chats/supergroupId) can never be set from the phone.\n//\n// argv tokens are verified against the real CLI (packages/cli/src/commands/):\n// status → `status`, projects → `projects list`, crews → `crew list <p>`,\n// launch → `launch <p>`, effort → `effort [mode]`, config → `config get|set`,\n// spawn → `crew spawn <p> <task>`.\n\nexport type ParsedCommand =\n | { kind: \"ok\"; name: string; argv: string[] } // argv to pass to the squadrant CLI\n | { kind: \"usage\"; name: string; message: string } // known command, bad args\n | { kind: \"unknown\"; message: string } // not in registry / not a slash command\n | { kind: \"denied\"; message: string }; // e.g. /config set on a protected key\n\n/** Default-deny allowlist of config keys writable over Telegram (#321). Starts\n * intentionally tiny; extend deliberately. Secrets are NEVER added here. */\nexport const WRITABLE_CONFIG_KEYS: readonly string[] = [\"defaults.effort\"];\n\nconst EFFORT_MODES = new Set([\"max\", \"balance\", \"low\"]);\n\ninterface Entry {\n /** Build the argv (or a usage/denied result) from the post-name token list. */\n build(args: string[]): ParsedCommand;\n usage: string;\n}\n\nfunction ok(name: string, argv: string[]): ParsedCommand {\n return { kind: \"ok\", name, argv };\n}\nfunction usage(name: string, message: string): ParsedCommand {\n return { kind: \"usage\", name, message };\n}\n\nconst REGISTRY: Record<string, Entry> = {\n status: { usage: \"/status\", build: () => ok(\"status\", [\"status\"]) },\n projects: { usage: \"/projects\", build: () => ok(\"projects\", [\"projects\", \"list\"]) },\n crews: {\n usage: \"/crews <project>\",\n build: (a) => (a[0] ? ok(\"crews\", [\"crew\", \"list\", a[0]]) : usage(\"crews\", \"usage: /crews <project>\")),\n },\n launch: {\n usage: \"/launch <project>\",\n build: (a) => (a[0] ? ok(\"launch\", [\"launch\", a[0]]) : usage(\"launch\", \"usage: /launch <project>\")),\n },\n effort: {\n usage: \"/effort [max|balance|low]\",\n build: (a) => {\n if (a.length === 0) return ok(\"effort\", [\"effort\"]);\n if (!EFFORT_MODES.has(a[0])) return usage(\"effort\", \"usage: /effort [max|balance|low]\");\n return ok(\"effort\", [\"effort\", a[0]]);\n },\n },\n config: {\n usage: \"/config get <key> | /config set <key> <value>\",\n build: (a) => {\n const sub = a[0];\n if (sub === \"get\") {\n const key = a[1];\n if (!key) return usage(\"config\", \"usage: /config get <key>\");\n return ok(\"config\", [\"config\", \"get\", key]);\n }\n if (sub === \"set\") {\n const key = a[1];\n const value = a.slice(2).join(\" \");\n if (!key || value === \"\") return usage(\"config\", \"usage: /config set <key> <value>\");\n if (!WRITABLE_CONFIG_KEYS.includes(key)) {\n return {\n kind: \"denied\",\n message: `⛔ '${key}' is not writable over Telegram. Allowed: ${WRITABLE_CONFIG_KEYS.join(\", \")}`,\n };\n }\n return ok(\"config\", [\"config\", \"set\", key, value]);\n }\n return usage(\"config\", \"usage: /config get <key> | /config set <key> <value>\");\n },\n },\n spawn: {\n usage: \"/spawn <project> <task...>\",\n build: (a) => {\n const project = a[0];\n const task = a.slice(1).join(\" \");\n if (!project || task === \"\") return usage(\"spawn\", \"usage: /spawn <project> <task...>\");\n return ok(\"spawn\", [\"crew\", \"spawn\", project, task]);\n },\n },\n mute: {\n usage: \"/mute <project>\",\n build: (a) => (a[0] ? ok(\"mute\", [\"telegram\", \"notify\", a[0], \"off\"]) : usage(\"mute\", \"usage: /mute <project>\")),\n },\n unmute: {\n usage: \"/unmute <project>\",\n build: (a) => (a[0] ? ok(\"unmute\", [\"telegram\", \"notify\", a[0], \"on\"]) : usage(\"unmute\", \"usage: /unmute <project>\")),\n },\n};\n\nfunction helpText(): string {\n const lines = Object.values(REGISTRY).map((e) => ` ${e.usage}`);\n return [\"Available commands:\", ...lines, \" /help\"].join(\"\\n\");\n}\n\n/** Strip the `@botname` suffix Telegram appends to menu-tapped commands in groups. */\nexport function stripBotMention(token: string): string {\n return token.split(\"@\")[0];\n}\n\n/** Parse a raw Telegram message into a curated command. Non-slash text and\n * unregistered commands return `unknown`. */\nexport function parseCommand(text: string): ParsedCommand {\n const trimmed = text.trim();\n if (!trimmed.startsWith(\"/\")) {\n return { kind: \"unknown\", message: \"unknown command — send /help\" };\n }\n const tokens = trimmed.slice(1).split(/\\s+/).filter((t) => t.length > 0);\n const name = stripBotMention(tokens[0] ?? \"\").toLowerCase();\n const args = tokens.slice(1);\n\n if (name === \"help\") {\n return { kind: \"usage\", name: \"help\", message: helpText() };\n }\n const entry = REGISTRY[name];\n if (!entry) {\n return { kind: \"unknown\", message: `unknown command '/${name}' — send /help` };\n }\n return entry.build(args);\n}\n","// Boot-if-down capability for Telegram auto-launch (#403). Mirrors the\n// `group dispatch` warmup pattern (liveness probe → spawn `squadrant launch` →\n// bounded warmup poll) but as an injectable factory: deps are stubbed in tests\n// and wired from the daemon host (Task 5). The bridge stays decoupled from\n// captain lifecycle — it only sees the returned `ensure(project)` closure.\n//\n// Debounce: concurrent calls for the same project share ONE launch + poll loop\n// via an in-flight promise map, so a burst of inbound messages can't spawn N\n// captains. The map entry clears on resolution (alive | launched | timeout).\n\nexport type EnsureResult = \"alive\" | \"launched\" | \"timeout\";\n\nexport interface EnsureCaptainDeps {\n isAlive: (project: string) => Promise<boolean>; // liveness probe\n launch: (project: string) => Promise<void>; // spawn `squadrant launch <project>`\n warmupTimeoutMs?: number; // default 120_000\n pollMs?: number; // default 1_000\n sleep?: (ms: number) => Promise<void>; // injectable for tests\n now?: () => number; // injectable for tests\n}\n\nconst DEFAULT_WARMUP_TIMEOUT_MS = 120_000;\nconst DEFAULT_POLL_MS = 1_000;\nconst defaultSleep = (ms: number) => new Promise<void>((r) => setTimeout(r, ms));\n\nexport function createEnsureCaptainAlive(\n deps: EnsureCaptainDeps,\n): (project: string) => Promise<EnsureResult> {\n const warmupTimeoutMs = deps.warmupTimeoutMs ?? DEFAULT_WARMUP_TIMEOUT_MS;\n const pollMs = deps.pollMs ?? DEFAULT_POLL_MS;\n const sleep = deps.sleep ?? defaultSleep;\n const now = deps.now ?? (() => Date.now());\n\n const inFlight = new Map<string, Promise<EnsureResult>>();\n\n async function run(project: string): Promise<EnsureResult> {\n if (await deps.isAlive(project)) return \"alive\";\n await deps.launch(project);\n const deadline = now() + warmupTimeoutMs;\n while (now() < deadline) {\n if (await deps.isAlive(project)) return \"launched\";\n await sleep(pollMs);\n }\n return \"timeout\";\n }\n\n return function ensure(project: string): Promise<EnsureResult> {\n // The guard is read+set synchronously (no await before set) so concurrent\n // callers for the same project provably share a single launch.\n const existing = inFlight.get(project);\n if (existing) return existing;\n const p = run(project).finally(() => inFlight.delete(project));\n inFlight.set(project, p);\n return p;\n };\n}\n","// Pure formatters for the Telegram bridge. No I/O, no side effects.\nimport type { ControlEvent } from \"@squadrant/shared\";\n\n/** Forum-topic title for a project. v1 uses the project name verbatim. */\nexport function topicName(project: string): string {\n return project;\n}\n\n/** Outbound text pushed to a project's Telegram topic for a lifecycle event. */\nexport function formatLifecycle(project: string, ev: ControlEvent): string {\n switch (ev.type) {\n case \"task.done\":\n return `✅ [${project}] CREW DONE · ${ev.id}` + (ev.message ? `\\n${ev.message}` : \"\");\n case \"task.blocked\":\n return `🚧 [${project}] CREW BLOCKED · ${ev.id}\\n${ev.question}`;\n case \"task.idle\":\n return `💤 [${project}] CREW IDLE · ${ev.id}`;\n case \"task.failed\":\n return `❌ [${project}] CREW FAILED · ${ev.id}\\n${ev.error}`;\n case \"task.approval.requested\":\n return `🔐 [${project}] APPROVAL NEEDED · ${ev.id}\\n${ev.question}`;\n case \"task.input.requested\":\n return `❓ [${project}] INPUT NEEDED · ${ev.id}\\n${ev.question}`;\n case \"task.timeout\":\n return `⏱️ [${project}] CREW TIMEOUT · ${ev.id}`;\n default:\n return `ℹ️ [${project}] ${ev.type} · ${ev.id}`;\n }\n}\n\n/** Captain-pane rendering of an inbound Telegram reply — labeled as external. */\nexport function formatInbound(text: string): string {\n return `📩 [from Telegram] ${text}`;\n}\n\n/** Mask all but the last 4 characters of a bot token for safe display. */\nexport function maskToken(token: string): string {\n if (token.length <= 4) return token;\n return \"*\".repeat(token.length - 4) + token.slice(-4);\n}\n","// Persisted Telegram bridge state: getUpdates offset + (project,scope) → topicId\n// registry. Synchronous JSON in stateRoot/telegram-state.json.\nimport fs from \"node:fs\";\nimport path from \"node:path\";\n\nexport interface TelegramState {\n offset: number;\n /** key = `${project}::${scope}` (see topicKey); value = message_thread_id. */\n topics: Record<string, number>;\n /** key = project; value = true when active. Absent/false = MUTED (default). */\n notify: Record<string, boolean>;\n /** Last seen inbound message sender — populated passively by the bridge poll. */\n lastUserId?: number;\n}\n\nfunction statePath(stateRoot: string): string {\n return path.join(stateRoot, \"telegram-state.json\");\n}\n\n/** Registry key for a topic. v1 only ever uses scope \"project\"; per-crew routing\n * (scope \"crew:<taskId>\") is additive later without a schema change. */\nexport function topicKey(project: string, scope = \"project\"): string {\n return `${project}::${scope}`;\n}\n\nexport function loadState(stateRoot: string): TelegramState {\n try {\n const raw = fs.readFileSync(statePath(stateRoot), \"utf-8\");\n const data = JSON.parse(raw) as Partial<TelegramState>;\n const result: TelegramState = {\n offset: typeof data.offset === \"number\" ? data.offset : 0,\n topics: data.topics ?? {},\n notify: data.notify ?? {},\n };\n if (typeof data.lastUserId === \"number\") result.lastUserId = data.lastUserId;\n return result;\n } catch {\n return { offset: 0, topics: {}, notify: {} };\n }\n}\n\nexport function saveState(stateRoot: string, s: TelegramState): void {\n fs.mkdirSync(stateRoot, { recursive: true });\n fs.writeFileSync(statePath(stateRoot), JSON.stringify(s, null, 2) + \"\\n\");\n}\n\nexport function setTopic(\n stateRoot: string,\n project: string,\n topicId: number,\n scope = \"project\",\n): void {\n const s = loadState(stateRoot);\n s.topics[topicKey(project, scope)] = topicId;\n saveState(stateRoot, s);\n}\n\nexport function isNotifyActive(stateRoot: string, project: string): boolean {\n return loadState(stateRoot).notify[project] === true;\n}\n\nexport function setLastUserId(stateRoot: string, id: number): void {\n const s = loadState(stateRoot);\n s.lastUserId = id;\n saveState(stateRoot, s);\n}\n\nexport function setNotify(stateRoot: string, project: string, active: boolean): void {\n const s = loadState(stateRoot);\n s.notify[project] = active;\n saveState(stateRoot, s);\n}\n\nexport function findProjectByThread(\n stateRoot: string,\n threadId: number,\n): { project: string; scope: string } | null {\n const s = loadState(stateRoot);\n for (const [key, id] of Object.entries(s.topics)) {\n if (id !== threadId) continue;\n const sep = key.indexOf(\"::\");\n if (sep === -1) continue;\n return { project: key.slice(0, sep), scope: key.slice(sep + 2) };\n }\n return null;\n}\n","// Telegram Bot API over plain fetch — no runtime SDK (keeps the tsup single\n// binary lean). @grammyjs/types is a devDependency: type-only, erased at build.\nimport type { Update } from \"@grammyjs/types\";\n\nexport interface TelegramClient {\n /** Long-poll for updates. timeoutSec is the Bot API `timeout` (default 50s). */\n getUpdates(offset: number, timeoutSec?: number): Promise<Update[]>;\n sendMessage(chatId: number, threadId: number | undefined, text: string, replyMarkup?: unknown): Promise<void>;\n /** Answer a callback_query — REQUIRED on every tap path or the spinner hangs ~15s. */\n answerCallbackQuery(callbackQueryId: string, text?: string): Promise<void>;\n /** Replace an existing message's inline keyboard (panel re-render). */\n editMessageReplyMarkup(chatId: number, messageId: number, replyMarkup: unknown): Promise<void>;\n /** Returns the new topic's message_thread_id. */\n createForumTopic(chatId: number, name: string): Promise<number>;\n /** Verify the bot token and return the bot identity. */\n getMe(): Promise<{ id: number; username: string }>;\n /** Register the bot's command menu with Telegram. */\n setMyCommands(commands: Array<{ command: string; description: string }>): Promise<void>;\n}\n\ninterface TgResponse<T> {\n ok: boolean;\n result?: T;\n error_code?: number;\n description?: string;\n}\n\nexport function createTelegramClient(opts: { token: string; fetch?: typeof fetch }): TelegramClient {\n const fetchImpl = opts.fetch ?? fetch;\n const base = `https://api.telegram.org/bot${opts.token}`;\n\n async function call<T>(method: string, body: Record<string, unknown>): Promise<T> {\n const res = await fetchImpl(`${base}/${method}`, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify(body),\n });\n const json = (await res.json()) as TgResponse<T>;\n if (!res.ok || !json.ok) {\n const code = json.error_code ?? res.status;\n const desc = json.description ?? \"unknown error\";\n throw new Error(`telegram ${method} failed (${code}): ${desc}`);\n }\n return json.result as T;\n }\n\n return {\n async getMe() {\n const r = await call<{ id: number; username: string }>(\"getMe\", {});\n return { id: r.id, username: r.username };\n },\n getUpdates(offset, timeoutSec = 50) {\n return call<Update[]>(\"getUpdates\", { offset, timeout: timeoutSec });\n },\n async sendMessage(chatId, threadId, text, replyMarkup) {\n const body: Record<string, unknown> = { chat_id: chatId, text };\n if (threadId !== undefined) body.message_thread_id = threadId;\n if (replyMarkup !== undefined) body.reply_markup = replyMarkup;\n await call<unknown>(\"sendMessage\", body);\n },\n async answerCallbackQuery(callbackQueryId, text) {\n const body: Record<string, unknown> = { callback_query_id: callbackQueryId };\n if (text !== undefined) body.text = text;\n await call<unknown>(\"answerCallbackQuery\", body);\n },\n async editMessageReplyMarkup(chatId, messageId, replyMarkup) {\n await call<unknown>(\"editMessageReplyMarkup\", { chat_id: chatId, message_id: messageId, reply_markup: replyMarkup });\n },\n async createForumTopic(chatId, name) {\n const r = await call<{ message_thread_id: number }>(\"createForumTopic\", { chat_id: chatId, name });\n return r.message_thread_id;\n },\n async setMyCommands(commands) {\n await call<boolean>(\"setMyCommands\", { commands });\n },\n };\n}\n","// Pure inline-keyboard builders + callback_data codec for tap-first Telegram\n// commands. No I/O — unit-tested independent of the bridge. callback_data is\n// prefix-routed and kept ≤64 bytes (Bot API limit).\nimport type { NotifyConfig, CrewTier } from \"@squadrant/shared\";\n\nexport type InlineButton = { text: string; callback_data: string };\nexport type InlineKeyboard = { inline_keyboard: InlineButton[][] };\n\nexport type PickAction = \"cr\" | \"lc\" | \"mu\" | \"um\";\n\nexport type ParsedCallback =\n | { t: \"notify\"; dim: \"cap\" | \"crew\" | \"active\"; val: string }\n | { t: \"effort\"; mode: string }\n | { t: \"pick\"; action: PickAction; project: string }\n | { t: \"spawn\"; project: string };\n\n/** Prefix the label with a bullet when it represents the current state. */\nconst mark = (on: boolean, label: string): string => (on ? `• ${label}` : label);\n\n// Curated crew-tier subset shown as a pick-one row (done_only is reachable via\n// the typed `/notify crew done_only` form for power users).\nconst TIERS: CrewTier[] = [\"none\", \"alert_only\", \"all\"];\n\nexport function notifyPanel(s: NotifyConfig): InlineKeyboard {\n return {\n inline_keyboard: [\n [{ text: `Captain: ${s.cap ? \"ON\" : \"OFF\"}`, callback_data: `n:cap:${s.cap ? \"off\" : \"on\"}` }],\n TIERS.map((t) => ({ text: mark(s.crew === t, `crew:${t}`), callback_data: `n:crew:${t}` })),\n [{ text: s.active ? \"🔕 Mute topic\" : \"🔔 Unmute\", callback_data: `n:active:${s.active ? \"off\" : \"on\"}` }],\n ],\n };\n}\n\nexport function effortPanel(current: \"max\" | \"balance\" | \"low\"): InlineKeyboard {\n const modes = [\"max\", \"balance\", \"low\"] as const;\n return {\n inline_keyboard: [modes.map((m) => ({ text: mark(current === m, m), callback_data: `e:${m}` }))],\n };\n}\n\nexport function projectPicker(action: PickAction, projects: string[]): InlineKeyboard {\n return { inline_keyboard: projects.map((p) => [{ text: p, callback_data: `${action}:${p}` }]) };\n}\n\n// Guided /spawn (slice 2). The picker emits `sp:<project>`; tapping one sends a\n// ForceReply prompt whose text encodes the project behind SPAWN_PROMPT_PREFIX, so\n// the reply can be routed to `crew spawn` statelessly (no pending-spawn map).\nexport const SPAWN_PROMPT_PREFIX = \"🆕 Reply with the task for a crew on: \";\n\nexport function buildSpawnPrompt(project: string): string {\n return `${SPAWN_PROMPT_PREFIX}${project}`;\n}\n\nexport function parseSpawnPrompt(text: string | undefined): string | null {\n if (!text || !text.startsWith(SPAWN_PROMPT_PREFIX)) return null;\n const project = text.slice(SPAWN_PROMPT_PREFIX.length).trim();\n return project.length > 0 ? project : null;\n}\n\nexport function spawnPicker(projects: string[]): InlineKeyboard {\n return { inline_keyboard: projects.map((p) => [{ text: p, callback_data: `sp:${p}` }]) };\n}\n\nconst PICK_ACTIONS: PickAction[] = [\"cr\", \"lc\", \"mu\", \"um\"];\n\nexport function parseCallback(data: string): ParsedCallback | null {\n const parts = data.split(\":\");\n if (parts[0] === \"n\" && (parts[1] === \"cap\" || parts[1] === \"crew\" || parts[1] === \"active\") && parts[2]) {\n return { t: \"notify\", dim: parts[1], val: parts[2] };\n }\n if (parts[0] === \"e\" && parts[1]) return { t: \"effort\", mode: parts[1] };\n if (PICK_ACTIONS.includes(parts[0] as PickAction) && parts[1]) {\n return { t: \"pick\", action: parts[0] as PickAction, project: parts.slice(1).join(\":\") };\n }\n if (parts[0] === \"sp\" && parts[1]) return { t: \"spawn\", project: parts.slice(1).join(\":\") };\n return null;\n}\n","// Crew notification tier → event-type membership. Tiers are cumulative:\n// done_only ⊂ alert_only ⊂ all. See the layered-notification design.\nimport type { CrewTier } from \"@squadrant/shared\";\n\nconst DONE_ONLY = new Set([\"task.done\", \"task.failed\"]);\nconst ALERTS = new Set([\n ...DONE_ONLY,\n \"task.blocked\",\n \"task.approval.requested\",\n \"task.input.requested\",\n \"task.timeout\",\n]);\n\nexport function tierIncludes(tier: CrewTier, eventType: string): boolean {\n switch (tier) {\n case \"none\": return false;\n case \"done_only\": return DONE_ONLY.has(eventType);\n case \"alert_only\": return ALERTS.has(eventType);\n case \"all\": return true;\n }\n}\n","// Daemon-internal Telegram subsystem (modeled on CmuxEventsBridge). Owns one\n// outbound hook (pushLifecycle) and one inbound getUpdates long-poll. Opt-in and\n// crash-contained: no send/poll error may escape into the daemon.\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport type { ControlEvent, CrewTier, NotifyConfig, TelegramConfig } from \"@squadrant/shared\";\nimport { resolveNotify, loadProjectOverride, saveProjectOverride, loadConfig } from \"@squadrant/shared\";\nimport type { TelegramClient } from \"./client.js\";\nimport { isAuthorized, isControlEnabled } from \"./auth.js\";\nimport { parseCommand, stripBotMention } from \"./commands.js\";\nimport type { EnsureResult } from \"./ensure-captain.js\";\nimport { formatInbound, formatLifecycle, topicName } from \"./format.js\";\nimport { buildSpawnPrompt, effortPanel, notifyPanel, parseCallback, parseSpawnPrompt, projectPicker, spawnPicker, type PickAction } from \"./panels.js\";\nimport { findProjectByThread, loadState, saveState, setLastUserId, setNotify, setTopic, topicKey } from \"./state.js\";\nimport { tierIncludes } from \"./tiers.js\";\n\n/** A Telegram callback_query (button tap). Narrowed to the fields the bridge uses. */\ninterface CallbackQuery {\n id: string;\n from?: { id: number };\n message?: { chat: { id: number }; message_id: number; message_thread_id?: number };\n data?: string;\n}\n\nexport interface TelegramBridge {\n start(): void;\n stop(): void;\n /** Outbound, best-effort: a Telegram failure is swallowed (logged), never thrown. */\n pushLifecycle(project: string, ev: ControlEvent): void;\n}\n\nexport interface TelegramBridgeOptions {\n cfg: TelegramConfig;\n stateRoot: string;\n /** Root for per-project override files. Defaults to ~/.config/squadrant. */\n configRoot?: string;\n client: TelegramClient;\n appendCaptainMessage: (a: { stateRoot: string; project: string; text: string; source: \"telegram\" }) => Promise<void>;\n log: (msg: string) => void;\n // ── Control surfaces (#402/#403/#321) — all optional. When undefined the bridge\n // keeps exact v1 behavior (queue-only project topics, General topic dropped).\n /** Boot-if-down before delivering to a project topic. Injected by the daemon host. */\n ensureCaptainAlive?: (project: string) => Promise<EnsureResult>;\n /** Execute a curated squadrant CLI argv and return capped output. */\n runCommand?: (argv: string[]) => Promise<string>;\n /** Post a reply to the General topic (threadId undefined) or a project topic.\n * The optional replyMarkup attaches an inline-button panel (tap-first commands). */\n sendReply?: (threadId: number | undefined, text: string, replyMarkup?: unknown) => Promise<void>;\n}\n\n// Bot API long-poll window. The loop also sleeps cfg.pollMs between iterations so\n// a fast-returning poll can't busy-loop.\nconst LONG_POLL_SEC = 50;\n\nconst sleep = (ms: number) => new Promise<void>((r) => setTimeout(r, ms));\n\nconst CREW_TIERS = [\"all\", \"alert_only\", \"done_only\", \"none\"];\n\n/** Parse a `/notify crew <tier>` or `/notify cap <on|off>` preference command.\n * Returns null for anything else (ordinary message or malformed). */\nexport function parseNotifyPref(text: string): { dimension: \"crew\" | \"cap\"; value: string } | null {\n const parts = text.trim().split(/\\s+/);\n if (stripBotMention(parts[0] ?? \"\").toLowerCase() !== \"/notify\") return null;\n const dimension = parts[1]?.toLowerCase();\n if ((dimension === \"crew\" || dimension === \"cap\") && parts[2]) return { dimension, value: parts[2].toLowerCase() };\n return null;\n}\n\n/** True for a bare `/spawn` (no project/task args) — the guided-picker trigger.\n * Strips the `@botname` suffix Telegram appends to menu-tapped commands. */\nexport function isBareSpawn(text: string): boolean {\n const trimmed = text.trim();\n if (!trimmed.startsWith(\"/\")) return false;\n const tokens = trimmed.slice(1).split(/\\s+/).filter((t) => t.length > 0);\n return stripBotMention(tokens[0] ?? \"\").toLowerCase() === \"spawn\" && tokens.length === 1;\n}\n\n/** Recognize the two in-topic notification toggles. Returns the desired active\n * state, or null if the text is an ordinary message. */\nexport function notifyToggle(text: string): boolean | null {\n const first = stripBotMention(text.trim().split(/\\s+/)[0] ?? \"\").toLowerCase();\n if (first === \"/unmute\") return true;\n if (first === \"/mute\") return false;\n return null;\n}\n\nexport function createTelegramBridge(opts: TelegramBridgeOptions): TelegramBridge {\n const { cfg, stateRoot, client, appendCaptainMessage, log, ensureCaptainAlive, runCommand, sendReply } = opts;\n const configRoot = opts.configRoot ?? path.join(os.homedir(), \".config\", \"squadrant\");\n const pollMs = cfg.pollMs ?? 1000;\n let running = false;\n\n function persistOffset(next: number): void {\n const s = loadState(stateRoot);\n s.offset = next;\n saveState(stateRoot, s);\n }\n\n // Outbound: resolve active (live state wins over config default) + crew-tier\n // filter, then resolve (or lazily create) the project's topic and send.\n async function deliverOutbound(project: string, ev: ControlEvent): Promise<void> {\n const resolved = resolveNotify(cfg.notify, loadProjectOverride(project, configRoot));\n const live = loadState(stateRoot).notify[project]; // boolean | undefined\n const active = live ?? resolved.active;\n if (!active) return; // muted → no topic create, no send\n if (!tierIncludes(resolved.crew, ev.type)) return; // tier filter\n let threadId = loadState(stateRoot).topics[topicKey(project)];\n if (threadId === undefined) {\n threadId = await client.createForumTopic(cfg.supergroupId, topicName(project));\n setTopic(stateRoot, project, threadId);\n }\n await client.sendMessage(cfg.supergroupId, threadId, formatLifecycle(project, ev));\n }\n\n // Live notify state for a project: resolved config (built-in→global→override)\n // with the live `active` overlay (state wins over config default).\n function resolveLiveNotify(project: string): NotifyConfig {\n const resolved = resolveNotify(cfg.notify, loadProjectOverride(project, configRoot));\n const live = loadState(stateRoot).notify[project]; // boolean | undefined\n return { ...resolved, active: live ?? resolved.active };\n }\n\n // Re-render a panel's keyboard, swallowing the Bot API \"message is not\n // modified\" error that fires when the new keyboard equals the old one.\n async function editMarkup(chatId: number, messageId: number, markup: unknown): Promise<void> {\n try {\n await client.editMessageReplyMarkup(chatId, messageId, markup);\n } catch (e) {\n const msg = (e as Error).message;\n if (!/not modified/i.test(msg)) throw e;\n }\n }\n\n // callback_query (inline-button tap). ALWAYS answerCallbackQuery on every path\n // (else the spinner hangs ~15s). Gate on the TAPPER's user-id, never the panel.\n // Render state fresh. Never throw into the poll loop.\n async function handleCallback(cq: CallbackQuery): Promise<void> {\n try {\n if (!cq.data || !cq.message) {\n await client.answerCallbackQuery(cq.id);\n return;\n }\n if (!isControlEnabled(cfg) || !isAuthorized(cq.from?.id, cfg)) {\n await client.answerCallbackQuery(cq.id, \"⛔ not authorized\");\n return;\n }\n const action = parseCallback(cq.data);\n if (!action) {\n await client.answerCallbackQuery(cq.id);\n return;\n }\n const chatId = cq.message.chat.id;\n const messageId = cq.message.message_id;\n\n if (action.t === \"notify\") {\n const resolved = findProjectByThread(stateRoot, cq.message.message_thread_id ?? -1);\n if (!resolved) {\n await client.answerCallbackQuery(cq.id, \"no project for this topic\");\n return;\n }\n const project = resolved.project;\n if (action.dim === \"active\") {\n setNotify(stateRoot, project, action.val === \"on\");\n } else if (action.dim === \"cap\") {\n saveProjectOverride(project, { telegram: { notify: { cap: action.val === \"on\" } } }, configRoot);\n } else {\n saveProjectOverride(project, { telegram: { notify: { crew: action.val as CrewTier } } }, configRoot);\n }\n await client.answerCallbackQuery(cq.id, `✅ ${action.dim} = ${action.val}`);\n await editMarkup(chatId, messageId, notifyPanel(resolveLiveNotify(project)));\n return;\n }\n\n if (action.t === \"effort\") {\n if (runCommand) await runCommand([\"effort\", action.mode]);\n await client.answerCallbackQuery(cq.id, `✅ effort = ${action.mode}`);\n await editMarkup(chatId, messageId, effortPanel(action.mode as \"max\" | \"balance\" | \"low\"));\n return;\n }\n\n if (action.t === \"spawn\") {\n // Send a ForceReply prompt carrying the project; the reply is routed to\n // `crew spawn` statelessly via parseSpawnPrompt (no pending-state map).\n await reply(cq.message.message_thread_id, buildSpawnPrompt(action.project), { force_reply: true, selective: true });\n await client.answerCallbackQuery(cq.id);\n return;\n }\n\n // action.t === \"pick\" — General-topic project actions.\n const { action: act, project } = action;\n if (act === \"cr\") {\n const out = runCommand ? await runCommand([\"crew\", \"list\", project]) : \"(command runner unavailable)\";\n await client.answerCallbackQuery(cq.id);\n await reply(undefined, out);\n } else if (act === \"lc\") {\n if (runCommand) await runCommand([\"launch\", project]);\n await client.answerCallbackQuery(cq.id, `launching ${project}`);\n } else if (act === \"mu\") {\n setNotify(stateRoot, project, false);\n await client.answerCallbackQuery(cq.id, `🔕 muted ${project}`);\n } else {\n setNotify(stateRoot, project, true);\n await client.answerCallbackQuery(cq.id, `🔔 unmuted ${project}`);\n }\n } catch (e) {\n log(`telegram callback failed data=${cq.data}: ${(e as Error).message}`);\n try {\n await client.answerCallbackQuery(cq.id, \"⚠️ failed\");\n } catch {\n /* answer failed too — already logged; never throw into the poll loop */\n }\n }\n }\n\n // Reply best-effort: a send failure must never escape into the poll loop.\n async function reply(threadId: number | undefined, text: string, replyMarkup?: unknown): Promise<void> {\n if (!sendReply) return;\n try {\n // Keep the 2-arg call shape when there's no panel (markup undefined).\n if (replyMarkup !== undefined) await sendReply(threadId, text, replyMarkup);\n else await sendReply(threadId, text);\n } catch (e) {\n log(`telegram reply failed: ${(e as Error).message}`);\n }\n }\n\n /** Current global effort dial (falls back to today's \"balance\"). */\n function currentEffort(): \"max\" | \"balance\" | \"low\" {\n try {\n return loadConfig(path.join(configRoot, \"config.json\")).defaults.effort ?? \"balance\";\n } catch {\n return \"balance\";\n }\n }\n\n /** Registered project names for the General-topic pickers. */\n function projectNames(): string[] {\n try {\n return Object.keys(loadConfig(path.join(configRoot, \"config.json\")).projects);\n } catch {\n return [];\n }\n }\n\n /** Guided /spawn: reply the project picker (works in General or a project topic). */\n async function replySpawnPicker(threadId: number | undefined): Promise<void> {\n const projects = projectNames();\n if (projects.length === 0) {\n await reply(threadId, \"no projects registered\");\n return;\n }\n await reply(threadId, \"Pick a project to spawn a crew on:\", spawnPicker(projects));\n }\n\n // General topic (no thread id): curated command channel (#402). Fail-closed —\n // a slash command runs ONLY when remoteControl is on AND the sender is\n // allowlisted. Freeform text gets a /help hint (never silently dropped).\n // Command/reply failures are caught here so they can't escape the poll loop.\n async function handleGeneral(text: string, fromId: number | undefined): Promise<void> {\n if (!text.startsWith(\"/\")) {\n await reply(undefined, \"Send /help for commands.\");\n return;\n }\n if (!isControlEnabled(cfg) || !isAuthorized(fromId, cfg)) {\n await reply(undefined, \"⛔ not authorized\");\n return;\n }\n // Tap-first: a parameterized command with NO argument replies a button panel\n // instead of a usage error. Typed forms (with an arg) fall through to run.\n const tokens = text.trim().slice(1).split(/\\s+/).filter((t) => t.length > 0);\n const name = stripBotMention(tokens[0] ?? \"\").toLowerCase();\n const noArg = tokens.length === 1;\n if (noArg && name === \"effort\") {\n await reply(undefined, \"Effort mode:\", effortPanel(currentEffort()));\n return;\n }\n if (noArg && name === \"spawn\") {\n await replySpawnPicker(undefined);\n return;\n }\n const PICKERS: Record<string, PickAction> = { crews: \"cr\", launch: \"lc\", mute: \"mu\", unmute: \"um\" };\n if (noArg && name in PICKERS) {\n const projects = projectNames();\n if (projects.length === 0) {\n await reply(undefined, \"no projects registered\");\n return;\n }\n await reply(undefined, `Pick a project:`, projectPicker(PICKERS[name], projects));\n return;\n }\n const parsed = parseCommand(text);\n if (parsed.kind !== \"ok\") {\n await reply(undefined, parsed.message);\n return;\n }\n try {\n const out = runCommand ? await runCommand(parsed.argv) : \"(command runner unavailable)\";\n await reply(undefined, out);\n } catch (e) {\n await reply(undefined, `⚠️ command failed: ${(e as Error).message}`);\n log(`telegram command failed argv=${JSON.stringify(parsed.argv)}: ${(e as Error).message}`);\n }\n }\n\n // Project topic: the v1 captain.message flow + Gap-1 auto-launch (#403). When\n // control is off OR the sender isn't allowlisted, behaves exactly as v1\n // (append only). The append throws on delivery-infra failure so the caller can\n // decline to advance the offset (at-least-once); auto-launch failures are\n // contained and never block the append.\n async function handleProjectTopic(text: string, threadId: number, fromId: number | undefined): Promise<void> {\n const resolved = findProjectByThread(stateRoot, threadId);\n if (!resolved) return; // no project bound to this topic\n\n if (isBareSpawn(text)) {\n // Guided /spawn — picker, never appended. Fail-closed like the toggles.\n if (!isControlEnabled(cfg) || !isAuthorized(fromId, cfg)) {\n await reply(threadId, \"⛔ not authorized\");\n return;\n }\n await replySpawnPicker(threadId);\n return;\n }\n\n const toggle = notifyToggle(text);\n if (toggle !== null) {\n // Explicit toggle command — fail-closed, never appended as a captain message.\n if (!isControlEnabled(cfg) || !isAuthorized(fromId, cfg)) {\n await reply(threadId, \"⛔ not authorized\");\n return;\n }\n setNotify(stateRoot, resolved.project, toggle);\n await reply(threadId, toggle ? `🔔 ${resolved.project} notifications ON` : `🔕 ${resolved.project} notifications OFF`);\n return;\n }\n\n // Any /notify attempt (including an incomplete one like a bare `/notify`) is\n // handled here and NEVER appended as a captain message. The first token is\n // matched after stripping a `@botname` suffix Telegram adds in groups.\n if (stripBotMention(text.trim().split(/\\s+/)[0] ?? \"\").toLowerCase() === \"/notify\") {\n // Fail-closed: only an allowlisted sender under remoteControl may proceed.\n if (!isControlEnabled(cfg) || !isAuthorized(fromId, cfg)) {\n await reply(threadId, \"⛔ not authorized\");\n return;\n }\n const pref = parseNotifyPref(text);\n if (pref === null) {\n // Incomplete (bare `/notify`, or a dimension with no value) → tap-first panel.\n // Typed forms (`/notify cap on`) still parse below for power users.\n await reply(threadId, `🔔 ${resolved.project} notifications`, notifyPanel(resolveLiveNotify(resolved.project)));\n return;\n }\n // Deliberate preference change — writes the per-project config file (not live state).\n if (pref.dimension === \"crew\") {\n if (!CREW_TIERS.includes(pref.value)) {\n await reply(threadId, \"crew must be all|alert_only|done_only|none\");\n return;\n }\n saveProjectOverride(resolved.project, { telegram: { notify: { crew: pref.value as never } } }, configRoot);\n } else {\n if (pref.value !== \"on\" && pref.value !== \"off\") {\n await reply(threadId, \"cap must be on|off\");\n return;\n }\n saveProjectOverride(resolved.project, { telegram: { notify: { cap: pref.value === \"on\" } } }, configRoot);\n }\n await reply(threadId, `✅ ${pref.dimension} = ${pref.value}`);\n return;\n }\n\n setNotify(stateRoot, resolved.project, true); // engagement → auto-unmute (sticky)\n if (ensureCaptainAlive && isControlEnabled(cfg) && isAuthorized(fromId, cfg)) {\n try {\n const r = await ensureCaptainAlive(resolved.project);\n if (r === \"timeout\") await reply(threadId, \"⚠️ captain didn't warm up; message queued.\");\n } catch (e) {\n log(`telegram auto-launch failed project=${resolved.project}: ${(e as Error).message}`);\n }\n }\n await appendCaptainMessage({ stateRoot, project: resolved.project, text: formatInbound(text), source: \"telegram\" });\n }\n\n // Inbound: classify by thread id. General topic → command channel; project\n // topic → captain.message (+ auto-launch). Throws only on append failure.\n async function handleUpdate(u: { message?: { chat: { id: number }; message_thread_id?: number; text?: string; from?: { id: number }; reply_to_message?: { text?: string } }; callback_query?: CallbackQuery }): Promise<void> {\n if (u.callback_query) {\n await handleCallback(u.callback_query);\n return;\n }\n const m = u.message;\n if (!m || m.text === undefined) return;\n if (!cfg.chats.includes(m.chat.id)) return; // not an allowlisted chat (coarse filter)\n // Passively capture the sender's user-id for setup auto-population (#user-id).\n if (m.from?.id !== undefined && loadState(stateRoot).lastUserId !== m.from.id) {\n setLastUserId(stateRoot, m.from.id);\n }\n // A reply to a guided-/spawn ForceReply prompt → `crew spawn`, gated, never\n // appended. Runs before the thread-id branch because a reply can land in\n // General (no thread id) OR a project topic.\n const spawnProject = parseSpawnPrompt(m.reply_to_message?.text);\n if (spawnProject) {\n const threadId = m.message_thread_id;\n if (!isControlEnabled(cfg) || !isAuthorized(m.from?.id, cfg)) {\n await reply(threadId, \"⛔ not authorized\");\n return;\n }\n const task = m.text.trim();\n if (!task) {\n await reply(threadId, \"spawn cancelled — empty task\");\n return;\n }\n if (runCommand) await runCommand([\"crew\", \"spawn\", spawnProject, task]);\n await reply(threadId, `🆕 spawning a crew on ${spawnProject}…`);\n return; // NOT appended as a captain message\n }\n if (m.message_thread_id === undefined) {\n await handleGeneral(m.text, m.from?.id);\n return;\n }\n await handleProjectTopic(m.text, m.message_thread_id, m.from?.id);\n }\n\n async function pollLoop(): Promise<void> {\n while (running) {\n try {\n const offset = loadState(stateRoot).offset;\n const updates = await client.getUpdates(offset, LONG_POLL_SEC);\n for (const u of updates) {\n await handleUpdate(u);\n persistOffset(u.update_id + 1);\n }\n } catch (e) {\n log(`telegram inbound poll failed: ${(e as Error).message}`);\n }\n if (running) await sleep(pollMs);\n }\n }\n\n return {\n start() {\n if (running) return;\n running = true;\n void pollLoop();\n },\n stop() {\n running = false;\n },\n pushLifecycle(project, ev) {\n // Fire-and-forget; all errors swallowed so outbound can never throw into\n // the daemon's notify path.\n void deliverOutbound(project, ev).catch((e) => {\n log(`telegram outbound failed project=${project}: ${(e as Error).message}`);\n });\n },\n };\n}\n","// Pure helpers for the interactive `squadrant telegram setup` wizard.\n// These are exported for testing with injected dependencies.\n// getUpdates is single-consumer — setup runs before the daemon starts polling (#321).\nimport fs from \"node:fs\";\nimport type { TelegramClient } from \"./client.js\";\n\n/**\n * Decide whether to reuse an existing supergroup or re-detect via getUpdates.\n * Returns 'reuse' when supergroupId is already configured and --redetect was not passed.\n * Prevents getUpdates conflicts with the running daemon poll (#22205).\n */\nexport function resolveSetupGroup(\n existingSupergroupId: number | undefined,\n opts: { redetect: boolean },\n): \"reuse\" | \"detect\" {\n if (existingSupergroupId !== undefined && !opts.redetect) return \"reuse\";\n return \"detect\";\n}\n\n/**\n * Poll getUpdates until a supergroup message arrives, returning both the chat id\n * and the sender's user id (the latter seeds the control allowlist, #321).\n * Injects `sleep` for testability; never used with real delays in tests.\n */\nexport async function detectGroupAndUser(\n client: TelegramClient,\n opts: { timeoutMs?: number; sleep?: (ms: number) => Promise<void> } = {},\n): Promise<{ supergroupId: number; userId: number | undefined }> {\n const timeoutMs = opts.timeoutMs ?? 60_000;\n const sleep = opts.sleep ?? ((ms: number) => new Promise((r) => setTimeout(r, ms)));\n const deadline = Date.now() + timeoutMs;\n let offset = 0;\n\n while (Date.now() < deadline) {\n const updates = await client.getUpdates(offset, 10);\n for (const u of updates) {\n if (u.update_id >= offset) offset = u.update_id + 1;\n if (u.message?.chat?.type === \"supergroup\") {\n return { supergroupId: u.message.chat.id, userId: u.message.from?.id };\n }\n }\n await sleep(2000);\n }\n\n throw new Error(\"Timed out waiting for the bot to receive a message in a supergroup\");\n}\n\n/** Convenience wrapper that returns only the supergroup id. */\nexport async function detectGroupId(\n client: TelegramClient,\n opts: { timeoutMs?: number; sleep?: (ms: number) => Promise<void> } = {},\n): Promise<number> {\n return (await detectGroupAndUser(client, opts)).supergroupId;\n}\n\n/**\n * Write or update the telegram block in a squadrant config file.\n * Preserves all existing keys; creates the file with defaults if absent.\n */\nexport function writeTelegramConfig(\n configPath: string,\n opts: { token: string; supergroupId: number; users?: number[]; remoteControl?: boolean },\n): void {\n let config: Record<string, unknown>;\n let raw: string | null = null;\n\n try {\n raw = fs.readFileSync(configPath, \"utf-8\");\n } catch (err: unknown) {\n if ((err as NodeJS.ErrnoException).code !== \"ENOENT\") {\n throw new Error(`refusing to overwrite unreadable config at ${configPath}: ${String(err)}`);\n }\n }\n\n if (raw !== null) {\n try {\n config = JSON.parse(raw) as Record<string, unknown>;\n } catch (err: unknown) {\n throw new Error(`refusing to overwrite corrupt config at ${configPath}: ${String(err)}`);\n }\n } else {\n config = {};\n }\n\n // Idempotent: re-running setup updates the token/group but preserves existing\n // control fields (users/remoteControl) unless this run supplies new ones.\n const prev = (config.telegram && typeof config.telegram === \"object\")\n ? (config.telegram as Record<string, unknown>) : {};\n const next: Record<string, unknown> = {\n botToken: opts.token,\n supergroupId: opts.supergroupId,\n chats: [opts.supergroupId],\n };\n const users = opts.users ?? prev.users;\n const remoteControl = opts.remoteControl ?? prev.remoteControl;\n if (users !== undefined) next.users = users;\n if (remoteControl !== undefined) next.remoteControl = remoteControl;\n config.telegram = next;\n\n fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + \"\\n\");\n}\n","// @squadrant/core Telegram subsystem barrel.\nexport * from \"./bot-commands.js\";\nexport * from \"./auth.js\";\nexport * from \"./commands.js\";\nexport * from \"./ensure-captain.js\";\nexport * from \"./format.js\";\nexport * from \"./state.js\";\nexport * from \"./client.js\";\nexport * from \"./bridge.js\";\nexport * from \"./setup.js\";\n","// @squadrant/core — driver-agnostic daemon / control-plane core.\nexport * from \"./daemon.js\";\nexport * from \"./mailbox.js\";\nexport * from \"./protocol.js\";\nexport * from \"./state-machine.js\";\nexport * from \"./liveness.js\";\nexport * from \"./watchdog.js\";\nexport * from \"./store.js\";\nexport * from \"./snapshot.js\";\nexport * from \"./launchd.js\";\nexport * from \"./crew-pane-reader.js\";\nexport * from \"./interfaces.js\";\nexport * from \"./gate.js\";\nexport * from \"./daemon/context.js\";\nexport * from \"./daemon/attach.js\";\nexport * from \"./daemon/start.js\";\nexport * from \"./daemon/delivery.js\";\nexport * from \"./daemon/interactive-probe.js\";\nexport * from \"./delivery/captain-delivery.js\";\nexport * from \"./delivery/defer-delivery.js\";\nexport * from \"./session-freshness.js\";\nexport * from \"./crew-protocol.js\";\nexport * from \"./crew-lifecycle.js\";\nexport * from \"./telegram/index.js\";\n","import { execFile, execFileSync } from \"node:child_process\";\nimport type { RuntimeDriver, RuntimeProbeResult, RuntimeSpawnOptions, WorkspaceRef, PaneRef, RuntimePaneOptions } from \"./types.js\";\nimport { resolveCmuxBin } from \"@squadrant/shared\";\nimport { checkToolCompat } from \"@squadrant/shared\";\nimport { compatManifest } from \"@squadrant/shared\";\n\n// 15s — cmux operations are local IPC (sub-50ms normally). 15s covers unusual\n// system load or a momentarily stuck cmux server without causing the captain\n// blindness that an unbounded hang would (see #209).\nexport const CMUX_TIMEOUT = 15_000;\n\nexport class CmuxTimeoutError extends Error {\n constructor(cmd: string) {\n super(`cmux timeout after ${CMUX_TIMEOUT}ms on: ${cmd}`);\n this.name = \"CmuxTimeoutError\";\n }\n}\n\n// Re-exported so root consumers keep the same import path (root → core direction).\nimport { DeferDelivery } from \"@squadrant/core\";\nexport { DeferDelivery };\n\n/** True when running inside a cmux workspace (CMUX_WORKSPACE_ID is set). */\nexport function isInsideCmux(): boolean {\n return !!process.env.CMUX_WORKSPACE_ID;\n}\n\n// Synchronous cmux invocation for select-workspace / current-workspace calls\n// not yet abstracted behind RuntimeDriver. Uses execFileSync (no shell) with\n// stderr piped so cmux diagnostic messages (e.g. \"Pane not found\") don't leak\n// to the parent terminal. Returns trimmed stdout.\nexport function cmuxLocal(args: string[]): string {\n return execFileSync(resolveCmuxBin(), args, {\n encoding: \"utf-8\",\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n timeout: CMUX_TIMEOUT,\n }).trim();\n}\n\n// Invoke cmux with an argv array and NO shell. Every element (especially crew\n// prompt text passed through send/send-to-surface) reaches cmux as a single\n// literal argument — backticks, $(), quotes are never parsed. See #118.\n// Async to avoid blocking the Node.js event loop during daemon timer ticks.\nfunction cmux(args: string[]): Promise<string> {\n return new Promise((resolve, reject) => {\n execFile(\n resolveCmuxBin(),\n args,\n // CMUX_QUIET=1 silences cmux 0.64's one-time deprecation hints (e.g. the\n // \"list-workspaces is now an alias for cmux workspace list\" notice). Those\n // notices print to the command's stdout and would otherwise pollute the\n // output we parse. Inherit the rest of the environment unchanged.\n { encoding: \"utf-8\", timeout: CMUX_TIMEOUT, env: { ...process.env, CMUX_QUIET: \"1\" } },\n (err, stdout) => {\n if (err) {\n reject((err as NodeJS.ErrnoException).code === \"ETIMEDOUT\"\n ? new CmuxTimeoutError(args.join(\" \"))\n : err);\n return;\n }\n resolve((stdout as string).trim());\n },\n );\n });\n}\n\n// Shape of `cmux workspace list --json` (cmux 0.64.16). Only the fields we\n// consume are typed; everything else in the payload is ignored.\ninterface CmuxWorkspaceListJson {\n workspaces?: Array<{\n ref?: string;\n custom_title?: string | null;\n has_custom_title?: boolean;\n current_directory?: string | null;\n }>;\n}\n\n// Shape of `cmux tree --json` (cmux 0.64.16). Surfaces nest as\n// windows[].workspaces[].panes[].surfaces[]; only consumed fields are typed.\ninterface CmuxTreeJson {\n windows?: Array<{\n workspaces?: Array<{\n ref?: string;\n panes?: Array<{\n surfaces?: Array<{ ref?: string; surface_ref?: string; title?: string | null }>;\n }>;\n }>;\n }>;\n}\n\n// Parse `cmux workspace list --json` into WorkspaceRefs. Replaces the old\n// regex over the human-readable `list-workspaces` text (audit B2). The display\n// name is the workspace's custom title when set (byte-identical to what the\n// text form showed, e.g. \"⚓ squadrant-captain\" — this is what squadrant matches\n// captains by), falling back to the cwd for untitled workspaces.\nfunction parseList(output: string): WorkspaceRef[] {\n let parsed: CmuxWorkspaceListJson;\n try {\n parsed = JSON.parse(output) as CmuxWorkspaceListJson;\n } catch {\n return [];\n }\n const refs: WorkspaceRef[] = [];\n for (const ws of parsed.workspaces ?? []) {\n if (!ws.ref) continue;\n refs.push({\n id: ws.ref,\n name: (ws.has_custom_title && ws.custom_title) ? ws.custom_title : (ws.current_directory ?? ws.ref),\n status: \"running\",\n });\n }\n return refs;\n}\n\n// cmux `send` treats \\n, \\r (and \\t) as Enter/Tab keystrokes, so any newline in a\n// multi-line message would submit it line-by-line. Collapse all newline/CR/tab\n// (real bytes AND literal backslash-escapes) to single spaces so the whole message\n// is delivered as one line, then the explicit send-key Enter submits it once.\nexport function sanitizeForCmuxSend(text: string): string {\n return text\n .replace(/\\\\[nrt]/g, \" \")\n .replace(/[\\n\\r\\t]+/g, \" \")\n .replace(/ {2,}/g, \" \")\n .trim();\n}\n\n/**\n * Extract the in-progress draft from a cmux read-screen capture (#258 / #268).\n * Scans from the bottom of the screen so history lines that contain `> ` are\n * ignored; only the actual input area (the last matching line) is returned.\n * Handles both `>` (synthetic/test) and `❯` (U+276F, the real Claude Code\n * prompt character) as the input caret. The real prompt is followed by a\n * non-breaking space (U+00A0); JS `\\s` covers it, so `\\s+` matches either.\n * Also handles box-drawing `│ ❯ text │` variants.\n *\n * Three-state return (#268):\n * \"draft text\" — input box found with content → caller must DEFER\n * \"\" — input box positively confirmed empty → caller may DELIVER\n * null — HR boundaries not found (overlay/menu/scrolled) → caller must DEFER\n */\nexport function parseDraftFromScreen(screen: string): string | null {\n // Empty screen means the input box is definitely not visible — defer (#268).\n if (!screen) return null;\n const lines = screen.split(/\\r?\\n/);\n\n // Locate the last two HR lines (runs of U+2500 ─) — they are the bottom and top\n // boundaries of the live input box. Everything above the top HR is transcript\n // content and is never scanned, preventing sent user messages with a ❯/> prefix\n // from being mistaken for the live draft (#258).\n const HR_RE = /^\\s*─{10,}\\s*$/;\n let bottomHR = -1;\n let topHR = -1;\n for (let i = lines.length - 1; i >= 0; i--) {\n if (HR_RE.test(lines[i])) {\n if (bottomHR === -1) {\n bottomHR = i;\n } else {\n topHR = i;\n break;\n }\n }\n }\n\n // Can't locate both boundaries — input box not visible (overlay/menu/scrolled\n // transcript). Defer so keystrokes never land in an unknown UI state (#268).\n if (topHR === -1) return null;\n\n // Extract content lines strictly between the two HRs (the live input box only).\n const inputLines = lines.slice(topHR + 1, bottomHR);\n\n for (const line of inputLines) {\n let extracted: string | undefined;\n // Box-drawing input line: │ [>❯] text │\n const boxMatch = line.match(/│\\s*[>❯]\\s+(.*?)\\s*│/);\n if (boxMatch) {\n extracted = boxMatch[1].trim();\n } else {\n // Plain input line — allow empty content after the prompt glyph\n const plainMatch = line.match(/^\\s*[>❯]\\s*(.*)$/);\n if (plainMatch) extracted = plainMatch[1].trim();\n }\n if (extracted !== undefined) {\n // Heuristic #1 — Leading cursor glyph (▌/█) at position 0.\n // CC renders its input cursor via native ANSI terminal positioning, NOT as a ▌ cell\n // character: a live cmux read-screen of an idle CC session with cursor at position 0\n // yields ❯\\xa0 with no ▌ (confirmed by 258-parse-bug-fixture.txt L24 and a fresh\n // crew session capture). Therefore ▌ at the start cannot arise from the user moving\n // the cursor to the beginning of real typed text — it only appears when CC itself\n // renders a UI placeholder at that position (#294). Safe to treat as empty. (#297)\n if (/^[▌█▔▎▏▌█]/.test(extracted)) continue;\n\n // Strip terminal cursor glyphs (▌, █, etc.) that trail the caret position\n const draft = extracted.replace(/\\s*[▌█▔▎▏▌█]+\\s*$/, \"\").trim();\n\n // Claude Code UI placeholder: appears in Working state when input is locked\n // (user cannot type). \"Press [key] to [action]\" strings are UI instructions\n // shown as ghost suggestions — never real user-typed content (#294).\n if (/^Press\\s+(?:up|down|left|right|enter|escape|esc|tab|any\\s+key|ctrl|shift|alt)\\s+to\\s+/i.test(draft)) continue;\n\n if (draft) return draft;\n }\n }\n\n return \"\";\n}\n\n/**\n * Extract the RAW input-box content for the #302 buffer-liveness probe — all\n * content lines between the last two HRs, joined, with the prompt glyph and any\n * trailing cursor glyph stripped (but NOT the #294 ghost heuristics: the probe\n * needs the literal rendered text to diff before/after a backspace). Returns\n * null if the box boundaries aren't visible (overlay/scroll). Unlike\n * parseDraftFromScreen this captures EVERY content line, so a multi-line draft's\n * change on its last line is not missed.\n */\nexport function readInputBoxRaw(screen: string): string | null {\n if (!screen) return null;\n const lines = screen.split(/\\r?\\n/);\n const HR_RE = /^\\s*─{10,}\\s*$/;\n let bottomHR = -1;\n let topHR = -1;\n for (let i = lines.length - 1; i >= 0; i--) {\n if (HR_RE.test(lines[i])) {\n if (bottomHR === -1) bottomHR = i;\n else { topHR = i; break; }\n }\n }\n if (topHR === -1) return null;\n const parts: string[] = [];\n for (const line of lines.slice(topHR + 1, bottomHR)) {\n let s = line.replace(/│/g, \" \"); // drop box-drawing borders\n s = s.replace(/^\\s*[>❯]\\s?/, \"\"); // drop the leading prompt glyph + one space\n s = s.replace(/\\s*[▌█▔▎▏]+\\s*$/, \"\"); // drop a trailing cursor glyph\n parts.push(s);\n }\n return parts.join(\"\").replace(/\\s+$/, \"\"); // trim only the trailing edge\n}\n\n// #292: Claude Code renders a persistent bottom status block once its TUI is past\n// the cold-init splash — the auto-mode indicator (⏵⏵), the context meter\n// (\"Ctx Used\"), the shortcuts hint, or the accept-edits toggle. Absence of all of\n// these means we're still on the loading/splash screen, where keystrokes are\n// silently dropped (#235). Grounded in docs/reports/258-parse-bug-fixture.txt.\nconst CC_INITIALIZED_RE = /⏵⏵|Ctx Used|for shortcuts|accept edits/i;\n\n// A live turn shows a working spinner. The whimsical verb (\"Working…\",\n// \"Cerebrating…\", \"Crunched…\") varies across versions, so we key on stable\n// markers instead. CRUCIAL: a turn is NOT always streaming tokens — during a\n// tool wait (e.g. the shell commands the captain startup checklist runs first)\n// the spinner reads \"✻ Crunched for 27s · 1 shell still running\", which carries\n// NO token-down-counter and no \"esc to interrupt\". Keying only on those two\n// (the original #292 mistake) misread a shell-waiting captain as \"idle\", so the\n// startup-prompt loop re-sent on every poll → 3 duplicate startup runs. We now\n// also match the shell-running hint and the in-parens elapsed timer (\"(4s\",\n// \"(1m 4s\") — both confined to the live spinner line, never on an idle,\n// input-ready screen. Grounded in docs/reports/258-parse-bug-fixture.txt\n// (line 4: shell-wait, no counter; line 22: token-stream).\nconst CC_WORKING_RE = /↓\\s*[\\d.]+\\s*k?\\s*tokens?\\b|esc to interrupt|\\bshell still running\\b|·\\s*\\d+\\s*shell\\b|\\(\\d+m?\\s*\\d*s\\b/i;\n\n/**\n * Classify a captain surface's read-screen into the three states #292's\n * deterministic startup delivery needs:\n * \"loading\" — splash / cold-init; keystrokes would be dropped, do not send yet.\n * \"idle\" — TUI up and accepting input; safe to deliver the startup prompt.\n * \"working\" — a turn is in flight; sending would queue a DUPLICATE startup run.\n * \"working\" is checked first so an active spinner above an (empty) input box wins.\n */\nexport function classifyStartupSurface(screen: string): \"loading\" | \"idle\" | \"working\" {\n if (CC_WORKING_RE.test(screen)) return \"working\";\n if (CC_INITIALIZED_RE.test(screen)) return \"idle\";\n return \"loading\";\n}\n\n// #339 instrumentation gate. The DONE→captain submit is a text burst then a\n// SEPARATE send-key Enter (two distinct socket writes); intermittently the Enter\n// lands as a newline instead of a submit, stranding the payload in the input box.\n// Root-causing needs ONE real frame in the wild. Gated behind SQUADRANT_DEBUG_SEND\n// so it is a strict no-op — zero extra reads, zero latency — when unset.\nexport function sendDebugEnabled(): boolean {\n return !!process.env.SQUADRANT_DEBUG_SEND;\n}\n\n// Classify a post-send input-box read into a submit verdict for #339:\n// \"submitted\" — box empty after Enter (the payload left the input box)\n// \"stuck\" — box still holds the payload (Enter inserted a newline, no submit)\n// \"box-gone\" — box not visible post-send (overlay/scroll — inconclusive)\n// \"unknown\" — box has unrelated content (a fresh draft / next turn rendered)\nexport function classifySendOutcome(payload: string, postBox: string | null): string {\n if (postBox === null) return \"box-gone\";\n if (postBox === \"\") return \"submitted\";\n if (postBox === payload || postBox.includes(payload)) return \"stuck\";\n return \"unknown\";\n}\n\nexport function createCmuxDriver(): RuntimeDriver {\n return {\n name: \"cmux\",\n\n async probe(): Promise<RuntimeProbeResult> {\n try {\n const version = await cmux([\"--version\"]);\n const warn = checkToolCompat(\"cmux\", version, compatManifest.tools.cmux);\n if (warn) process.stderr.write(`[squadrant] ${warn}\\n`);\n return { installed: true, version };\n } catch {\n return { installed: false, version: \"\" };\n }\n },\n\n async list(): Promise<WorkspaceRef[]> {\n try {\n // --json: structured output (B2); --id-format refs: ids as\n // workspace:N refs, not numeric (from #325). Both are required.\n return parseList(await cmux([\"workspace\", \"list\", \"--json\", \"--id-format\", \"refs\"]));\n } catch {\n return [];\n }\n },\n\n async status(nameOrId: string): Promise<WorkspaceRef | null> {\n const refs = await this.list();\n const hit = refs.find((r) => r.name === nameOrId || r.id === nameOrId);\n return hit ?? null;\n },\n\n async spawn(opts: RuntimeSpawnOptions): Promise<WorkspaceRef> {\n const newWorkspaceArgs = [\"workspace\", \"create\", \"--command\", opts.command];\n if (opts.workdir) newWorkspaceArgs.push(\"--cwd\", opts.workdir);\n const output = await cmux(newWorkspaceArgs);\n const id = output.match(/workspace:\\d+/)?.[0] || output.split(/\\s+/).pop() || \"\";\n if (!id) {\n throw new Error(`cmux spawn did not return a workspace id: ${output}`);\n }\n await cmux([\"workspace\", \"rename\", id, \"--title\", opts.name]);\n // Rename the initial tab to the workspace name so send() can route to it\n let initialSurface: string | undefined;\n try {\n const tree = await cmux([\"tree\", \"--workspace\", id, \"--id-format\", \"refs\"]);\n const m = tree.match(/surface\\s+(surface:\\d+)\\s+\\[\\w+\\]\\s+\"([^\"]*)\"/);\n if (m) {\n initialSurface = m[1];\n await cmux([\"rename-tab\", \"--workspace\", id, \"--surface\", m[1], opts.name]);\n }\n } catch { /* rename is best-effort */ }\n if (opts.pinToTop) {\n try {\n await cmux([\"workspace-action\", \"--workspace\", id, \"--action\", \"pin\"]);\n } catch { /* workspace may not be pinned — proceed to close regardless */ }\n if (initialSurface) {\n try {\n await cmux([\"tab-action\", \"--workspace\", id, \"--surface\", initialSurface, \"--action\", \"pin\"]);\n } catch { /* tab pin is best-effort */ }\n }\n }\n return { id, name: opts.name, status: \"running\" };\n },\n\n async send(ref: string, message: string): Promise<void> {\n // Route to the tab named after the workspace (e.g. \":captain\" tab) so\n // messages don't land on a focused crew tab by mistake. Fall back to\n // workspace-level send when no matching tab is found.\n const allRefs = await this.list();\n const ws = allRefs.find((r) => r.id === ref);\n if (ws) {\n try {\n const surfaces = await this.listSurfaces(ws.id);\n const target = surfaces.find((s) => s.title === ws.name);\n if (target) {\n await cmux([\"send\", \"--workspace\", ws.id, \"--surface\", target.surfaceId, sanitizeForCmuxSend(message)]);\n await cmux([\"send-key\", \"--workspace\", ws.id, \"--surface\", target.surfaceId, \"Enter\"]);\n return;\n }\n } catch { /* fall through to default */ }\n }\n await cmux([\"send\", \"--workspace\", ref, sanitizeForCmuxSend(message)]);\n await cmux([\"send-key\", \"--workspace\", ref, \"Enter\"]);\n },\n\n async sendKey(ref: string, key: string): Promise<void> {\n await cmux([\"send-key\", \"--workspace\", ref, key]);\n },\n\n async readScreen(ref: string): Promise<string> {\n try {\n return await cmux([\"read-screen\", \"--workspace\", ref]);\n } catch {\n return \"\";\n }\n },\n\n async stop(ref: string): Promise<void> {\n // cmux 0.64.16 refuses to close a pinned workspace. Unpin first so that\n // squadrant launch --fresh works even when the captain workspace is pinned.\n try {\n await cmux([\"workspace-action\", \"--workspace\", ref, \"--action\", \"unpin\"]);\n } catch { /* workspace may not be pinned — proceed to close regardless */ }\n try {\n await cmux([\"workspace\", \"close\", ref]);\n } catch { /* may already be closed */ }\n },\n\n async newPane(opts: RuntimePaneOptions): Promise<PaneRef> {\n // #295 / audit A1+B3: a crew tab must never steal focus from the captain.\n // cmux 0.64.16's new-surface and new-pane both DEFAULT to --focus false,\n // so we pass it explicitly (intent + resilience if the default changes)\n // and create the surface focus-neutrally. This REPLACES the old\n // snapshot-then-move-surface refocus dance, which depended on the fragile\n // \"tree order == array index\" invariant that the 0.64 freeform canvas +\n // staggered restore broke — risking a focus-steal regression.\n const cmd = opts.direction === \"tab\"\n ? [\"new-surface\", \"--type\", \"terminal\", \"--workspace\", opts.workspaceId, \"--focus\", \"false\"]\n : [\"new-pane\", \"--type\", \"terminal\", \"--direction\", opts.direction, \"--workspace\", opts.workspaceId, \"--focus\", \"false\"];\n const output = await cmux(cmd);\n const surfaceId = output.match(/surface:\\d+/)?.[0];\n if (!surfaceId) {\n const verb = opts.direction === \"tab\" ? \"new-surface\" : \"new-pane\";\n throw new Error(`cmux ${verb} did not return a surface id: ${output}`);\n }\n if (opts.title) {\n try {\n await cmux([\"rename-tab\", \"--workspace\", opts.workspaceId, \"--surface\", surfaceId, \"--title\", opts.title]);\n } catch { /* rename is best-effort */ }\n }\n return { workspaceId: opts.workspaceId, surfaceId };\n },\n\n async closePane(pane: PaneRef): Promise<void> {\n try {\n await cmux([\"close-surface\", \"--workspace\", pane.workspaceId, \"--surface\", pane.surfaceId]);\n } catch { /* may already be closed */ }\n },\n\n async sendToPane(pane: PaneRef, message: string): Promise<void> {\n await cmux([\"send\", \"--workspace\", pane.workspaceId, \"--surface\", pane.surfaceId, sanitizeForCmuxSend(message)]);\n await cmux([\"send-key\", \"--workspace\", pane.workspaceId, \"--surface\", pane.surfaceId, \"Enter\"]);\n },\n\n async readPaneScreen(pane: PaneRef): Promise<string> {\n try {\n return await cmux([\"read-screen\", \"--workspace\", pane.workspaceId, \"--surface\", pane.surfaceId]);\n } catch {\n return \"\";\n }\n },\n\n async spawnInjector(opts: {\n captainWorkspace: WorkspaceRef;\n command: string;\n title?: string;\n placement: \"background\" | \"visible\";\n }): Promise<PaneRef> {\n // Both placements use a background tab (new-surface) in the captain's\n // existing pane — full-height, NO split. A split-pane is wrong here:\n // cmux 0.62.2 has no resize/hide verb, so a `new-pane` split can never be\n // shrunk and stays an ugly full-height 50/50 split forever (#117). The\n // relay still runs as a cmux descendant in the same workspace, preserving\n // the in-cmux delivery requirement (#112).\n //\n // cmux 0.64.16's new-surface DEFAULTS to --focus false, so \"background\"\n // passes --focus false and the relay tab is created without ever stealing\n // focus from the captain — no snapshot-then-move-surface refocus dance\n // (audit A1+B3; the 0.64 freeform canvas broke the old tree-order==index\n // assumption it relied on). \"visible\" passes --focus true to leave the\n // debug tab focused for ergonomics.\n const wsId = opts.captainWorkspace.id;\n const focus = opts.placement === \"visible\" ? \"true\" : \"false\";\n const output = await cmux([\"new-surface\", \"--type\", \"terminal\", \"--workspace\", wsId, \"--focus\", focus]);\n const surfaceId = output.match(/surface:\\d+/)?.[0];\n if (!surfaceId) {\n throw new Error(`cmux spawnInjector did not return a surface id: ${output}`);\n }\n if (opts.title) {\n try {\n await cmux([\"rename-tab\", \"--workspace\", wsId, \"--surface\", surfaceId, \"--title\", opts.title]);\n } catch { /* rename is best-effort */ }\n }\n await cmux([\"send\", \"--workspace\", wsId, \"--surface\", surfaceId, opts.command]);\n await cmux([\"send-key\", \"--workspace\", wsId, \"--surface\", surfaceId, \"Enter\"]);\n return { workspaceId: wsId, surfaceId, title: opts.title };\n },\n\n async sendToSurface(surface: PaneRef, text: string, opts?: { probe?: boolean }): Promise<void> {\n const ws = surface.workspaceId;\n const sf = surface.surfaceId;\n const deliver = async () => {\n // #339 debug-gated instrumentation. When OFF this is the exact two-write\n // submit it always was (no extra reads, no latency). When ON we capture\n // one real frame: the input box BEFORE the send, the payload, and the box\n // AFTER the Enter — so a stranded submit can be told apart from a clean one.\n const dbg = sendDebugEnabled();\n let preBox: string | null = null;\n if (dbg) {\n try {\n preBox = readInputBoxRaw(await cmux([\"read-screen\", \"--workspace\", ws, \"--surface\", sf]));\n } catch { /* unreadable — leave preBox null, logged as such */ }\n }\n const payload = sanitizeForCmuxSend(text);\n await cmux([\"send\", \"--workspace\", ws, \"--surface\", sf, payload]);\n await cmux([\"send-key\", \"--workspace\", ws, \"--surface\", sf, \"Enter\"]);\n // Post-send read-back is READ-ONLY — never a re-send — so it can NEVER\n // double-submit (the #339 constraint). It only observes whether the box\n // still holds the payload (Enter mis-landed) or is empty (submit took).\n if (dbg) {\n let postBox: string | null = null;\n try {\n postBox = readInputBoxRaw(await cmux([\"read-screen\", \"--workspace\", ws, \"--surface\", sf]));\n } catch { /* unreadable — leave postBox null, classified box-gone */ }\n const verdict = classifySendOutcome(payload, postBox);\n process.stderr.write(`[squadrant] send-debug ${JSON.stringify({ surface: sf, verdict, payload, preBox, postBox })}\\n`);\n }\n };\n\n // #258/#268 Approach B: deliver only when the captain's input is positively\n // confirmed empty. null = box not visible (overlay/menu/scroll) → always defer.\n let screen = \"\";\n try {\n screen = await cmux([\"read-screen\", \"--workspace\", ws, \"--surface\", sf]);\n } catch { /* screen unreadable — parseDraftFromScreen(\"\") → null → defer below */ }\n const draft = parseDraftFromScreen(screen);\n\n // null = box not confirmed visible → never keystroke into an overlay (#268).\n if (draft === null) throw new DeferDelivery(null);\n\n // Empty input — nothing to protect, deliver directly.\n if (draft === \"\") { await deliver(); return; }\n\n // A draft is present. On the hot path (no probe) we NEVER keystroke — we\n // defer and carry the content so the relay can track stability (#302).\n if (!opts?.probe) throw new DeferDelivery(draft);\n\n // #302 buffer-liveness probe (replaces the old destructive backspace×N\n // clear + re-paste, which MATERIALIZED ghost suggestions). A real draft is\n // the ONLY thing that yields the \"last char removed, still non-empty\"\n // signature under ONE backspace (verified live, CC 2.1.x); a ghost either\n // stays invariant or dismisses to empty. So we PROTECT only on that exact\n // signature, and we NEVER re-paste screen-read content.\n const before = readInputBoxRaw(screen);\n await cmux([\"send-key\", \"--workspace\", ws, \"--surface\", sf, \"backspace\"]);\n let afterScreen = \"\";\n try {\n afterScreen = await cmux([\"read-screen\", \"--workspace\", ws, \"--surface\", sf]);\n } catch { /* unreadable after probe — treat as no real draft, fall through to deliver */ }\n const after = readInputBoxRaw(afterScreen);\n\n if (before !== null && after !== null && after.length > 0 && after === before.slice(0, -1)) {\n // Confirmed REAL draft. Restore the single char our probe removed (NOT a\n // full re-paste — at most one known char), then defer. Never clobber, and\n // a ghost can never reach this branch, so it can never be materialized.\n await cmux([\"send\", \"--workspace\", ws, \"--surface\", sf, before.slice(-1)]);\n throw new DeferDelivery(draft);\n }\n\n // No real draft (ghost dismissed/invariant, or buffer now empty) → deliver.\n await deliver();\n },\n\n async listSurfaces(workspaceId: string): Promise<PaneRef[]> {\n let output: string;\n try {\n // --json: structured output (B2); --id-format refs: surface ids as\n // surface:N refs, not numeric (from #325). Both are required.\n output = await cmux([\"tree\", \"--workspace\", workspaceId, \"--json\", \"--id-format\", \"refs\"]);\n } catch {\n return [];\n }\n let parsed: CmuxTreeJson;\n try {\n parsed = JSON.parse(output) as CmuxTreeJson;\n } catch {\n return [];\n }\n // Navigate windows[].workspaces[].panes[].surfaces[], collecting every\n // surface that belongs to the requested workspace. Replaces the old regex\n // over `cmux tree` text (audit B2). Surface refs are globally unique, so\n // filtering by the parent workspace ref is sufficient.\n const surfaces: PaneRef[] = [];\n for (const win of parsed.windows ?? []) {\n for (const ws of win.workspaces ?? []) {\n if (ws.ref !== workspaceId) continue;\n for (const pane of ws.panes ?? []) {\n for (const sf of pane.surfaces ?? []) {\n const ref = sf.ref ?? sf.surface_ref;\n if (ref) surfaces.push({ workspaceId, surfaceId: ref, title: sf.title ?? \"\" });\n }\n }\n }\n }\n return surfaces;\n },\n };\n}\n","import type { SquadrantConfig } from \"@squadrant/shared\";\nimport type { RuntimeDriver, RuntimeProbeResult } from \"./types.js\";\n\nconst DEFAULT_RUNTIME = \"cmux\";\n\nexport class RuntimeRegistry {\n constructor(private drivers: Record<string, RuntimeDriver>) {}\n\n forProject(projectName: string, config: SquadrantConfig): RuntimeDriver {\n const projectRuntime = config.projects[projectName]?.runtime;\n const runtimeName = projectRuntime ?? config.runtime ?? DEFAULT_RUNTIME;\n return this.get(runtimeName);\n }\n\n global(config: SquadrantConfig): RuntimeDriver {\n const runtimeName = config.runtime ?? DEFAULT_RUNTIME;\n return this.get(runtimeName);\n }\n\n get(name: string): RuntimeDriver {\n const driver = this.drivers[name];\n if (!driver) {\n throw new Error(`Unknown runtime '${name}' — no driver registered`);\n }\n return driver;\n }\n\n async probeAll(): Promise<Record<string, RuntimeProbeResult>> {\n const results: Record<string, RuntimeProbeResult> = {};\n for (const [name, driver] of Object.entries(this.drivers)) {\n results[name] = await driver.probe();\n }\n return results;\n }\n}\n","export { createCmuxDriver, DeferDelivery, CMUX_TIMEOUT, classifyStartupSurface, isInsideCmux, cmuxLocal } from \"./cmux.js\";\nexport { RuntimeRegistry } from \"./registry.js\";\nexport type {\n RuntimeDriver,\n RuntimeProbeResult,\n RuntimeSpawnOptions,\n WorkspaceRef,\n PaneRef,\n PanePlacement,\n RuntimePaneOptions,\n} from \"./types.js\";\n","import { execFileSync, execSync } from \"node:child_process\";\nimport type {\n NotifierDriver,\n NotifierProbeResult,\n NotifierScope,\n} from \"./types.js\";\nimport { CMUX_TIMEOUT } from \"../runtimes/cmux.js\";\n\nexport function createCmuxNotifier(_scope: NotifierScope): NotifierDriver {\n return {\n name: \"cmux\",\n\n async probe(): Promise<NotifierProbeResult> {\n try {\n execSync(\"squadrant runtime status --command\", { encoding: \"utf-8\", stdio: \"pipe\" });\n return { installed: true, reachable: true };\n } catch (err) {\n const code = (err as { code?: string }).code;\n if (code === \"ENOENT\") {\n return { installed: false, reachable: false };\n }\n // Any non-ENOENT error: squadrant shim crashed, workspace down, or\n // config unreadable all collapse to \"installed but not reachable\".\n return { installed: true, reachable: false };\n }\n },\n\n async notify(message: string): Promise<void> {\n // execFileSync with an argv array and NO shell: the message is one literal\n // argv element, so backticks / $() in notification text are never parsed\n // by a shell. See #120 (same class as #118/#119).\n execFileSync(\"squadrant\", [\"runtime\", \"send\", \"--command\", message], { encoding: \"utf-8\", timeout: CMUX_TIMEOUT });\n },\n };\n}\n","import type { SquadrantConfig } from \"@squadrant/shared\";\nimport type {\n NotifierDriver,\n NotifierFactory,\n NotifierProbeResult,\n} from \"./types.js\";\n\nconst DEFAULT_NOTIFIER = \"cmux\";\n\nexport class NotifierRegistry {\n constructor(private factories: Record<string, NotifierFactory>) {}\n\n get(config: SquadrantConfig): NotifierDriver {\n const name = config.notifier ?? DEFAULT_NOTIFIER;\n return this.getFactory(name)({});\n }\n\n getFactory(name: string): NotifierFactory {\n const factory = this.factories[name];\n if (!factory) {\n throw new Error(`Unknown notifier provider '${name}' — no factory registered`);\n }\n return factory;\n }\n\n async probeAll(): Promise<Record<string, NotifierProbeResult>> {\n const results: Record<string, NotifierProbeResult> = {};\n for (const [name, factory] of Object.entries(this.factories)) {\n try {\n results[name] = await factory({}).probe();\n } catch {\n results[name] = { installed: false, reachable: false };\n }\n }\n return results;\n }\n}\n","export { createCmuxNotifier } from \"./cmux.js\";\nexport { NotifierRegistry } from \"./registry.js\";\nexport type {\n NotifierDriver,\n NotifierFactory,\n NotifierProbeResult,\n NotifierScope,\n} from \"./types.js\";\n","import fs from \"node:fs/promises\";\nimport { existsSync } from \"node:fs\";\nimport path from \"node:path\";\nimport type {\n WorkspaceDriver,\n WorkspaceProbeResult,\n WorkspaceScope,\n} from \"@squadrant/shared\";\n\n// Rejects `../` escapes and absolute paths via lexical containment check.\n// Does NOT resolve symlinks — a symlink inside the vault pointing outside\n// will be followed by fs.* calls. Vault contents are trusted in the squadrant\n// threat model (user-owned, not untrusted input). Tracked in issue #25.\nfunction resolveInRoot(root: string, relative: string): string {\n const joined = path.resolve(root, relative);\n const normalized = path.resolve(root) + path.sep;\n if (joined !== path.resolve(root) && !joined.startsWith(normalized)) {\n throw new Error(`Path '${relative}' escapes workspace root`);\n }\n return joined;\n}\n\nexport function createObsidianDriver(scope: WorkspaceScope): WorkspaceDriver {\n const root = scope.root;\n if (typeof root !== \"string\" || root === \"\") {\n throw new Error(\"ObsidianDriver requires scope.root (string)\");\n }\n\n return {\n name: \"obsidian\",\n\n async probe(): Promise<WorkspaceProbeResult> {\n return {\n installed: true,\n rootExists: existsSync(root),\n };\n },\n\n async read(rel: string): Promise<string> {\n return fs.readFile(resolveInRoot(root, rel), \"utf-8\");\n },\n\n async write(rel: string, content: string): Promise<void> {\n const abs = resolveInRoot(root, rel);\n await fs.mkdir(path.dirname(abs), { recursive: true });\n await fs.writeFile(abs, content);\n },\n\n async exists(rel: string): Promise<boolean> {\n try {\n await fs.access(resolveInRoot(root, rel));\n return true;\n } catch {\n return false;\n }\n },\n\n async list(rel: string): Promise<string[]> {\n try {\n return await fs.readdir(resolveInRoot(root, rel));\n } catch {\n return [];\n }\n },\n\n async mkdir(rel: string): Promise<void> {\n await fs.mkdir(resolveInRoot(root, rel), { recursive: true });\n },\n };\n}\n","import { resolveHome, type SquadrantConfig } from \"@squadrant/shared\";\nimport type {\n WorkspaceDriver,\n WorkspaceFactory,\n WorkspaceProbeResult,\n} from \"@squadrant/shared\";\n\nconst DEFAULT_WORKSPACE = \"obsidian\";\n\nexport class WorkspaceRegistry {\n constructor(private factories: Record<string, WorkspaceFactory>) {}\n\n hub(config: SquadrantConfig): WorkspaceDriver {\n const name = config.workspace ?? DEFAULT_WORKSPACE;\n return this.get(name)({ root: resolveHome(config.hubVault) });\n }\n\n forProject(projectName: string, config: SquadrantConfig): WorkspaceDriver {\n const proj = config.projects[projectName];\n if (!proj) throw new Error(`Project '${projectName}' not found`);\n const name = proj.workspace ?? config.workspace ?? DEFAULT_WORKSPACE;\n return this.get(name)({ root: resolveHome(proj.spokeVault) });\n }\n\n get(name: string): WorkspaceFactory {\n const factory = this.factories[name];\n if (!factory) {\n throw new Error(`Unknown workspace provider '${name}' — no factory registered`);\n }\n return factory;\n }\n\n async probeAll(config: SquadrantConfig): Promise<Record<string, WorkspaceProbeResult>> {\n const results: Record<string, WorkspaceProbeResult> = {};\n for (const [name, factory] of Object.entries(this.factories)) {\n const scope = { root: resolveHome(config.hubVault) };\n results[name] = await factory(scope).probe();\n }\n return results;\n }\n}\n","export { createObsidianDriver } from \"./obsidian.js\";\nexport { WorkspaceRegistry } from \"./registry.js\";\nexport type {\n WorkspaceDriver,\n WorkspaceFactory,\n WorkspaceProbeResult,\n WorkspaceScope,\n} from \"@squadrant/shared\";\n","// src/control/cmux/events-bridge.ts\n// Daemon-side bridge from cmux's native event stream to squadrant ControlEvents\n// (audit item B1 — reduce fragile screen-scraping).\n//\n// Unlike the per-crew OpencodeSseBridge, `cmux events` is a SINGLE global stream\n// for the whole cmux app: one newline-delimited JSON frame per cmux event,\n// carrying every agent's hook events. So this bridge is ONE long-lived\n// subscription owned by the daemon. Each `agent` frame is correlated back to a\n// crew TaskRecord by cwd (each interactive crew runs in a unique worktree path)\n// and classified into a run-state (deriveRunState):\n// - `agent.hook.Stop` — the \"turn ended / crew idle\" signal the pane reader\n// infers by scraping — → `task.turn.completed`.\n// - `agent.hook.PreToolUse` / `UserPromptSubmit` (a turn is live) →\n// `task.progress` (B4/A3): a real-activity signal that refreshes the crew's\n// liveness clock so the watchdog does not false-stall a crew mid long,\n// screen-quiet tool call (#292).\n//\n// ADDITIVE & SAFE: this runs ALONGSIDE the existing relay-proxy/pane-reader path,\n// which stays as the fallback. Both emissions are liveness, NOT completion\n// (anti-#2576): terminal state still comes from the explicit `squadrant crew signal\n// done`. The state-machine reducer already absorbs duplicate/late\n// task.turn.completed and task.progress (a blocked crew stays blocked), so\n// feeding them from BOTH paths is harmless.\nimport type { ChildProcess } from \"node:child_process\";\nimport { spawn as nodeSpawn } from \"node:child_process\";\nimport { resolveCmuxBin } from \"@squadrant/shared\";\nimport type { ControlEvent } from \"@squadrant/shared\";\n\n/** Minimal subset of ChildProcess this bridge needs (injectable for tests). */\nexport interface CmuxEventsChild {\n stdout: NodeJS.ReadableStream | null;\n kill(signal?: NodeJS.Signals): boolean | void;\n on(event: \"exit\", cb: (code: number | null) => void): unknown;\n on(event: \"error\", cb: (err: Error) => void): unknown;\n}\n\n/** Per-surface agent run-state derived from the hook stream (B4/A3). */\nexport type RunState = \"working\" | \"idle\";\n\n/**\n * Pure. Classify an `agent.hook.*` event name into the crew's run-state, or\n * null for hooks that carry no run-state signal.\n *\n * PreToolUse / UserPromptSubmit → \"working\" (a turn is live)\n * Stop → \"idle\" (turn ended)\n * SubagentStop / anything else → null (subagent end ≠ turn end)\n *\n * `Stop` is the existing turn-end signal (→ task.turn.completed). The \"working\"\n * hooks are the B4/A3 addition: they let the daemon keep a crew's liveness clock\n * fresh while it is mid (possibly long, screen-quiet) tool call, so the watchdog\n * does not false-stall it (#292). Only `PreToolUse` is live-confirmed in cmux\n * 0.64.16; `UserPromptSubmit` is mapped opportunistically (harmless if absent).\n */\nexport function deriveRunState(eventName: string): RunState | null {\n switch (eventName) {\n case \"agent.hook.PreToolUse\":\n case \"agent.hook.UserPromptSubmit\":\n return \"working\";\n case \"agent.hook.Stop\":\n return \"idle\";\n default:\n return null;\n }\n}\n\n/** A correlated hook frame, passed to the caller's record resolver. */\nexport interface CmuxAgentHook {\n cwd?: string;\n /** The emitting agent kind (`payload._source`, e.g. \"claude\"). */\n source?: string;\n /** The agent session id (`payload.session_id`). */\n sessionId?: string;\n}\n\nexport interface CmuxEventsBridgeDeps {\n /** Ingress into the daemon's event pipeline (resolves project + handles). */\n emit: (ev: ControlEvent) => void;\n /**\n * Map an agent hook frame to its owning crew record, or undefined if none.\n * The daemon supplies this from the store (non-terminal interactive records\n * matched by cwd). Keeping it injected keeps the bridge pure and testable.\n */\n resolve: (hook: CmuxAgentHook) => { id: string } | undefined;\n /** Durable resume cursor passed to `cmux events --cursor-file`. */\n cursorFile: string;\n /** Injectable spawn for tests; defaults to spawning the real cmux binary. */\n spawnImpl?: (bin: string, args: string[]) => CmuxEventsChild;\n /** Injectable cmux binary path; defaults to resolveCmuxBin(). */\n cmuxBin?: string;\n /** Injectable backoff for tests; defaults to setTimeout. */\n sleep?: (ms: number) => Promise<void>;\n /** Backoff between respawn attempts after the child exits (ms, default 1000). */\n reconnectMs?: number;\n log?: (msg: string) => void;\n /** Test-only: stop after the first child exits (don't respawn). */\n stopAfterFirstRun?: boolean;\n}\n\n/**\n * One long-lived `cmux events` subscription for the whole daemon. The CLI's\n * `--reconnect` resumes the socket in-process; `--cursor-file` makes resume\n * durable across daemon (and child) restarts. If the child process itself dies,\n * we respawn with backoff so the consumer self-heals.\n */\nexport class CmuxEventsBridge {\n private child: CmuxEventsChild | null = null;\n private stopped = false;\n private buf = \"\";\n private deps: CmuxEventsBridgeDeps;\n\n constructor(deps: CmuxEventsBridgeDeps) {\n this.deps = deps;\n }\n\n /** Begin the subscription. Idempotent. */\n start(): void {\n if (this.child || this.stopped) return;\n void this.run();\n }\n\n /** Stop the subscription and kill the child (daemon shutdown). */\n stop(): void {\n this.stopped = true;\n const c = this.child;\n this.child = null;\n if (c) {\n try { c.kill(); } catch { /* already gone */ }\n }\n }\n\n private async run(): Promise<void> {\n const spawnImpl =\n this.deps.spawnImpl ??\n ((bin, args) => nodeSpawn(bin, args, { stdio: [\"ignore\", \"pipe\", \"ignore\"] }) as ChildProcess as unknown as CmuxEventsChild);\n const bin = this.deps.cmuxBin ?? resolveCmuxBin();\n const sleep = this.deps.sleep ?? ((ms: number) => new Promise((r) => setTimeout(r, ms)));\n const reconnectMs = this.deps.reconnectMs ?? 1000;\n const args = [\n \"events\",\n \"--reconnect\",\n \"--cursor-file\", this.deps.cursorFile,\n \"--category\", \"agent\",\n \"--no-heartbeat\",\n ];\n\n while (!this.stopped) {\n this.buf = \"\";\n let child: CmuxEventsChild;\n try {\n child = spawnImpl(bin, args);\n } catch (e) {\n this.deps.log?.(`cmux events spawn failed: ${(e as Error).message}`);\n if (this.deps.stopAfterFirstRun) return;\n await sleep(reconnectMs);\n continue;\n }\n this.child = child;\n await new Promise<void>((resolve) => {\n let settled = false;\n const done = () => { if (!settled) { settled = true; resolve(); } };\n child.stdout?.on(\"data\", (b: Buffer | string) => this.onData(b));\n child.stdout?.on(\"end\", done);\n child.on(\"exit\", done);\n child.on(\"error\", (err) => {\n this.deps.log?.(`cmux events child error: ${err.message}`);\n done();\n });\n });\n this.child = null;\n if (this.stopped || this.deps.stopAfterFirstRun) break;\n // Child died (cmux app restart, binary error): resume from the cursor.\n await sleep(reconnectMs);\n }\n }\n\n private onData(chunk: Buffer | string): void {\n this.buf += typeof chunk === \"string\" ? chunk : chunk.toString(\"utf-8\");\n let nl: number;\n while ((nl = this.buf.indexOf(\"\\n\")) >= 0) {\n const line = this.buf.slice(0, nl);\n this.buf = this.buf.slice(nl + 1);\n this.handleLine(line);\n }\n }\n\n private handleLine(rawLine: string): void {\n const line = rawLine.trim();\n if (!line || line[0] !== \"{\") return;\n let f:\n | {\n type?: string;\n category?: string;\n name?: string;\n source?: string;\n payload?: { _source?: string; session_id?: string; cwd?: string; phase?: string; tool_name?: string };\n }\n | undefined;\n try {\n f = JSON.parse(line);\n } catch {\n return; // partial/non-JSON keepalive or ack we don't parse\n }\n // Only agent hook events; ignore ack/heartbeat and other categories.\n if (f?.type !== \"event\" || f.category !== \"agent\") return;\n // Classify the hook into a run-state. `Stop` is the main-session turn-end;\n // PreToolUse/UserPromptSubmit mean a turn is live; SubagentStop and any\n // other hook carry no turn-level run-state and are ignored.\n const runState = f.name ? deriveRunState(f.name) : null;\n if (!runState) return;\n const p = f.payload ?? {};\n // Each hook fires a \"received\" then \"completed\" phase frame; act on the\n // settled one so we emit exactly once per hook.\n if (p.phase === \"received\") return;\n const rec = this.deps.resolve({\n cwd: p.cwd,\n source: p._source ?? f.source,\n sessionId: p.session_id,\n });\n if (!rec) return;\n if (runState === \"idle\") {\n // Turn-end / idle — the signal the pane reader infers by scraping.\n this.deps.emit({\n type: \"task.turn.completed\",\n id: rec.id,\n turnId: p.session_id ?? \"cmux\",\n });\n return;\n }\n // working: feed a real-activity signal into the liveness path. task.progress\n // refreshes lastHeartbeatAt (the clock evaluateStall keys off), so a crew\n // that is mid long tool-call but screen-quiet is NOT false-stalled (#292),\n // and a crew the scrape path wrongly idled resumes to 'working'. ADDITIVE:\n // the reducer absorbs this idempotently, and a blocked crew stays blocked.\n // #354: carry the tool name on PreToolUse so the reducer can open a\n // tool-in-flight window (pendingTool) — the discriminator the watchdog uses\n // to tell a hung tool call apart from a quiet thinking turn.\n this.deps.emit({ type: \"task.progress\", id: rec.id, note: f.name, tool: p.tool_name });\n }\n}\n","import type { RuntimeDriver, PaneRef } from \"../runtimes/types.js\";\nimport { DeferDelivery } from \"../runtimes/cmux.js\";\n\n/**\n * #332: daemon-side cmux access. The daemon (a launchd process, NOT a cmux\n * descendant) can now drive cmux directly because the CLI auto-discovers its\n * canonical socket (~/.local/state/cmux/cmux.sock) from any process.\n *\n * Every method is FAIL-SOFT: a cmux/socket error degrades to a safe sentinel\n * ([] / null / no-op) so a transient failure NEVER false-reaps a live crew.\n * The ONE exception is DeferDelivery, which `send` re-throws so the delivery\n * loop can defer-while-typing (#258/#302).\n *\n * This is the seam #333's LifecycleSource port sits beside.\n */\nexport class DaemonCmux {\n constructor(private readonly driver: RuntimeDriver) {}\n\n async send(surface: PaneRef, text: string, opts?: { probe?: boolean }): Promise<void> {\n try {\n await this.driver.sendToSurface(surface, text, opts);\n } catch (e) {\n if (e instanceof DeferDelivery) throw e;\n }\n }\n\n async listSurfaces(workspaceId: string): Promise<PaneRef[]> {\n try { return await this.driver.listSurfaces(workspaceId); }\n catch { return []; }\n }\n\n async readScreen(ref: string): Promise<string | null> {\n try { return await this.driver.readScreen(ref); }\n catch { return null; }\n }\n\n async readPaneScreen(pane: PaneRef): Promise<string | null> {\n try { return await this.driver.readPaneScreen(pane); }\n catch { return null; }\n }\n\n async findWorkspaceId(name: string): Promise<string | null> {\n try {\n const ref = await this.driver.status(name);\n return ref?.id ?? null;\n } catch {\n return null;\n }\n }\n\n async isAvailable(): Promise<boolean> {\n try { await this.driver.listSurfaces(\"\"); return true; }\n catch { return false; }\n }\n}\n","// Runtime-bound crew-pane helpers — discovery, first-turn delivery, captain\n// workspace resolution. Extracted from packages/cli/src/commands/crew.ts so\n// they are unit-testable with a mock RuntimeDriver.\n\nimport net from \"node:net\";\nimport { loadConfig } from \"@squadrant/shared\";\nimport type { PaneRef, RuntimeDriver } from \"@squadrant/shared\";\nimport { RuntimeRegistry } from \"./runtimes/registry.js\";\nimport { createCmuxDriver } from \"./runtimes/cmux.js\";\nimport { titleFor, isCrewTitle, isTurnAccepted } from \"@squadrant/core\";\nimport type { TurnAcceptanceConfig } from \"@squadrant/core\";\n\n// Poll-based first-turn delivery timing constants.\nconst SEND_FIRST_TURN_FLOOR_MS = 1500;\nconst POLL_INTERVAL_MS = 750;\nconst SEND_FIRST_TURN_TIMEOUT_MS = 20000;\nconst POST_SEND_CHECK_MS = 750;\n\n/** Reserve an ephemeral TCP port for a crew's embedded HTTP server. Binds :0,\n * reads the OS-assigned port, then releases it. A small TOCTOU window exists\n * between release and the crew binding the port; acceptable for local\n * single-user spawns. */\nexport function getFreePort(): Promise<number> {\n return new Promise((resolve, reject) => {\n const srv = net.createServer();\n srv.once(\"error\", reject);\n srv.listen(0, \"127.0.0.1\", () => {\n const addr = srv.address();\n const port = typeof addr === \"object\" && addr ? addr.port : 0;\n srv.close(() => (port ? resolve(port) : reject(new Error(\"no free port assigned\"))));\n });\n });\n}\n\nexport async function listProjectCrews(\n runtime: RuntimeDriver,\n workspaceId: string,\n project: string,\n): Promise<PaneRef[]> {\n const surfaces = await runtime.listSurfaces(workspaceId);\n return surfaces.filter((s) => s.title && isCrewTitle(project, s.title));\n}\n\nexport async function findCrew(\n runtime: RuntimeDriver,\n workspaceId: string,\n project: string,\n name: string,\n): Promise<PaneRef | null> {\n const want = titleFor(project, name);\n const surfaces = await runtime.listSurfaces(workspaceId);\n return surfaces.find((s) => s.title === want) ?? null;\n}\n\nexport async function resolveCaptainWorkspace(project: string): Promise<{\n runtime: RuntimeDriver;\n workspaceId: string;\n}> {\n const config = loadConfig();\n const proj = config.projects[project];\n if (!proj) {\n throw new Error(`Project '${project}' not found. Run 'squadrant projects list'.`);\n }\n const runtime = new RuntimeRegistry({ cmux: createCmuxDriver() }).forProject(project, config);\n const captain = await runtime.status(proj.captainName);\n if (!captain) {\n throw new Error(\n `Captain workspace '${proj.captainName}' is not running. Run 'squadrant launch ${project}' first.`,\n );\n }\n return { runtime, workspaceId: captain.id };\n}\n\nexport async function sendFirstTurnWhenReady(\n runtime: Pick<RuntimeDriver, \"readPaneScreen\" | \"sendToPane\">,\n pane: PaneRef,\n task: string,\n preLaunchScreen: string,\n acceptanceConfig?: TurnAcceptanceConfig,\n): Promise<void> {\n await new Promise((r) => setTimeout(r, SEND_FIRST_TURN_FLOOR_MS));\n\n const maxPolls = Math.floor(\n (SEND_FIRST_TURN_TIMEOUT_MS - SEND_FIRST_TURN_FLOOR_MS) / POLL_INTERVAL_MS,\n );\n let previousScreen = \"\";\n let stable = false;\n\n for (let i = 0; i < maxPolls && !stable; i++) {\n const screen = (await runtime.readPaneScreen(pane)) ?? \"\";\n // Ready = the agent prompt is actually up: screen is non-empty, settled\n // (unchanged between two consecutive reads), AND has advanced past the\n // un-entered launch command line. The last condition prevents sending the\n // task onto the shell line before the TUI takes over — which concatenates\n // onto the launch command and triggers a shell parse error (opencode\n // boot-race). A momentarily static launch line is not readiness.\n if (screen.length > 0 && screen === previousScreen && screen !== preLaunchScreen) {\n stable = true;\n } else {\n previousScreen = screen;\n await new Promise((r) => setTimeout(r, POLL_INTERVAL_MS));\n }\n }\n\n // Snapshot the screen immediately before sending so the post-send check can\n // tell whether the keystrokes were received. Comparing against the raw task\n // text is unreliable: sendToPane collapses newlines to spaces (#136), so a\n // multi-line task never appears verbatim in the single-line pane render and\n // the check would always re-send a duplicate first turn (#168).\n const preSendScreen = (await runtime.readPaneScreen(pane)) ?? \"\";\n await runtime.sendToPane(pane, task);\n\n // Bounded retry loop (#235): after sending, poll the pane for evidence that\n // the TUI actually accepted the turn.\n const retryLimit = acceptanceConfig?.retryLimit ?? 2;\n for (let attempt = 0; attempt < retryLimit; attempt++) {\n await new Promise((r) => setTimeout(r, POST_SEND_CHECK_MS));\n const afterScreen = (await runtime.readPaneScreen(pane)) ?? \"\";\n if (isTurnAccepted(preSendScreen, afterScreen, acceptanceConfig)) {\n return;\n }\n if (attempt < retryLimit - 1) {\n await runtime.sendToPane(pane, task);\n }\n }\n}\n","// @squadrant/workspaces — environment/surface seam (cmux runtime · obsidian vault · cmux notifier).\nexport * from \"./runtimes/index.js\";\nexport * from \"./notifiers/index.js\";\nexport * from \"./workspaces/index.js\";\nexport { CmuxEventsBridge, deriveRunState } from \"./cmux/events-bridge.js\";\nexport type { RunState, CmuxEventsChild, CmuxAgentHook, CmuxEventsBridgeDeps } from \"./cmux/events-bridge.js\";\nexport { DaemonCmux } from \"./cmux/daemon-cmux.js\";\nexport { getFreePort, listProjectCrews, findCrew, resolveCaptainWorkspace, sendFirstTurnWhenReady } from \"./crew-pane.js\";\n","import { execSync } from \"node:child_process\";\nimport type { AgentDriver, AgentProbeResult, SpawnOptions, AgentResult } from \"./types.js\";\n\nexport function createClaudeDriver(): AgentDriver {\n return {\n name: \"claude\",\n templateSuffix: \"claude\",\n\n async probe(): Promise<AgentProbeResult> {\n try {\n const version = execSync(\"claude --version\", { encoding: \"utf-8\" }).trim();\n return {\n installed: true,\n version,\n capabilities: [\n \"teams\",\n \"json_output\",\n \"model_routing\",\n \"skills\",\n \"auto_approve\",\n \"streaming\",\n \"prompt_file\",\n ],\n };\n } catch {\n return { installed: false, version: \"\", capabilities: [] };\n }\n },\n\n buildCommand(opts: SpawnOptions): string {\n let cmd = \"claude\";\n\n if (opts.model) {\n cmd += ` --model ${opts.model}`;\n }\n\n if (opts.autoApprove) {\n cmd += \" --dangerously-skip-permissions\";\n } else if (opts.permissionMode) {\n cmd += ` --permission-mode ${opts.permissionMode}`;\n }\n\n if (opts.promptFile) {\n cmd += ` --append-system-prompt-file ${opts.promptFile}`;\n }\n\n if (opts.settingsPath) {\n cmd += ` --settings ${opts.settingsPath}`;\n }\n\n // Load squadrant plugin for skills\n const pluginDir = `${process.env.HOME}/.config/squadrant/plugin`;\n cmd += ` --plugin-dir ${pluginDir}`;\n\n if (!opts.interactive) {\n cmd += ` -p \"${opts.prompt.replace(/\"/g, '\\\\\"')}\"`;\n }\n return cmd;\n },\n\n parseOutput(raw: string): AgentResult {\n const lines = raw.trim().split(\"\\n\").filter((l) => l.startsWith(\"{\"));\n if (lines.length === 0) {\n return { status: \"success\", output: raw.trim() };\n }\n try {\n const last = JSON.parse(lines[lines.length - 1]);\n return { status: \"success\", output: last.result || last.content || raw.trim() };\n } catch {\n return { status: \"success\", output: raw.trim() };\n }\n },\n\n async stop(pid: number): Promise<void> {\n try {\n process.kill(pid, \"SIGTERM\");\n } catch {\n // process may already be gone\n }\n },\n };\n}\n","import { execSync } from \"node:child_process\";\nimport type { AgentDriver, AgentProbeResult, SpawnOptions, AgentResult } from \"./types.js\";\n\nexport function createCodexDriver(): AgentDriver {\n return {\n name: \"codex\",\n templateSuffix: \"generic\",\n\n async probe(): Promise<AgentProbeResult> {\n try {\n const version = execSync(\"codex --version\", { encoding: \"utf-8\", stdio: [\"pipe\", \"pipe\", \"pipe\"] }).trim();\n const help = execSync(\"codex --help\", { encoding: \"utf-8\", stdio: [\"pipe\", \"pipe\", \"pipe\"] });\n const hasExec = help.includes(\"exec\");\n return {\n installed: true,\n version,\n capabilities: [\n \"auto_approve\",\n \"json_output\",\n \"sandbox\",\n ...(hasExec ? [\"streaming\" as const] : []),\n ],\n };\n } catch {\n return { installed: false, version: \"\", capabilities: [] };\n }\n },\n\n buildCommand(opts: SpawnOptions): string {\n let cmd = `codex exec \"${opts.prompt.replace(/\"/g, '\\\\\"')}\" --json`;\n if (opts.autoApprove) cmd += \" --full-auto\";\n return cmd;\n },\n\n parseOutput(raw: string): AgentResult {\n const lines = raw.trim().split(\"\\n\").filter((l) => l.startsWith(\"{\"));\n if (lines.length === 0) {\n return { status: \"success\", output: raw.trim() };\n }\n try {\n const last = JSON.parse(lines[lines.length - 1]);\n return { status: \"success\", output: last.output || last.result || raw.trim() };\n } catch {\n return { status: \"success\", output: raw.trim() };\n }\n },\n\n async stop(pid: number): Promise<void> {\n try { process.kill(pid, \"SIGTERM\"); } catch { /* already gone */ }\n },\n };\n}\n","import { execSync } from \"node:child_process\";\nimport type { AgentDriver, AgentProbeResult, SpawnOptions, AgentResult } from \"./types.js\";\n\nexport function createGeminiDriver(): AgentDriver {\n return {\n name: \"gemini\",\n templateSuffix: \"generic\",\n\n async probe(): Promise<AgentProbeResult> {\n try {\n const version = execSync(\"gemini --version\", { encoding: \"utf-8\", stdio: [\"pipe\", \"pipe\", \"pipe\"] }).trim();\n return {\n installed: true,\n version,\n capabilities: [\"auto_approve\", \"json_output\", \"streaming\"],\n };\n } catch {\n return { installed: false, version: \"\", capabilities: [] };\n }\n },\n\n buildCommand(opts: SpawnOptions): string {\n let cmd = `gemini -p \"${opts.prompt.replace(/\"/g, '\\\\\"')}\"`;\n if (opts.autoApprove) cmd += \" --yolo\";\n if (opts.jsonOutput) cmd += \" --output-format json\";\n return cmd;\n },\n\n parseOutput(raw: string): AgentResult {\n try {\n const parsed = JSON.parse(raw.trim());\n return { status: \"success\", output: parsed.response || raw.trim() };\n } catch {\n return { status: \"success\", output: raw.trim() };\n }\n },\n\n async stop(pid: number): Promise<void> {\n try { process.kill(pid, \"SIGTERM\"); } catch { /* already gone */ }\n },\n };\n}\n","import { execSync } from \"node:child_process\";\nimport type { AgentDriver, AgentProbeResult, SpawnOptions, AgentResult } from \"./types.js\";\n\nexport function createOpencodeDriver(): AgentDriver {\n return {\n name: \"opencode\",\n templateSuffix: \"opencode\",\n\n async probe(): Promise<AgentProbeResult> {\n try {\n const version = execSync(\"opencode --version\", { encoding: \"utf-8\", stdio: [\"pipe\", \"pipe\", \"pipe\"] }).trim();\n return {\n installed: true,\n version,\n capabilities: [\"auto_approve\", \"json_output\", \"streaming\", \"model_routing\"],\n };\n } catch {\n return { installed: false, version: \"\", capabilities: [] };\n }\n },\n\n buildCommand(opts: SpawnOptions): string {\n // Interactive crews: boot the TUI; the caller delivers opts.prompt as the\n // first turn via runtime.send once the session is ready, so the crew stays\n // alive for follow-up turns through `squadrant crew send`. When a port is\n // given, bind the embedded HTTP server on it so the daemon's SSE bridge\n // can subscribe to /event for turn-end detection (the bare TUI uses an\n // ephemeral unix socket with no reachable /event endpoint).\n if (opts.interactive) return opts.port ? `opencode --port ${opts.port}` : \"opencode\";\n let cmd = `opencode run \"${opts.prompt.replace(/\"/g, '\\\\\"')}\"`;\n if (opts.jsonOutput) cmd += \" --format json\";\n if (opts.model) cmd += ` -m ${opts.model}`;\n return cmd;\n },\n\n parseOutput(raw: string): AgentResult {\n try {\n const parsed = JSON.parse(raw.trim());\n return { status: \"success\", output: parsed.response || parsed.output || raw.trim() };\n } catch {\n return { status: \"success\", output: raw.trim() };\n }\n },\n\n async stop(pid: number): Promise<void> {\n try { process.kill(pid, \"SIGTERM\"); } catch { /* already gone */ }\n },\n };\n}\n","export type AgentCapability =\n | \"teams\"\n | \"json_output\"\n | \"sandbox\"\n | \"model_routing\"\n | \"skills\"\n | \"auto_approve\"\n | \"streaming\"\n | \"prompt_file\";\n\nexport type Role = \"command\" | \"captain\" | \"crew\" | \"exploration\" | \"side\";\n\nexport interface AgentProbeResult {\n installed: boolean;\n version: string;\n capabilities: AgentCapability[];\n}\n\nexport interface SpawnOptions {\n prompt: string;\n workdir: string;\n role: Role;\n model?: string;\n autoApprove?: boolean;\n jsonOutput?: boolean;\n promptFile?: string;\n // Claude's --permission-mode value (e.g. \"acceptEdits\", \"plan\", \"default\").\n // \"acceptEdits\" auto-accepts file edits while still prompting for risky ops\n // (Bash, etc.) — the semi-automatic gate used for cheaper-model crews. If\n // autoApprove is also set, --dangerously-skip-permissions supersedes this.\n permissionMode?: string;\n // Interactive crew sessions: drivers should NOT bake the prompt into the\n // command (no `-p`). Caller will deliver the prompt via runtime.send after\n // the CLI is ready, so the session stays alive between turns.\n interactive?: boolean;\n // TCP port for an agent's embedded HTTP server. Opencode interactive crews\n // launch as `opencode --port <N>` so the daemon's SSE bridge can subscribe\n // to the crew's /event stream for reliable turn-end detection.\n port?: number;\n // Per-invocation settings file (Claude's --settings flag). The\n // daemon-supervised claude crew spawn writes a per-crew settings.json\n // containing the squadrant Stop hook and passes the path here so the hook\n // is scoped to this session only (no global ~/.claude/settings.json edit).\n settingsPath?: string;\n}\n\nexport interface AgentResult {\n status: \"success\" | \"error\" | \"timeout\";\n output: string;\n filesChanged?: string[];\n}\n\nexport interface AgentDriver {\n name: string;\n templateSuffix: string;\n\n probe(): Promise<AgentProbeResult>;\n buildCommand(opts: SpawnOptions): string;\n parseOutput(raw: string): AgentResult;\n stop(pid: number): Promise<void>;\n}\n\nexport interface RoleRequirements {\n required: AgentCapability[];\n preferred: AgentCapability[];\n}\n\nexport const ROLE_REQUIREMENTS: Record<Role, RoleRequirements> = {\n command: { required: [\"auto_approve\"], preferred: [\"teams\", \"json_output\"] },\n captain: { required: [\"auto_approve\"], preferred: [\"teams\", \"model_routing\", \"skills\"] },\n crew: { required: [\"auto_approve\"], preferred: [\"json_output\", \"sandbox\"] },\n exploration: { required: [\"auto_approve\"], preferred: [] },\n side: { required: [\"auto_approve\"], preferred: [\"skills\"] },\n};\n","import { ROLE_REQUIREMENTS, type AgentCapability, type AgentDriver, type AgentProbeResult, type Role } from \"./types.js\";\n\nexport interface ValidationResult {\n allowed: boolean;\n missingRequired: AgentCapability[];\n missingPreferred: AgentCapability[];\n reason?: string;\n}\n\nexport class CapabilityRegistry {\n private drivers: Record<string, AgentDriver>;\n private probeResults: Record<string, AgentProbeResult> = {};\n\n constructor(drivers: Record<string, AgentDriver>) {\n this.drivers = drivers;\n }\n\n async probeAll(): Promise<void> {\n for (const [name, driver] of Object.entries(this.drivers)) {\n this.probeResults[name] = await driver.probe();\n }\n }\n\n get(name: string): AgentDriver | undefined {\n return this.drivers[name];\n }\n\n getDriver(name: string): AgentDriver {\n const driver = this.drivers[name];\n if (!driver) {\n throw new Error(`No driver registered for agent '${name}'`);\n }\n return driver;\n }\n\n getProbeResult(name: string): AgentProbeResult | undefined {\n return this.probeResults[name];\n }\n\n validateRole(agent: string, role: Role): ValidationResult {\n const probe = this.probeResults[agent];\n if (!probe || !probe.installed) {\n return {\n allowed: false,\n missingRequired: [],\n missingPreferred: [],\n reason: `Agent '${agent}' is not installed`,\n };\n }\n\n const reqs = ROLE_REQUIREMENTS[role];\n const caps = new Set(probe.capabilities);\n\n const missingRequired = reqs.required.filter((c) => !caps.has(c));\n const missingPreferred = reqs.preferred.filter((c) => !caps.has(c));\n\n if (missingRequired.length > 0) {\n return {\n allowed: false,\n missingRequired,\n missingPreferred,\n reason: `${agent} cannot be ${role}: missing required capabilities [${missingRequired.join(\", \")}]`,\n };\n }\n\n return { allowed: true, missingRequired: [], missingPreferred };\n }\n\n installedAgents(): string[] {\n return Object.entries(this.probeResults)\n .filter(([, probe]) => probe.installed)\n .map(([name]) => name);\n }\n}\n","// buildAgentCmd — build the CLI command string used to launch a captain/command\n// session. Extracted from packages/cli/src/commands/launch.ts so it can be\n// unit-tested without spawning real processes.\n\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport type { Role } from \"./types.js\";\nimport type { CapabilityRegistry } from \"./registry.js\";\n\n/**\n * Build the shell command string that launches an agent session for a given\n * role. For Claude, handles fresh/continue, permission-mode flags, role\n * template file, and plugin-dir. For all other agents, delegates to the\n * driver's own buildCommand.\n *\n * @param agentName - e.g. \"claude\", \"opencode\", \"codex\"\n * @param registry - populated CapabilityRegistry\n * @param role - \"captain\" | \"command\" | \"crew\" | …\n * @param fresh - true → new session; false → continue last session\n * @param permissionMode - \"acceptEdits\" | \"auto\" | \"bypassPermissions\"\n * @param model - optional model override\n * @param templatesDir - resolved path to ~/.config/squadrant/templates\n */\nexport function buildAgentCmd(\n agentName: string,\n registry: CapabilityRegistry,\n role: string,\n fresh: boolean,\n permissionMode: string,\n model?: string,\n templatesDir?: string,\n): string {\n const driver = registry.getDriver(agentName);\n\n if (driver.name === \"claude\") {\n let cmd = fresh ? \"claude\" : \"claude -c\";\n\n if (permissionMode === \"acceptEdits\") {\n cmd += \" --permission-mode acceptEdits\";\n } else if (permissionMode === \"auto\") {\n cmd += \" --permission-mode auto\";\n } else if (permissionMode === \"bypassPermissions\") {\n cmd += \" --dangerously-skip-permissions\";\n }\n\n if (model) {\n cmd += ` --model ${model}`;\n }\n\n if (templatesDir) {\n const roleFile = path.join(templatesDir, `${role}.claude.md`);\n const legacyRoleFile = path.join(templatesDir, `${role}.CLAUDE.md`);\n const actualRoleFile = fs.existsSync(roleFile)\n ? roleFile\n : fs.existsSync(legacyRoleFile) ? legacyRoleFile : null;\n if (actualRoleFile) {\n cmd += ` --append-system-prompt-file ${actualRoleFile}`;\n }\n\n const pluginDir = path.join(templatesDir, \"..\", \"plugin\");\n if (fs.existsSync(pluginDir)) {\n cmd += ` --plugin-dir ${pluginDir}`;\n }\n }\n\n return cmd;\n }\n\n // Non-Claude agents: delegate to driver.buildCommand.\n const roleFile = templatesDir\n ? path.join(templatesDir, `${role}.${driver.templateSuffix}.md`)\n : undefined;\n return driver.buildCommand({\n prompt: `You are a squadrant ${role}. Read your instructions from ${roleFile ?? role} and begin.`,\n workdir: process.cwd(),\n role: role as Role,\n model,\n autoApprove: true,\n promptFile: roleFile && fs.existsSync(roleFile) ? roleFile : undefined,\n });\n}\n","export { createClaudeDriver } from \"./claude.js\";\nexport { createCodexDriver } from \"./codex.js\";\nexport { createGeminiDriver } from \"./gemini.js\";\nexport { createOpencodeDriver } from \"./opencode.js\";\nexport { CapabilityRegistry } from \"./registry.js\";\nexport { buildAgentCmd } from \"./launch-cmd.js\";\nexport type {\n AgentDriver,\n AgentCapability,\n AgentProbeResult,\n AgentResult,\n SpawnOptions,\n Role,\n RoleRequirements,\n} from \"./types.js\";\nexport { ROLE_REQUIREMENTS } from \"./types.js\";\n","import { mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport os from \"node:os\";\nimport type {\n ProjectionEmitResult,\n ProjectionEmitter,\n ProjectionSource,\n} from \"@squadrant/shared\";\n\nfunction renderMdc(source: ProjectionSource): string {\n const skillSections = source.skills\n .map(\n (s) =>\n `## Skill: ${s.name}\\n\\n*${s.description}*\\n\\n${s.content}`,\n )\n .join(\"\\n\\n\");\n\n const body = [source.instructions.trim(), skillSections]\n .filter((s) => s.length > 0)\n .join(\"\\n\\n\");\n\n const frontmatter = [\n \"---\",\n \"description: Squadrant-projected rules and skills\",\n \"globs: ['**/*']\",\n \"alwaysApply: true\",\n \"---\",\n \"\",\n ].join(\"\\n\");\n\n return `${frontmatter}${body}\\n`;\n}\n\nasync function readExisting(p: string): Promise<string | null> {\n try {\n return await readFile(p, \"utf-8\");\n } catch (err) {\n if ((err as { code?: string }).code === \"ENOENT\") return null;\n throw err;\n }\n}\n\nfunction buildDiff(existing: string | null, generated: string): string {\n if (existing === null) return `NEW FILE\\n---\\n${generated}`;\n if (existing === generated) return \"UNCHANGED\";\n return `OVERWRITE\\n--- old\\n${existing}\\n--- new\\n${generated}`;\n}\n\nexport function createCursorEmitter(): ProjectionEmitter {\n return {\n name: \"cursor\",\n\n destinations(scope, projectRoot) {\n if (scope === \"user\") {\n return [\n {\n path: path.join(os.homedir(), \".cursor/rules/squadrant-global.mdc\"),\n shared: false,\n format: \"mdc\",\n },\n ];\n }\n if (!projectRoot) return [];\n return [\n {\n path: path.join(projectRoot, \".cursor/rules/squadrant.mdc\"),\n shared: false,\n format: \"mdc\",\n },\n ];\n },\n\n async emit(source, dest, opts): Promise<ProjectionEmitResult> {\n const generated = renderMdc(source);\n const existing = await readExisting(dest.path);\n\n if (opts?.dryRun) {\n return {\n written: false,\n path: dest.path,\n bytesWritten: 0,\n diff: buildDiff(existing, generated),\n };\n }\n\n await mkdir(path.dirname(dest.path), { recursive: true });\n await writeFile(dest.path, generated, \"utf-8\");\n\n return {\n written: true,\n path: dest.path,\n bytesWritten: Buffer.byteLength(generated, \"utf-8\"),\n };\n },\n };\n}\n","export const MARKER_START = \"<!-- squadrant:start -->\";\nexport const MARKER_END = \"<!-- squadrant:end -->\";\n\nexport function mergeWithMarkers(existing: string | null, generated: string): string {\n const body = generated.replace(/\\s+$/, \"\");\n const block = `${MARKER_START}\\n${body}\\n${MARKER_END}\\n`;\n\n if (!existing) return block;\n\n const startIdx = existing.indexOf(MARKER_START);\n const endIdx = existing.indexOf(MARKER_END);\n\n if (startIdx === -1 && endIdx === -1) {\n const sep = existing.endsWith(\"\\n\") ? \"\\n\" : \"\\n\\n\";\n return `${existing}${sep}${block}`;\n }\n\n if (startIdx === -1 || endIdx === -1) {\n throw new Error(\n `Corrupted squadrant markers — found only ${startIdx === -1 ? \"end\" : \"start\"} marker. ` +\n `Remove the stray marker or delete the file and re-run projection emit.`,\n );\n }\n\n if (endIdx < startIdx) {\n throw new Error(`Corrupted squadrant markers — end appears before start. Manual repair needed.`);\n }\n\n const before = existing.slice(0, startIdx);\n const after = existing.slice(endIdx + MARKER_END.length);\n const trimmedAfter = after.startsWith(\"\\n\") ? after.slice(1) : after;\n return `${before}${block}${trimmedAfter}`;\n}\n","import { mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport os from \"node:os\";\nimport { mergeWithMarkers } from \"./marker.js\";\nimport type {\n ProjectionEmitResult,\n ProjectionEmitter,\n ProjectionSource,\n} from \"@squadrant/shared\";\n\nfunction renderMarkdown(source: ProjectionSource): string {\n const skillSections = source.skills\n .map((s) => `## Skill: ${s.name}\\n\\n*${s.description}*\\n\\n${s.content}`)\n .join(\"\\n\\n\");\n return [source.instructions.trim(), skillSections]\n .filter((s) => s.length > 0)\n .join(\"\\n\\n\");\n}\n\nasync function readExisting(p: string): Promise<string | null> {\n try { return await readFile(p, \"utf-8\"); }\n catch (err) {\n if ((err as { code?: string }).code === \"ENOENT\") return null;\n throw err;\n }\n}\n\nexport function createCodexEmitter(): ProjectionEmitter {\n return {\n name: \"codex\",\n\n destinations(scope, projectRoot) {\n if (scope === \"user\") {\n return [{\n path: path.join(os.homedir(), \".codex/AGENTS.md\"),\n shared: true,\n format: \"markdown\",\n }];\n }\n if (!projectRoot) return [];\n return [{\n path: path.join(projectRoot, \"AGENTS.md\"),\n shared: true,\n format: \"markdown\",\n }];\n },\n\n async emit(source, dest, opts): Promise<ProjectionEmitResult> {\n const body = renderMarkdown(source);\n const existing = await readExisting(dest.path);\n const generated = mergeWithMarkers(existing, body);\n\n if (opts?.dryRun) {\n return {\n written: false,\n path: dest.path,\n bytesWritten: 0,\n diff: existing === generated ? \"UNCHANGED\" : `MERGE\\n--- old\\n${existing ?? \"\"}\\n--- new\\n${generated}`,\n };\n }\n\n await mkdir(path.dirname(dest.path), { recursive: true });\n await writeFile(dest.path, generated, \"utf-8\");\n\n return {\n written: true,\n path: dest.path,\n bytesWritten: Buffer.byteLength(generated, \"utf-8\"),\n };\n },\n };\n}\n","import { mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport os from \"node:os\";\nimport { mergeWithMarkers } from \"./marker.js\";\nimport type {\n ProjectionEmitResult,\n ProjectionEmitter,\n ProjectionSource,\n} from \"@squadrant/shared\";\n\nfunction renderMarkdown(source: ProjectionSource): string {\n const skillSections = source.skills\n .map((s) => `## Skill: ${s.name}\\n\\n*${s.description}*\\n\\n${s.content}`)\n .join(\"\\n\\n\");\n return [source.instructions.trim(), skillSections]\n .filter((s) => s.length > 0)\n .join(\"\\n\\n\");\n}\n\nasync function readExisting(p: string): Promise<string | null> {\n try { return await readFile(p, \"utf-8\"); }\n catch (err) {\n if ((err as { code?: string }).code === \"ENOENT\") return null;\n throw err;\n }\n}\n\nexport function createGeminiEmitter(): ProjectionEmitter {\n return {\n name: \"gemini\",\n\n destinations(scope, projectRoot) {\n if (scope === \"user\") {\n return [{\n path: path.join(os.homedir(), \".gemini/GEMINI.md\"),\n shared: true,\n format: \"markdown\",\n }];\n }\n if (!projectRoot) return [];\n return [{\n path: path.join(projectRoot, \"GEMINI.md\"),\n shared: true,\n format: \"markdown\",\n }];\n },\n\n async emit(source, dest, opts): Promise<ProjectionEmitResult> {\n const body = renderMarkdown(source);\n const existing = await readExisting(dest.path);\n const generated = mergeWithMarkers(existing, body);\n\n if (opts?.dryRun) {\n return {\n written: false,\n path: dest.path,\n bytesWritten: 0,\n diff: existing === generated ? \"UNCHANGED\" : `MERGE\\n--- old\\n${existing ?? \"\"}\\n--- new\\n${generated}`,\n };\n }\n\n await mkdir(path.dirname(dest.path), { recursive: true });\n await writeFile(dest.path, generated, \"utf-8\");\n\n return {\n written: true,\n path: dest.path,\n bytesWritten: Buffer.byteLength(generated, \"utf-8\"),\n };\n },\n };\n}\n","import { mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport os from \"node:os\";\nimport { mergeWithMarkers } from \"./marker.js\";\nimport type {\n ProjectionEmitResult,\n ProjectionEmitter,\n ProjectionSource,\n} from \"@squadrant/shared\";\n\nfunction renderMarkdown(source: ProjectionSource): string {\n const skillSections = source.skills\n .map((s) => `## Skill: ${s.name}\\n\\n*${s.description}*\\n\\n${s.content}`)\n .join(\"\\n\\n\");\n return [source.instructions.trim(), skillSections]\n .filter((s) => s.length > 0)\n .join(\"\\n\\n\");\n}\n\nasync function readExisting(p: string): Promise<string | null> {\n try { return await readFile(p, \"utf-8\"); }\n catch (err) {\n if ((err as { code?: string }).code === \"ENOENT\") return null;\n throw err;\n }\n}\n\nexport function createOpencodeEmitter(): ProjectionEmitter {\n return {\n name: \"opencode\",\n\n destinations(scope, projectRoot) {\n if (scope === \"user\") {\n return [{\n path: path.join(os.homedir(), \".config\", \"opencode\", \"AGENTS.md\"),\n shared: true,\n format: \"markdown\",\n }];\n }\n if (!projectRoot) return [];\n return [{\n path: path.join(projectRoot, \"AGENTS.md\"),\n shared: true,\n format: \"markdown\",\n }];\n },\n\n async emit(source, dest, opts): Promise<ProjectionEmitResult> {\n const body = renderMarkdown(source);\n const existing = await readExisting(dest.path);\n const generated = mergeWithMarkers(existing, body);\n\n if (opts?.dryRun) {\n return {\n written: false,\n path: dest.path,\n bytesWritten: 0,\n diff: existing === generated ? \"UNCHANGED\" : `MERGE\\n--- old\\n${existing ?? \"\"}\\n--- new\\n${generated}`,\n };\n }\n\n await mkdir(path.dirname(dest.path), { recursive: true });\n await writeFile(dest.path, generated, \"utf-8\");\n\n return {\n written: true,\n path: dest.path,\n bytesWritten: Buffer.byteLength(generated, \"utf-8\"),\n };\n },\n };\n}\n","import type { ProjectionEmitter, ProjectionEmitterFactory } from \"@squadrant/shared\";\n\nexport class ProjectionRegistry {\n constructor(private factories: Record<string, ProjectionEmitterFactory>) {}\n\n get(name: string): ProjectionEmitter {\n const factory = this.factories[name];\n if (!factory) {\n const available = Object.keys(this.factories).join(\", \") || \"(none)\";\n throw new Error(\n `Unknown projection target '${name}'. Available: ${available}.`,\n );\n }\n return factory();\n }\n\n list(): string[] {\n return Object.keys(this.factories);\n }\n}\n","export { createCursorEmitter } from \"./cursor.js\";\nexport { createCodexEmitter } from \"./codex.js\";\nexport { createGeminiEmitter } from \"./gemini.js\";\nexport { createOpencodeEmitter } from \"./opencode.js\";\nexport { ProjectionRegistry } from \"./registry.js\";\nexport { mergeWithMarkers, MARKER_START, MARKER_END } from \"./marker.js\";\nexport type {\n ProjectionSource,\n ProjectionDestination,\n ProjectionEmitter,\n ProjectionEmitResult,\n ProjectionEmitterFactory,\n} from \"@squadrant/shared\";\n","// src/control/codex/app-server-client.ts\n// Typed JSON-RPC 2.0 client for `codex app-server` v2.\n// Transport: stdio (newline-delimited JSON). See spec §3.\n// Defensive parser per orca codex-fetcher.ts:160-164: ignore non-JSON lines.\n\nimport { EventEmitter } from \"node:events\";\nimport { spawn as nodeSpawn, type ChildProcessByStdio } from \"node:child_process\";\nimport type { Readable, Writable } from \"node:stream\";\n\ntype Child = ChildProcessByStdio<Writable, Readable, Readable>;\n\nexport interface AppServerClientOpts {\n /** Override for tests; defaults to spawning real `codex app-server`. */\n spawn?: () => Child;\n clientInfo?: { name: string; version: string };\n}\n\nexport function _parseChunk(acc: { buf: string }, chunk: string): unknown[] {\n acc.buf += chunk;\n const out: unknown[] = [];\n let idx: number;\n while ((idx = acc.buf.indexOf(\"\\n\")) >= 0) {\n const line = acc.buf.slice(0, idx);\n acc.buf = acc.buf.slice(idx + 1);\n if (!line.trim()) continue;\n try { out.push(JSON.parse(line)); } catch { /* skip non-JSON defensively */ }\n }\n return out;\n}\n\nexport class AppServerClient extends EventEmitter {\n private proc?: Child;\n private acc = { buf: \"\" };\n private opts: AppServerClientOpts;\n constructor(opts: AppServerClientOpts = {}) { super(); this.opts = opts; }\n\n start(): void {\n if (this.proc) throw new Error(\"AppServerClient already started\");\n const sp = this.opts.spawn ?? defaultSpawn;\n this.proc = sp();\n this.proc.stdout.on(\"data\", (d: Buffer | string) => this._onStdout(d.toString()));\n this.proc.stderr.on(\"data\", (d: Buffer | string) => this.emit(\"stderr\", d.toString()));\n this.proc.on(\"exit\", (code, signal) => {\n this._onClosed();\n this.emit(\"closed\", { code, signal });\n });\n this.proc.on(\"error\", (e) => this.emit(\"error\", e));\n }\n\n kill(): void {\n if (this.proc) this.proc.kill();\n }\n\n async initialize(): Promise<unknown> {\n if (this._handshakeDone) return;\n if (!this.proc) throw new Error(\"AppServerClient not started\");\n const info = this.opts.clientInfo ?? { name: \"squadrant\", version: \"0\" };\n // Send initialize directly (bypass gate) — only initialize may pre-handshake.\n const id = this.nextId++;\n const env = { jsonrpc: \"2.0\", id, method: \"initialize\", params: { clientInfo: info } };\n const res = await new Promise<unknown>((resolve, reject) => {\n this.pending.set(id, { resolve, reject });\n this.proc!.stdin.write(JSON.stringify(env) + \"\\n\");\n });\n // Send 'initialized' as a notification (no id).\n this.proc.stdin.write(JSON.stringify({ jsonrpc: \"2.0\", method: \"initialized\" }) + \"\\n\");\n this._handshakeDone = true;\n return res;\n }\n\n async startThread(params: { cwd: string; model?: string; sandbox?: string; approvalPolicy?: string; developerInstructions?: string }): Promise<{ threadId: string }> {\n const res = await this._sendRequest(\"thread/start\", params) as { thread?: { id?: string } };\n const id = res?.thread?.id;\n if (typeof id !== \"string\") throw new Error(`thread/start: unexpected response shape (no thread.id): ${JSON.stringify(res).slice(0, 200)}`);\n return { threadId: id };\n }\n\n resumeThread(params: { threadId: string; cwd?: string }): Promise<unknown> {\n return this._sendRequest(\"thread/resume\", params);\n }\n\n /** Archive a thread so the app-server tears it down (and reaps any per-thread\n * MCP servers it spawned). Called when a codex crew closes. */\n archiveThread(threadId: string): Promise<unknown> {\n return this._sendRequest(\"thread/archive\", { threadId });\n }\n\n readThread(params: { threadId: string; lastN?: number }): Promise<unknown> {\n return this._sendRequest(\"thread/read\", params);\n }\n\n async sendTurn(threadId: string, text: string): Promise<{ turnId: string }> {\n const ack = await this._sendRequest(\"turn/start\", {\n threadId, input: [{ type: \"text\", text }],\n }) as { turn?: { id?: string } };\n const turnId = ack?.turn?.id;\n if (typeof turnId !== \"string\") throw new Error(`turn/start: unexpected ack shape (no turn.id): ${JSON.stringify(ack).slice(0, 200)}`);\n return new Promise((resolve, reject) => {\n const onNote = (n: { method: string; params?: any }) => {\n if (n.params?.turn?.id !== turnId) return;\n if (n.method === \"turn/completed\") { cleanup(); resolve({ turnId }); }\n if (n.method === \"turn/failed\") { cleanup(); reject(new Error(n.params?.error ?? \"turn failed\")); }\n };\n const onClientClosed = () => { cleanup(); reject(new Error(\"AppServerClient: client closed before turn completed\")); };\n const cleanup = () => {\n this.off(\"notification\", onNote);\n this.off(\"_clientClosed\", onClientClosed);\n };\n this.on(\"notification\", onNote);\n this.once(\"_clientClosed\", onClientClosed);\n });\n }\n\n steerTurn(threadId: string, text: string): Promise<unknown> {\n return this._sendRequest(\"turn/steer\", { threadId, input: [{ type: \"text\", text }] });\n }\n\n interruptTurn(threadId: string): Promise<unknown> {\n return this._sendRequest(\"turn/interrupt\", { threadId });\n }\n\n injectItems(threadId: string, items: unknown[]): Promise<unknown> {\n return this._sendRequest(\"thread/inject_items\", { threadId, items });\n }\n\n respondToServerRequest(id: number, result: unknown): void {\n if (!this.proc) throw new Error(\"AppServerClient not started\");\n this.proc.stdin.write(JSON.stringify({ jsonrpc: \"2.0\", id, result }) + \"\\n\");\n }\n\n private nextId = 1;\n private pending = new Map<number, { resolve: (v: unknown) => void; reject: (e: Error) => void }>();\n protected _handshakeDone = false;\n\n private _onClosed(): void {\n // Mass-reject pending RPC promises so callers don't hang on child death.\n const closedErr = new Error(\"AppServerClient: child closed before response\");\n for (const slot of this.pending.values()) slot.reject(closedErr);\n this.pending.clear();\n // Tell any waiters listening for child-close (sendTurn) to bail.\n this.emit(\"_clientClosed\");\n }\n\n protected _sendRequest(method: string, params?: unknown): Promise<unknown> {\n if (!this._handshakeDone && method !== \"initialize\") {\n throw new Error(`AppServerClient: cannot call '${method}' before handshake (spec §3.2)`);\n }\n if (!this.proc) throw new Error(\"AppServerClient not started\");\n const id = this.nextId++;\n const env = { jsonrpc: \"2.0\", id, method, params: params ?? {} };\n return new Promise((resolve, reject) => {\n this.pending.set(id, { resolve, reject });\n this.proc!.stdin.write(JSON.stringify(env) + \"\\n\");\n });\n }\n\n private _dispatchResponse(msg: any): boolean {\n if (typeof msg?.id !== \"number\") return false;\n const slot = this.pending.get(msg.id);\n if (!slot) return false;\n this.pending.delete(msg.id);\n if (msg.error) slot.reject(new Error(`${msg.error.message ?? \"rpc-error\"} (code ${msg.error.code})`));\n else slot.resolve(msg.result);\n return true;\n }\n\n private _onStdout(s: string): void {\n for (const msg of _parseChunk(this.acc, s)) this._dispatch(msg);\n }\n\n private _dispatch(msg: unknown): void {\n if (this._dispatchResponse(msg)) return;\n const m = msg as any;\n if (typeof m?.method === \"string\" && typeof m?.id === \"number\") {\n this.emit(\"serverRequest\", { id: m.id, method: m.method, params: m.params });\n return;\n }\n if (typeof m?.method === \"string\" && m?.id === undefined) {\n this.emit(\"notification\", { method: m.method, params: m.params });\n }\n }\n}\n\nfunction defaultSpawn(): Child {\n return nodeSpawn(\"codex\", [\"app-server\"], { stdio: [\"pipe\", \"pipe\", \"pipe\"] }) as Child;\n}\n","// src/control/codex/config.ts\n// Read the user's codex config (~/.codex/config.toml or $CODEX_HOME/config.toml)\n// and resolve the active model, applying [notice.model_migrations] so squadrant\n// uses the same model the TUI would use (e.g. gpt-5.3-codex → gpt-5.5).\n\nimport { readFile } from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\n\nexport async function resolveCodexModel(): Promise<string | undefined> {\n const home = process.env[\"CODEX_HOME\"] ?? join(homedir(), \".codex\");\n const configPath = join(home, \"config.toml\");\n\n let text: string;\n try {\n text = await readFile(configPath, \"utf8\");\n } catch {\n return undefined;\n }\n\n // Extract top-level `model = \"...\"` (only before the first section header).\n const topLevel = text.split(/^\\[/m)[0] ?? \"\";\n const modelMatch = topLevel.match(/^model\\s*=\\s*\"([^\"]+)\"/m);\n if (!modelMatch) return undefined;\n let model = modelMatch[1]!;\n\n // Apply [notice.model_migrations] — the TUI uses this map to upgrade legacy\n // model names (e.g. gpt-5.3-codex → gpt-5.5) before calling thread/start.\n // Without this, the app-server sends the stale name and ChatGPT OAuth rejects\n // it with a 400: \"The 'gpt-5.3-codex' model is not supported\".\n // Capture the section body up to the next section header (`^[`) or end of\n // input. JS regex has no `\\z`; `(?![\\s\\S])` is the end-of-input assertion so\n // migrations still resolve when the section is the last one in the file.\n const migSection = text.match(/^\\[notice\\.model_migrations\\]([\\s\\S]*?)(?=^\\[|(?![\\s\\S]))/m);\n if (migSection) {\n const migRe = /^\"([^\"]+)\"\\s*=\\s*\"([^\"]+)\"/mg;\n let m: RegExpExecArray | null;\n while ((m = migRe.exec(migSection[1]!)) !== null) {\n if (m[1] === model) { model = m[2]!; break; }\n }\n }\n\n return model;\n}\n","// src/control/codex/normalize.ts\n// Pure mapping from app-server ServerNotification → squadrant ControlEvent.\n// Spec §4.7. Unknown methods return null (status-line only / forward-compat).\n//\n// Anti-#2576 invariant: NO codex notification maps to task.done.\n// task.done is emitted exclusively by the driver on clean process exit.\n//\n// NOTE: Server-requests (frames that carry an `id` field alongside `method`)\n// are NOT handled here — they are routed by CodexInteractiveDriver (Task 2.4).\n// Extending this function with request handling would be incorrect.\nimport type { ControlEvent } from \"@squadrant/shared\";\n\n/** Minimal shape accepted from the JSON-RPC notification stream. */\nexport type AppServerNotification = { method: string; params?: Record<string, unknown> };\n\n/**\n * Map one app-server notification to a ControlEvent, or null when the\n * notification is informational (token-usage, compaction, status-change)\n * and does not need to enter the squadrant event bus.\n *\n * @param taskId The squadrant task ID that owns this notification stream.\n * @param n Raw notification frame from the app-server JSON-RPC channel.\n */\nexport function normalizeAppServerNotification(\n taskId: string,\n n: AppServerNotification,\n): ControlEvent | null {\n const p = n.params ?? {};\n\n switch (n.method) {\n // ── turn lifecycle ────────────────────────────────────────────────────\n case \"turn/started\":\n return {\n type: \"task.turn.started\",\n id: taskId,\n // TurnStartedNotification carries params.turn.id, not a top-level turnId.\n turnId: String((p[\"turn\"] as Record<string, unknown>)?.[\"id\"] ?? \"\"),\n };\n\n case \"turn/completed\":\n return {\n type: \"task.turn.completed\",\n id: taskId,\n // TurnCompletedNotification: same shape as TurnStartedNotification.\n turnId: String((p[\"turn\"] as Record<string, unknown>)?.[\"id\"] ?? \"\"),\n };\n\n // ── streaming delta (heartbeat / content) ─────────────────────────────\n // AgentMessageDeltaNotification: { threadId, turnId, itemId, delta }\n case \"item/agentMessage/delta\":\n // ReasoningTextDeltaNotification: { threadId, turnId, itemId, delta, contentIndex }\n case \"item/reasoning/textDelta\":\n // CommandExecutionOutputDeltaNotification: { threadId, turnId, itemId, delta }\n case \"item/commandExecution/outputDelta\":\n return {\n type: \"task.delta\",\n id: taskId,\n turnId: String(p[\"turnId\"] ?? \"\"),\n chunk: String(p[\"delta\"] ?? \"\"),\n };\n\n // command/exec/outputDelta is connection-scoped (no turnId); map to delta\n // with empty turnId so the bus can still forward it.\n // CommandExecOutputDeltaNotification: { processId, stream, deltaBase64, capReached }\n case \"command/exec/outputDelta\":\n return {\n type: \"task.delta\",\n id: taskId,\n turnId: \"\",\n chunk: String(p[\"deltaBase64\"] ?? \"\"),\n };\n\n // ── error ─────────────────────────────────────────────────────────────\n // ErrorNotification: { error: TurnError, willRetry, threadId, turnId }\n case \"error\": {\n const err = p[\"error\"] as Record<string, unknown> | undefined;\n const message = String(err?.[\"message\"] ?? p[\"message\"] ?? \"error\");\n return { type: \"task.failed\", id: taskId, error: message };\n }\n\n // ── status-line only — return null ────────────────────────────────────\n // ThreadTokenUsageUpdatedNotification: { threadId, turnId, tokenUsage }\n case \"thread/tokenUsage/updated\":\n // ContextCompactedNotification (deprecated): { threadId, turnId }\n case \"thread/compacted\":\n // ThreadStatusChangedNotification\n case \"thread/status/changed\":\n return null;\n\n // ── unknown / future methods ──────────────────────────────────────────\n default:\n return null;\n }\n}\n","// src/control/codex/driver.ts\n// Daemon-side interactive driver for codex. Owns ONE long-lived AppServerClient\n// child, maps TaskRecord ↔ threadId, emits squadrant ControlEvents via the\n// injected emit() hook. Notification mapping delegates to\n// normalizeAppServerNotification (Task 2.3); the driver only routes server-\n// requests and lifecycle. Spec §4.1/§4.6/§4.7.\n\nimport { AppServerClient } from \"./app-server-client.js\";\nimport { resolveCodexModel } from \"./config.js\";\nimport { normalizeAppServerNotification } from \"./normalize.js\";\nimport type { ControlEvent, TaskRecord } from \"@squadrant/shared\";\nimport { TERMINAL_STATES } from \"@squadrant/shared\";\n\n/**\n * Boot-time guard for the daemon's codex reattach loop. Reattaching a thread\n * re-spawns its per-thread MCP servers (gitnexus/pay), so reattaching EVERY\n * non-terminal codex task on boot re-storms one MCP set per historical crew\n * (observed: 22 zombie tasks → 22 gitnexus servers → RAM exhaustion). Only\n * reattach a task that is (a) interactive codex, (b) non-terminal — closed\n * crews are `cancelled` via codex-close, so they're skipped, (c) still fresh:\n * a dead crew's pane is gone and hasn't heartbeat within the staleness window,\n * and (d) has a resumeRef to resume from.\n */\nexport function shouldReattachCodex(\n rec: TaskRecord,\n now: number,\n staleMs: number,\n): boolean {\n if (rec.provider !== \"codex\" || rec.mode !== \"interactive\") return false;\n if (TERMINAL_STATES.has(rec.state)) return false;\n const last = rec.attempts.at(-1)?.lastHeartbeatAt ?? rec.lastHeartbeat ?? 0;\n if (now - last > staleMs) return false;\n return Boolean(rec.attempts.at(-1)?.resumeRef);\n}\n\nexport interface DriverDeps {\n /** Override for tests; defaults to a real AppServerClient. */\n makeClient?: () => AppServerClient;\n /** Ingress into the daemon's event pipeline. */\n emit: (ev: ControlEvent) => void;\n}\n\nexport class CodexInteractiveDriver {\n private client?: AppServerClient;\n private handshakeP?: Promise<void>;\n private threadByTask = new Map<string, string>();\n private taskByThread = new Map<string, string>();\n /**\n * taskId → in-flight dispatch promise. The first-turn say() can arrive while\n * dispatch() is still awaiting startThread (threadByTask not yet set); say()\n * awaits this gate before reading threadByTask so the first turn isn't lost\n * with \"no thread for task\" (issue #212).\n */\n private dispatchByTask = new Map<string, Promise<void>>();\n /** taskId → last pending server-request {id, method} (for answer()) */\n private serverRequestByTask = new Map<string, { id: number; method: string }>();\n private deps: DriverDeps;\n\n constructor(deps: DriverDeps) { this.deps = deps; }\n\n private async ensureClient(): Promise<AppServerClient> {\n if (this.client) return this.client;\n const c = (this.deps.makeClient ?? (() => new AppServerClient({ clientInfo: { name: \"squadrant\", version: \"iv\" } })))();\n this.client = c;\n c.start();\n c.on(\"notification\", (n) => this.onNotification(n));\n c.on(\"serverRequest\", (r) => this.onServerRequest(r));\n c.on(\"closed\", () => { this.client = undefined; this.handshakeP = undefined; });\n return c;\n }\n\n private async ensureHandshake(): Promise<void> {\n const c = await this.ensureClient();\n if (!this.handshakeP) this.handshakeP = c.initialize().then(() => {});\n return this.handshakeP;\n }\n\n async dispatch(rec: TaskRecord & { cwd?: string; model?: string }): Promise<void> {\n // Register the in-flight dispatch synchronously so a concurrent first-turn\n // say() can await it (see dispatchByTask / issue #212). Cleared once the\n // thread is mapped (or dispatch failed), after which say() reads the map.\n const p = this.runDispatch(rec);\n this.dispatchByTask.set(rec.id, p.then(() => {}, () => {}));\n try {\n await p;\n } finally {\n this.dispatchByTask.delete(rec.id);\n }\n }\n\n private async runDispatch(rec: TaskRecord & { cwd?: string; model?: string }): Promise<void> {\n try {\n const c = await this.ensureClient();\n await withTimeout(this.ensureHandshake(), 10_000, \"handshake timed out\");\n // When no model is explicitly set on the task record, read the user's\n // codex config and apply model migrations (e.g. gpt-5.3-codex → gpt-5.5).\n // Without this the app-server falls back to the raw config value and\n // ChatGPT OAuth rejects it with a 400 (verified: gpt-5.5 succeeds).\n const model = rec.model ?? await resolveCodexModel();\n const { threadId } = await c.startThread({\n cwd: rec.cwd ?? process.cwd(),\n model,\n // Parity with claude/opencode crews, which run UNSANDBOXED (no Seatbelt).\n // Codex was the only agent under `workspace-write`, and that FS sandbox\n // blocked `squadrant crew signal …` from reaching the daemon socket (which\n // lives outside the workspace) — breaking the done/blocked/failed\n // lifecycle. Codex's AF_UNIX-socket allowance has no stable config path\n // (it's gated behind the experimental_network feature), so the surgical\n // writable_roots escape is not viable. danger-full-access removes the FS\n // jail so signals work; approvalPolicy still gates risky ops when set to\n // \"untrusted\" (the gate axis is independent of the sandbox axis).\n sandbox: \"danger-full-access\",\n approvalPolicy: rec.approvalPolicy ?? \"never\",\n developerInstructions: buildCodexDeveloperInstructions(rec),\n });\n this.threadByTask.set(rec.id, threadId);\n this.taskByThread.set(threadId, rec.id);\n this.deps.emit({ type: \"task.session\", id: rec.id, resumeRef: threadId });\n this.deps.emit({ type: \"task.started\", id: rec.id });\n } catch (e) {\n const msg = e instanceof Error ? e.message : String(e);\n this.deps.emit({ type: \"task.failed\", id: rec.id, error: `handshake/start failed: ${msg}` });\n throw e;\n }\n }\n\n async say(taskId: string, text: string): Promise<void> {\n // Wait out any in-flight dispatch so the first turn isn't dropped during\n // the startThread window (#212). The gate never rejects; a failed dispatch\n // simply leaves threadByTask empty → the existing \"no thread\" throw stands.\n await this.dispatchByTask.get(taskId);\n const c = this.client!;\n const tid = this.threadByTask.get(taskId);\n if (!tid) throw new Error(`no thread for task ${taskId}`);\n await c.sendTurn(tid, text);\n }\n\n async steer(taskId: string, text: string): Promise<void> {\n const c = this.client!;\n const tid = this.threadByTask.get(taskId);\n if (!tid) throw new Error(`no thread for task ${taskId}`);\n await c.steerTurn(tid, text);\n }\n\n async interrupt(taskId: string): Promise<void> {\n const c = this.client!;\n const tid = this.threadByTask.get(taskId);\n if (!tid) throw new Error(`no thread for task ${taskId}`);\n await c.interruptTurn(tid);\n }\n\n /**\n * Tear down a task's thread when its crew closes. Squadrant runs ONE shared\n * app-server with a thread per crew; closing the cmux pane only kills the\n * `crew attach` renderer, so without this the thread — and the gitnexus/pay\n * MCP servers it spawned — leak forever (verified: ~53MB per orphaned crew).\n * Archiving the thread lets the app-server reap it and its MCP children.\n */\n async close(taskId: string): Promise<void> {\n const tid = this.threadByTask.get(taskId);\n this.serverRequestByTask.delete(taskId);\n if (!tid) return;\n this.threadByTask.delete(taskId);\n this.taskByThread.delete(tid);\n try {\n await this.client?.archiveThread(tid);\n } catch {\n // Best-effort: the app-server may already be gone. The maps are cleared\n // regardless so a daemon restart won't try to reattach a dead thread.\n }\n }\n\n /** Kill the long-lived app-server child process on daemon shutdown. */\n stop(): void {\n this.client?.kill();\n }\n\n async answer(taskId: string, payload: unknown): Promise<void> {\n const c = this.client!;\n const rec = this.serverRequestByTask.get(taskId);\n if (rec == null) throw new Error(`no pending server-request for task ${taskId}`);\n c.respondToServerRequest(rec.id, this.mapAnswerPayload(payload, rec.method));\n this.serverRequestByTask.delete(taskId);\n }\n\n /**\n * Map the captain-facing payload ({text, decision}) to the response shape\n * the codex app-server expects for the specific request method.\n *\n * Old protocol (applyPatchApproval / execCommandApproval):\n * { decision: ReviewDecision } where ReviewDecision = \"approved\" | \"denied\" | …\n *\n * v2 protocol (item/commandExecution/requestApproval / item/fileChange/requestApproval):\n * { decision: CommandExecutionApprovalDecision } where decision = \"accept\" | \"decline\" | …\n *\n * Non-approval requests (text input) pass through unchanged.\n */\n private mapAnswerPayload(payload: unknown, method: string): unknown {\n if (typeof payload !== \"object\" || !payload) return payload;\n const p = payload as Record<string, unknown>;\n if (typeof p.decision !== \"string\") return payload;\n if (method === \"applyPatchApproval\" || method === \"execCommandApproval\") {\n const d = p.decision === \"approve\" ? \"approved\" : \"denied\";\n return { decision: d };\n }\n if (method === \"item/commandExecution/requestApproval\" || method === \"item/fileChange/requestApproval\") {\n const d = p.decision === \"approve\" ? \"accept\" : \"decline\";\n return { decision: d };\n }\n // Unknown method — send the raw decision value\n return { decision: p.decision };\n }\n\n async reattach(rec: TaskRecord & { cwd?: string }): Promise<void> {\n await this.ensureHandshake();\n const c = this.client!;\n const resumeRef = rec.attempts.at(-1)?.resumeRef;\n if (!resumeRef) throw new Error(`reattach: no resumeRef on task ${rec.id}`);\n await c.resumeThread({ threadId: resumeRef, cwd: rec.cwd });\n this.threadByTask.set(rec.id, resumeRef);\n this.taskByThread.set(resumeRef, rec.id);\n this.deps.emit({ type: \"task.reattached\", id: rec.id });\n }\n\n private onNotification(n: { method: string; params?: any }): void {\n const tid = n.params?.threadId ?? n.params?.thread_id;\n const taskId = tid ? this.taskByThread.get(tid) : undefined;\n if (!taskId) return; // status-line only\n const ev = normalizeAppServerNotification(taskId, n);\n if (ev) this.deps.emit(ev);\n }\n\n private onServerRequest(r: { id: number; method: string; params?: any }): void {\n const tid = r.params?.threadId ?? r.params?.thread_id;\n let taskId = tid ? this.taskByThread.get(tid) : undefined;\n if (!taskId && !tid) {\n // Codex approval-shaped server-requests don't reliably carry threadId.\n // Fall back to the sole active task if exactly one exists; otherwise drop.\n if (this.taskByThread.size === 1) {\n taskId = this.taskByThread.values().next().value;\n } else {\n process.stderr.write(\n `[codex/driver] serverRequest ${r.method} dropped: no threadId and ${this.taskByThread.size} active tasks\\n`,\n );\n return;\n }\n }\n if (!taskId) return;\n this.serverRequestByTask.set(taskId, { id: r.id, method: r.method });\n const isApproval = r.method.includes(\"Approval\") || r.method.includes(\"approval\");\n if (isApproval) {\n this.deps.emit({\n type: \"task.approval.requested\",\n id: taskId,\n requestId: r.id,\n question: String(r.params?.question ?? r.method),\n kind: r.method,\n });\n } else {\n this.deps.emit({\n type: \"task.input.requested\",\n id: taskId,\n requestId: r.id,\n question: String(r.params?.question ?? r.method),\n });\n }\n }\n}\n\n/**\n * Build the per-thread developerInstructions for a codex crew. Unlike\n * claude/opencode (which get SQUADRANT_CREW_* env vars on their shell launch\n * line), codex tasks share ONE long-lived app-server child, so a process-level\n * env var would be wrong for concurrent tasks. Instead we tell each thread its\n * concrete task id + project and the exact flag-based signal command, so the\n * codex crew can report terminal state via `squadrant crew signal`. Appended\n * after the crew role body (when present) so the role still leads.\n */\nexport function buildCodexDeveloperInstructions(\n rec: { id: string; project: string; roleInstructions?: string },\n): string {\n const directive =\n `You are squadrant crew task ${rec.id} in project ${rec.project}. ` +\n `When you finish, run EXACTLY: squadrant crew signal done --task-id ${rec.id} --project ${rec.project} --message \"<one-line summary>\". ` +\n `If you are blocked or fail, run squadrant crew signal blocked|failed with the same --task-id ${rec.id} --project ${rec.project} flags.`;\n return rec.roleInstructions ? `${rec.roleInstructions}\\n\\n${directive}` : directive;\n}\n\nfunction withTimeout<T>(p: Promise<T>, ms: number, msg: string): Promise<T> {\n return new Promise((resolve, reject) => {\n const t = setTimeout(() => reject(new Error(msg)), ms);\n p.then(\n (v) => { clearTimeout(t); resolve(v); },\n (e) => { clearTimeout(t); reject(e); },\n );\n });\n}\n","// src/control/opencode/sse-bridge.ts\n// Daemon-side bridge from an opencode crew's HTTP event bus to squadrant\n// ControlEvents. Interactive opencode crews launch as `opencode --port <N>`,\n// which binds a local HTTP server exposing an SSE stream at GET /event. The TUI\n// itself is just one client of that server; the daemon is another. We subscribe\n// once per crew and translate the documented `session.idle` event (emitted when\n// a turn finishes) into `task.turn.completed`, which the state-machine reduces\n// to `awaiting-input`. This gives opencode the same reliable turn-end signal\n// codex gets from its app-server — WITHOUT the crew shelling out to squadrant.\n//\n// `session.idle` is liveness, NOT completion (anti-#2576): a finished turn is\n// not a finished task. Terminal state still comes from the explicit\n// `squadrant crew signal done` in the crew template; the reducer absorbs any\n// session.idle that arrives after the task is already terminal.\nimport type { ControlEvent } from \"@squadrant/shared\";\n\nexport interface OpencodeSseBridgeDeps {\n /** Ingress into the daemon's event pipeline (resolves project + handles). */\n emit: (ev: ControlEvent) => void;\n /** Injectable for tests; defaults to global fetch. */\n fetchImpl?: typeof fetch;\n /** Injectable backoff for tests; defaults to setTimeout. */\n sleep?: (ms: number) => Promise<void>;\n /** Backoff between reconnect attempts (ms, default 500). */\n reconnectMs?: number;\n /** Attempts to reach the server before giving up the boot wait (default 60 ≈ 30s). */\n maxBootAttempts?: number;\n log?: (msg: string) => void;\n}\n\n/**\n * One long-lived SSE subscription per opencode crew. Keyed by taskId so the\n * daemon can stop it when the crew closes. Self-stops when the server's stream\n * ends (crew CLI exited) — at that point terminal state has already been\n * recorded via signal, or the watchdog/close path will reconcile.\n */\nexport class OpencodeSseBridge {\n private controllers = new Map<string, AbortController>();\n /** taskId → the crew's opencode server port (for permission-reply POSTs). */\n private portByTask = new Map<string, number>();\n /** taskId → the last unresolved permission on the bus (for answer()). */\n private pendingPermByTask = new Map<string, { permID: string; sessionID: string }>();\n /** Synthetic monotonic request id. opencode has no numeric id on the bus, but\n * task.approval.requested carries one (codex parity) to key gate promotion. */\n private nextRequestId = 1;\n private deps: OpencodeSseBridgeDeps;\n\n constructor(deps: OpencodeSseBridgeDeps) {\n this.deps = deps;\n }\n\n /** Begin subscribing to the crew's /event stream. Idempotent per task. */\n start(o: { taskId: string; port: number }): void {\n if (this.controllers.has(o.taskId)) return;\n this.portByTask.set(o.taskId, o.port);\n const ac = new AbortController();\n this.controllers.set(o.taskId, ac);\n void this.run(o.taskId, o.port, ac);\n }\n\n /** Stop subscribing for a task (crew closed / terminal). */\n stop(taskId: string): void {\n const ac = this.controllers.get(taskId);\n if (ac) { ac.abort(); this.controllers.delete(taskId); }\n this.portByTask.delete(taskId);\n this.pendingPermByTask.delete(taskId);\n }\n\n /**\n * Resolve a pending opencode permission by POSTing the captain's decision to\n * the crew's server (live-verified, opencode 1.15.13: POST\n * /session/{sessionID}/permissions/{permissionID} with\n * { response: \"once\" | \"reject\" } → 200, fires permission.replied). Mirrors\n * codex's driver.answer(). Returns true if there WAS a pending permission (so\n * the caller knows the answer was an approval, not a reply to a plain `signal\n * blocked` question); false if nothing was pending (already resolved on the\n * bus, or no gate).\n */\n async answer(taskId: string, decision: \"approve\" | \"deny\"): Promise<boolean> {\n const pend = this.pendingPermByTask.get(taskId);\n const port = this.portByTask.get(taskId);\n if (!pend || port == null) return false;\n this.pendingPermByTask.delete(taskId);\n const fetchImpl = this.deps.fetchImpl ?? fetch;\n const response = decision === \"approve\" ? \"once\" : \"reject\";\n try {\n await fetchImpl(`http://127.0.0.1:${port}/session/${pend.sessionID}/permissions/${pend.permID}`, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify({ response }),\n });\n } catch (e) {\n this.deps.log?.(`opencode permission reply failed for ${taskId}: ${(e as Error).message}`);\n }\n // Clear blocked → working; the crew continues (or aborts) the turn, and a\n // later session.idle settles it back to awaiting-input.\n this.deps.emit({ type: \"task.started\", id: taskId });\n return true;\n }\n\n private async run(taskId: string, port: number, ac: AbortController): Promise<void> {\n const fetchImpl = this.deps.fetchImpl ?? fetch;\n const sleep = this.deps.sleep ?? ((ms: number) => new Promise((r) => setTimeout(r, ms)));\n const reconnectMs = this.deps.reconnectMs ?? 500;\n const maxBoot = this.deps.maxBootAttempts ?? 60;\n const url = `http://127.0.0.1:${port}/event`;\n let booted = false;\n let bootAttempts = 0;\n\n while (!ac.signal.aborted) {\n try {\n const res = await fetchImpl(url, {\n signal: ac.signal,\n headers: { accept: \"text/event-stream\" },\n });\n if (!res.ok || !res.body) throw new Error(`status ${res.status}`);\n booted = true;\n await this.consume(taskId, res.body, ac);\n // Stream ended cleanly: the opencode server closed (crew CLI exited).\n // Nothing more to subscribe to — stop without reconnecting.\n break;\n } catch (e) {\n if (ac.signal.aborted) return;\n if (!booted) {\n bootAttempts++;\n if (bootAttempts >= maxBoot) {\n this.deps.log?.(\n `opencode SSE bridge: gave up connecting to ${url} after ${bootAttempts} attempts: ${(e as Error).message}`,\n );\n this.controllers.delete(taskId);\n return;\n }\n }\n await sleep(reconnectMs);\n }\n }\n this.controllers.delete(taskId);\n }\n\n private async consume(\n taskId: string,\n body: ReadableStream<Uint8Array>,\n ac: AbortController,\n ): Promise<void> {\n const reader = body.getReader();\n const decoder = new TextDecoder();\n let buf = \"\";\n try {\n while (!ac.signal.aborted) {\n const { done, value } = await reader.read();\n if (done) return;\n buf += decoder.decode(value, { stream: true });\n let nl: number;\n while ((nl = buf.indexOf(\"\\n\")) >= 0) {\n const line = buf.slice(0, nl);\n buf = buf.slice(nl + 1);\n this.handleLine(taskId, line);\n }\n }\n } finally {\n try { await reader.cancel(); } catch { /* already closed */ }\n }\n }\n\n private handleLine(taskId: string, rawLine: string): void {\n let line = rawLine.trim();\n if (!line) return;\n // SSE field form `data: {json}`; opencode also emits bare JSON lines.\n if (line.startsWith(\"data:\")) line = line.slice(5).trim();\n if (!line.startsWith(\"{\")) return;\n let json:\n | {\n type?: string;\n properties?: {\n id?: string;\n sessionID?: string;\n requestID?: string;\n permission?: string;\n patterns?: string[];\n };\n }\n | undefined;\n try {\n json = JSON.parse(line);\n } catch {\n return; // partial/non-JSON keepalive line\n }\n if (json?.type === \"session.idle\") {\n // turnId is informational for opencode (no per-turn id on the bus); use\n // the session id so the ledger attempt carries a stable correlation key.\n this.deps.emit({\n type: \"task.turn.completed\",\n id: taskId,\n turnId: json.properties?.sessionID ?? \"opencode\",\n });\n } else if (json?.type === \"permission.asked\") {\n // A gated tool (e.g. bash, when --approval set bash:\"ask\") needs approval.\n // Live-verified payload (opencode 1.15.13): properties = PermissionRequest\n // { id:\"per_…\", sessionID:\"ses_…\", permission:\"bash\", patterns:[cmd], … }.\n // Record the pending request so answer() can POST the decision, and surface\n // it as task.approval.requested (codex parity) — the reducer turns it into\n // blocked and the relay renders CREW BLOCKED with the tool + command.\n const p = json.properties;\n if (p?.id && p?.sessionID) {\n this.pendingPermByTask.set(taskId, { permID: p.id, sessionID: p.sessionID });\n const tool = p.permission ?? \"a tool\";\n const cmd = Array.isArray(p.patterns) && p.patterns.length ? `: ${p.patterns.join(\" \")}` : \"\";\n this.deps.emit({\n type: \"task.approval.requested\",\n id: taskId,\n requestId: this.nextRequestId++,\n question: `opencode requests permission to run ${tool}${cmd}`,\n kind: tool,\n });\n }\n } else if (json?.type === \"permission.replied\") {\n // The permission was resolved on the bus (by us or another client) — clear\n // pending state so a later captain answer is a no-op rather than a stale POST.\n this.pendingPermByTask.delete(taskId);\n }\n }\n}\n","import { execSync } from \"node:child_process\";\nimport { readFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport type { InteractiveHookAdapter } from \"./types.js\";\nimport type { ControlEvent } from \"@squadrant/shared\";\n\n// PostToolUse fires after EVERY tool call mid-turn — it is the only liveness\n// signal that refreshes the heartbeat while a crew is still working.\n// Stop fires at turn completion and maps to task.turn.completed so the task\n// transitions to awaiting-input (immune to stall detection) — without this,\n// a captain AFK for >heartbeatBudgetMs would get a false CREW STALLED.\n// SubagentStop fires only at a turn boundary but is liveness-only — it fires\n// while the parent agent still owns the turn. SessionEnd is NOT liveness: it\n// signals the session is gone (crash / Ctrl-C / /exit), so it terminalizes the\n// record (→ task.session.ended) rather than resuming 'working' (#139).\nconst EVENTS = [\"Stop\", \"SubagentStop\", \"SessionEnd\", \"PostToolUse\", \"Notification\"] as const;\n\n/**\n * Probe whether the local Claude CLI supports `--settings <path>`. The\n * daemon-supervised crew path needs per-invocation settings to inject the\n * squadrant Stop hook without polluting the user's global `~/.claude/settings.json`\n * (the scrapped PR #71 mistake). Returns \"flag\" when --settings is available\n * (the happy path), \"project-dir\" when the fallback (write `.claude/settings.json`\n * under the project dir + cd) is needed.\n */\nexport function probeClaudeSettingsFlag(): \"flag\" | \"project-dir\" {\n try {\n const help = execSync(\"claude --help\", { encoding: \"utf-8\", stdio: [\"ignore\", \"pipe\", \"ignore\"] });\n return help.includes(\"--settings \") ? \"flag\" : \"project-dir\";\n } catch {\n return \"project-dir\";\n }\n}\n\n/**\n * Pure: returns true when a Notification hook message indicates Claude is waiting\n * for the user to grant a tool-use permission. Idle notifications (\"Waiting for\n * your input\", \"Claude is thinking\") return false — only permission/approval\n * language triggers the fast-path task.blocked path.\n */\nexport function isPermissionNotification(message: string): boolean {\n if (!message || !message.trim()) return false;\n const lower = message.toLowerCase();\n return lower.includes(\"permission\") || lower.includes(\"approve\");\n}\n\n/** Pure, idempotent merge of squadrant hooks into a Claude settings object. */\nexport function mergeClaudeHooks(settings: any, hookCmd: string): any {\n const next = structuredClone(settings ?? {});\n next.hooks ??= {};\n for (const ev of EVENTS) {\n if (!Array.isArray(next.hooks[ev])) next.hooks[ev] = [];\n const already = next.hooks[ev].some((m: any) =>\n Array.isArray(m?.hooks) && m.hooks.some((h: any) => typeof h.command === \"string\" && h.command.includes(hookCmd)),\n );\n if (!already) {\n next.hooks[ev].push({ matcher: \"\", hooks: [{ type: \"command\", command: `${hookCmd} ${ev}`, timeout: 10 }] });\n }\n }\n return next;\n}\n\n/**\n * Pure, conservative detector for a trailing question that needs captain input.\n * Returns the question text when the LAST non-empty line of the message (outside\n * any fenced code block) ends with \"?\", else null. Intentionally narrow to avoid\n * false-blocked: rhetorical mid-text questions and questions inside ```fences```\n * are ignored because only the final visible line counts. When unsure → null.\n */\nexport function detectTrailingQuestion(text: string): string | null {\n if (!text) return null;\n let inFence = false;\n let lastLine: string | null = null;\n for (const raw of text.split(/\\r?\\n/)) {\n const line = raw.trim();\n if (line.startsWith(\"```\")) { inFence = !inFence; continue; }\n if (inFence || line === \"\") continue;\n lastLine = line;\n }\n if (lastLine && lastLine.endsWith(\"?\")) return lastLine;\n return null;\n}\n\n/**\n * Pure: derive the Claude transcript JSONL path for a session. Claude stores\n * transcripts at ~/.claude/projects/<escaped-cwd>/<session_id>.jsonl, where the\n * cwd is escaped by replacing every non-alphanumeric char with \"-\" (verified\n * against the live ~/.claude/projects layout — e.g. /Users/q3labsadmin/.claude-mem\n * -> -Users-q3labsadmin--claude-mem). Returns null if sessionId or cwd is missing.\n * This is the layered fallback for #174 when the Stop payload omits transcript_path.\n */\nexport function deriveTranscriptPath(sessionId: string, cwd: string): string | null {\n if (!sessionId || !cwd) return null;\n const escaped = cwd.replace(/[^a-zA-Z0-9]/g, \"-\");\n return join(homedir(), \".claude\", \"projects\", escaped, `${sessionId}.jsonl`);\n}\n\n/**\n * I/O: read the LAST assistant message text from a Claude transcript JSONL file.\n * Kept separate from the pure detector so the detector stays trivially testable.\n * Never throws — returns null on any read/parse failure (the hook must exit 0).\n */\nfunction readLastAssistantText(transcriptPath: string): string | null {\n try {\n const raw = readFileSync(transcriptPath, \"utf-8\");\n const lines = raw.split(/\\r?\\n/);\n for (let i = lines.length - 1; i >= 0; i--) {\n const line = lines[i].trim();\n if (!line) continue;\n let entry: any;\n try { entry = JSON.parse(line); } catch { continue; }\n const isAssistant = entry?.type === \"assistant\" || entry?.message?.role === \"assistant\";\n if (!isAssistant) continue;\n const content = entry?.message?.content;\n if (typeof content === \"string\") return content;\n if (Array.isArray(content)) {\n const txt = content\n .filter((b: any) => b?.type === \"text\" && typeof b.text === \"string\")\n .map((b: any) => b.text)\n .join(\"\\n\")\n .trim();\n return txt || null;\n }\n return null;\n }\n return null;\n } catch {\n return null;\n }\n}\n\n/**\n * I/O: obtain the last-assistant text from a LAYERED source, first hit wins:\n * 0. payload.last_assistant_message — the field Claude puts the final assistant\n * text in DIRECTLY on the Stop payload (verified against claude-cli 2.1.156:\n * carries the full final message, including a trailing question, no I/O). This\n * is the primary source and the real #174 delivery fix — earlier diagnoses\n * chased transcript_path (which can be absent), but the message is right here.\n * 1. else payload.transcript_path (documented field, when present + readable);\n * 2. else the path derived from payload.session_id + cwd (defensive fallback for\n * older clients that omit both of the above).\n * cwd preference: payload.cwd (Claude hook contract) → SQUADRANT_CREW_CWD → cwd().\n * Best-effort: a null/miss from one source falls through to the next; never throws.\n */\nfunction resolveLastAssistantText(payload: unknown): string | null {\n const p = payload as any;\n const direct = p?.last_assistant_message;\n if (typeof direct === \"string\" && direct.trim()) return direct;\n const candidates: string[] = [];\n const tp = p?.transcript_path;\n if (typeof tp === \"string\" && tp) candidates.push(tp);\n const cwd = (typeof p?.cwd === \"string\" && p.cwd) ? p.cwd : (process.env.SQUADRANT_CREW_CWD || process.cwd());\n const derived = deriveTranscriptPath(p?.session_id, cwd);\n if (derived) candidates.push(derived);\n for (const path of candidates) {\n const text = readLastAssistantText(path);\n if (text != null) return text;\n }\n return null;\n}\n\n/**\n * Map a Claude hook event name to a squadrant ControlEvent. Codifies the anti-#2576\n * invariant: NO Claude hook ever maps to `task.done`/`task.failed`.\n * PostToolUse/SubagentStop = resume-liveness only (task.progress). SessionEnd is\n * the lone terminalizing hook: the session is gone, so it maps to\n * task.session.ended → cancelled (#139) — silent, never done/failed.\n * Terminal `done`/`failed` come exclusively from explicit `squadrant crew signal`.\n *\n * Stop = turn boundary. It normally maps to task.turn.completed → awaiting-input\n * (stall-immune) so a captain reviewing output never trips a false CREW STALLED\n * (fixes #131). NARROW EXCEPTION #1 (#174): when the crew's last assistant message\n * ENDS with a direct question, Stop maps to task.blocked instead, surfacing the\n * question to the captain as CREW BLOCKED. The last-assistant text is obtained from\n * a LAYERED source (last_assistant_message on the payload → transcript_path →\n * derived path from session_id+cwd); the payload field is the primary, I/O-free\n * source. All transcript I/O is best-effort and never throws (hook must exit 0).\n *\n * Notification = Claude needs user attention. NARROW EXCEPTION #2\n * (#notification-hook): when the payload.message indicates a permission request\n * (isPermissionNotification), this maps to task.blocked instantly — bypassing the\n * ~20-30s relay poll. The relay poll remains as a fallback for opencode crews and\n * as a safety net; both may fire task.blocked for the same prompt, but the\n * state-machine idempotency (already-blocked → no-op, from #176) deduplicates.\n * Non-permission notifications (idle liveness) → task.progress. Missing/non-string\n * message → task.progress (never throws, hook must exit 0).\n */\nexport function mapClaudeHookToEvent(\n event: string,\n payload: unknown,\n taskId: string,\n): ControlEvent | null {\n switch (event) {\n case \"Stop\": {\n const text = resolveLastAssistantText(payload);\n const question = text ? detectTrailingQuestion(text) : null;\n if (question) {\n return { type: \"task.blocked\", id: taskId, reason: \"crew asked a question (auto-detected)\", question };\n }\n return { type: \"task.turn.completed\", id: taskId, turnId: \"hook-stop\" };\n }\n case \"Notification\": {\n const msg = (payload as any)?.message;\n if (typeof msg === \"string\" && isPermissionNotification(msg)) {\n return { type: \"task.blocked\", id: taskId, reason: \"crew awaiting permission (notification hook)\", question: msg };\n }\n return { type: \"task.progress\", id: taskId, note: \"notification\" };\n }\n case \"SessionEnd\":\n // #139: the session is GONE. NOT liveness — mapping this to task.progress\n // resumed a dead crew to 'working' (awaiting-input → working), where\n // nothing heartbeats and the watchdog false-stalled it ~budget later.\n // Terminalize the record instead (reducer: task.session.ended → cancelled).\n return { type: \"task.session.ended\", id: taskId };\n case \"SubagentStop\":\n case \"PostToolUse\":\n // The only resume-liveness hooks: PostToolUse fires after every tool call\n // mid-turn; SubagentStop fires while the parent still owns the turn.\n return { type: \"task.progress\", id: taskId, note: event.toLowerCase() };\n default:\n return null;\n }\n}\n\nexport const claudeInteractive: InteractiveHookAdapter = {\n provider: \"claude\",\n tier: \"strong\",\n injectHook(launchSpec) {\n // Claude reads merged ~/.config settings; nothing to add to argv here.\n // The settings merge is performed by the launcher (Task 18) before spawn.\n return launchSpec;\n },\n};\n","import { detectTrailingQuestion } from \"./claude.js\";\n\n/**\n * Pure classifier for a crew pane's TAIL (last ~25 lines), used by the daemon's\n * fast interactive-prompt probe (Phase 2b). A crew blocked at a permission\n * prompt shows daemon state=working with NO heartbeat — the hook bridge only\n * fires PostToolUse, which never happens while the prompt is up — so the daemon\n * cannot see the block until the multi-minute stall budget. This detector lets\n * the probe surface that wait as CREW BLOCKED within one probe cadence.\n *\n * - \"approval\": a permission-dialog shape — a \"Do you want to ...?\" prompt line\n * plus a numbered Yes/No option block. text = the human-readable prompt line.\n * - \"question\": the agent's output region (TUI chrome stripped) ends in a\n * direct question. Mainly the opencode path; Claude turn-end questions are\n * already handled by the #174 Stop-hook transcript path.\n * - \"error\": the pane shows a fatal CLI error banner (e.g. Anthropic\n * `API Error: 529 Overloaded`, an HTTP 5xx, retry exhaustion). A turn that\n * dies on a transient API error leaves the process ALIVE with the banner\n * frozen in the pane and no further heartbeat — the probe's only window onto\n * it (#196). text = the banner line. Checked LAST so a genuine approval /\n * question that merely mentions an error stays recoverable, never terminal.\n * - else null.\n *\n * Conservative by design: it only runs against a quiet working pane and must not\n * false-block, so an ambiguous tail returns null.\n */\nexport function classifyPaneTail(\n tail: string,\n): { kind: \"approval\" | \"question\" | \"error\"; text: string } | null {\n if (!tail) return null;\n const raw = tail.split(/\\r?\\n/);\n // cleaned[i] is the agent-region text of line i, or null if the line is pure\n // TUI chrome (box border, empty input prompt, status line) and should be ignored.\n const cleaned = raw.map(stripChrome);\n\n // ── approval: numbered Yes/No option block + a \"?\"-terminated prompt above ──\n const options: { label: string; ci: number }[] = [];\n for (let i = 0; i < cleaned.length; i++) {\n const c = cleaned[i];\n if (c == null) continue;\n const m = c.match(OPTION_RE);\n if (m) options.push({ label: m[2], ci: i });\n }\n const hasYes = options.some((o) => /\\byes\\b/i.test(o.label));\n const hasNo = options.some((o) => /\\bno\\b/i.test(o.label));\n if (options.length >= 2 && hasYes && hasNo) {\n // The prompt is the nearest \"?\"-terminated agent line above the first option.\n const firstOptCi = options[0].ci;\n for (let i = firstOptCi - 1; i >= 0; i--) {\n const c = cleaned[i];\n if (c == null) continue;\n if (c.endsWith(\"?\")) return { kind: \"approval\", text: c };\n }\n // Unmistakable Yes/No dialog but no \"?\"-line extracted → still actionable.\n return { kind: \"approval\", text: \"Crew is awaiting permission approval.\" };\n }\n\n // ── question: trailing question in the chrome-stripped agent output region ──\n const region = cleaned.filter((c): c is string => c != null).join(\"\\n\");\n const q = detectTrailingQuestion(region);\n if (q) return { kind: \"question\", text: q };\n\n // ── error: a fatal CLI error banner (#196), checked LAST so a recoverable\n // approval/question above always wins. Match the LAST banner line (the final\n // error after any retry chatter is the most informative).\n let errLine: string | null = null;\n for (const c of cleaned) {\n if (c != null && ERROR_BANNER_RE.some((re) => re.test(c))) errLine = c;\n }\n if (errLine) return { kind: \"error\", text: errLine.slice(0, 200) };\n\n return null;\n}\n\n// Distinctive fatal-error-banner signatures a crew's CLI prints when a turn\n// dies (Anthropic / OpenAI / opencode). Anchored to CLI banner SHAPES — never a\n// bare \"error\" / lone status code — so a crew merely discussing errors in prose\n// is never mis-failed. Combined with the probe's working+quiet precondition,\n// these only fire on a genuinely stalled, error-frozen pane.\nconst ERROR_BANNER_RE: RegExp[] = [\n /\\bAPI Error\\b/i, // Claude: \"API Error: 529 ...\"\n /\\bOverloaded\\b/, // Anthropic overloaded_error message\n /\\b(?:429|500|502|503|504|529)\\b[^?]*\\b(?:overloaded|unavailable|internal server error|bad gateway|gateway timeout|too many requests|service unavailable)\\b/i,\n /\\bretr(?:y|ies)\\s+(?:exhausted|limit\\s+(?:reached|exceeded))\\b/i,\n /\\bmaximum\\s+retries\\b/i,\n];\n\n// A numbered option line, after chrome stripping: an optional cursor marker\n// (❯ / > / ›), a number, a dot, then the label. e.g. \"❯ 1. Yes\".\nconst OPTION_RE = /^[❯>›]?\\s*(\\d+)\\.\\s+(.*\\S)\\s*$/;\n\n// Box-drawing / rule characters that make up a pure-chrome line.\nconst PURE_CHROME_RE = /^[\\s─━│┃╭╮╰╯┌┐└┘├┤┬┴┼═║╔╗╚╝╠╣╦╩╬▁▂▃▄▅▆▇█▔▏▕]+$/;\nconst STATUS_LINE_RE = /accept edits on|shift\\+tab|⏵⏵|\\? for shortcuts|esc to interrupt|tokens? (used|left)|context left/i;\n\n/**\n * Strip the box-drawing border / cursor padding from one pane line and decide\n * whether it carries agent content. Returns the trimmed content, or null if the\n * line is pure TUI chrome (border, empty input prompt, status line) that the\n * classifier must ignore.\n */\nfunction stripChrome(raw: string): string | null {\n // Defensive ANSI strip — cmux read-screen is usually plain text, but a stray\n // escape would otherwise leak into the extracted prompt text.\n let line = raw.replace(/\u001b\\[[0-9;]*m/g, \"\");\n // Peel leading/trailing vertical box borders and surrounding whitespace.\n line = line.replace(/^[\\s│┃▏▕|]+/, \"\").replace(/[\\s│┃▏▕|]+$/, \"\");\n const trimmed = line.trim();\n if (trimmed === \"\") return null;\n if (PURE_CHROME_RE.test(trimmed)) return null;\n if (/^>\\s*$/.test(trimmed)) return null; // empty input prompt\n if (STATUS_LINE_RE.test(trimmed)) return null;\n return trimmed;\n}\n","import type { InteractiveHookAdapter } from \"./types.js\";\nimport { claudeInteractive } from \"./claude.js\";\n\nconst ADAPTERS: Record<string, InteractiveHookAdapter> = {\n claude: claudeInteractive,\n};\n\nexport function getInteractiveAdapter(provider: string): InteractiveHookAdapter {\n const a = ADAPTERS[provider];\n if (!a) throw new Error(`no interactive adapter for provider '${provider}'`);\n return a;\n}\n","export {};\n//# sourceMappingURL=types.js.map","// src/control/headless/types.ts\nexport const HEADLESS_ERROR_TAIL = 2000;\n\nexport interface HeadlessResult {\n outcome: \"done\" | \"failed\";\n /** Always a string: result text, JSON-stringified non-string result, or raw stdout fallback. Becomes resultRef contents. */\n payload?: string;\n sessionId?: string;\n error?: string;\n exitCode?: number;\n parseWarning?: boolean;\n}\n\nexport interface HeadlessAdapter {\n provider: string;\n buildCommand(task: string, sessionId?: string): string[];\n parseResult(stdout: string, exitCode: number): HeadlessResult;\n}\n","// src/control/headless/claude.ts\nimport type { HeadlessAdapter } from \"./types.js\";\nimport { HEADLESS_ERROR_TAIL } from \"./types.js\";\n\nexport const claudeHeadless: HeadlessAdapter = {\n provider: \"claude\",\n buildCommand(task, sessionId) {\n const argv = [\"claude\", \"-p\", \"--output-format\", \"json\"];\n if (sessionId) argv.push(\"--resume\", sessionId);\n argv.push(task);\n return argv;\n },\n parseResult(stdout, exitCode) {\n if (exitCode !== 0) {\n return { outcome: \"failed\", exitCode, error: stdout.slice(-HEADLESS_ERROR_TAIL) };\n }\n try {\n const j = JSON.parse(stdout);\n if (j.is_error) return { outcome: \"failed\", error: String(j.result ?? \"is_error\"), sessionId: j.session_id };\n const payload = typeof j.result === \"string\" ? j.result : j.result == null ? \"\" : JSON.stringify(j.result);\n return { outcome: \"done\", sessionId: j.session_id, payload };\n } catch {\n return { outcome: \"done\", parseWarning: true, payload: stdout };\n }\n },\n};\n","// src/control/headless/opencode.ts\nimport type { HeadlessAdapter } from \"./types.js\";\nimport { HEADLESS_ERROR_TAIL } from \"./types.js\";\n\n// opencode `run` is used for one-shot; serve-session wiring is a later spec.\n// Process-exit is the done-signal here (foundational scope).\nexport const opencodeHeadless: HeadlessAdapter = {\n provider: \"opencode\",\n buildCommand(task, sessionId) {\n const argv = [\"opencode\", \"run\", \"--format\", \"json\"];\n if (sessionId) argv.push(\"--session\", sessionId);\n argv.push(task);\n return argv;\n },\n parseResult(stdout, exitCode) {\n if (exitCode !== 0) return { outcome: \"failed\", exitCode, error: stdout.slice(-HEADLESS_ERROR_TAIL) };\n try {\n const j = JSON.parse(stdout);\n const payload = typeof j.result === \"string\" ? j.result : JSON.stringify(j.result ?? stdout);\n return { outcome: \"done\", sessionId: j.sessionID ?? j.session_id, payload };\n } catch {\n return { outcome: \"done\", parseWarning: true, payload: stdout };\n }\n },\n};\n","// src/control/headless/codex.ts\nimport type { HeadlessAdapter } from \"./types.js\";\nimport { HEADLESS_ERROR_TAIL } from \"./types.js\";\n\nexport const codexHeadless: HeadlessAdapter = {\n provider: \"codex\",\n buildCommand(task, sessionId) {\n // Verified against codex-cli 0.130.0 `codex exec [OPTIONS] [PROMPT]`:\n // --json: JSONL events to stdout (valid).\n // --skip-git-repo-check: REQUIRED — the daemon spawns codex with a\n // non-trusted/non-git cwd under launchd; without it codex aborts with\n // \"Not inside a trusted directory and --skip-git-repo-check was not\n // specified.\" (real production failure, red-team/verify-on-implement).\n // resume is a SUBCOMMAND (`codex exec resume <id>`), NOT a `--session`\n // flag. Resume is unused in foundational scope (multi-turn/reply\n // deferred) — kept best-effort; flag order is verify-on-implement when\n // the interactive-wiring spec lands.\n // --sandbox workspace-write: codex exec defaults to a READ-ONLY sandbox,\n // so a crew could analyze/spec but never edit code (real prod finding:\n // codex bailed \"workspace is mounted read-only\"). workspace-write lets it\n // edit within its cwd (set by the launcher per-task) — NOT full-disk\n // (danger-full-access) which would be reckless for an autonomous agent.\n const opts = [\"--json\", \"--skip-git-repo-check\", \"--sandbox\", \"workspace-write\"];\n if (sessionId) return [\"codex\", \"exec\", \"resume\", sessionId, ...opts, task];\n return [\"codex\", \"exec\", ...opts, task];\n },\n parseResult(stdout, exitCode) {\n if (exitCode !== 0) return { outcome: \"failed\", exitCode, error: stdout.slice(-HEADLESS_ERROR_TAIL) };\n // codex result format undocumented; keep raw, never guess failure.\n return { outcome: \"done\", payload: stdout };\n },\n};\n","// src/control/headless/registry.ts\nimport type { HeadlessAdapter } from \"./types.js\";\nimport { claudeHeadless } from \"./claude.js\";\nimport { opencodeHeadless } from \"./opencode.js\";\nimport { codexHeadless } from \"./codex.js\";\n\nconst ADAPTERS: Record<string, HeadlessAdapter> = {\n claude: claudeHeadless,\n opencode: opencodeHeadless,\n codex: codexHeadless,\n};\n\nexport function getHeadlessAdapter(provider: string): HeadlessAdapter {\n const a = ADAPTERS[provider];\n if (!a) throw new Error(`no headless adapter for provider '${provider}'`);\n return a;\n}\n","// src/control/headless-launcher.ts\nimport type { spawn as nodeSpawn } from \"node:child_process\";\nimport type { ControlEvent } from \"@squadrant/shared\";\nimport { getHeadlessAdapter } from \"./headless/registry.js\";\n\nexport interface RunHeadlessOpts {\n provider: string;\n task: string;\n id: string;\n sessionId?: string;\n /**\n * Working dir for the spawned child. Headless previously inherited the\n * daemon's launchd cwd (`/`) — wrong for every provider, and the reason\n * codex could only do read-only work. Unset → inherit (back-compat).\n */\n cwd?: string;\n spawn: typeof nodeSpawn;\n emit: (e: ControlEvent) => void;\n /** Where to persist captured payload; defaults handled by caller (Task 17). */\n writeResult?: (id: string, payload: string) => string;\n}\n\nexport interface HeadlessHandle {\n result: Promise<void>;\n kill: () => void;\n}\n\n// Max bytes retained in the stdout/stderr capture buffers (oldest dropped).\nconst OUT_CAP = 4 * 1024 * 1024;\nconst ERR_CAP = 4 * 1024 * 1024;\n// Emit task.progress at most once per interval OR once per batch, whichever first.\nconst PROGRESS_INTERVAL_MS = 250;\nconst PROGRESS_CHUNK_BATCH = 50;\n\nexport function runHeadless(opts: RunHeadlessOpts): HeadlessHandle {\n const adapter = getHeadlessAdapter(opts.provider);\n const argv = adapter.buildCommand(opts.task, opts.sessionId);\n const child = opts.spawn(argv[0], argv.slice(1), {\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n cwd: opts.cwd, // undefined → inherit daemon cwd (back-compat)\n });\n opts.emit({ type: \"task.started\", id: opts.id, pid: child.pid ?? undefined });\n\n let out = \"\";\n let err = \"\";\n\n // Debounce state — coalesces task.progress to avoid O(chunks) file writes.\n let lastProgressAt = 0;\n let chunksSinceProgress = 0;\n let debounceTimer: ReturnType<typeof setTimeout> | null = null;\n\n function flushProgress(): void {\n if (debounceTimer) { clearTimeout(debounceTimer); debounceTimer = null; }\n lastProgressAt = Date.now();\n chunksSinceProgress = 0;\n opts.emit({ type: \"task.progress\", id: opts.id }); // stdout activity = liveness\n }\n\n child.stdout?.on(\"data\", (d) => {\n out += String(d);\n if (out.length > OUT_CAP) out = out.slice(out.length - OUT_CAP);\n chunksSinceProgress++;\n const now = Date.now();\n if (chunksSinceProgress >= PROGRESS_CHUNK_BATCH || now - lastProgressAt >= PROGRESS_INTERVAL_MS) {\n flushProgress();\n } else if (!debounceTimer) {\n const delay = PROGRESS_INTERVAL_MS - (now - lastProgressAt);\n debounceTimer = setTimeout(() => { debounceTimer = null; flushProgress(); }, delay);\n }\n });\n child.stderr?.on(\"data\", (d) => {\n err += String(d);\n if (err.length > ERR_CAP) err = err.slice(err.length - ERR_CAP);\n });\n\n const result = new Promise<void>((resolve) => {\n child.once(\"error\", (e: Error) => {\n if (debounceTimer) { clearTimeout(debounceTimer); debounceTimer = null; }\n opts.emit({ type: \"task.failed\", id: opts.id, error: `spawn error: ${e.message}`, exitCode: undefined });\n resolve(); // never hang the daemon; resolve() is idempotent\n });\n child.on(\"close\", (code) => {\n // Flush any batched-but-not-yet-emitted activity before the terminal event.\n if (chunksSinceProgress > 0) flushProgress();\n else if (debounceTimer) { clearTimeout(debounceTimer); debounceTimer = null; }\n const parseInput = (code !== 0 && err) ? err : (out || err);\n const res = adapter.parseResult(parseInput, code ?? 0);\n if (res.outcome === \"failed\") {\n opts.emit({ type: \"task.failed\", id: opts.id, error: res.error ?? \"non-zero exit\", exitCode: res.exitCode });\n } else {\n const ref = opts.writeResult ? opts.writeResult(opts.id, res.payload ?? \"\") : \"\";\n opts.emit({ type: \"task.done\", id: opts.id, resultRef: ref, parseWarning: res.parseWarning });\n }\n resolve();\n });\n });\n\n return { result, kill: () => child.kill(\"SIGTERM\") };\n}\n","// @squadrant/agents — AI-agent driver seam (claude · codex · opencode · gemini).\nexport * from \"./drivers/index.js\";\nexport * from \"./projection/index.js\";\nexport * from \"./codex/app-server-client.js\";\nexport * from \"./codex/driver.js\";\nexport * from \"./codex/normalize.js\";\nexport * from \"./opencode/sse-bridge.js\";\nexport * from \"./interactive/claude.js\";\nexport * from \"./interactive/pane-classifier.js\";\nexport * from \"./interactive/registry.js\";\nexport * from \"./interactive/types.js\";\nexport * from \"./headless/registry.js\";\nexport * from \"./headless/types.js\";\nexport * from \"./headless-launcher.js\";\n","#!/usr/bin/env node\n\nimport { Command } from \"commander\";\nimport { readFileSync, existsSync, writeFileSync } from \"node:fs\";\nimport { fileURLToPath } from \"node:url\";\nimport { dirname, join } from \"node:path\";\nimport { homedir } from \"node:os\";\nimport { ensureRuntimeSynced } from \"@squadrant/shared\";\nimport { ensureDaemon } from \"@squadrant/core\";\nimport { doctorCommand } from \"./commands/doctor.js\";\nimport { initCommand } from \"./commands/init.js\";\nimport { projectsCommand } from \"./commands/projects.js\";\nimport { statusCommand } from \"./commands/status.js\";\nimport { commandCommand } from \"./commands/command.js\";\nimport { crewCommand } from \"./commands/crew.js\";\nimport { sideCommand } from \"./commands/side.js\";\nimport { addControlPlaneCrewCommands } from \"./commands/crew-control.js\";\nimport { dashboardCommand } from \"./commands/dashboard.js\";\nimport { launchCommand } from \"./commands/launch.js\";\nimport { shutdownCommand } from \"./commands/shutdown.js\";\nimport { feedbackCommand } from \"./commands/feedback.js\";\nimport { standupCommand } from \"./commands/standup.js\";\nimport { retroCommand } from \"./commands/retro.js\";\nimport { runtimeCommand } from \"./commands/runtime.js\";\nimport { workspaceCommand } from \"./commands/workspace.js\";\nimport { notifyCommand } from \"./commands/notify.js\";\nimport { projectionCommand } from \"./commands/projection.js\";\nimport { codexChatSmokeCommand } from \"./commands/codex-chat-smoke.js\";\nimport { configCommand } from \"./commands/config.js\";\nimport { healCommand } from \"./commands/heal.js\";\nimport { groupCommand } from \"./commands/group.js\";\nimport { cmuxCommand } from \"./commands/cmux.js\";\nimport { effortCommand } from \"./commands/effort.js\";\nimport { telegramCommand } from \"./commands/telegram.js\";\nimport { detectDrift } from \"@squadrant/shared\";\nimport { needsCheck, withStamp } from \"@squadrant/shared\";\nimport { getDefaultConfig } from \"@squadrant/shared\";\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\nconst pkg = JSON.parse(readFileSync(join(__dirname, \"..\", \"package.json\"), \"utf-8\"));\n\n// Self-heal the runtime copy of source-managed dirs before any command runs,\n// so source changes (skills, role templates, scripts) can never silently\n// drift from ~/.config/squadrant. Never throws.\nensureRuntimeSynced({\n sourceRoot: join(__dirname, \"..\"),\n runtimeRoot: join(homedir(), \".config\", \"squadrant\"),\n});\n\n// Non-blocking config-drift banner. Suppressed during \"squadrant config\" —\n// the config command already surfaces drift, making the banner redundant.\n// Detect + print only — never mutates config and never throws.\nif (process.argv[2] !== \"config\") {\n try {\n const cfgPath = join(homedir(), \".config\", \"squadrant\", \"config.json\");\n if (existsSync(cfgPath)) {\n const cfg = JSON.parse(readFileSync(cfgPath, \"utf-8\"));\n if (needsCheck(cfg, pkg.version)) {\n const items = detectDrift(cfg, getDefaultConfig());\n if (items.length === 0) {\n writeFileSync(cfgPath, JSON.stringify(withStamp(cfg, pkg.version), null, 2) + \"\\n\");\n } else {\n const from = cfg._squadrantVersion ?? \"an earlier version\";\n process.stderr.write(\n `\\n\\u26A1 squadrant updated ${from} \\u2192 ${pkg.version} \\u2014 ${items.length} config change(s) detected.\\n` +\n ` Run \\`squadrant config check\\` (or use the config-doctor skill) to reconcile.\\n\\n`,\n );\n }\n }\n }\n } catch {\n // Drift banner is best-effort; never block the CLI.\n }\n}\n\n// Self-heal the control-plane daemon the same way we self-heal the runtime:\n// best-effort, never throws; the CLI fails loud later if the socket is unreachable.\n// ensureDaemon resolves its own entrypoint (see launchd.daemonEntryPath) — no\n// path is passed here so no call site can get it wrong.\n// SQUADRANT_DAEMON_SKIP short-circuits this for read-only / CI invocations that must\n// not attempt to boot the daemon (e.g. config-check tests on Linux without launchctl).\nif (!process.env.SQUADRANT_DAEMON_SKIP) {\n ensureDaemon();\n}\n\nconst program = new Command();\n\nprogram\n .name(\"squadrant\")\n .description(\"Multi-project orchestration for your coding agents (Claude, Codex, opencode, Gemini)\")\n .version(pkg.version);\n\nprogram.addCommand(doctorCommand);\nprogram.addCommand(initCommand);\nprogram.addCommand(projectsCommand);\nprogram.addCommand(statusCommand);\n// Legacy crew verbs (spawn/send/read/close/list) stay intact for live captains;\n// control-plane verbs (dispatch/status/tasks/reply) are attached onto the same\n// `squadrant crew` command so PR #85 doesn't break the captain-ops playbook.\naddControlPlaneCrewCommands(crewCommand);\nprogram.addCommand(crewCommand);\nprogram.addCommand(sideCommand);\nprogram.addCommand(commandCommand);\nprogram.addCommand(dashboardCommand);\nprogram.addCommand(launchCommand);\nprogram.addCommand(shutdownCommand);\nprogram.addCommand(feedbackCommand);\nprogram.addCommand(standupCommand);\nprogram.addCommand(retroCommand);\nprogram.addCommand(runtimeCommand);\nprogram.addCommand(workspaceCommand);\nprogram.addCommand(notifyCommand);\nprogram.addCommand(projectionCommand);\nprogram.addCommand(codexChatSmokeCommand);\nprogram.addCommand(configCommand);\nprogram.addCommand(healCommand);\nprogram.addCommand(groupCommand);\nprogram.addCommand(cmuxCommand);\nprogram.addCommand(effortCommand);\nprogram.addCommand(telegramCommand);\n\nprogram.parseAsync().catch((e) => {\n process.stderr.write(`error: ${e instanceof Error ? e.message : String(e)}\\n`);\n process.exit(1);\n});\n","import { Command } from \"commander\";\nimport { execSync } from \"node:child_process\";\nimport fs from \"node:fs\";\nimport { stat } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport chalk from \"chalk\";\nimport { loadConfig } from \"@squadrant/shared\";\nimport { compatManifest, type ToolEntry } from \"@squadrant/shared\";\nimport { checkToolCompat } from \"@squadrant/shared\";\nimport { createCmuxDriver, RuntimeRegistry, createCmuxNotifier, NotifierRegistry, createObsidianDriver, WorkspaceRegistry } from \"@squadrant/workspaces\";\nimport { queryHealth, printServiceHealth } from \"./health-view.js\";\nimport {\n createCursorEmitter,\n createCodexEmitter,\n createGeminiEmitter,\n createOpencodeEmitter,\n ProjectionRegistry,\n} from \"@squadrant/agents\";\n\nfunction commandExists(cmd: string): boolean {\n try {\n execSync(`which ${cmd}`, { stdio: \"ignore\" });\n return true;\n } catch {\n return false;\n }\n}\n\nfunction claudeVersionOk(): boolean {\n try {\n const version = execSync(\"claude --version\", { encoding: \"utf-8\" }).trim();\n const match = version.match(/(\\d+)\\.(\\d+)\\.(\\d+)/);\n if (!match) return false;\n const [major, minor, patch] = match.slice(1).map(Number);\n const [minMajor, minMinor, minPatch] = compatManifest.tools.claude.min.split(\".\").map(Number);\n return (\n major > minMajor ||\n (major === minMajor && minor > minMinor) ||\n (major === minMajor && minor === minMinor && patch >= minPatch)\n );\n } catch {\n return false;\n }\n}\n\nfunction settingsHaveAgentTeams(): boolean {\n try {\n const home = process.env.HOME || \"\";\n const settings = JSON.parse(\n fs.readFileSync(`${home}/.claude/settings.json`, \"utf-8\"),\n );\n return settings?.env?.CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS === \"1\";\n } catch {\n return false;\n }\n}\n\nfunction pluginInstalled(pluginKey: string): boolean {\n try {\n const home = process.env.HOME || \"\";\n const plugins = JSON.parse(\n fs.readFileSync(\n `${home}/.claude/plugins/installed_plugins.json`,\n \"utf-8\",\n ),\n );\n return pluginKey in (plugins?.plugins || {});\n } catch {\n return false;\n }\n}\n\nfunction nodeVersionOk(): boolean {\n const major = parseInt(process.versions.node.split(\".\")[0], 10);\n const [minMajor] = compatManifest.tools.node.min.split(\".\").map(Number);\n return major >= minMajor;\n}\n\nfunction tryGetVersion(cmd: string): string {\n try {\n return execSync(`${cmd} --version`, { encoding: \"utf-8\" }).trim();\n } catch {\n return \"\";\n }\n}\n\nfunction check(label: string, pass: boolean): boolean {\n const icon = pass ? chalk.green(\"✔ PASS\") : chalk.red(\"✘ FAIL\");\n console.log(` ${icon} ${label}`);\n return pass;\n}\n\nexport const doctorCommand = new Command(\"doctor\")\n .description(\"Check system health and prerequisites\")\n .action(async () => {\n console.log(chalk.bold(\"\\nSquadrant Doctor\\n\"));\n\n const results: boolean[] = [];\n\n results.push(check(\"Claude Code installed\", commandExists(\"claude\")));\n results.push(check(`Claude Code version >= ${compatManifest.tools.claude.min}`, claudeVersionOk()));\n results.push(check(\"Obsidian installed\", commandExists(\"obsidian\") || fs.existsSync(\"/Applications/Obsidian.app\")));\n results.push(check(\"Node.js >= 18\", nodeVersionOk()));\n results.push(\n check(\n \"Agent Teams enabled (CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1)\",\n settingsHaveAgentTeams(),\n ),\n );\n results.push(check(\"Plugin: superpowers\", pluginInstalled(\"superpowers@claude-plugins-official\")));\n results.push(\n check(\"Plugin: claude-mem\", pluginInstalled(\"claude-mem@thedotmack\")),\n );\n results.push(check(\"Plugin: context7\", pluginInstalled(\"context7@claude-plugins-official\")));\n\n const config = loadConfig();\n\n const runtimes = new RuntimeRegistry({ cmux: createCmuxDriver() });\n const probeResults = await runtimes.probeAll();\n\n // Global runtime must be installed\n const globalRuntimeName = config.runtime ?? \"cmux\";\n const globalProbe = probeResults[globalRuntimeName];\n results.push(check(\n `Runtime '${globalRuntimeName}' installed`,\n !!globalProbe?.installed,\n ));\n\n // Any project-level override must also be installed\n const overrides = new Set<string>();\n for (const proj of Object.values(config.projects)) {\n if (proj.runtime && proj.runtime !== globalRuntimeName) overrides.add(proj.runtime);\n }\n for (const runtimeName of overrides) {\n const probe = probeResults[runtimeName];\n results.push(check(\n `Runtime '${runtimeName}' installed (project override)`,\n !!probe?.installed,\n ));\n }\n\n // Probe workspace providers\n const workspaces = new WorkspaceRegistry({ obsidian: createObsidianDriver });\n const hubDriver = workspaces.hub(config);\n const hubProbe = await hubDriver.probe();\n results.push(check(\n `Workspace '${config.workspace ?? \"obsidian\"}' — hub reachable`,\n hubProbe.installed && hubProbe.rootExists,\n ));\n\n for (const [name] of Object.entries(config.projects)) {\n const spokeDriver = workspaces.forProject(name, config);\n const probe = await spokeDriver.probe();\n results.push(check(\n `Workspace — spoke '${name}' reachable`,\n probe.installed && probe.rootExists,\n ));\n }\n\n // Probe notifier providers\n const notifiers = new NotifierRegistry({ cmux: createCmuxNotifier });\n const notifierProbes = await notifiers.probeAll();\n for (const [name, probe] of Object.entries(notifierProbes)) {\n results.push(check(\n `Notifier '${name}' installed`,\n probe.installed,\n ));\n if (probe.installed) {\n results.push(check(\n `Notifier '${name}' reachable`,\n probe.reachable,\n ));\n }\n }\n\n // Probe projection targets\n console.log(chalk.bold(\"\\nProjection\"));\n const projectionRegistry = new ProjectionRegistry({\n cursor: createCursorEmitter,\n codex: createCodexEmitter,\n gemini: createGeminiEmitter,\n opencode: createOpencodeEmitter,\n });\n for (const name of projectionRegistry.list()) {\n const emitter = projectionRegistry.get(name);\n const [userDest] = emitter.destinations(\"user\");\n if (!userDest) continue;\n const dir = path.dirname(userDest.path);\n let status: string;\n try {\n await stat(dir);\n status = chalk.green(\"✓ dir writable\");\n } catch {\n status = chalk.yellow(\"! dir missing (will be created on emit)\");\n }\n console.log(` ${name.padEnd(10)} ${userDest.path} — ${status}`);\n }\n\n results.push(\n check(\n \"Squadrant config exists\",\n fs.existsSync(\n process.env.SQUADRANT_CONFIG ||\n `${process.env.HOME}/.config/squadrant/config.json`,\n ),\n ),\n );\n\n const passed = results.filter(Boolean).length;\n const total = results.length;\n\n console.log(\n `\\n${passed === total ? chalk.green(\"All checks passed\") : chalk.yellow(`${passed}/${total} checks passed`)}\\n`,\n );\n\n // #77 service-health: live per-component liveness from the daemon. Printed\n // before the prereq-fail exit so a degraded install still shows what is up.\n printServiceHealth(await queryHealth());\n\n // Non-blocking version compat drift for every tool in the manifest.\n // Tools not installed are skipped silently; only drift (below min / above\n // lastVerified) produces a warning line — nothing here causes an exit.\n console.log(chalk.bold(\"\\nTool Version Compat\\n\"));\n const toolVersionMap: Record<string, string> = {\n cmux: probeResults[\"cmux\"]?.version ?? \"\",\n claude: tryGetVersion(\"claude\"),\n node: process.versions.node,\n codex: tryGetVersion(\"codex\"),\n gemini: tryGetVersion(\"gemini\"),\n opencode: tryGetVersion(\"opencode\"),\n };\n for (const [name, entry] of Object.entries(compatManifest.tools) as [string, ToolEntry][]) {\n const version = toolVersionMap[name] ?? \"\";\n if (!version) continue;\n const warn = checkToolCompat(name, version, entry);\n if (warn) {\n console.log(` ${chalk.yellow(\"⚠ WARN\")} ${name}: ${warn}`);\n } else {\n console.log(` ${chalk.green(\"✔ OK \")} ${name}: ${version}`);\n }\n }\n\n if (results.some((r) => !r)) {\n process.exit(1);\n }\n\n // --- Agent Probes ---\n console.log(chalk.bold(\"\\nAgent Drivers\\n\"));\n\n const { createClaudeDriver, createCodexDriver, createGeminiDriver, createOpencodeDriver, CapabilityRegistry } = await import(\"@squadrant/agents\");\n\n const agentDrivers = {\n claude: createClaudeDriver(),\n codex: createCodexDriver(),\n gemini: createGeminiDriver(),\n opencode: createOpencodeDriver(),\n };\n\n const registry = new CapabilityRegistry(agentDrivers);\n await registry.probeAll();\n\n for (const [name, driver] of Object.entries(agentDrivers)) {\n const probe = registry.getProbeResult(name);\n if (!probe || !probe.installed) {\n console.log(` ${chalk.gray(\"○ SKIP\")} ${name} — not installed`);\n continue;\n }\n const caps = probe.capabilities.join(\", \");\n console.log(` ${chalk.green(\"✔ FOUND\")} ${name} ${chalk.gray(probe.version)} — [${caps}]`);\n }\n\n // Show role assignments from config\n if (config.defaults.roles) {\n console.log(chalk.bold(\"\\nRole Assignments\\n\"));\n for (const [role, assignment] of Object.entries(config.defaults.roles)) {\n const validation = registry.validateRole(assignment.agent, role as any);\n const statusIcon = validation.allowed ? chalk.green(\"✔\") : chalk.red(\"✘\");\n const warns = validation.missingPreferred.length > 0\n ? chalk.yellow(` (missing preferred: ${validation.missingPreferred.join(\", \")})`)\n : \"\";\n console.log(` ${statusIcon} ${role}: ${assignment.agent}${assignment.model ? ` (${assignment.model})` : \"\"}${warns}`);\n if (!validation.allowed && validation.reason) {\n console.log(` ${chalk.red(validation.reason)}`);\n }\n }\n }\n });\n","// src/commands/health-view.ts\n//\n// Client + pure renderer for the daemon's #77 service-health surface. Shared by\n// `squadrant doctor` and `squadrant status --detailed`. The query is a RAW socket\n// call (never kickstarts the daemon); rendering is pure and unit-tested.\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport chalk from \"chalk\";\nimport { sendRequest, ageText } from \"@squadrant/core\";\nexport { ageText } from \"@squadrant/core\";\nimport type { ComponentHealth, HealthState } from \"@squadrant/core\";\n\nconst SOCK = join(homedir(), \".config\", \"squadrant\", \"squadrant.sock\");\n\n/**\n * Query the daemon for component liveness. Returns null when the daemon is\n * unreachable (the surface shows \"daemon unreachable\" rather than kickstarting\n * it). Optionally scoped to one project.\n */\nexport async function queryHealth(project?: string): Promise<ComponentHealth[] | null> {\n try {\n const reply = await sendRequest(SOCK, { kind: \"health\", project });\n return Array.isArray(reply) ? (reply as ComponentHealth[]) : [];\n } catch {\n return null;\n }\n}\n\nexport function healthIcon(state: HealthState): string {\n switch (state) {\n case \"alive\": return \"✔\";\n case \"stale\": return \"•\";\n case \"gone\": return \"✘\";\n case \"stopped\": return \"⏻\";\n case \"unknown\": return \"○\";\n }\n}\n\n/** Color the state token without affecting the plain-text rendering used in tests. */\nexport function colorState(state: HealthState): string {\n switch (state) {\n case \"alive\": return chalk.green(state);\n case \"stale\": return chalk.yellow(state);\n case \"gone\": return chalk.red(state);\n // stopped = intentional shutdown, not a fault — magenta, never alarm-red.\n case \"stopped\": return chalk.magenta(state);\n case \"unknown\": return chalk.dim(state);\n }\n}\n\n/** Pure plain-text row (no color) — kept colorless so it is trivially testable. */\nexport function healthRow(c: ComponentHealth, now: number): string {\n const head = `${healthIcon(c.state)} ${c.kind.padEnd(8)} ${c.ref.padEnd(16)} ${c.state.padEnd(8)} ${ageText(c.lastSeenMs, now)}`;\n return c.detail ? `${head} ${c.detail}` : head;\n}\n\n/**\n * Print the Service Health section to stdout (used by doctor + status --detailed).\n * Groups rows by project; flags the daemon being unreachable.\n */\nexport function printServiceHealth(rows: ComponentHealth[] | null, now: number = Date.now()): void {\n console.log(chalk.bold(\"\\nService Health\\n\"));\n if (rows == null) {\n console.log(` ${chalk.red(\"✘\")} daemon unreachable — squadrant liveness is unknown (start the daemon)`);\n return;\n }\n if (rows.length === 0) {\n console.log(chalk.dim(\" no registered projects\"));\n return;\n }\n const byProject = new Map<string, ComponentHealth[]>();\n for (const c of rows) {\n const list = byProject.get(c.project) ?? [];\n list.push(c);\n byProject.set(c.project, list);\n }\n for (const [project, comps] of byProject) {\n console.log(` ${chalk.cyan(project)}`);\n for (const c of comps) {\n // Reuse the pure row for layout; recolor the state token in place.\n const plain = healthRow(c, now);\n console.log(` ${plain.replace(c.state, colorState(c.state))}`);\n }\n }\n}\n","import { Command } from \"commander\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport os from \"node:os\";\nimport { execSync } from \"node:child_process\";\nimport chalk from \"chalk\";\nimport {\n getDefaultConfig,\n saveConfig,\n DEFAULT_CONFIG_PATH,\n resolveHome,\n} from \"@squadrant/shared\";\nimport { createObsidianDriver, WorkspaceRegistry } from \"@squadrant/workspaces\";\nimport { ensureRuntimeSynced } from \"@squadrant/shared\";\n\nfunction findPackageRoot(): string {\n let dir = path.dirname(new URL(import.meta.url).pathname);\n while (dir !== \"/\") {\n if (fs.existsSync(path.join(dir, \"package.json\"))) return dir;\n dir = path.dirname(dir);\n }\n return process.cwd();\n}\n\nfunction copyDirRecursive(src: string, dest: string): void {\n fs.mkdirSync(dest, { recursive: true });\n for (const entry of fs.readdirSync(src, { withFileTypes: true })) {\n const srcPath = path.join(src, entry.name);\n const destPath = path.join(dest, entry.name);\n if (entry.isDirectory()) {\n copyDirRecursive(srcPath, destPath);\n } else {\n fs.copyFileSync(srcPath, destPath);\n }\n }\n}\n\nexport const initCommand = new Command(\"init\")\n .description(\"First-time setup: scaffold hub vault, scripts, and config\")\n .option(\"--hub <path>\", \"Hub vault path\", \"~/squadrant-hub\")\n .action((opts: { hub: string }) => {\n const hubPath = resolveHome(opts.hub);\n const pkgRoot = findPackageRoot();\n const configDir = path.join(os.homedir(), \".config\", \"squadrant\");\n\n console.log(chalk.bold(\"\\nSquadrant Init\\n\"));\n\n // Verify the default workspace provider is registered (squadrant ships obsidian;\n // if user already has a config pointing to an unknown provider, bail early)\n const registry = new WorkspaceRegistry({ obsidian: createObsidianDriver });\n try {\n if (fs.existsSync(DEFAULT_CONFIG_PATH)) {\n const existing = JSON.parse(fs.readFileSync(DEFAULT_CONFIG_PATH, \"utf-8\"));\n const wsName = existing.workspace ?? \"obsidian\";\n registry.get(wsName);\n }\n } catch (err) {\n console.log(chalk.red(` ✘ ${(err as Error).message}`));\n return;\n }\n\n // 1. Create config\n if (fs.existsSync(DEFAULT_CONFIG_PATH)) {\n console.log(chalk.yellow(\" ⚠ Config already exists, skipping creation\"));\n } else {\n const config = getDefaultConfig();\n config.hubVault = hubPath;\n saveConfig(config);\n console.log(chalk.green(` ✔ Config created at ${DEFAULT_CONFIG_PATH}`));\n }\n\n // 2. Scaffold hub vault from template\n const hubTemplate = path.join(pkgRoot, \"obsidian\", \"hub\");\n if (fs.existsSync(hubPath)) {\n console.log(chalk.yellow(` ⚠ Hub vault already exists at ${hubPath}, skipping`));\n } else if (fs.existsSync(hubTemplate)) {\n copyDirRecursive(hubTemplate, hubPath);\n console.log(chalk.green(` ✔ Hub vault scaffolded at ${hubPath}`));\n } else {\n fs.mkdirSync(hubPath, { recursive: true });\n console.log(chalk.yellow(` ⚠ Hub template not found; created empty dir at ${hubPath}`));\n }\n\n // 2b. Always refresh dashboard.md and ensure projects/ exists (idempotent — see #44)\n const hubDashboardSrc = path.join(pkgRoot, \"obsidian\", \"hub\", \"dashboard.md\");\n const hubDashboardDest = path.join(hubPath, \"dashboard.md\");\n if (fs.existsSync(hubDashboardSrc)) {\n fs.copyFileSync(hubDashboardSrc, hubDashboardDest);\n console.log(chalk.green(` ✔ Dashboard page refreshed at ${hubDashboardDest}`));\n }\n const projectsDir = path.join(hubPath, \"projects\");\n fs.mkdirSync(projectsDir, { recursive: true });\n\n // 3. Sync source-managed runtime dirs (plugin, scripts, templates) via\n // the same self-heal path the CLI runs on every invocation: copy +\n // prune + chmod, so a re-init never leaves stale files behind.\n ensureRuntimeSynced({ sourceRoot: pkgRoot, runtimeRoot: configDir });\n console.log(chalk.green(` ✔ Runtime assets synced to ${configDir}`));\n\n // 6. Enable Agent Teams in settings.json if not set\n const settingsPath = path.join(os.homedir(), \".claude\", \"settings.json\");\n try {\n let settings: Record<string, unknown> = {};\n if (fs.existsSync(settingsPath)) {\n settings = JSON.parse(fs.readFileSync(settingsPath, \"utf-8\"));\n }\n const env = (settings.env as Record<string, string>) || {};\n if (env.CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS !== \"1\") {\n settings.env = { ...env, CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS: \"1\" };\n fs.mkdirSync(path.dirname(settingsPath), { recursive: true });\n fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + \"\\n\");\n console.log(chalk.green(\" ✔ Agent Teams enabled in ~/.claude/settings.json\"));\n } else {\n console.log(chalk.green(\" ✔ Agent Teams already enabled\"));\n }\n } catch {\n console.log(chalk.yellow(\" ⚠ Could not update ~/.claude/settings.json\"));\n }\n\n // 5. Print manual steps\n console.log(chalk.bold(\"\\nManual steps required:\\n\"));\n console.log(\" 1. Install plugins in Claude Code:\");\n console.log(chalk.cyan(\" /plugin marketplace add thedotmack/claude-mem\"));\n console.log(chalk.cyan(\" /plugin install claude-mem\"));\n console.log(\" Install context7 and superpowers from /plugin marketplace\");\n console.log(\"\");\n console.log(\" 2. Install cmux if not already installed:\");\n console.log(chalk.cyan(\" npm install -g cmux\"));\n console.log(\"\");\n console.log(\" 3. Open Obsidian and add the hub vault:\");\n console.log(chalk.cyan(` ${hubPath}`));\n console.log(\"\");\n console.log(\" 4. Run \" + chalk.cyan(\"squadrant doctor\") + \" to verify setup\\n\");\n\n if (!fs.existsSync(\"/Applications/cmux.app\")) {\n console.log(chalk.yellow(\" ⚠ cmux not found — download from https://cmux.dev\\n\"));\n }\n });\n","import { Command } from \"commander\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport chalk from \"chalk\";\nimport {\n loadConfig,\n saveConfig,\n resolveHome,\n ProjectConfig,\n} from \"@squadrant/shared\";\nimport { restartDaemonIfRunning, type RestartOutcome } from \"../control/restart-daemon.js\";\n\nexport function restartAfterProjectsAdd(opts: {\n noRestart?: boolean;\n doRestart?: (o: { reason: string; noRestart?: boolean }) => RestartOutcome;\n}): void {\n const doRestart = opts.doRestart ?? restartDaemonIfRunning;\n const outcome = doRestart({ reason: \"project registration\", noRestart: opts.noRestart });\n if (outcome === \"skipped-not-running\") {\n console.log(chalk.dim(\" (daemon not running — change applies on next start)\"));\n } else if (outcome === \"skipped-opt-out\") {\n console.log(chalk.dim(\" (run 'squadrant heal daemon' to apply)\"));\n }\n}\n\nfunction findPackageRoot(): string {\n let dir = path.dirname(new URL(import.meta.url).pathname);\n while (dir !== \"/\") {\n if (fs.existsSync(path.join(dir, \"package.json\"))) return dir;\n dir = path.dirname(dir);\n }\n return process.cwd();\n}\n\nfunction copyDirRecursive(src: string, dest: string): void {\n fs.mkdirSync(dest, { recursive: true });\n for (const entry of fs.readdirSync(src, { withFileTypes: true })) {\n const srcPath = path.join(src, entry.name);\n const destPath = path.join(dest, entry.name);\n if (entry.isDirectory()) {\n copyDirRecursive(srcPath, destPath);\n } else {\n fs.copyFileSync(srcPath, destPath);\n }\n }\n}\n\nconst listCmd = new Command(\"list\")\n .description(\"List registered projects\")\n .action(() => {\n const config = loadConfig();\n const projects = Object.entries(config.projects);\n\n if (projects.length === 0) {\n console.log(chalk.yellow(\"\\nNo projects registered. Use: squadrant projects add <name> <path>\\n\"));\n return;\n }\n\n console.log(chalk.bold(\"\\nRegistered Projects\\n\"));\n console.log(\n chalk.dim(\n ` ${\"NAME\".padEnd(18)} ${\"CAPTAIN\".padEnd(22)} ${\"GROUP\".padEnd(15)} ${\"ROLE\".padEnd(18)} PATH`,\n ),\n );\n console.log(chalk.dim(\" \" + \"─\".repeat(100)));\n\n for (const [name, project] of projects) {\n const group = project.group || chalk.dim(\"—\");\n const role = project.groupRole || chalk.dim(\"—\");\n console.log(\n ` ${name.padEnd(18)} ${project.captainName.padEnd(22)} ${String(group).padEnd(15)} ${String(role).padEnd(18)} ${project.path}`,\n );\n }\n console.log(\"\");\n });\n\nconst addCmd = new Command(\"add\")\n .description(\"Register a project\")\n .argument(\"<name>\", \"Project name\")\n .argument(\"<path>\", \"Path to project directory\")\n .option(\"--captain <name>\", \"Captain workspace name (default: <project>-captain)\")\n .option(\"--spoke <path>\", \"Spoke vault path (default: ~/squadrant-hub/spokes/<name>)\")\n .option(\"--group <name>\", \"Project group name (siblings share context)\")\n .option(\"--group-role <role>\", \"Role within the group (auto-set to 'primary' if first in group)\")\n .option(\"--no-restart\", \"skip daemon restart after registration\")\n .action((name: string, projectPath: string, opts: { captain?: string; spoke?: string; group?: string; groupRole?: string; restart?: boolean }) => {\n const config = loadConfig();\n\n if (config.projects[name]) {\n console.log(chalk.yellow(`\\n⚠ Project '${name}' already registered. Remove it first.\\n`));\n process.exit(1);\n }\n\n const resolvedPath = resolveHome(projectPath);\n\n // Warn if path doesn't look like a git repo\n if (!fs.existsSync(path.join(resolvedPath, \".git\"))) {\n console.log(chalk.yellow(`\\n ⚠ No .git found at ${resolvedPath}. Make sure this is the project root, not a parent directory.\\n`));\n }\n\n const captainName = opts.captain || `\\u2693 ${name}-captain`;\n\n // Validate captain name is unique across all projects\n const existingCaptains = Object.entries(config.projects)\n .map(([pName, p]) => ({ project: pName, captain: p.captainName }));\n const conflict = existingCaptains.find((c) => c.captain === captainName);\n if (conflict) {\n console.log(chalk.red(`\\n ✘ Captain name '${captainName}' already used by project '${conflict.project}'.`));\n console.log(chalk.dim(` Use --captain <unique-name> to specify a different name.\\n`));\n process.exit(1);\n }\n\n // Captain name must not collide with command workspace name\n if (captainName === (config.commandName || \"command\")) {\n console.log(chalk.red(`\\n ✘ Captain name '${captainName}' conflicts with the command workspace name.\\n`));\n process.exit(1);\n }\n // Handle project groups\n let group = opts.group;\n let groupRole = opts.groupRole;\n if (group) {\n const siblings = Object.entries(config.projects)\n .filter(([, p]) => p.group === group);\n const primary = siblings.find(([, p]) => p.groupRole === \"primary\");\n\n if (siblings.length === 0) {\n // First project in this group — auto-assign primary\n if (!groupRole) {\n groupRole = \"primary\";\n console.log(chalk.dim(` Auto-assigned as primary for group '${group}'`));\n }\n } else if (!groupRole) {\n // Group exists, no role specified — show siblings and require a role\n console.log(chalk.yellow(`\\n Group '${group}' already has ${siblings.length} project(s):`));\n for (const [sName, sProj] of siblings) {\n console.log(chalk.dim(` - ${sName} (${sProj.groupRole || \"no role\"})`));\n }\n if (primary) {\n console.log(chalk.red(`\\n ✘ Please specify --group-role (e.g., \"fork of ${primary[0]}\", \"landing page\", \"docs\")\\n`));\n } else {\n console.log(chalk.red(`\\n ✘ Please specify --group-role (e.g., \"primary\", \"fork\", \"landing page\", \"docs\")\\n`));\n }\n process.exit(1);\n }\n\n // Warn if trying to set primary when one already exists\n if (groupRole === \"primary\" && primary) {\n console.log(chalk.yellow(`\\n ⚠ Group '${group}' already has '${primary[0]}' as primary. Overriding.`));\n }\n }\n\n const spokeVault = opts.spoke\n ? resolveHome(opts.spoke)\n : path.join(config.hubVault, \"spokes\", name);\n\n const project: ProjectConfig = {\n path: resolvedPath,\n captainName,\n spokeVault,\n host: \"local\",\n ...(group && { group }),\n ...(groupRole && { groupRole }),\n };\n\n config.projects[name] = project;\n saveConfig(config);\n console.log(chalk.green(`\\n ✔ Project '${name}' registered`));\n restartAfterProjectsAdd({ noRestart: opts.restart === false });\n\n // Scaffold spoke vault from template\n const pkgRoot = findPackageRoot();\n const spokeTemplate = path.join(pkgRoot, \"obsidian\", \"spoke\");\n\n if (fs.existsSync(spokeVault)) {\n console.log(chalk.yellow(` ⚠ Spoke vault already exists at ${spokeVault}, skipping scaffold`));\n } else if (fs.existsSync(spokeTemplate)) {\n copyDirRecursive(spokeTemplate, spokeVault);\n // Update project field in status.md frontmatter\n const statusPath = path.join(spokeVault, \"status.md\");\n if (fs.existsSync(statusPath)) {\n const content = fs.readFileSync(statusPath, \"utf-8\");\n const updated = content.replace(/^project: unnamed/m, `project: ${name}`);\n fs.writeFileSync(statusPath, updated);\n }\n console.log(chalk.green(` ✔ Spoke vault scaffolded at ${spokeVault}`));\n } else {\n fs.mkdirSync(spokeVault, { recursive: true });\n console.log(chalk.yellow(` ⚠ Spoke template not found; created empty dir at ${spokeVault}`));\n }\n\n console.log(\"\");\n });\n\nconst removeCmd = new Command(\"remove\")\n .description(\"Unregister a project (does not delete files)\")\n .argument(\"<name>\", \"Project name\")\n .action((name: string) => {\n const config = loadConfig();\n\n if (!config.projects[name]) {\n console.log(chalk.yellow(`\\n⚠ Project '${name}' not found.\\n`));\n process.exit(1);\n }\n\n delete config.projects[name];\n saveConfig(config);\n console.log(chalk.green(`\\n ✔ Project '${name}' removed from config (files untouched)\\n`));\n });\n\nexport const projectsCommand = new Command(\"projects\")\n .description(\"Manage registered projects\")\n .addCommand(listCmd)\n .addCommand(addCmd)\n .addCommand(removeCmd);\n","import { execFileSync } from \"node:child_process\";\nimport { existsSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { LABEL, kickstartArgv, tryAcquireDaemonLock, releaseDaemonLock } from \"@squadrant/core\";\n\nexport type RestartOutcome = \"restarted\" | \"skipped-not-running\" | \"skipped-opt-out\";\n\nconst DEFAULT_SOCK_PATH = join(homedir(), \".config\", \"squadrant\", \"squadrant.sock\");\n\nfunction defaultIsRunning(): boolean {\n return existsSync(DEFAULT_SOCK_PATH);\n}\n\nfunction defaultRunKickstart(): void {\n const uid = process.getuid?.() ?? 0;\n const target = `gui/${uid}/${LABEL}`;\n if (tryAcquireDaemonLock()) {\n try {\n execFileSync(\"launchctl\", kickstartArgv(target, true), { stdio: \"ignore\" });\n } finally {\n releaseDaemonLock();\n }\n }\n}\n\nexport function restartDaemonIfRunning(opts: {\n reason: string;\n noRestart?: boolean;\n isRunning?: () => boolean;\n runKickstart?: () => void;\n env?: NodeJS.ProcessEnv;\n log?: (m: string) => void;\n}): RestartOutcome {\n const env = opts.env ?? process.env;\n if (env[\"VITEST\"] || opts.noRestart) return \"skipped-opt-out\";\n\n const isRunning = opts.isRunning ?? defaultIsRunning;\n if (!isRunning()) return \"skipped-not-running\";\n\n const log = opts.log ?? console.log;\n log(`↻ restarting daemon to apply ${opts.reason}…`);\n const runKickstart = opts.runKickstart ?? defaultRunKickstart;\n runKickstart();\n return \"restarted\";\n}\n","import { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport matter from \"gray-matter\";\nimport { loadConfig } from \"@squadrant/shared\";\nimport { createObsidianDriver, WorkspaceRegistry } from \"@squadrant/workspaces\";\nimport { queryHealth, printServiceHealth } from \"./health-view.js\";\n\ninterface StatusFrontmatter {\n project?: string;\n captain_session?: string;\n last_updated?: string;\n active_crew?: number;\n tasks_total?: number;\n tasks_completed?: number;\n tasks_in_progress?: number;\n tasks_pending?: number;\n}\n\nfunction timeAgo(dateStr: string | undefined): string {\n if (!dateStr) return chalk.dim(\"—\");\n const date = new Date(dateStr);\n if (isNaN(date.getTime())) return chalk.dim(\"—\");\n\n const diff = Date.now() - date.getTime();\n const mins = Math.floor(diff / 60_000);\n const hours = Math.floor(diff / 3_600_000);\n const days = Math.floor(diff / 86_400_000);\n\n if (mins < 1) return \"just now\";\n if (mins < 60) return `${mins}m ago`;\n if (hours < 24) return `${hours}h ago`;\n return `${days}d ago`;\n}\n\nfunction progressBar(completed: number, total: number): string {\n if (total === 0) return chalk.dim(\"no tasks\");\n const pct = Math.round((completed / total) * 100);\n const filled = Math.round(pct / 10);\n const bar = \"█\".repeat(filled) + \"░\".repeat(10 - filled);\n return `${bar} ${pct}%`;\n}\n\nexport const statusCommand = new Command(\"status\")\n .description(\"Show status of all projects from spoke vault status files\")\n .option(\"--detailed\", \"also show live per-component service health from the daemon (#77)\")\n .action(async (opts: { detailed?: boolean }) => {\n const config = loadConfig();\n const projects = Object.entries(config.projects);\n const registry = new WorkspaceRegistry({ obsidian: createObsidianDriver });\n\n if (projects.length === 0) {\n console.log(chalk.yellow(\"\\nNo projects registered. Use: squadrant projects add <name> <path>\\n\"));\n return;\n }\n\n console.log(chalk.bold(\"\\nProject Status\\n\"));\n console.log(\n chalk.dim(\n ` ${\"PROJECT\".padEnd(18)} ${\"CAPTAIN\".padEnd(12)} ${\"CREW\".padEnd(6)} ${\"PROGRESS\".padEnd(25)} LAST UPDATE`,\n ),\n );\n console.log(chalk.dim(\" \" + \"─\".repeat(85)));\n\n for (const [name, project] of projects) {\n const workspace = registry.forProject(name, config);\n\n if (!(await workspace.exists(\"status.md\"))) {\n console.log(` ${name.padEnd(18)} ${chalk.dim(\"no status.md\")}`);\n continue;\n }\n\n let fm: StatusFrontmatter = {};\n try {\n const raw = await workspace.read(\"status.md\");\n fm = matter(raw).data as StatusFrontmatter;\n } catch {\n console.log(` ${name.padEnd(18)} ${chalk.red(\"error reading status.md\")}`);\n continue;\n }\n\n const sessionIndicator =\n fm.captain_session === \"active\"\n ? chalk.green(\"●\")\n : chalk.dim(\"○\");\n const captainDisplay = `${project.captainName.padEnd(11)} ${sessionIndicator}`;\n const crew = String(fm.active_crew ?? 0).padEnd(6);\n const progress = progressBar(\n fm.tasks_completed ?? 0,\n fm.tasks_total ?? 0,\n ).padEnd(25);\n const updated = timeAgo(fm.last_updated);\n\n console.log(\n ` ${name.padEnd(18)} ${captainDisplay} ${crew} ${progress} ${updated}`,\n );\n }\n\n console.log(\"\");\n\n // #77: --detailed adds the live service-health view (relay/captain/crew/\n // command per-component last-seen + state) queried from the daemon.\n if (opts.detailed) {\n printServiceHealth(await queryHealth());\n }\n });\n","import { Command } from \"commander\";\nimport { execSync } from \"node:child_process\";\nimport path from \"node:path\";\nimport os from \"node:os\";\nimport chalk from \"chalk\";\nimport { loadConfig } from \"@squadrant/shared\";\nimport { createCmuxDriver, RuntimeRegistry } from \"@squadrant/workspaces\";\nimport type { PaneRef } from \"@squadrant/workspaces\";\nimport {\n createClaudeDriver,\n createCodexDriver,\n createGeminiDriver,\n createOpencodeDriver,\n CapabilityRegistry,\n} from \"@squadrant/agents\";\nimport { resolveCmuxBin } from \"@squadrant/shared\";\n\nconst TEMPLATES_DIR = path.join(os.homedir(), \".config\", \"squadrant\", \"templates\");\n\ntype CommandTask = \"briefing\" | \"learnings-review\" | \"wiki-aggregate\";\n\nconst TASK_PROMPTS: Record<CommandTask, string> = {\n briefing:\n \"Run your daily briefing using the squadrant:command-ops skill. Read all spoke handoffs, yesterday's logs, current status; produce a concise cross-project briefing; save to {hubVault}/daily-logs/YYYY-MM-DD.md; then exit.\",\n \"learnings-review\":\n \"Run a learnings review using the squadrant:command-ops skill. Scan {spokeVault}/learnings across all projects, identify cross-project patterns, propose captured-skill or fix actions, and exit when done.\",\n \"wiki-aggregate\":\n \"Run a wiki aggregation pass using the squadrant:command-ops skill. Scan each spoke wiki index, identify shared knowledge worth promoting, write hub wiki pages, and exit when done.\",\n};\n\nexport interface CommandSpawnInput {\n task: CommandTask;\n direction?: \"right\" | \"left\" | \"up\" | \"down\";\n agent?: string;\n}\n\nfunction detectCurrentWorkspace(): string {\n const out = execSync(`\"${resolveCmuxBin()}\" current-workspace`, { encoding: \"utf-8\" }).trim();\n const match = out.match(/workspace:\\d+/);\n if (!match) {\n throw new Error(\"Could not detect current cmux workspace. Run `squadrant command` from inside a cmux workspace.\");\n }\n return match[0];\n}\n\nexport async function runCommandSpawn(input: CommandSpawnInput): Promise<PaneRef> {\n const prompt = TASK_PROMPTS[input.task];\n if (!prompt) {\n throw new Error(`Unknown task '${input.task}'. Known: briefing, learnings-review, wiki-aggregate.`);\n }\n\n const config = loadConfig();\n const runtime = new RuntimeRegistry({ cmux: createCmuxDriver() }).global(config);\n\n const workspaceId = detectCurrentWorkspace();\n\n const agents = new CapabilityRegistry({\n claude: createClaudeDriver(),\n codex: createCodexDriver(),\n gemini: createGeminiDriver(),\n opencode: createOpencodeDriver(),\n });\n const agentName = input.agent ?? \"claude\";\n const agent = agents.get(agentName);\n if (!agent) {\n throw new Error(`Unknown agent '${agentName}'. Known: claude, codex, gemini, opencode.`);\n }\n\n const promptFile = path.join(TEMPLATES_DIR, `command.${agent.templateSuffix}.md`);\n const cliCommand = agent.buildCommand({\n prompt,\n workdir: process.cwd(),\n role: \"command\",\n promptFile,\n });\n\n const direction = input.direction ?? \"right\";\n const title = `🤖 command-${input.task}`;\n const pane = await runtime.newPane({ workspaceId, direction, title });\n await runtime.sendToPane(pane, cliCommand);\n return pane;\n}\n\nexport const commandCommand = new Command(\"command\")\n .description(\"Spawn a one-shot Command session in a split pane (briefing | learnings-review | wiki-aggregate)\")\n .option(\"--task <name>\", \"Task prompt to bake in (briefing|learnings-review|wiki-aggregate)\", \"briefing\")\n .option(\"--direction <dir>\", \"Split direction (right|left|up|down)\", \"right\")\n .option(\"--agent <name>\", \"Agent CLI to use (claude|codex|gemini|opencode)\", \"claude\")\n .action(async (opts: { task: CommandTask; direction: \"right\" | \"left\" | \"up\" | \"down\"; agent: string }) => {\n try {\n const pane = await runCommandSpawn({ task: opts.task, direction: opts.direction, agent: opts.agent });\n console.log(chalk.green(`✔ Command spawned in ${pane.workspaceId} ${pane.surfaceId} (task: ${opts.task})`));\n } catch (err) {\n console.error(chalk.red((err as Error).message));\n process.exit(1);\n }\n });\n","import { Command } from \"commander\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport os from \"node:os\";\nimport chalk from \"chalk\";\nimport { loadConfig } from \"@squadrant/shared\";\nimport { addWorktree, removeWorktree, resolveWorktreeBase, resolveTextInput, TERMINAL_STATES } from \"@squadrant/shared\";\nimport type { TaskRecord } from \"@squadrant/shared\";\nimport { resolveCrewRoute } from \"../control/crew-routing.js\";\nimport { createCmuxDriver, RuntimeRegistry } from \"@squadrant/workspaces\";\nimport { listProjectCrews, findCrew, resolveCaptainWorkspace, sendFirstTurnWhenReady, getFreePort } from \"@squadrant/workspaces\";\nimport type { PaneRef, PanePlacement, RuntimeDriver } from \"@squadrant/workspaces\";\nimport {\n createClaudeDriver,\n createCodexDriver,\n createGeminiDriver,\n createOpencodeDriver,\n CapabilityRegistry,\n} from \"@squadrant/agents\";\nimport { buildDispatchRequest, squadrantdCall, sendCodexFirstTurn } from \"./crew-control.js\";\nimport { tailLines } from \"./crew-output.js\";\nimport { writePerCrewSettingsLocal, writePerCrewOpencodeConfig } from \"../lib/per-crew-settings.js\";\nimport { buildCompletionProtocol, shellQuote, titleFor, nameFromTitle, nextAutoName, reapCrewChildren } from \"@squadrant/core\";\nimport type { TurnAcceptanceConfig } from \"@squadrant/core\";\n\nconst TEMPLATES_DIR = path.join(os.homedir(), \".config\", \"squadrant\", \"templates\");\n\n// Base branch for `--worktree` crew branches is derived at spawn time from\n// origin/HEAD so repos using main, trunk, etc. work out of the box (#359).\n// Still avoids \"current HEAD\" deliberately — basing off the captain's volatile\n// HEAD would reintroduce the coupling this isolation feature exists to remove.\n\nexport interface CrewSpawnInput {\n project: string;\n task: string;\n name?: string;\n direction?: PanePlacement;\n agent?: string;\n approvalPolicy?: string;\n /** Opt-out (#296): run this crew in the root checkout instead of an isolated\n * worktree. Pass true for small/one-off tasks that don't need branch isolation.\n * Default (undefined/false) = isolated worktree — parallel-safe. */\n shared?: boolean;\n /** CP3 opt-in: gate risky tools (bash) so the captain approves them.\n * codex maps this to approvalPolicy='untrusted'; opencode maps it to a\n * bash:\"ask\" per-crew config. Default (false) = fully autonomous. */\n approval?: boolean;\n /** Per-spawn model override — takes precedence over defaults.roles.crew.model.\n * Agent-specific alias (e.g. \"sonnet\", \"opus\" for claude; \"gpt-5.5\" for codex). */\n model?: string;\n /** True when --agent was explicitly passed by the caller; suppresses crew routing. */\n agentExplicit?: boolean;\n}\n\nexport async function runCrewSpawn(input: CrewSpawnInput): Promise<PaneRef> {\n const config = loadConfig();\n const proj = config.projects[input.project];\n if (!proj) {\n throw new Error(`Project '${input.project}' not found. Run 'squadrant projects list'.`);\n }\n\n const runtime = new RuntimeRegistry({ cmux: createCmuxDriver() }).forProject(input.project, config);\n const captain = await runtime.status(proj.captainName);\n if (!captain) {\n throw new Error(\n `Captain workspace '${proj.captainName}' is not running. Run 'squadrant launch ${input.project}' first.`,\n );\n }\n\n const existing = await listProjectCrews(runtime, captain.id, input.project);\n const existingTitles = existing.map((s) => s.title!);\n if (input.name) {\n const wantTitle = titleFor(input.project, input.name);\n if (existingTitles.includes(wantTitle)) {\n throw new Error(\n `Crew '${input.name}' already exists for ${input.project}. Use 'squadrant crew send ${input.project} ${input.name}' to send a follow-up, or pick a different --name.`,\n );\n }\n }\n const name = input.name ?? nextAutoName(existingTitles, input.project);\n\n // Crews run in an isolated worktree+branch by default so multiple parallel\n // crews never collide on a shared HEAD (#296). Pass shared:true (CLI: --shared)\n // for small/one-off tasks that should run on the root checkout.\n // Build/daemon still run from the MAIN checkout's dist (#216): worktrees edit\n // source only. The worktree path becomes the crew's cwd via the existing cwd\n // plumbing (dispatch record + buildCommand workdir).\n const spawnCwd = !input.shared\n ? addWorktree({\n repoRoot: proj.path,\n worktreeDir: config.defaults.worktreeDir ?? \".worktrees\",\n project: input.project,\n name,\n base: resolveWorktreeBase(proj.path),\n })\n : proj.path;\n\n // #275 leveled crew routing: consult routing rules when agent/model were not\n // explicitly provided by the caller. Explicit --agent or --model always win.\n const route = !input.agentExplicit && !input.model\n ? resolveCrewRoute(input.task, config)\n : null;\n if (route) {\n console.log(chalk.dim(`routed: tier=${route.tier} → ${route.agent}${route.model ? `/${route.model}` : \"\"} (rule: \"${route.matchedRule}\")`));\n }\n\n const agents = new CapabilityRegistry({\n claude: createClaudeDriver(),\n codex: createCodexDriver(),\n gemini: createGeminiDriver(),\n opencode: createOpencodeDriver(),\n });\n const agentName = route?.agent ?? input.agent ?? \"claude\";\n const agent = agents.get(agentName);\n if (!agent) {\n throw new Error(`Unknown agent '${agentName}'. Known: claude, codex, gemini, opencode.`);\n }\n\n // Codex: route through the interactive control-plane daemon (PR #98) instead\n // of the print-mode CLI path. The dispatched task is driven via the\n // crew-attach renderer running in the captain tab, so 'crew send' / 'crew\n // read' / 'crew close' work identically to the Claude crew UX.\n if (agentName === \"codex\") {\n // Mirror claude's --append-system-prompt-file: read the crew role template\n // and forward it to codex via thread/start.developerInstructions so the\n // session knows it's a crew member, not a bare shell.\n const codexRoleFile = path.join(TEMPLATES_DIR, `crew.${agent.templateSuffix}.md`);\n const roleInstructions = fs.existsSync(codexRoleFile)\n ? fs.readFileSync(codexRoleFile, \"utf8\")\n : undefined;\n return runCodexInteractiveSpawn({\n project: input.project,\n task: input.task,\n cwd: spawnCwd,\n runtime,\n workspaceId: captain.id,\n name,\n direction: input.direction ?? \"tab\",\n approvalPolicy: input.approvalPolicy,\n roleInstructions,\n });\n }\n\n const promptFile = path.join(TEMPLATES_DIR, `crew.${agent.templateSuffix}.md`);\n // Claude crews run interactively (no -p) so the session stays alive between\n // turns; the task is sent via cmux after the CLI boots. Other agents that\n // don't yet honor `interactive` will keep their existing print-mode shape —\n // a known limitation tracked for future work.\n const interactive = agent.name === \"claude\" || agent.name === \"opencode\";\n // Honor configured model routing only when the spawn agent matches the\n // configured role agent — model names are agent-specific (e.g. \"sonnet\" is\n // a Claude alias; codex/gemini have their own routing). Cross-agent crews\n // fall back to the agent's own default to avoid passing an invalid model arg.\n const crewRole = config.defaults.roles?.crew;\n const configModel = crewRole && crewRole.agent === agent.name ? crewRole.model : undefined;\n const crewModel = input.model ?? route?.model ?? configModel;\n\n // Claude crews route through the control-plane daemon (PR #85 + this spec)\n // so the captain learns terminal state via `squadrant crew status` instead\n // of scraping the pane. The cmux tab still does the actual CLI launch —\n // the daemon doesn't own Claude's PID (Approach 3 boundary). Hook bridge\n // (per-crew settings.json with Stop/SubagentStop/SessionEnd → squadrant\n // crew _hook) keeps the daemon's heartbeat fresh; explicit\n // `squadrant crew signal done` from the crew template emits terminal state.\n if (agentName === \"claude\") {\n const req = buildDispatchRequest({\n provider: \"claude\",\n mode: \"interactive\",\n project: input.project,\n cwd: spawnCwd,\n task: input.task,\n name,\n });\n // Fail loud if daemon unreachable — refusal-to-degrade.\n const rec = (await squadrantdCall(req)) as TaskRecord;\n // Write squadrant hooks to <cwd>/.claude/settings.local.json so they are\n // auto-loaded as a project-local settings source. The cmux claude wrapper\n // injects its own hooks via --settings (level 2 precedence), but hooks\n // merge across *different* settings sources — only multiple --settings\n // flags collide. .claude/settings.local.json is gitignored and merges\n // with any existing user hooks (#134).\n writePerCrewSettingsLocal({ projectCwd: spawnCwd });\n const cliCommand = agent.buildCommand({\n prompt: input.task,\n workdir: spawnCwd,\n role: \"crew\",\n promptFile,\n interactive: true,\n // Permission mode is config-driven (defaults.permissions.crew) so squadrant\n // can default crews to 'auto' or keep the semi-automatic 'acceptEdits'\n // gate (auto-accept edits, still prompt for risky ops). Falls back to\n // 'acceptEdits' when unset.\n permissionMode: config.defaults.permissions?.crew ?? \"acceptEdits\",\n ...(crewModel ? { model: crewModel } : {}),\n });\n const direction: PanePlacement = input.direction ?? \"tab\";\n const title = titleFor(input.project, name);\n const pane = await runtime.newPane({ workspaceId: captain.id, direction, title });\n // Prefix the CLI command with env so the hook bridge + signal verb\n // running inside the crew's cmux tab can identify their task.\n const envPrefix = `SQUADRANT_CREW_TASK_ID=${rec.id} SQUADRANT_CREW_PROJECT=${input.project}`;\n await runtime.sendToPane(pane, `cd ${shellQuote(spawnCwd)} && ${envPrefix} ${cliCommand}`);\n const preLaunchScreen = (await runtime.readPaneScreen(pane)) ?? \"\";\n await sendFirstTurnWhenReady(runtime, pane, `${input.task}\\n\\n${buildCompletionProtocol(rec.id, input.project)}`, preLaunchScreen);\n return { ...pane, title };\n }\n\n // Opencode crews route through the control-plane daemon so the captain\n // learns terminal state via `squadrant crew status` instead of scraping the\n // pane. Same approach as claude: daemon owns the state ledger, cmux tab\n // does the actual CLI launch. No hook bridge (opencode has no hooks); the\n // crew template instructs explicit `squadrant crew signal done|blocked|failed`.\n if (agentName === \"opencode\") {\n // Bind the crew's embedded opencode HTTP server on a known port so the\n // daemon's SSE bridge can subscribe to /event for turn-end detection.\n const serverPort = await getFreePort();\n const req = buildDispatchRequest({\n provider: \"opencode\",\n mode: \"interactive\",\n project: input.project,\n cwd: spawnCwd,\n task: input.task,\n name,\n // opencode has no heartbeat hook, so a normal budget would false-stall\n // every crew after 5min; use a 24h budget to effectively disable stall\n // detection. The SSE bridge (serverPort) provides turn-end liveness.\n budgetMs: 86400000,\n serverPort,\n });\n const rec = (await squadrantdCall(req)) as TaskRecord;\n const opencodeConfigPath = writePerCrewOpencodeConfig({\n stateRoot: path.join(os.homedir(), \".config\", \"squadrant\", \"state\"),\n project: input.project,\n taskId: rec.id,\n // CP3 opt-in: --approval gates bash so the captain approves shell commands.\n // Without it, bash stays auto-approved (default behavior unchanged).\n ...(input.approval ? { gateBash: true } : {}),\n });\n const cliCommand = agent.buildCommand({\n prompt: input.task,\n workdir: spawnCwd,\n role: \"crew\",\n promptFile,\n interactive: true,\n model: crewModel,\n port: serverPort,\n });\n const direction: PanePlacement = input.direction ?? \"tab\";\n const title = titleFor(input.project, name);\n const pane = await runtime.newPane({ workspaceId: captain.id, direction, title });\n const envPrefix = `SQUADRANT_CREW_TASK_ID=${rec.id} SQUADRANT_CREW_PROJECT=${input.project}`;\n await runtime.sendToPane(pane, `cd ${shellQuote(spawnCwd)} && ${envPrefix} OPENCODE_CONFIG=${opencodeConfigPath} ${cliCommand}`);\n const preLaunchScreen = (await runtime.readPaneScreen(pane)) ?? \"\";\n await sendFirstTurnWhenReady(runtime, pane, `${input.task}\\n\\n${buildCompletionProtocol(rec.id, input.project)}`, preLaunchScreen, {\n // #235: opencode's idle splash (\"Ask anything…\") keeps mutating (cursor\n // blink, status line toggle), so the old screen-changed check would always\n // see a *different* screen and never re-send a dropped turn. The splashMarker\n // confirms the TUI actually left splash before declaring acceptance.\n splashMarker: \"Ask anything…\",\n // opencode has a wider boot-race window than claude, so allow 3 retries\n // instead of the default 2.\n retryLimit: 3,\n } satisfies TurnAcceptanceConfig);\n return { ...pane, title };\n }\n\n const cliCommand = agent.buildCommand({\n prompt: input.task,\n workdir: spawnCwd,\n role: \"crew\",\n promptFile,\n interactive,\n model: crewModel,\n });\n\n const direction: PanePlacement = input.direction ?? \"tab\";\n const title = titleFor(input.project, name);\n const pane = await runtime.newPane({ workspaceId: captain.id, direction, title });\n\n // Step 1: launch the CLI in the new tab.\n await runtime.sendToPane(pane, cliCommand);\n\n // Step 2: for interactive sessions, poll until the CLI is ready, then send\n // the task as the first prompt. For non-interactive (legacy) the prompt is\n // already baked into cliCommand, so we're done.\n if (interactive) {\n const preLaunchScreen = (await runtime.readPaneScreen(pane)) ?? \"\";\n await sendFirstTurnWhenReady(runtime, pane, input.task, preLaunchScreen);\n }\n\n return { ...pane, title };\n}\n\nasync function runCodexInteractiveSpawn(o: {\n project: string;\n task: string;\n cwd: string;\n runtime: RuntimeDriver;\n workspaceId: string;\n name: string;\n direction: PanePlacement;\n approvalPolicy?: string;\n roleInstructions?: string;\n}): Promise<PaneRef> {\n const req = buildDispatchRequest({\n provider: \"codex\",\n mode: \"interactive\",\n project: o.project,\n cwd: o.cwd,\n task: o.task,\n name: o.name,\n ...(o.approvalPolicy ? { approvalPolicy: o.approvalPolicy } : {}),\n ...(o.roleInstructions ? { roleInstructions: o.roleInstructions } : {}),\n });\n const rec = (await squadrantdCall(req)) as TaskRecord;\n const title = titleFor(o.project, o.name);\n const pane = await o.runtime.newPane({\n workspaceId: o.workspaceId,\n direction: o.direction,\n title,\n });\n await o.runtime.sendToPane(pane, `squadrant crew attach ${rec.id}`);\n // Match the claude UX where the task arg becomes the first turn. The codex\n // dispatch only opens the thread; the task text never reaches the model\n // unless we send it. Fire-and-forget: the renderer in the tab will pick up\n // streamed deltas once it attaches. Skip the deprecated \"(interactive)\"\n // placeholder which `crew chat` passes when no task was provided.\n if (o.task && o.task !== \"(interactive)\") {\n void sendCodexFirstTurn(rec.id, o.task).catch((e: unknown) => {\n process.stderr.write(`(first-turn delivery failed: ${(e as Error).message})\\n`);\n });\n }\n return { ...pane, title };\n}\n\nexport async function runCrewSend(project: string, name: string, message: string): Promise<void> {\n const { runtime, workspaceId } = await resolveCaptainWorkspace(project);\n const crew = await findCrew(runtime, workspaceId, project, name);\n if (!crew) {\n throw new Error(`Crew '${name}' not found for ${project}. Run 'squadrant crew list ${project}'.`);\n }\n // Best-effort attention-state handling before delivering the captain's answer.\n // Terminal task (done/failed): reopen so the next signal done fires CREW DONE (#148).\n // Blocked task: emit task.started to clear blocked→working so a subsequent real\n // permission prompt re-fires CREW BLOCKED (#182). Without this the second block\n // hits the idempotency guard (state-machine:69) and the captain misses it.\n // Awaiting-input task: same resume — crew re-enters working so the next block fires.\n try {\n const tasks = (await squadrantdCall({ kind: \"list\", project })) as TaskRecord[];\n const task = tasks.find((t) => t.name === name);\n if (task) {\n if (TERMINAL_STATES.has(task.state)) {\n await squadrantdCall({ kind: \"event\", project, event: { type: \"task.reopened\", id: task.id } });\n } else if (task.state === \"blocked\" || task.state === \"awaiting-input\") {\n await squadrantdCall({ kind: \"event\", project, event: { type: \"task.started\", id: task.id } });\n }\n }\n } catch {\n // Swallow daemon errors so crews without a daemon or offline daemon\n // still receive the sent message.\n }\n await runtime.sendToPane(crew, message);\n}\n\nexport async function runCrewRead(project: string, name: string): Promise<string> {\n const { runtime, workspaceId } = await resolveCaptainWorkspace(project);\n const crew = await findCrew(runtime, workspaceId, project, name);\n if (!crew) {\n throw new Error(`Crew '${name}' not found for ${project}. Run 'squadrant crew list ${project}'.`);\n }\n return runtime.readPaneScreen(crew);\n}\n\nexport async function runCrewClose(project: string, name: string): Promise<void> {\n const { runtime, workspaceId } = await resolveCaptainWorkspace(project);\n // resolveCaptainWorkspace already validated the project exists; reload for its\n // root path so we can tell a worktree crew (cwd != root) from a root crew.\n const projRoot = loadConfig().projects[project]?.path;\n // Terminalize the daemon task FIRST — before (and independent of) finding the\n // cmux pane (#184, hardened for #139). Without this, non-terminal tasks\n // (blocked/working/awaiting-input) linger in the daemon ledger and keep firing\n // phantom CREW BLOCKED/IDLE/STALLED pushes. Crucially, a DEAD crew's pane is\n // already gone, so gating terminalization on findCrew (the old order) left that\n // zombie record dangling forever. 'cancelled' is terminal but NOT in\n // ATTENTION_STATES, so firePush stays silent — captain initiated the close.\n let taskId: string | undefined;\n // Worktree to clean up after the pane closes — set only when this crew ran in\n // its own worktree (cwd recorded by the daemon differs from the root checkout).\n // A non-worktree crew has cwd === root (or unset), so this stays undefined and\n // close is unaffected (#216).\n let worktreeCwd: string | undefined;\n try {\n const tasks = (await squadrantdCall({ kind: \"list\", project })) as TaskRecord[];\n const task = tasks.find((t) => t.name === name);\n if (task) {\n taskId = task.id;\n if (task.cwd && projRoot && task.cwd !== projRoot) {\n worktreeCwd = task.cwd;\n }\n if (!TERMINAL_STATES.has(task.state)) {\n await squadrantdCall({ kind: \"event\", project, event: { type: \"task.cancelled\", id: task.id, reason: \"closed by captain\" } });\n }\n // Codex teardown: the pane only hosts the `crew attach` renderer; the thread\n // (and its per-thread MCP servers) live on the shared app-server, so closing\n // the pane alone leaks them. Tell the daemon to archive the thread. Fires for\n // terminal and non-terminal crews alike (a finished codex crew still holds a\n // live thread until archived).\n if (task.provider === \"codex\") {\n await squadrantdCall({ kind: \"codex-close\", taskId: task.id });\n }\n }\n } catch {\n // Swallow daemon errors — a crew without a daemon must still close.\n }\n // Close the cmux pane if it still exists. A dead crew's pane is already gone —\n // that is not an error (the record is terminalized above); proceed to reap\n // children / clean the worktree. Only a genuine miss (no pane AND no daemon\n // task) is a typo → surface the not-found error.\n const crew = await findCrew(runtime, workspaceId, project, name);\n if (crew) {\n await runtime.closePane(crew);\n } else if (taskId === undefined) {\n throw new Error(`Crew '${name}' not found for ${project}. Run 'squadrant crew list ${project}'.`);\n }\n // Reap any surviving child processes (vitest workers, node subprocs, etc.)\n // that the cmux pane-close cascade may have missed.\n if (taskId !== undefined) {\n await reapCrewChildren(taskId);\n }\n // Auto-clean the crew's worktree AFTER its processes are gone, so we don't\n // yank a dir out from under a live shell. Best-effort: a failed removal must\n // not break close (the branch is preserved regardless).\n if (worktreeCwd && projRoot) {\n try {\n removeWorktree(projRoot, worktreeCwd);\n } catch (e) {\n process.stderr.write(`(worktree remove failed: ${(e as Error).message})\\n`);\n }\n }\n}\n\nexport async function runCrewList(project: string): Promise<Array<{ name: string; surfaceId: string }>> {\n const { runtime, workspaceId } = await resolveCaptainWorkspace(project);\n const crews = await listProjectCrews(runtime, workspaceId, project);\n return crews.map((c) => ({\n name: nameFromTitle(project, c.title!),\n surfaceId: c.surfaceId,\n }));\n}\n\nexport const crewCommand = new Command(\"crew\").description(\n \"Spawn and manage interactive crew sessions next to the project's captain\",\n);\n\ncrewCommand\n .command(\"spawn\")\n .description(\n \"Spawn an interactive crew session as a tab in the captain's workspace (use --direction to split into a pane instead)\",\n )\n .argument(\"<project>\", \"Project name (must be registered)\")\n .argument(\"[task]\", \"Initial task prompt for the crew session (omit with --task-file)\")\n .option(\"--name <name>\", \"Crew name (default: auto-generated crew-N)\")\n .option(\"--direction <dir>\", \"Placement: tab (default) or split direction (right|left|up|down)\", \"tab\")\n .option(\"--agent <name>\", \"Agent CLI to use (claude|codex|gemini|opencode)\", \"claude\")\n .option(\"--approval\", \"gate risky tools so the captain approves them (codex: approvalPolicy='untrusted'; opencode: bash:'ask')\", false)\n .option(\"--shared\", \"run the crew in the root checkout instead of an isolated worktree (for small/one-off tasks)\", false)\n .option(\"--task-file <path>\", \"Read task prompt from file instead of positional arg ('-' for stdin)\")\n .option(\"--model <alias>\", \"Override crew model for this spawn (e.g. sonnet, opus); takes precedence over config defaults.roles.crew.model\")\n .action(\n async (\n project: string,\n task: string | undefined,\n opts: { name?: string; direction: PanePlacement; agent: string; approval: boolean; shared: boolean; taskFile?: string; model?: string },\n cmd: Command,\n ) => {\n try {\n const resolvedTask = await resolveTextInput({ positional: task, filePath: opts.taskFile, label: \"task\" });\n const agentExplicit = cmd.getOptionValueSource(\"agent\") === \"cli\";\n const pane = await runCrewSpawn({\n project,\n task: resolvedTask,\n name: opts.name,\n direction: opts.direction,\n agent: opts.agent,\n agentExplicit,\n // --approval is provider-agnostic: codex consumes approvalPolicy,\n // opencode consumes the `approval` flag (→ bash:\"ask\" per-crew config).\n ...(opts.approval ? { approvalPolicy: \"untrusted\", approval: true } : {}),\n ...(opts.shared ? { shared: true } : {}),\n ...(opts.model ? { model: opts.model } : {}),\n });\n console.log(chalk.green(`✔ Crew '${pane.title}' spawned (${pane.surfaceId})`));\n } catch (err) {\n console.error(chalk.red((err as Error).message));\n process.exit(1);\n }\n },\n );\n\ncrewCommand\n .command(\"list\")\n .description(\"List live crew sessions for a project\")\n .argument(\"<project>\", \"Project name\")\n .action(async (project: string) => {\n try {\n const crews = await runCrewList(project);\n if (crews.length === 0) {\n console.log(chalk.yellow(`No live crew sessions for ${project}.`));\n return;\n }\n for (const c of crews) {\n console.log(` ${c.name} (${c.surfaceId})`);\n }\n } catch (err) {\n console.error(chalk.red((err as Error).message));\n process.exit(1);\n }\n });\n\ncrewCommand\n .command(\"send\")\n .description(\"Send a follow-up message to an existing crew session\")\n .argument(\"<project>\", \"Project name\")\n .argument(\"<name>\", \"Crew name (e.g. crew-1)\")\n .argument(\"[message]\", \"Message to send (omit with --message-file)\")\n .option(\"--message-file <path>\", \"Read message from file instead of positional arg ('-' for stdin)\")\n .action(async (project: string, name: string, message: string | undefined, opts: { messageFile?: string }) => {\n try {\n const resolvedMessage = await resolveTextInput({ positional: message, filePath: opts.messageFile, label: \"message\" });\n await runCrewSend(project, name, resolvedMessage);\n console.log(chalk.green(`✔ Sent to ${project}:${name}`));\n } catch (err) {\n console.error(chalk.red((err as Error).message));\n process.exit(1);\n }\n });\n\ncrewCommand\n .command(\"read\")\n .description(\"Read the current screen of a crew session (tail by default; use --full for the entire scrollback)\")\n .argument(\"<project>\", \"Project name\")\n .argument(\"<name>\", \"Crew name\")\n .option(\"--lines <N>\", \"Number of trailing lines to show\", \"40\")\n .option(\"--full\", \"Show the entire scrollback (overrides --lines)\")\n .action(async (project: string, name: string, opts: { lines?: string; full?: boolean }) => {\n try {\n const screen = await runCrewRead(project, name);\n const out = opts.full ? screen : tailLines(screen, Number(opts.lines ?? 40));\n console.log(out);\n } catch (err) {\n console.error(chalk.red((err as Error).message));\n process.exit(1);\n }\n });\n\ncrewCommand\n .command(\"close\")\n .description(\"Shutdown a crew session (closes its tab)\")\n .argument(\"<project>\", \"Project name\")\n .argument(\"<name>\", \"Crew name\")\n .action(async (project: string, name: string) => {\n try {\n await runCrewClose(project, name);\n console.log(chalk.green(`✔ Closed ${project}:${name}`));\n } catch (err) {\n console.error(chalk.red((err as Error).message));\n process.exit(1);\n }\n });\n","import type { SquadrantConfig } from \"@squadrant/shared\";\n\nexport interface CrewRouteResult {\n agent: string;\n model?: string;\n tier: string;\n matchedRule: string;\n}\n\n/**\n * Resolve a crew route from task text against config.defaults.crewRouting.rules.\n * Returns the first matching rule's agent/model, or null if no rule matches or\n * crewRouting is absent. Pure — no side effects.\n */\nexport function resolveCrewRoute(taskText: string, config: SquadrantConfig): CrewRouteResult | null {\n const rules = config.defaults.crewRouting?.rules;\n if (!rules || rules.length === 0) return null;\n for (const rule of rules) {\n const re = new RegExp(rule.match, \"i\");\n if (re.test(taskText)) {\n return {\n agent: rule.agent,\n ...(rule.model !== undefined ? { model: rule.model } : {}),\n tier: rule.tier,\n matchedRule: rule.match,\n };\n }\n }\n return null;\n}\n","// src/commands/crew-control.ts\nimport { Command } from \"commander\";\nimport { createConnection } from \"node:net\";\nimport { randomUUID } from \"node:crypto\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { mkdirSync, writeFileSync } from \"node:fs\";\nimport { sendRequest } from \"@squadrant/core\";\nimport { ensureDaemon } from \"@squadrant/core\";\nimport type { ControlEvent, Mode, Provider, TaskRecord } from \"@squadrant/shared\";\nimport { mapClaudeHookToEvent } from \"@squadrant/agents\";\nimport { filterTasks, formatCompactTasks } from \"./crew-output.js\";\nimport { crewAttachCommand } from \"./crew-attach.js\";\nimport { crewChatCommand } from \"./crew-chat.js\";\n\nconst SOCK = join(homedir(), \".config\", \"squadrant\", \"squadrant.sock\");\n\n// Codex thread setup is async after `dispatch` returns; let startThread finish\n// before sending the first turn. Empirically codex handshake completes in well\n// under a second; 1.5s is a safe margin without blocking the spawn return for\n// long (this function is invoked fire-and-forget).\nconst CODEX_FIRST_TURN_DELAY_MS = 1500;\n\n/**\n * Send the spawn task arg to a freshly-dispatched codex interactive task as\n * the first turn — mirrors how `squadrant crew spawn --agent claude \"<task>\"`\n * sends the task arg into the claude CLI's first prompt.\n *\n * Reuses the existing attach-socket `say` op (same one used by `crew send` and\n * `crew attach` follow-ups). Opens a transient socket, attaches, sends say,\n * closes. The renderer running in the captain tab attaches independently and\n * receives the streamed reply.\n */\nexport async function sendCodexFirstTurn(taskId: string, text: string): Promise<void> {\n await new Promise((r) => setTimeout(r, CODEX_FIRST_TURN_DELAY_MS));\n await new Promise<void>((resolve, reject) => {\n const conn = createConnection(SOCK);\n conn.setEncoding(\"utf-8\");\n conn.on(\"data\", () => { /* drain attach frames; we just want to send */ });\n conn.on(\"error\", reject);\n conn.once(\"connect\", () => {\n try {\n conn.write(JSON.stringify({ op: \"attach\", taskId }) + \"\\n\");\n conn.write(JSON.stringify({ op: \"say\", taskId, text }) + \"\\n\");\n } catch (e) {\n reject(e);\n return;\n }\n // Brief flush window before close so the daemon processes both frames.\n setTimeout(() => { conn.end(); resolve(); }, 100);\n });\n });\n}\n\nexport function buildDispatchRequest(o: {\n project: string; provider: Provider; mode: Mode; task: string; budgetMs?: number; cwd?: string;\n approvalPolicy?: string; roleInstructions?: string; name?: string; serverPort?: number;\n}): { kind: \"dispatch\"; record: TaskRecord } {\n const now = Date.now();\n const attemptId = randomUUID();\n return {\n kind: \"dispatch\",\n record: {\n id: randomUUID(), project: o.project, provider: o.provider, mode: o.mode,\n state: \"submitted\", task: o.task, cwd: o.cwd, createdAt: now, lastHeartbeat: now,\n lastEvent: \"dispatch\", heartbeatBudgetMs: o.budgetMs ?? 300000,\n attempts: [{ attemptId, startedAt: now, lastHeartbeatAt: now }],\n ...(o.approvalPolicy ? { approvalPolicy: o.approvalPolicy } : {}),\n ...(o.roleInstructions ? { roleInstructions: o.roleInstructions } : {}),\n ...(o.name ? { name: o.name } : {}),\n ...(o.serverPort ? { serverPort: o.serverPort } : {}),\n },\n };\n}\n\nexport function buildStatusRequest(project: string, id: string) {\n return { kind: \"status\" as const, project, id };\n}\n\nexport function buildGateResolveRequest(o: { project: string; gateId: string; message: string }) {\n const lower = o.message.toLowerCase().trim();\n const decision = lower.startsWith(\"approve\") ? \"approve\" : lower.startsWith(\"deny\") ? \"deny\" : undefined;\n return {\n kind: \"gate-resolve\" as const,\n project: o.project,\n gateId: o.gateId,\n resolvedBy: \"captain\",\n payload: { text: o.message, ...(decision ? { decision } : {}) },\n };\n}\n\nexport async function squadrantdCall(req: unknown): Promise<unknown> {\n try {\n return await sendRequest(SOCK, req);\n } catch {\n ensureDaemon(); // resolves its own entrypoint — never pass a path here\n // kickstart→socket is racy; bounded backoff. If all attempts fail,\n // throw the last error (fail loud, no scrape fallback).\n let lastErr: unknown;\n for (let i = 0; i < 3; i++) {\n try {\n return await sendRequest(SOCK, req);\n } catch (e) {\n lastErr = e;\n await new Promise((r) => setTimeout(r, 200));\n }\n }\n throw lastErr;\n }\n}\n\n/**\n * Build an explicit terminal/blocked event request from a crew's `signal`\n * verb. Defaults to reading `SQUADRANT_CREW_TASK_ID` and `SQUADRANT_CREW_PROJECT`\n * from env so the claude/opencode crew templates can run e.g.\n * `squadrant crew signal done --message \"…\"` without knowing their own ids.\n *\n * Explicit `taskId`/`project` (from `--task-id`/`--project` flags) take\n * precedence over env. This is the codex path: a single long-lived app-server\n * child serves all codex tasks as threads, so a process-level env var is\n * unsafe (wrong for concurrent tasks). The codex crew is told its concrete ids\n * via per-thread developerInstructions and signals with the explicit flags.\n *\n * Anti-#2576 invariant lives at the OTHER end (the hook bridge in\n * `_hook`). This builder is the *explicit* path: a crew running this verb\n * has *intentionally* declared terminal state after its own settle-check.\n */\nexport function buildSignalRequest(\n signal: \"done\" | \"blocked\" | \"failed\",\n o: {\n message?: string;\n question?: string;\n error?: string;\n /** Explicit override (codex); falls back to SQUADRANT_CREW_TASK_ID env. */\n taskId?: string;\n /** Explicit override (codex); falls back to SQUADRANT_CREW_PROJECT env. */\n project?: string;\n /** Injectable for tests; defaults to writing under ~/.config/squadrant/state/_results. */\n writeResult?: (id: string, payload: string) => string;\n },\n): { kind: \"event\"; project: string; event: ControlEvent } {\n const taskId = o.taskId ?? process.env.SQUADRANT_CREW_TASK_ID;\n const project = o.project ?? process.env.SQUADRANT_CREW_PROJECT;\n if (!taskId)\n throw new Error(\"not running under a crew (SQUADRANT_CREW_TASK_ID unset)\");\n if (!project)\n throw new Error(\"not running under a crew (SQUADRANT_CREW_PROJECT unset)\");\n let event: ControlEvent;\n if (signal === \"done\") {\n const resultRef = o.writeResult ? o.writeResult(taskId, o.message ?? \"\") : \"\";\n event = {\n type: \"task.done\",\n id: taskId,\n resultRef,\n ...(o.message !== undefined ? { message: o.message } : {}),\n };\n } else if (signal === \"blocked\") {\n event = { type: \"task.blocked\", id: taskId, reason: \"crew signaled blocked\", question: o.question ?? \"\" };\n } else {\n event = { type: \"task.failed\", id: taskId, error: o.error ?? \"crew signaled failed\" };\n }\n return { kind: \"event\", project, event };\n}\n\n/** Default writer used by the `signal done` subcommand. Tests inject their own. */\nfunction defaultWriteResult(id: string, payload: string): string {\n const dir = join(homedir(), \".config\", \"squadrant\", \"state\", \"_results\");\n mkdirSync(dir, { recursive: true });\n const file = join(dir, `${id}.txt`);\n writeFileSync(file, payload);\n return file;\n}\n\n/**\n * Attach the control-plane verbs onto an existing `squadrant crew` command so\n * they coexist with the legacy cmux-scrape verbs (spawn/send/read/close/list).\n * The control-plane task listing is `tasks` (not `list`) to avoid colliding\n * with the legacy `list` that captains' playbook still uses. This is the\n * deferred-legacy coexistence state — wired so PR #85 does not break live\n * captains. Migrating captain-ops to the control-plane verbs is the deferred\n * legacy-re-pointing spec's job.\n */\nexport function addControlPlaneCrewCommands(crew: Command): void {\n crew\n .command(\"dispatch <project> <task>\")\n .description(\"Dispatch a crew task via the control-plane daemon\")\n .requiredOption(\"--provider <p>\", \"claude|opencode|codex (gemini: experimental, headless not supported)\")\n .option(\"--mode <m>\", \"headless|interactive\", \"interactive\")\n .option(\"--cwd <dir>\", \"working dir for the crew (project/worktree); required for codex to edit code\")\n .action(async (project: string, task: string, opts: { provider: Provider; mode: Mode; cwd?: string }) => {\n const req = buildDispatchRequest({ project, task, provider: opts.provider, mode: opts.mode, cwd: opts.cwd });\n const r = await squadrantdCall(req);\n process.stdout.write(JSON.stringify(r) + \"\\n\");\n });\n\n crew\n .command(\"status <project> <id>\")\n .description(\"Read a control-plane task's state\")\n .action(async (project: string, id: string) => {\n const r = await squadrantdCall(buildStatusRequest(project, id));\n process.stdout.write(JSON.stringify(r) + \"\\n\");\n });\n\n crew\n .command(\"tasks <project>\")\n .description(\"List control-plane tasks for a project (control-plane analogue of legacy `list`), or purge a task with --purge\")\n .option(\"--json\", \"Full JSON output (one or more records)\")\n .option(\"--id <taskId>\", \"Show only tasks matching this id prefix\")\n .option(\"--state <state>\", \"Filter by task state\")\n .option(\"--state-only <taskId>\", \"Print just the state string for a single task\")\n .option(\"--purge <taskId>\", \"Purge a task record from the store (default: only terminal records)\")\n .option(\"--force\", \"Force-purge a non-terminal record (use with --purge)\")\n .action(async (project: string, opts: { json?: boolean; id?: string; state?: string; stateOnly?: string; purge?: string; force?: boolean }) => {\n if (opts.purge) {\n const r = await squadrantdCall({ kind: \"purge\", project, id: opts.purge, force: opts.force ?? false }) as TaskRecord;\n console.log(`purged ${r.provider}/${r.id} (was ${r.state})`);\n return;\n }\n const raw = (await squadrantdCall({ kind: \"list\", project })) as TaskRecord[];\n let records = raw;\n if (opts.stateOnly) {\n records = filterTasks(records, { id: opts.stateOnly, stateOnly: true });\n process.stdout.write(formatCompactTasks(records, { stateOnly: true }) + \"\\n\");\n return;\n }\n records = filterTasks(records, { id: opts.id, state: opts.state });\n const compact = opts.json !== true;\n process.stdout.write(formatCompactTasks(records, { compact }) + \"\\n\");\n });\n\n // TODO(downstream interactive-wiring spec): deliverReply is not yet wired in\n // squadrantd, so this transitions task state but never reaches the agent. Deferred.\n // --gate <gateId> routes through the gate-resolve verb instead (spec §4.9).\n crew\n .command(\"reply <project> <id> <message>\")\n .description(\"Reply to a blocked control-plane task (delivery deferred), or resolve a gate via --gate\")\n .option(\"--gate <gateId>\", \"resolve a pending gate by id (codex interactive, spec §4.9)\")\n .action(async (project: string, id: string, message: string, opts: { gate?: string }) => {\n if (opts.gate) {\n const r = await squadrantdCall(buildGateResolveRequest({ project, gateId: opts.gate, message }));\n process.stdout.write(JSON.stringify(r) + \"\\n\");\n return;\n }\n process.stderr.write(\"reply delivery is not yet wired (deferred); state transitioned only\\n\");\n const r = await squadrantdCall({ kind: \"reply\", project, id, message });\n process.stdout.write(JSON.stringify(r) + \"\\n\");\n });\n\n // Bridge from Claude's native Stop/SubagentStop/SessionEnd hooks to the\n // squadrant control plane. Reads hook payload JSON on stdin (Claude hook\n // contract); env-gated on SQUADRANT_CREW_TASK_ID/SQUADRANT_CREW_PROJECT so the\n // hook is a no-op outside spawned crews. Anti-#2576: maps only to\n // task.progress (liveness), never task.done — terminal state comes from\n // `squadrant crew signal` (explicit, post-settle-check).\n crew\n .command(\"_hook <event>\", { hidden: true })\n .description(\"internal: bridge from claude Stop/SubagentStop/SessionEnd hooks to squadrantd\")\n .action(async (event: string) => {\n const taskId = process.env.SQUADRANT_CREW_TASK_ID;\n const project = process.env.SQUADRANT_CREW_PROJECT;\n if (!taskId || !project) { process.exit(0); }\n // Drain stdin (Claude posts hook JSON there). Tolerate missing/malformed.\n let stdin = \"\";\n try {\n for await (const chunk of process.stdin) stdin += chunk;\n } catch { /* ignore */ }\n let payload: unknown = undefined;\n if (stdin.trim()) {\n try { payload = JSON.parse(stdin); } catch { /* ignore malformed */ }\n }\n const ev = mapClaudeHookToEvent(event, payload, taskId);\n if (!ev) { process.exit(0); }\n try {\n await squadrantdCall({ kind: \"event\", project, event: ev });\n } catch {\n // Daemon down: do NOT block Claude. Hook contract requires exit 0;\n // a non-zero exit would block the conversation.\n }\n process.exit(0);\n });\n\n // The explicit done/blocked/failed signal — the anti-#2576 escape from\n // liveness-only Stop hooks. The crew runs this AFTER its own settle-check\n // (git status clean, etc.) to declare terminal state to the captain.\n crew\n .command(\"signal <state>\")\n .description(\"Emit explicit terminal signal from a crew session: done|blocked|failed (reads SQUADRANT_CREW_* env, or --task-id/--project for codex)\")\n .option(\"--message <m>\", \"Summary written to resultRef (done)\")\n .option(\"--question <q>\", \"Question to surface to captain (blocked)\")\n .option(\"--error <e>\", \"Error message (failed)\")\n .option(\"--task-id <id>\", \"Explicit task id (codex; overrides SQUADRANT_CREW_TASK_ID env)\")\n .option(\"--project <p>\", \"Explicit project (codex; overrides SQUADRANT_CREW_PROJECT env)\")\n .action(async (state: string, opts: { message?: string; question?: string; error?: string; taskId?: string; project?: string }) => {\n if (state !== \"done\" && state !== \"blocked\" && state !== \"failed\") {\n process.stderr.write(`unknown signal '${state}' (expected: done|blocked|failed)\\n`);\n process.exit(2);\n }\n try {\n const req = buildSignalRequest(state as \"done\" | \"blocked\" | \"failed\", {\n ...(opts.message !== undefined ? { message: opts.message } : {}),\n ...(opts.question !== undefined ? { question: opts.question } : {}),\n ...(opts.error !== undefined ? { error: opts.error } : {}),\n ...(opts.taskId !== undefined ? { taskId: opts.taskId } : {}),\n ...(opts.project !== undefined ? { project: opts.project } : {}),\n writeResult: defaultWriteResult,\n });\n await squadrantdCall(req);\n process.exit(0);\n } catch (e) {\n process.stderr.write(`${(e as Error).message}\\n`);\n process.exit(1);\n }\n });\n\n crew.addCommand(crewAttachCommand);\n crew.addCommand(crewChatCommand);\n}\n\n// Standalone control-plane-only command (kept for back-compat / direct use;\n// the CLI composes these onto the legacy `crew` command via the function above).\nexport const crewControlCommand = new Command(\"crew\")\n .description(\"Dispatch and track crew via the squadrant control plane\");\naddControlPlaneCrewCommands(crewControlCommand);\n","import type { TaskRecord } from \"@squadrant/shared\";\n\nexport function tailLines(\n text: string,\n maxLines = 40,\n maxBytes = 4096,\n): string {\n if (!text) return \"\";\n const lines = text.split(\"\\n\");\n if (lines.at(-1) === \"\") lines.pop();\n const kept = lines.slice(-maxLines);\n let result = kept.join(\"\\n\");\n if (Buffer.byteLength(result, \"utf-8\") > maxBytes) {\n const truncated: string[] = [];\n let bytes = 0;\n for (const line of kept) {\n const lineBytes = Buffer.byteLength(line, \"utf-8\") + 1;\n if (bytes + lineBytes > maxBytes) break;\n truncated.push(line);\n bytes += lineBytes;\n }\n result = truncated.join(\"\\n\");\n }\n return result;\n}\n\nfunction shortId(id: string): string {\n return id.slice(0, 8);\n}\n\nexport function formatTaskLine(record: TaskRecord): string {\n const sid = shortId(record.id);\n const title = record.task\n .split(\"\\n\")[0]\n .slice(0, 60);\n return `${sid} ${record.provider} ${record.state} ${record.lastEvent} ${title}`;\n}\n\nexport function filterTasks(\n records: TaskRecord[],\n opts: { id?: string; state?: string; stateOnly?: boolean },\n): TaskRecord[] {\n let filtered = records;\n if (opts.id) {\n filtered = filtered.filter((r) => r.id.startsWith(opts.id!));\n }\n if (opts.state) {\n filtered = filtered.filter((r) => r.state === opts.state);\n }\n return filtered;\n}\n\nexport function formatCompactTasks(\n records: TaskRecord[],\n opts: { compact?: boolean; stateOnly?: boolean },\n): string {\n if (records.length === 0) {\n return \"(no tasks match filter)\";\n }\n if (opts.stateOnly) {\n return records[0].state;\n }\n if (opts.compact === false) {\n return JSON.stringify(records, null, 2);\n }\n return records.map(formatTaskLine).join(\"\\n\");\n}\n","// src/commands/crew-attach.ts\nimport { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport { createConnection } from \"node:net\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { createInterface } from \"node:readline\";\nimport { decodeFrames, type AttachFrame, type AttachInbound } from \"@squadrant/core\";\n\nfunction socketPath(): string {\n return process.env.SQUADRANTD_SOCK ?? join(homedir(), \".config\", \"squadrant\", \"squadrant.sock\");\n}\n\n// --- Pure formatters (exported for tests) ---\n\nconst ANSI_RE = /\\x1b\\[[0-9;]*m/g;\n\nexport function stripAnsi(s: string): string {\n return s.replace(ANSI_RE, \"\");\n}\n\nfunction rule(width: number, ch = \"─\"): string {\n return ch.repeat(Math.max(0, width));\n}\n\nexport function formatTurnHeader(turn: number, width = 60): string {\n const label = ` codex · turn ${turn} `;\n const remaining = Math.max(2, width - label.length - 2);\n const left = \"╭─\";\n const right = rule(remaining) + \"╮\";\n return chalk.cyan.bold(left) + chalk.cyan.bold(label) + chalk.cyan(right);\n}\n\nexport function formatTurnFooter(elapsedMs: number, width = 60): string {\n const secs = (elapsedMs / 1000).toFixed(1);\n const label = ` done · ${secs}s `;\n const remaining = Math.max(2, width - label.length - 2);\n const left = \"╰─\";\n const right = rule(remaining) + \"╯\";\n return chalk.dim(left + label + right);\n}\n\nexport type RendererState = \"idle\" | \"working\" | \"awaiting-input\" | \"blocked\";\n\nexport function formatStatus(state: RendererState, turn: number, elapsedMs: number): string {\n const secs = (elapsedMs / 1000).toFixed(1);\n return chalk.dim(` · state=${state} turn=${turn} elapsed=${secs}s`);\n}\n\nexport function formatApproval(kind: string, question: string): string {\n return chalk.yellow.bold(`[approval] ${kind}`) + chalk.yellow(`: ${question}`);\n}\n\nexport function formatApprovalPrompt(): string {\n return chalk.yellow(\"[approve/deny]> \");\n}\n\nexport function formatInputQuestion(question: string): string {\n return chalk.cyan.bold(\"[codex asks] \") + question;\n}\n\nexport function formatInputPrompt(): string {\n return chalk.cyan(\"[answer]> \");\n}\n\nexport function formatDoneFollowup(): string {\n return chalk.dim(\"[done — type a follow-up or Ctrl-C]\");\n}\n\nexport function formatAttached(): string {\n return chalk.dim(\"(attached)\");\n}\n\nexport function formatReattached(): string {\n return chalk.dim(\"(reattached)\");\n}\n\nexport function formatClosed(reason: string): string {\n return chalk.dim(`(closed: ${reason})`);\n}\n\nexport function formatConnectionClosed(): string {\n return chalk.dim(\"(connection closed)\");\n}\n\nexport function formatConnectionLost(): string {\n return chalk.dim(\"(connection lost — retrying...)\");\n}\n\nexport function formatReattachFailed(taskId: string): string {\n return chalk.red(`(reattach failed — re-run: squadrant crew attach ${taskId})`);\n}\n\nexport function formatGatePromoted(gateId: string): string {\n return chalk.dim(`(no client was attached; question promoted to gate ${gateId})`);\n}\n\n// --- Retry/backoff pure logic (exported for tests) ---\n\n/** Minimum elapsed ms on a connection before it's considered stable (no-frame path). */\nexport const STABLE_MS = 5_000;\n\n/** Total retry budget per disconnect episode before giving up. */\nexport const RETRY_BUDGET_MS = 60_000;\n\n/**\n * Exponential backoff delay for reconnect attempt N (0-indexed).\n * Caps at 16s to bound the per-attempt wait.\n */\nexport function computeBackoffDelay(attempt: number): number {\n return Math.min(1000 * Math.pow(2, attempt), 16_000);\n}\n\n/**\n * Returns true if the connection should be considered \"stable\" —\n * meaning backoff should reset on the next disconnect.\n * Stable = received >=1 real frame OR survived >= STABLE_MS.\n */\nexport function isConnectionStable(\n connectTimeMs: number,\n framesReceived: number,\n nowMs: number\n): boolean {\n return connectTimeMs > 0 && (framesReceived > 0 || nowMs - connectTimeMs >= STABLE_MS);\n}\n\n// --- CLI command ---\n\nexport const crewAttachCommand = new Command(\"attach\")\n .description(\"Attach to a live interactive task (renders deltas; takes follow-ups). Spec §4.6.\")\n .argument(\"<taskId>\", \"task id to attach to\")\n .action((taskId: string) => {\n // --- Retry state (persists across reconnects) ---\n let attempt = 0; // 0-indexed; grows on unstable disconnect, resets on stable\n let totalSpentMs = 0; // cumulative backoff spent this episode; resets on stable\n let retryLogged = false; // dedup: print \"connection lost\" once per episode\n\n // --- Per-connection state (reset each connect()) ---\n let connectTimeMs = 0;\n let framesReceived = 0;\n let taskClosed = false;\n let disconnecting = false;\n\n // Mutable send ref — updated on each new connection so readline/SIGINT always\n // writes to the current socket. Noop during backoff gaps.\n let send: (m: AttachInbound) => void = () => {};\n\n // --- Renderer state (persists across reconnects) ---\n let pendingRequestId: number | undefined;\n let turnCount = 0;\n let turnStartMs = 0;\n let inTurn = false;\n let state: RendererState = \"idle\";\n let attachedOnce = false;\n\n const elapsed = () => (turnStartMs ? Date.now() - turnStartMs : 0);\n const writeStatus = () => process.stdout.write(formatStatus(state, turnCount, elapsed()) + \"\\n\");\n\n let buf = \"\";\n\n function handleDisconnect(errorMsg?: string): void {\n if (disconnecting) return; // guard: error fires before close in Node.js\n disconnecting = true;\n send = () => {}; // noop until next connect()\n\n if (errorMsg) {\n process.stderr.write(`\\n${chalk.red(`(socket error: ${errorMsg})`)}\\n`);\n }\n\n if (taskClosed) {\n // Task ended cleanly via \"closed\" frame — no retry needed.\n process.stderr.write(\"\\n\" + formatConnectionClosed() + \"\\n\");\n process.exit(0);\n return;\n }\n\n const stable = isConnectionStable(connectTimeMs, framesReceived, Date.now());\n\n if (stable) {\n // New episode: the lost connection was healthy, so reset budget and backoff.\n attempt = 0;\n totalSpentMs = 0;\n retryLogged = false;\n }\n\n if (!retryLogged) {\n process.stderr.write(\"\\n\" + formatConnectionLost() + \"\\n\");\n retryLogged = true;\n }\n\n const delay = computeBackoffDelay(attempt);\n if (!stable) attempt += 1; // grow backoff only on unstable; stable already reset to 0\n\n totalSpentMs += delay;\n if (totalSpentMs > RETRY_BUDGET_MS) {\n process.stderr.write(formatReattachFailed(taskId) + \"\\n\");\n process.exit(1);\n return;\n }\n\n setTimeout(connect, delay);\n }\n\n function connect(): void {\n connectTimeMs = 0;\n framesReceived = 0;\n taskClosed = false;\n disconnecting = false;\n buf = \"\";\n\n const conn = createConnection(socketPath());\n send = (m: AttachInbound) => conn.write(JSON.stringify(m) + \"\\n\");\n\n conn.on(\"connect\", () => {\n connectTimeMs = Date.now();\n send({ op: \"attach\", taskId });\n });\n\n conn.on(\"data\", (chunk) => {\n buf += chunk.toString();\n const lastNl = buf.lastIndexOf(\"\\n\");\n if (lastNl < 0) return;\n const consumable = buf.slice(0, lastNl + 1);\n buf = buf.slice(lastNl + 1);\n for (const f of decodeFrames(consumable)) render(f);\n });\n\n conn.on(\"close\", () => handleDisconnect());\n conn.on(\"error\", (e) => handleDisconnect(e.message));\n }\n\n function render(f: AttachFrame): void {\n switch (f.type) {\n case \"delta\":\n framesReceived += 1;\n process.stdout.write(f.text);\n break;\n case \"turn-started\":\n framesReceived += 1;\n turnCount += 1;\n turnStartMs = Date.now();\n inTurn = true;\n state = \"working\";\n process.stdout.write(\"\\n\" + formatTurnHeader(turnCount) + \"\\n\");\n writeStatus();\n break;\n case \"turn-completed\":\n framesReceived += 1;\n process.stdout.write(\"\\n\" + formatTurnFooter(elapsed()) + \"\\n\");\n state = \"idle\";\n inTurn = false;\n process.stdout.write(formatDoneFollowup() + \"\\n> \");\n break;\n case \"input-requested\":\n framesReceived += 1;\n pendingRequestId = f.requestId;\n state = \"awaiting-input\";\n process.stdout.write(\"\\n\" + formatInputQuestion(f.question) + \"\\n\" + formatInputPrompt());\n break;\n case \"approval-requested\":\n framesReceived += 1;\n pendingRequestId = f.requestId;\n state = \"blocked\";\n process.stdout.write(\"\\n\" + formatApproval(f.kind, f.question) + \"\\n\" + formatApprovalPrompt());\n break;\n case \"gate-promoted\":\n framesReceived += 1;\n process.stdout.write(\"\\n\" + formatGatePromoted(f.gateId) + \"\\n> \");\n break;\n case \"reattached\":\n framesReceived += 1;\n process.stdout.write(\"\\n\" + (attachedOnce ? formatReattached() : formatAttached()) + \"\\n> \");\n attachedOnce = true;\n break;\n case \"closed\":\n taskClosed = true;\n process.stdout.write(\"\\n\" + formatClosed(f.reason) + \"\\n\");\n break;\n case \"_keepalive\":\n break;\n }\n }\n\n connect();\n\n const rl = createInterface({ input: process.stdin, terminal: false });\n rl.on(\"line\", (text) => {\n if (pendingRequestId != null) {\n const lower = text.toLowerCase();\n const decision = lower.startsWith(\"approve\") ? \"approve\" : lower.startsWith(\"deny\") ? \"deny\" : undefined;\n send({ op: \"answer\", taskId, requestId: pendingRequestId, payload: { text, decision } });\n pendingRequestId = undefined;\n if (state === \"awaiting-input\" || state === \"blocked\") state = \"working\";\n } else {\n send({ op: \"say\", taskId, text });\n }\n });\n process.on(\"SIGINT\", () => send({ op: \"interrupt\", taskId }));\n });\n","// src/commands/crew-chat.ts\n// DEPRECATED alias for `squadrant crew spawn --agent codex`. Kept so external\n// callers don't break; prints a warning and delegates to runCrewSpawn so the\n// session opens as a tab in the captain (same UX as `--agent claude`).\nimport { Command } from \"commander\";\nimport { runCrewSpawn } from \"./crew.js\";\n\nexport const crewChatCommand = new Command(\"chat\")\n .description(\"[DEPRECATED] alias for `squadrant crew spawn <project> '(interactive)' --agent codex`.\")\n .requiredOption(\"--provider <p>\", \"provider (codex only today)\")\n .requiredOption(\"--project <name>\", \"project name\")\n .option(\"--cwd <dir>\", \"(ignored; project cwd is used)\", process.cwd())\n .option(\"--model <m>\", \"(unused; reserved for future codex model routing)\")\n .option(\n \"--approval\",\n \"force codex approvalPolicy='untrusted' so tool/shell calls request approval\",\n false\n )\n .action(async (opts: { provider: string; project: string; cwd: string; model?: string; approval: boolean }) => {\n process.stderr.write(\n \"⚠️ `squadrant crew chat --provider codex` is deprecated. \" +\n \"Use: squadrant crew spawn <project> '(interactive)' --agent codex\" +\n (opts.approval ? \" --approval\" : \"\") +\n \"\\n\"\n );\n if (opts.provider !== \"codex\") {\n throw new Error(`crew chat is implemented for provider=codex only (got '${opts.provider}')`);\n }\n const pane = await runCrewSpawn({\n project: opts.project,\n task: \"(interactive)\",\n agent: \"codex\",\n ...(opts.approval ? { approvalPolicy: \"untrusted\" } : {}),\n });\n process.stdout.write(`Crew '${pane.title}' spawned (${pane.surfaceId})\\n`);\n });\n","import { mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { mergeClaudeHooks } from \"@squadrant/agents\";\n\n/**\n * Bash permission allowlist for crews running under `--permission-mode\n * acceptEdits` (Phase 2a). acceptEdits auto-accepts file edits but still\n * prompts on EVERY shell command. Without this, the Phase 2b pane probe fires\n * CREW BLOCKED on every commit/install/test/grep = notification spam.\n *\n * Conservative by design: two tiers —\n * 1. Read-only inspection (ps, ls, grep, jq, …) — never mutates anything.\n * 2. Safe-but-mutating dev ops (git commit, npm install, vitest, …) — needed\n * for normal crew work; scoped to safe subcommands.\n * Genuinely risky ops (`git reset --hard`, `git config`, `rm`, `curl`, `wget`,\n * `sudo`, `kill`, unknown binaries, out-of-workspace writes) STILL prompt and\n * surface as CREW BLOCKED. No blanket `Bash(*)`.\n *\n * Syntax: `Bash(<prefix>:*)` allows any command whose text starts with\n * <prefix>. Patterns match the raw command string — NOT the resolved binary.\n *\n * Known limitation: commands with a leading env-var assignment\n * (e.g. `SQUADRANT_CREW_TASK_ID=x sleep 5`) still prompt because the line\n * starts with the variable name, not the command. This is rare and acceptable;\n * it's not a bug.\n */\nexport const CREW_PERMISSION_ALLOWLIST: readonly string[] = [\n // git — read + safe mutations (reset/clean/config intentionally excluded)\n \"Bash(git status:*)\",\n \"Bash(git add:*)\",\n \"Bash(git commit:*)\",\n \"Bash(git push:*)\",\n \"Bash(git pull:*)\",\n \"Bash(git fetch:*)\",\n \"Bash(git checkout:*)\",\n \"Bash(git branch:*)\",\n \"Bash(git diff:*)\",\n \"Bash(git log:*)\",\n \"Bash(git stash:*)\",\n \"Bash(git restore:*)\",\n // git — read-only queries (no-mutation subcommands)\n \"Bash(git show:*)\",\n \"Bash(git rev-parse:*)\",\n \"Bash(git remote -v:*)\",\n \"Bash(git stash list:*)\",\n // npm / npx — installs + script/test/build runners\n \"Bash(npm install:*)\",\n \"Bash(npm ci:*)\",\n \"Bash(npm run:*)\",\n \"Bash(npm test:*)\",\n \"Bash(npm ls:*)\",\n \"Bash(npm view:*)\",\n \"Bash(npx vitest:*)\",\n \"Bash(npx tsc:*)\",\n // direct runners\n \"Bash(node:*)\",\n \"Bash(node --version:*)\",\n \"Bash(vitest:*)\",\n \"Bash(tsc:*)\",\n // pnpm\n \"Bash(pnpm ls:*)\",\n // process / system read — non-interactive, read-only\n \"Bash(ps:*)\",\n \"Bash(pgrep:*)\",\n \"Bash(lsof:*)\",\n \"Bash(top -l:*)\",\n \"Bash(uptime:*)\",\n \"Bash(whoami:*)\",\n \"Bash(uname:*)\",\n \"Bash(date:*)\",\n \"Bash(env:*)\",\n \"Bash(sysctl:*)\",\n // file read / navigation\n \"Bash(ls:*)\",\n \"Bash(cat:*)\",\n \"Bash(head:*)\",\n \"Bash(tail:*)\",\n \"Bash(wc:*)\",\n \"Bash(grep:*)\",\n \"Bash(rg:*)\",\n \"Bash(find:*)\",\n \"Bash(pwd:*)\",\n \"Bash(stat:*)\",\n \"Bash(file:*)\",\n \"Bash(realpath:*)\",\n \"Bash(basename:*)\",\n \"Bash(dirname:*)\",\n \"Bash(du:*)\",\n \"Bash(df:*)\",\n \"Bash(tree:*)\",\n // read-only text processing\n \"Bash(sort:*)\",\n \"Bash(uniq:*)\",\n \"Bash(cut:*)\",\n \"Bash(tr:*)\",\n \"Bash(jq:*)\",\n \"Bash(diff:*)\",\n \"Bash(column:*)\",\n // harmless utilities\n \"Bash(echo:*)\",\n \"Bash(which:*)\",\n \"Bash(true:*)\",\n \"Bash(sleep:*)\",\n \"Bash(printf:*)\",\n];\n\n/**\n * Pure: merge the crew permission allowlist into a settings object's\n * `permissions.allow`, de-duplicating and preserving any existing entries and\n * sibling permission keys (deny/ask). Never mutates the input.\n */\nexport function mergeCrewPermissions(settings: Record<string, unknown>): Record<string, unknown> {\n const next = structuredClone(settings ?? {});\n const permissions = (next.permissions ??= {}) as { allow?: unknown };\n const existing = Array.isArray(permissions.allow) ? (permissions.allow as string[]) : [];\n permissions.allow = [...new Set([...existing, ...CREW_PERMISSION_ALLOWLIST])];\n return next;\n}\n\n/**\n * Write a Claude `--settings`-compatible JSON file containing the squadrant\n * Stop/SubagentStop/SessionEnd hooks merged onto an empty base. Per-crew\n * scoping (one file per spawned task) keeps the hook out of the user's\n * global `~/.claude/settings.json` — captain/command Claude sessions are\n * untouched. Returns the absolute path to the written file.\n */\nexport function writePerCrewSettings(o: {\n stateRoot: string;\n project: string;\n taskId: string;\n hookCmd?: string;\n}): string {\n const dir = join(o.stateRoot, o.project, o.taskId);\n mkdirSync(dir, { recursive: true });\n const file = join(dir, \"settings.json\");\n const merged = mergeClaudeHooks({}, o.hookCmd ?? \"squadrant crew _hook\");\n writeFileSync(file, JSON.stringify(merged, null, 2));\n return file;\n}\n\n/**\n * Write squadrant hooks into `<projectCwd>/.claude/settings.local.json` so they\n * are auto-loaded by Claude Code as a project-local settings source (level 3\n * in the precedence hierarchy). Unlike the per-crew settings.json passed via\n * `--settings` (level 2), this auto-loaded file merges with the cmux wrapper's\n * `--settings` hooks rather than being overwritten by them (#134).\n *\n * Merges with any existing `.claude/settings.local.json` — does not clobber\n * the user's own personal hooks or permissions. Returns the absolute path.\n */\nexport function writePerCrewSettingsLocal(o: {\n projectCwd: string;\n hookCmd?: string;\n}): string {\n const dir = join(o.projectCwd, \".claude\");\n mkdirSync(dir, { recursive: true });\n const file = join(dir, \"settings.local.json\");\n let existing: Record<string, unknown> = {};\n try {\n const raw = readFileSync(file, \"utf-8\");\n existing = JSON.parse(raw);\n } catch {\n // File doesn't exist or isn't valid JSON — start fresh\n }\n const withHooks = mergeClaudeHooks(existing, o.hookCmd ?? \"squadrant crew _hook\");\n const merged = mergeCrewPermissions(withHooks);\n writeFileSync(file, JSON.stringify(merged, null, 2));\n return file;\n}\n\n/**\n * Write an opencode config file that auto-approves edit/bash/webfetch so\n * squadrant-spawned opencode crews never block on a manual permission prompt.\n * OPENCODE_CONFIG merges with (does not replace) the global config, so only\n * the permission block is needed — model/plugin/mcp flow through from\n * ~/.config/opencode/opencode.json automatically.\n *\n * Returns the absolute path to the written file.\n *\n * CP3 opt-in: with `gateBash`, bash flips to \"ask\" so the captain approves\n * shell commands (opencode emits `permission.asked` → daemon surfaces CREW\n * BLOCKED → captain's decision is POSTed back). Default (no flag) keeps bash\n * \"allow\" — opencode crews stay fully autonomous unless `--approval` is passed.\n */\nexport function writePerCrewOpencodeConfig(o: {\n stateRoot: string;\n project: string;\n taskId: string;\n gateBash?: boolean;\n}): string {\n const dir = join(o.stateRoot, o.project, o.taskId);\n mkdirSync(dir, { recursive: true });\n const file = join(dir, \"opencode.json\");\n const config = {\n permission: {\n read: \"allow\",\n edit: \"allow\",\n glob: \"allow\",\n grep: \"allow\",\n bash: o.gateBash ? \"ask\" : \"allow\",\n webfetch: \"allow\",\n websearch: \"allow\",\n task: \"allow\",\n lsp: \"allow\",\n external_directory: { \"**\": \"allow\" },\n },\n };\n writeFileSync(file, JSON.stringify(config, null, 2));\n return file;\n}\n","import { Command } from \"commander\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport os from \"node:os\";\nimport chalk from \"chalk\";\nimport { loadConfig } from \"@squadrant/shared\";\nimport { createCmuxDriver, RuntimeRegistry } from \"@squadrant/workspaces\";\nimport type { PaneRef, PanePlacement } from \"@squadrant/workspaces\";\nimport {\n createClaudeDriver,\n createCodexDriver,\n createGeminiDriver,\n createOpencodeDriver,\n CapabilityRegistry,\n} from \"@squadrant/agents\";\nimport { resolveCaptainWorkspace, sendFirstTurnWhenReady } from \"@squadrant/workspaces\";\nimport { resolveTextInput } from \"@squadrant/shared\";\nimport { addWorktree, removeWorktree, worktreePath, resolveWorktreeBase } from \"@squadrant/shared\";\n\nconst TEMPLATES_DIR = path.join(os.homedir(), \".config\", \"squadrant\", \"templates\");\n\n// Base branch derived at spawn time from origin/HEAD (#359).\n\nconst SIDE_ROLES = [\"research\", \"debug\"] as const;\ntype SideRole = (typeof SIDE_ROLES)[number];\n\n// POSIX single-quote a path so it is safe to embed in a shell command even\n// when the path contains spaces or special characters.\nfunction shellQuote(p: string): string {\n return \"'\" + p.replace(/'/g, \"'\\\\''\") + \"'\";\n}\n\nfunction titleFor(project: string, name: string): string {\n return `🗒 ${project}:${name}`;\n}\n\nfunction isSideTitle(project: string, title: string): boolean {\n return title.startsWith(`🗒 ${project}:`);\n}\n\nfunction nameFromTitle(project: string, title: string): string {\n return title.slice(`🗒 ${project}:`.length);\n}\n\nfunction nextAutoName(existingTitles: string[], project: string): string {\n const used = new Set<number>();\n for (const title of existingTitles) {\n const n = nameFromTitle(project, title).match(/^side-(\\d+)$/);\n if (n) used.add(Number(n[1]));\n }\n let i = 1;\n while (used.has(i)) i++;\n return `side-${i}`;\n}\n\n/** Builds the first-turn message: topic + injected context the agent needs\n * for handoff (spokeVault, project, role). For debug sessions, scratchWorktree\n * is the isolated worktree path the session is running in. */\nexport function buildSideFirstTurn(\n topic: string,\n project: string,\n role: string,\n spokeVault: string,\n scratchWorktree?: string,\n): string {\n const lines = [\n topic,\n \"\",\n \"---\",\n \"Side-session context (for handoff use):\",\n `Project: ${project}`,\n `Role: ${role}`,\n `Spoke vault: ${spokeVault}`,\n ];\n if (scratchWorktree) {\n lines.push(`Scratch worktree: ${scratchWorktree}`);\n }\n return lines.join(\"\\n\");\n}\n\nexport interface SideSpawnInput {\n project: string;\n topic: string;\n role: string;\n name?: string;\n direction?: PanePlacement;\n agent?: string;\n}\n\nexport async function runSideSpawn(input: SideSpawnInput): Promise<PaneRef> {\n const config = loadConfig();\n const proj = config.projects[input.project];\n if (!proj) {\n throw new Error(`Project '${input.project}' not found. Run 'squadrant projects list'.`);\n }\n\n if (!SIDE_ROLES.includes(input.role as SideRole)) {\n throw new Error(\n `Unknown side role '${input.role}'. Valid roles: ${SIDE_ROLES.join(\", \")}.`,\n );\n }\n\n const runtime = new RuntimeRegistry({ cmux: createCmuxDriver() }).forProject(\n input.project,\n config,\n );\n const captain = await runtime.status(proj.captainName);\n if (!captain) {\n throw new Error(\n `Captain workspace '${proj.captainName}' is not running. Run 'squadrant launch ${input.project}' first.`,\n );\n }\n\n const existing = await runtime.listSurfaces(captain.id);\n const existingTitles = existing\n .filter((s) => s.title && isSideTitle(input.project, s.title))\n .map((s) => s.title!);\n\n if (input.name) {\n const wantTitle = titleFor(input.project, input.name);\n if (existingTitles.includes(wantTitle)) {\n throw new Error(\n `Side session '${input.name}' already exists for ${input.project}.`,\n );\n }\n }\n const name = input.name ?? nextAutoName(existingTitles, input.project);\n\n // Debug sessions run in an isolated scratch git worktree so instrumentation\n // edits never touch the captain's checkout. Research sessions share the root\n // checkout. The #279 fix (cd into spawnCwd before launching CLI) applies to both.\n const spawnCwd = input.role === \"debug\"\n ? addWorktree({\n repoRoot: proj.path,\n worktreeDir: config.defaults.worktreeDir ?? \".worktrees\",\n project: input.project,\n name,\n base: resolveWorktreeBase(proj.path),\n })\n : proj.path;\n\n const agents = new CapabilityRegistry({\n claude: createClaudeDriver(),\n codex: createCodexDriver(),\n gemini: createGeminiDriver(),\n opencode: createOpencodeDriver(),\n });\n const sideRole = config.defaults.roles?.side;\n const agentName = input.agent ?? sideRole?.agent ?? \"claude\";\n const agent = agents.get(agentName);\n if (!agent) {\n throw new Error(`Unknown agent '${agentName}'. Known: claude, codex, gemini, opencode.`);\n }\n\n const sideModel = sideRole?.model;\n const promptFile = path.join(\n TEMPLATES_DIR,\n `side.${input.role}.${agent.templateSuffix}.md`,\n );\n\n const direction: PanePlacement = input.direction ?? \"tab\";\n const title = titleFor(input.project, name);\n const pane = await runtime.newPane({ workspaceId: captain.id, direction, title });\n\n const cliCommand = agent.buildCommand({\n prompt: input.topic,\n workdir: spawnCwd,\n role: \"side\",\n promptFile: fs.existsSync(promptFile) ? promptFile : undefined,\n interactive: true,\n permissionMode: config.defaults.permissions?.crew ?? \"auto\",\n ...(sideModel ? { model: sideModel } : {}),\n });\n\n await runtime.sendToPane(pane, `cd ${shellQuote(spawnCwd)} && ${cliCommand}`);\n const preLaunchScreen = (await runtime.readPaneScreen(pane)) ?? \"\";\n\n const firstTurn = buildSideFirstTurn(\n input.topic,\n input.project,\n input.role,\n proj.spokeVault ?? \"\",\n input.role === \"debug\" ? spawnCwd : undefined,\n );\n await sendFirstTurnWhenReady(runtime, pane, firstTurn, preLaunchScreen);\n\n return { ...pane, title };\n}\n\nexport async function runSideSend(\n project: string,\n name: string,\n message: string,\n): Promise<void> {\n const { runtime, workspaceId } = await resolveCaptainWorkspace(project);\n const want = titleFor(project, name);\n const surfaces = await runtime.listSurfaces(workspaceId);\n const pane = surfaces.find((s) => s.title === want) ?? null;\n if (!pane) {\n throw new Error(\n `Side session '${name}' not found for ${project}. Run 'squadrant side list ${project}'.`,\n );\n }\n await runtime.sendToPane(pane, message);\n}\n\nexport async function runSideList(\n project: string,\n): Promise<Array<{ name: string; surfaceId: string }>> {\n const { runtime, workspaceId } = await resolveCaptainWorkspace(project);\n const surfaces = await runtime.listSurfaces(workspaceId);\n return surfaces\n .filter((s) => s.title && isSideTitle(project, s.title))\n .map((s) => ({\n name: nameFromTitle(project, s.title!),\n surfaceId: s.surfaceId,\n }));\n}\n\nexport async function runSideClose(project: string, name: string): Promise<void> {\n const config = loadConfig();\n const proj = config.projects[project];\n const { runtime, workspaceId } = await resolveCaptainWorkspace(project);\n const want = titleFor(project, name);\n const surfaces = await runtime.listSurfaces(workspaceId);\n const pane = surfaces.find((s) => s.title === want) ?? null;\n if (!pane) {\n throw new Error(\n `Side session '${name}' not found for ${project}. Run 'squadrant side list ${project}'.`,\n );\n }\n await runtime.closePane(pane);\n // Prune the scratch worktree if this was a debug session. Detection is\n // filesystem-based: debug spawns create a worktree at the deterministic path;\n // research spawns do not. If the path exists, remove it (best-effort).\n if (proj) {\n const wtPath = worktreePath(\n proj.path,\n config.defaults.worktreeDir ?? \".worktrees\",\n project,\n name,\n );\n if (fs.existsSync(wtPath)) {\n try {\n removeWorktree(proj.path, wtPath);\n } catch (e) {\n process.stderr.write(`(worktree remove failed: ${(e as Error).message})\\n`);\n }\n }\n }\n}\n\nexport const sideCommand = new Command(\"side\").description(\n \"Spawn and manage side-sessions (research/debug) — fresh-context tabs off the daemon lifecycle\",\n);\n\nsideCommand\n .command(\"spawn\")\n .description(\n \"Spawn a fresh-context side-session tab for research or debug (--role required)\",\n )\n .argument(\"<project>\", \"Project name (must be registered)\")\n .argument(\"[topic]\", \"Topic or question for the session (omit with --topic-file)\")\n .requiredOption(\"--role <role>\", \"Session role: research | debug\")\n .option(\"--name <name>\", \"Session name (default: auto-generated side-N)\")\n .option(\n \"--direction <dir>\",\n \"Placement: tab (default) or split direction (right|left|up|down)\",\n \"tab\",\n )\n .option(\"--agent <name>\", \"Agent CLI to use (claude|opencode)\", \"claude\")\n .option(\"--topic-file <path>\", \"Read topic from file instead of positional arg ('-' for stdin)\")\n .action(\n async (\n project: string,\n topic: string | undefined,\n opts: { role: string; name?: string; direction: PanePlacement; agent: string; topicFile?: string },\n ) => {\n try {\n const resolvedTopic = await resolveTextInput({\n positional: topic,\n filePath: opts.topicFile,\n label: \"topic\",\n });\n const pane = await runSideSpawn({\n project,\n topic: resolvedTopic,\n role: opts.role,\n name: opts.name,\n direction: opts.direction,\n agent: opts.agent,\n });\n console.log(chalk.green(`✔ Side session '${pane.title}' spawned (${pane.surfaceId})`));\n } catch (err) {\n console.error(chalk.red((err as Error).message));\n process.exit(1);\n }\n },\n );\n\nsideCommand\n .command(\"list\")\n .description(\"List live side-sessions for a project\")\n .argument(\"<project>\", \"Project name\")\n .action(async (project: string) => {\n try {\n const sessions = await runSideList(project);\n if (sessions.length === 0) {\n console.log(chalk.yellow(`No live side-sessions for ${project}.`));\n return;\n }\n for (const s of sessions) {\n console.log(` ${s.name} (${s.surfaceId})`);\n }\n } catch (err) {\n console.error(chalk.red((err as Error).message));\n process.exit(1);\n }\n });\n\nsideCommand\n .command(\"send\")\n .description(\"Send a follow-up message to an existing side-session\")\n .argument(\"<project>\", \"Project name\")\n .argument(\"<name>\", \"Session name (e.g. side-1)\")\n .argument(\"[message]\", \"Message to send (omit with --message-file)\")\n .option(\"--message-file <path>\", \"Read message from file ('-' for stdin)\")\n .action(\n async (\n project: string,\n name: string,\n message: string | undefined,\n opts: { messageFile?: string },\n ) => {\n try {\n const resolvedMessage = await resolveTextInput({\n positional: message,\n filePath: opts.messageFile,\n label: \"message\",\n });\n await runSideSend(project, name, resolvedMessage);\n console.log(chalk.green(`✔ Sent to ${project}:${name}`));\n } catch (err) {\n console.error(chalk.red((err as Error).message));\n process.exit(1);\n }\n },\n );\n\nsideCommand\n .command(\"close\")\n .description(\"Close a side-session (closes its tab)\")\n .argument(\"<project>\", \"Project name\")\n .argument(\"<name>\", \"Session name\")\n .action(async (project: string, name: string) => {\n try {\n await runSideClose(project, name);\n console.log(chalk.green(`✔ Closed ${project}:${name}`));\n } catch (err) {\n console.error(chalk.red((err as Error).message));\n process.exit(1);\n }\n });\n","import { Command } from \"commander\";\nimport { execSync } from \"node:child_process\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport chalk from \"chalk\";\nimport { loadConfig } from \"@squadrant/shared\";\nimport { createCmuxDriver, RuntimeRegistry } from \"@squadrant/workspaces\";\nimport type { PaneRef } from \"@squadrant/workspaces\";\nimport {\n readAllStatuses,\n renderDashboard,\n syncHub,\n startWebServer,\n defaultProbeRunners,\n} from \"@squadrant/web\";\nimport type { SyncHubResult } from \"@squadrant/web\";\nimport { squadrantdCall } from \"./crew-control.js\";\nimport { resolveCmuxBin } from \"@squadrant/shared\";\n\nconst SOCK = join(homedir(), \".config\", \"squadrant\", \"squadrant.sock\");\n\nfunction detectCurrentWorkspace(): string {\n const out = execSync(`\"${resolveCmuxBin()}\" current-workspace`, { encoding: \"utf-8\" }).trim();\n const match = out.match(/workspace:\\d+/);\n if (!match) {\n throw new Error(\"Could not detect current cmux workspace. Run `squadrant dashboard --pane` from inside a cmux workspace.\");\n }\n return match[0];\n}\n\nexport interface DashboardOnceDeps {\n now?: () => string;\n write?: (s: string) => void;\n}\n\nexport async function runDashboardOnce(deps: DashboardOnceDeps = {}): Promise<void> {\n const config = loadConfig();\n const now = (deps.now ?? (() => new Date().toISOString()))();\n const write = deps.write ?? ((s) => process.stdout.write(s));\n\n const statuses = await readAllStatuses({ config, call: squadrantdCall });\n const width = process.stdout.columns ?? 100;\n write(renderDashboard(statuses, { now, width }));\n write(\"\\n\");\n}\n\nexport interface SyncHubCliDeps {\n writeFile?: (path: string, content: string) => void;\n mkdir?: (path: string) => void;\n}\n\nexport async function runSyncHub(deps: SyncHubCliDeps = {}): Promise<SyncHubResult[]> {\n const config = loadConfig();\n const statuses = await readAllStatuses({ config, call: squadrantdCall });\n return syncHub({ config, statuses, writeFile: deps.writeFile, mkdir: deps.mkdir });\n}\n\nexport interface DashboardPaneInput {\n direction?: \"right\" | \"left\" | \"up\" | \"down\";\n interval?: number;\n}\n\nexport async function runDashboardPane(input: DashboardPaneInput): Promise<PaneRef> {\n const config = loadConfig();\n const runtime = new RuntimeRegistry({ cmux: createCmuxDriver() }).global(config);\n const workspaceId = detectCurrentWorkspace();\n\n const interval = input.interval ?? 10;\n const direction = input.direction ?? \"right\";\n const title = \"📊 dashboard\";\n\n // Portable refresh loop — no `watch` install dependency.\n // FORCE_COLOR=1 makes chalk emit ANSI even when run through the loop.\n const loop = `clear; while true; do clear; FORCE_COLOR=1 squadrant dashboard --once; sleep ${interval}; done`;\n\n const pane = await runtime.newPane({ workspaceId, direction, title });\n await runtime.sendToPane(pane, loop);\n return pane;\n}\n\nexport interface DashboardWebInput {\n port: number;\n interval: number; // seconds\n}\n\n/**\n * Start the localhost-only observability web dashboard. Separate process from\n * the daemon (crash-isolated, read-only socket client). Keeps running until the\n * process is killed; the HTTP server + tick loop hold the event loop open.\n */\nexport async function runDashboardWeb(input: DashboardWebInput): Promise<void> {\n const handle = await startWebServer({\n port: input.port,\n intervalMs: input.interval * 1000,\n sockPath: SOCK,\n runners: defaultProbeRunners(),\n });\n console.log(chalk.green(`✔ Squadrant system dashboard → http://127.0.0.1:${handle.port}`));\n console.log(chalk.dim(` polling the daemon every ${input.interval}s · localhost only · read-only · Ctrl-C to stop`));\n}\n\nexport const dashboardCommand = new Command(\"dashboard\")\n .description(\"Live status grid of all projects (derived from daemon task state)\")\n .option(\"--once\", \"Print one snapshot and exit (used by --pane's refresh loop)\")\n .option(\"--pane\", \"Open a refreshing sidebar pane in the current cmux workspace\")\n .option(\"--web\", \"Serve the live system-health web dashboard on 127.0.0.1 (HTTP + SSE)\")\n .option(\"--port <port>\", \"Port for --web (default 7878)\", (v) => parseInt(v, 10), 7878)\n .option(\"--direction <dir>\", \"Pane split direction (right|left|up|down)\", \"right\")\n .option(\"--interval <seconds>\", \"Daemon poll interval for --web (default 5); refresh interval for --pane (default 10)\", (v) => parseInt(v, 10))\n .action(async (opts: { once?: boolean; pane?: boolean; web?: boolean; port: number; direction: \"right\" | \"left\" | \"up\" | \"down\"; interval?: number }) => {\n try {\n if (opts.web) {\n await runDashboardWeb({ port: opts.port, interval: opts.interval ?? 5 });\n return;\n }\n if (opts.pane) {\n const pane = await runDashboardPane({ direction: opts.direction, interval: opts.interval ?? 10 });\n console.log(chalk.green(`✔ Dashboard pane opened in ${pane.workspaceId} ${pane.surfaceId}`));\n return;\n }\n // Default behaviour: --once. (Bare `squadrant dashboard` prints once and exits.)\n await runDashboardOnce();\n } catch (err) {\n console.error(chalk.red((err as Error).message));\n process.exit(1);\n }\n });\n\ndashboardCommand\n .command(\"sync-hub\")\n .description(\"Mirror each spoke status.md into {hubVault}/projects/<name>.md for Obsidian Dataview\")\n .option(\"--json\", \"Emit results as JSON\")\n .action(async (opts: { json?: boolean }) => {\n const results = await runSyncHub();\n if (opts.json) {\n console.log(JSON.stringify(results, null, 2));\n return;\n }\n if (results.length === 0) {\n console.log(chalk.dim(\"\\n No mirrors written (no projects with usable status.md, or hubVault unset).\\n\"));\n return;\n }\n console.log(chalk.bold(\"\\n 📊 Hub mirror sync\\n\"));\n for (const r of results) {\n console.log(` ${chalk.green(\"✔\")} ${chalk.cyan(r.project.padEnd(16))} → ${chalk.dim(r.hubPath)}`);\n }\n console.log(\"\");\n });\n","import type { SquadrantConfig } from \"@squadrant/shared\";\nimport type { TaskRecord } from \"@squadrant/shared\";\n\nexport type SquadrantdCall = (req: unknown) => Promise<unknown>;\n\nexport type DashboardState = \"idle\" | \"busy\" | \"blocked\" | \"errored\" | \"offline\" | \"unknown\";\n\nexport interface ProjectStatus {\n project: string;\n state: DashboardState;\n lastChecked: string;\n captainWorkspace: string;\n excerpt: string;\n}\n\nexport interface ReadStatusDeps {\n config: SquadrantConfig;\n call?: SquadrantdCall;\n listTasks?: (project: string) => Promise<TaskRecord[]>;\n}\n\nfunction deriveState(tasks: TaskRecord[]): DashboardState {\n if (tasks.some(t => t.state === \"blocked\" || t.state === \"awaiting-input\")) return \"blocked\";\n if (tasks.some(t => t.state === \"failed\" || t.state === \"stalled\")) return \"errored\";\n if (tasks.some(t => t.state === \"working\")) return \"busy\";\n return \"idle\";\n}\n\nfunction buildExcerpt(tasks: TaskRecord[]): string {\n const working = tasks.filter(t => t.state === \"working\").length;\n const blocked = tasks.filter(t => t.state === \"blocked\" || t.state === \"awaiting-input\").length;\n const parts: string[] = [];\n if (working > 0) parts.push(`${working} working`);\n if (blocked > 0) parts.push(`${blocked} blocked`);\n const summary = parts.length > 0 ? parts.join(\", \") : \"idle\";\n\n const active = tasks.filter(t =>\n [\"working\", \"blocked\", \"awaiting-input\", \"submitted\"].includes(t.state)\n );\n const titles = active.slice(0, 3).map(t => {\n const firstLine = t.task ? t.task.split(\"\\n\")[0] : \"\";\n return t.name ?? (firstLine || t.id.slice(0, 8));\n }).join(\"; \");\n\n return titles ? `${summary} — ${titles}` : summary;\n}\n\nexport async function readAllStatuses(deps: ReadStatusDeps): Promise<ProjectStatus[]> {\n const listTasks = deps.listTasks ?? (async (project: string) => {\n if (!deps.call) throw new Error(\"ReadStatusDeps: call is required when listTasks is not provided\");\n const result = await deps.call({ kind: \"list\", project });\n return result as TaskRecord[];\n });\n\n const rows: ProjectStatus[] = [];\n for (const [name, project] of Object.entries(deps.config.projects)) {\n try {\n const tasks = await listTasks(name);\n rows.push({\n project: name,\n state: deriveState(tasks),\n lastChecked: new Date().toISOString(),\n captainWorkspace: project.captainName,\n excerpt: buildExcerpt(tasks),\n });\n } catch {\n rows.push({\n project: name,\n state: \"offline\",\n lastChecked: new Date().toISOString(),\n captainWorkspace: project.captainName,\n excerpt: \"\",\n });\n }\n }\n return rows;\n}\n","import chalk from \"chalk\";\nimport type { ProjectStatus, DashboardState } from \"./read-status.js\";\n\nexport interface RenderOptions {\n now: string; // ISO-8601 string, used for age calc + footer\n width?: number; // terminal width (defaults to process.stdout.columns or 100)\n}\n\nconst ICON: Record<DashboardState, (s: string) => string> = {\n idle: chalk.green,\n busy: chalk.cyan,\n blocked: chalk.yellow,\n errored: chalk.red,\n offline: chalk.dim,\n unknown: chalk.gray,\n};\n\nconst ICON_CHAR: Record<DashboardState, string> = {\n idle: \"●\",\n busy: \"◐\",\n blocked: \"⏸\",\n errored: \"✗\",\n offline: \"○\",\n unknown: \"·\",\n};\n\nexport function formatAge(lastChecked: string, now: string): string {\n if (!lastChecked) return \"?\";\n const t = Date.parse(lastChecked);\n const n = Date.parse(now);\n if (Number.isNaN(t) || Number.isNaN(n)) return \"?\";\n const sec = Math.max(0, Math.floor((n - t) / 1000));\n if (sec < 60) return `${sec}s`;\n if (sec < 60 * 60) return `${Math.floor(sec / 60)}m`;\n if (sec < 60 * 60 * 24) return `${Math.floor(sec / 3600)}h`;\n return \"stale\";\n}\n\nfunction firstLine(s: string): string {\n for (const line of s.split(/\\r?\\n/)) {\n if (line.trim().length > 0) return line.trim();\n }\n return \"\";\n}\n\nfunction pad(s: string, n: number): string {\n return s.length >= n ? s.slice(0, n) : s + \" \".repeat(n - s.length);\n}\n\nfunction truncate(s: string, n: number): string {\n return s.length <= n ? s : s.slice(0, Math.max(0, n - 1)) + \"…\";\n}\n\nexport function renderDashboard(rows: ProjectStatus[], opts: RenderOptions): string {\n const width = opts.width ?? 100;\n const lines: string[] = [];\n\n lines.push(\"\");\n lines.push(\" \" + chalk.bold(\"📊 Squadrant Dashboard\") + \" \" + chalk.dim(opts.now));\n lines.push(\"\");\n\n if (rows.length === 0) {\n lines.push(\" \" + chalk.yellow(\"No projects registered. Add one with: squadrant projects add <name> <path>\"));\n lines.push(\"\");\n return lines.join(\"\\n\");\n }\n\n // Column widths — fixed for the left side, excerpt fills the remainder.\n const NAME_W = 16;\n const STATE_W = 8;\n const AGE_W = 6;\n const FIXED = 2 /*indent*/ + 1 /*icon*/ + 1 + NAME_W + 1 + STATE_W + 1 + AGE_W + 3 /*│ */;\n const excerptW = Math.max(20, width - FIXED);\n\n for (const r of rows) {\n const icon = ICON[r.state](ICON_CHAR[r.state]);\n const name = chalk.cyan(pad(r.project, NAME_W));\n const state = ICON[r.state](pad(r.state, STATE_W));\n const age = pad(formatAge(r.lastChecked, opts.now), AGE_W);\n const excerpt = chalk.dim(truncate(firstLine(r.excerpt), excerptW));\n lines.push(` ${icon} ${name} ${state} ${age} │ ${excerpt}`);\n }\n\n lines.push(\"\");\n lines.push(chalk.dim(\" Refreshes every 10s · Ctrl+C to exit\"));\n lines.push(\"\");\n return lines.join(\"\\n\");\n}\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport type { SquadrantConfig } from \"@squadrant/shared\";\nimport { resolveHome } from \"@squadrant/shared\";\nimport type { ProjectStatus } from \"./read-status.js\";\n\nexport interface SyncHubResult {\n project: string;\n hubPath: string;\n}\n\nexport interface SyncHubDeps {\n config: SquadrantConfig;\n statuses: ProjectStatus[];\n writeFile?: (path: string, content: string) => void;\n mkdir?: (dirPath: string) => void;\n}\n\nexport function buildMirrorMarkdown(s: ProjectStatus): string {\n const fenced = \"```\";\n return [\n \"---\",\n `project: ${s.project}`,\n `auto_state: ${s.state}`,\n `auto_last_checked: \"${s.lastChecked}\"`,\n `captain_workspace: ${s.captainWorkspace}`,\n \"---\",\n \"\",\n `# ${s.project}`,\n \"\",\n \"> Mirror of `{spokeVault}/status.md`. Updated by `squadrant dashboard sync-hub` (#44).\",\n \"\",\n \"## Last activity excerpt\",\n \"\",\n fenced,\n s.excerpt,\n fenced,\n \"\",\n ].join(\"\\n\");\n}\n\nexport function syncHub(deps: SyncHubDeps): SyncHubResult[] {\n if (!deps.config.hubVault) return [];\n\n const writeFile = deps.writeFile ?? ((p, c) => fs.writeFileSync(p, c));\n const mkdir = deps.mkdir ?? ((p) => fs.mkdirSync(p, { recursive: true }));\n\n const projectsDir = path.join(resolveHome(deps.config.hubVault), \"projects\");\n mkdir(projectsDir);\n\n const out: SyncHubResult[] = [];\n for (const s of deps.statuses) {\n if (s.state === \"unknown\") continue;\n const hubPath = path.join(projectsDir, `${s.project}.md`);\n try {\n writeFile(hubPath, buildMirrorMarkdown(s));\n out.push({ project: s.project, hubPath });\n } catch { /* best-effort */ }\n }\n return out;\n}\n","// src/dashboard/web-server.ts\n//\n// The `squadrant dashboard --web` process: a localhost-only HTTP + SSE server that,\n// on each tick, queries the daemon's read-only `snapshot` verb, runs the Tier 3/4\n// external probes (which the daemon cannot — lineage wall), merges them, and\n// pushes the result to every connected browser. Crash-isolated from the daemon\n// (separate PID, read-only socket client) and bound to 127.0.0.1 with no auth.\n// Zero new deps: Node's built-in `http` + `EventSource` on the client.\nimport { createServer, type Server, type ServerResponse } from \"node:http\";\nimport { sendRequest } from \"@squadrant/core\";\nimport type { DaemonSnapshot } from \"@squadrant/core\";\nimport { mergeSnapshot, type FullSnapshot } from \"./snapshot-merge.js\";\nimport { runExternalProbes, type ProbeRunners } from \"./probes.js\";\nimport { renderHtml, renderTickJson } from \"./web-render.js\";\n\n/**\n * Query the daemon's read-only snapshot verb. Returns \"unreachable\" when the\n * daemon socket can't be reached — the page degrades (banner + Tier 3/4) rather\n * than blanking. Mirrors queryHealth() in health-view.ts.\n */\nexport async function querySnapshot(sockPath: string): Promise<DaemonSnapshot | \"unreachable\"> {\n try {\n const reply = await sendRequest(sockPath, { kind: \"snapshot\" });\n return reply as DaemonSnapshot;\n } catch {\n return \"unreachable\";\n }\n}\n\nexport interface WebServerOpts {\n port: number;\n intervalMs: number;\n sockPath: string;\n runners: ProbeRunners;\n host?: string;\n now?: () => number;\n probeTimeoutMs?: number;\n}\n\nexport interface WebServerHandle {\n /** The actually-bound port (useful when port 0 was requested in tests). */\n port: number;\n close: () => Promise<void>;\n}\n\n/**\n * Start the dashboard web server. Binds 127.0.0.1 only, serves the static page on\n * GET /, an SSE stream on GET /events, and pushes a fresh snapshot every\n * intervalMs. Returns a handle whose close() stops the tick loop and the server.\n */\nexport async function startWebServer(opts: WebServerOpts): Promise<WebServerHandle> {\n const host = opts.host ?? \"127.0.0.1\";\n const now = opts.now ?? (() => Date.now());\n const clients = new Set<ServerResponse>();\n let latest: FullSnapshot | null = null;\n\n async function tick(): Promise<void> {\n const daemon = await querySnapshot(opts.sockPath);\n const external = await runExternalProbes(opts.runners, opts.probeTimeoutMs);\n latest = mergeSnapshot(daemon, external, now());\n const payload = `data: ${renderTickJson(latest)}\\n\\n`;\n for (const res of clients) {\n try { res.write(payload); } catch { /* client gone; pruned on close */ }\n }\n }\n\n const server: Server = createServer((req, res) => {\n if (req.method !== \"GET\") { res.writeHead(405).end(); return; }\n if (req.url === \"/\" || req.url === \"/index.html\") {\n res.writeHead(200, { \"Content-Type\": \"text/html; charset=utf-8\" });\n res.end(latest ? renderHtml(latest, { port: opts.port }) : \"<!DOCTYPE html><body>starting…</body>\");\n return;\n }\n if (req.url === \"/events\") {\n res.writeHead(200, {\n \"Content-Type\": \"text/event-stream\",\n \"Cache-Control\": \"no-cache\",\n Connection: \"keep-alive\",\n });\n res.write(\"retry: 3000\\n\\n\");\n if (latest) res.write(`data: ${renderTickJson(latest)}\\n\\n`);\n clients.add(res);\n req.on(\"close\", () => clients.delete(res));\n return;\n }\n res.writeHead(404).end();\n });\n\n await new Promise<void>((resolve, reject) => {\n server.once(\"error\", reject);\n server.listen(opts.port, host, resolve);\n });\n const addr = server.address();\n const boundPort = typeof addr === \"object\" && addr ? addr.port : opts.port;\n\n // Prime `latest` before the first request lands, then start the loop.\n await tick();\n const timer = setInterval(() => { void tick().catch(() => { /* a tick must never crash the loop */ }); }, opts.intervalMs);\n timer.unref?.();\n\n return {\n port: boundPort,\n close: () =>\n new Promise<void>((resolve) => {\n clearInterval(timer);\n for (const res of clients) { try { res.end(); } catch { /* already closed */ } }\n clients.clear();\n server.close(() => resolve());\n }),\n };\n}\n","// src/dashboard/snapshot-merge.ts\n//\n// PURE merge of the two data sources behind the dashboard: the daemon's\n// Tier 0/1/2 `DaemonSnapshot` (or \"unreachable\") and the dashboard process's\n// Tier 3/4 `ExternalProbes`. The whole point of keeping this separate and pure\n// is the degrade-never-blank guarantee: when the daemon is unreachable the\n// external tiers still render, so a daemon outage never blanks the page.\nimport type { DaemonSnapshot } from \"@squadrant/core\";\nimport type { ExternalProbes } from \"./probes.js\";\n\nexport interface FullSnapshot {\n /** epoch ms this snapshot was assembled (drives \"updated Ns ago\"). */\n generatedAt: number;\n /** \"unreachable\" when the daemon socket query failed — Tier 0/1/2 are dark. */\n daemon: DaemonSnapshot | \"unreachable\";\n external: ExternalProbes;\n}\n\n/** Pure. Stamp the two sources into one FullSnapshot. */\nexport function mergeSnapshot(\n daemon: DaemonSnapshot | \"unreachable\",\n external: ExternalProbes,\n now: number,\n): FullSnapshot {\n return { generatedAt: now, daemon, external };\n}\n","// src/dashboard/probes.ts\n//\n// Tier 3 (external dependencies) + Tier 4 (config integrity) probes for the web\n// dashboard. These live in the DASHBOARD process, never the daemon: the daemon\n// runs under launchd and is outside cmux's process lineage, so it cannot probe\n// cmux (the \"lineage wall\"). Every probe is behind an injectable runner and is\n// independently try/caught with a short timeout — a thrown or hung probe yields\n// `unknown` and NEVER propagates, so one bad probe can never crash a tick.\nimport { join } from \"node:path\";\nimport { homedir } from \"node:os\";\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { execFile } from \"node:child_process\";\nimport type { SquadrantConfig } from \"@squadrant/shared\";\nimport { loadConfig } from \"@squadrant/shared\";\nimport { resolveCmuxBin } from \"@squadrant/shared\";\n\nexport type ProbeState = \"alive\" | \"stale\" | \"gone\" | \"unknown\";\n\nexport interface Probe {\n state: ProbeState;\n /** Human-facing context for a degraded/unknown cell. */\n detail?: string;\n}\n\nexport interface ExternalProbes {\n cmux: Probe;\n agentClis: Array<{ cli: string } & Probe>;\n vaults: {\n hub: { path: string } & Probe;\n spokes: Array<{ project: string; path: string } & Probe>;\n };\n config: {\n parseable: Probe;\n projectPaths: Array<{ project: string; path: string } & Probe>;\n sessions: Probe;\n };\n}\n\n/** Low-level I/O the probes depend on. Tests inject fakes; the dashboard process\n * injects {@link defaultProbeRunners}. */\nexport interface ProbeRunners {\n /** cmux reachable (e.g. `cmux --version` exited 0). */\n probeCmuxBin: () => Promise<boolean>;\n /** an agent CLI resolves on PATH. */\n probeOnPath: (cli: string) => Promise<boolean>;\n /** a directory/file exists (sync stat). */\n pathExists: (p: string) => boolean;\n /** load + parse config.json; throws when unparseable. */\n loadConfig: () => SquadrantConfig;\n /** distinct templateHash values recorded in sessions.json; throws when unreadable. */\n loadSessionsHashes: () => string[];\n}\n\nconst DEFAULT_TIMEOUT_MS = 2000;\nconst AGENT_CLIS = [\"claude\", \"codex\", \"gemini\", \"opencode\"] as const;\n\n/** Reject a promise that outlives `ms`, clearing the timer either way. */\nfunction withTimeout<T>(p: Promise<T>, ms: number): Promise<T> {\n let timer: ReturnType<typeof setTimeout>;\n const timeout = new Promise<never>((_, reject) => {\n timer = setTimeout(() => reject(new Error(\"probe timeout\")), ms);\n timer.unref?.();\n });\n return Promise.race([p.finally(() => clearTimeout(timer)), timeout]);\n}\n\n// ── Tier 3 — external dependencies ────────────────────────────────────────────\n\nexport async function probeCmux(run: ProbeRunners, timeoutMs = DEFAULT_TIMEOUT_MS): Promise<Probe> {\n try {\n const ok = await withTimeout(run.probeCmuxBin(), timeoutMs);\n return ok ? { state: \"alive\" } : { state: \"gone\", detail: \"cmux not reachable\" };\n } catch {\n return { state: \"unknown\" };\n }\n}\n\nexport async function probeAgentClis(\n run: ProbeRunners,\n timeoutMs = DEFAULT_TIMEOUT_MS,\n): Promise<Array<{ cli: string } & Probe>> {\n return Promise.all(\n AGENT_CLIS.map(async (cli) => {\n try {\n const ok = await withTimeout(run.probeOnPath(cli), timeoutMs);\n return ok ? { cli, state: \"alive\" as const } : { cli, state: \"gone\" as const, detail: `${cli} not on PATH` };\n } catch {\n return { cli, state: \"unknown\" as const };\n }\n }),\n );\n}\n\n/** Hub vault is alive only when its directory AND its `.obsidian/` both exist. */\nfunction vaultProbe(run: ProbeRunners, dir: string): Probe {\n try {\n if (!dir) return { state: \"unknown\", detail: \"no vault configured\" };\n if (!run.pathExists(dir)) return { state: \"gone\", detail: \"vault directory missing\" };\n if (!run.pathExists(join(dir, \".obsidian\"))) return { state: \"gone\", detail: \"no .obsidian/ (not a vault)\" };\n return { state: \"alive\" };\n } catch {\n return { state: \"unknown\" };\n }\n}\n\n/** Spoke vault directories live INSIDE the hub vault and correctly have no\n * `.obsidian/` of their own. Alive = directory exists; gone = directory missing. */\nfunction spokeProbe(run: ProbeRunners, dir: string): Probe {\n try {\n if (!dir) return { state: \"unknown\", detail: \"no vault configured\" };\n if (!run.pathExists(dir)) return { state: \"gone\", detail: \"spoke directory missing\" };\n return { state: \"alive\" };\n } catch {\n return { state: \"unknown\" };\n }\n}\n\nexport function probeVaults(run: ProbeRunners, config: SquadrantConfig): ExternalProbes[\"vaults\"] {\n return {\n hub: { path: config.hubVault, ...vaultProbe(run, config.hubVault) },\n spokes: Object.entries(config.projects).map(([project, p]) => ({\n project,\n path: p.spokeVault,\n ...spokeProbe(run, p.spokeVault),\n })),\n };\n}\n\n// ── Tier 4 — config integrity ─────────────────────────────────────────────────\n\nexport function probeProjectPaths(\n run: ProbeRunners,\n config: SquadrantConfig,\n): Array<{ project: string; path: string } & Probe> {\n return Object.entries(config.projects).map(([project, p]) => {\n try {\n const ok = run.pathExists(p.path);\n return ok\n ? { project, path: p.path, state: \"alive\" as const }\n : { project, path: p.path, state: \"gone\" as const, detail: \"project path missing\" };\n } catch {\n return { project, path: p.path, state: \"unknown\" as const };\n }\n });\n}\n\n/**\n * sessions.json template-drift signal. Re-deriving the exact \"current\" template\n * hash would couple the dashboard to the launcher's hashing internals + the\n * installed templates dir; instead we surface the honest, dependency-free signal\n * that the recorded sessions disagree: more than one distinct templateHash means\n * some workspaces are running against an older template (drift). One hash =\n * consistent; none recorded = unknown.\n */\nexport function probeSessions(run: ProbeRunners): Probe {\n try {\n const hashes = run.loadSessionsHashes();\n if (hashes.length === 0) return { state: \"unknown\", detail: \"no sessions recorded\" };\n if (hashes.length === 1) return { state: \"alive\" };\n return { state: \"stale\", detail: `template drift: ${hashes.length} distinct hashes` };\n } catch {\n return { state: \"unknown\" };\n }\n}\n\n// ── Top-level assembly ────────────────────────────────────────────────────────\n\n/**\n * Run every Tier 3/4 probe and assemble {@link ExternalProbes}. config.json is\n * loaded once (shared by vaults + project-path checks); if it fails to parse the\n * config tier degrades but cmux/CLI probes still run.\n */\nexport async function runExternalProbes(\n run: ProbeRunners,\n timeoutMs = DEFAULT_TIMEOUT_MS,\n): Promise<ExternalProbes> {\n const [cmux, agentClis] = await Promise.all([\n probeCmux(run, timeoutMs),\n probeAgentClis(run, timeoutMs),\n ]);\n\n let config: SquadrantConfig | null = null;\n let parseable: Probe;\n try {\n config = run.loadConfig();\n parseable = { state: \"alive\" };\n } catch {\n parseable = { state: \"gone\", detail: \"config.json unparseable\" };\n }\n\n const vaults = config\n ? probeVaults(run, config)\n : { hub: { path: \"\", state: \"unknown\" as const }, spokes: [] };\n const projectPaths = config ? probeProjectPaths(run, config) : [];\n const sessions = probeSessions(run);\n\n return { cmux, agentClis, vaults, config: { parseable, projectPaths, sessions } };\n}\n\n// ── Default real-I/O runners (dashboard process; not unit-tested) ──────────────\n\nconst SESSIONS_PATH = join(homedir(), \".config\", \"squadrant\", \"sessions.json\");\n\n/** Resolve a bare binary name against the PATH dirs (dependency-free `which`). */\nfunction onPath(cli: string): boolean {\n const dirs = (process.env.PATH ?? \"\").split(\":\").filter(Boolean);\n return dirs.some((d) => existsSync(join(d, cli)));\n}\n\n/** Distinct templateHash values recorded across all workspaces in sessions.json. */\nfunction readSessionsHashes(): string[] {\n const raw = JSON.parse(readFileSync(SESSIONS_PATH, \"utf-8\")) as {\n workspaces?: Record<string, { templateHash?: string }>;\n };\n const hashes = Object.values(raw.workspaces ?? {})\n .map((w) => w.templateHash)\n .filter((h): h is string => typeof h === \"string\" && h.length > 0);\n return [...new Set(hashes)];\n}\n\n/** The real runners used by `squadrant dashboard --web`. */\nexport function defaultProbeRunners(): ProbeRunners {\n return {\n probeCmuxBin: () =>\n new Promise<boolean>((resolve) => {\n try {\n execFile(resolveCmuxBin(), [\"--version\"], { timeout: 1500 }, (err) => resolve(!err));\n } catch {\n resolve(false);\n }\n }),\n probeOnPath: async (cli) => onPath(cli),\n pathExists: (p) => existsSync(p),\n loadConfig: () => loadConfig(),\n loadSessionsHashes: () => readSessionsHashes(),\n };\n}\n","// src/dashboard/web-render.ts\n//\n// PURE render of a FullSnapshot to (a) a complete HTML document for the initial\n// GET / load and (b) a per-tick JSON payload pushed over SSE. No I/O, no clock —\n// every age is derived from snapshot-time deltas or `snap.generatedAt`, so the\n// render is deterministic and unit-tested.\n//\n// Visual language: a glass-squadrant flight deck. A master-status ANNUNCIATOR and\n// an inline-SVG health DONUT read the fleet at a glance; OVERVIEW / PROJECTS /\n// DAEMON / ENVIRONMENT tabs (vanilla-JS, one SSE stream) hold the detail. Charts\n// are inline SVG only (donut server-rendered; sparklines drawn client-side from a\n// rolling history of successive SSE frames). Severity rolls UP (a `gone` bubbles a\n// red rollup to its project header); the stale-build / link-lost banners render\n// only when applicable; remediation is COPY-ABLE TEXT (never buttons — read-only\n// beta). Zero new deps: vanilla JS + modern CSS + inline SVG.\nimport type { HealthState, ComponentHealth, DaemonSnapshot } from \"@squadrant/core\";\nimport { healCmdFor, ageText } from \"@squadrant/core\";\nimport type { FullSnapshot } from \"./snapshot-merge.js\";\nimport type { ExternalProbes, Probe, ProbeState } from \"./probes.js\";\n\ntype AnyState = HealthState | ProbeState;\n\nconst ICON: Record<AnyState, string> = { alive: \"✔\", stale: \"•\", gone: \"✘\", stopped: \"⏻\", unknown: \"○\" };\n// Rollup ordering: gone (fault) is worst. `stopped` is an intentional shutdown —\n// it out-ranks a stale caution (it is the headline state of an offline project)\n// but never a genuine fault. unknown never out-ranks a real degradation.\nconst SEV: Record<AnyState, number> = { alive: 0, unknown: 1, stale: 2, stopped: 3, gone: 4 };\n// Squadrant annunciator vernacular for each state.\nconst STATE_WORD: Record<AnyState, string> = { alive: \"nominal\", stale: \"caution\", gone: \"fault\", stopped: \"stopped\", unknown: \"unknown\" };\n\nfunction esc(s: string): string {\n return s\n .replace(/&/g, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\")\n .replace(/\"/g, \"&quot;\");\n}\n\nfunction fmtBytes(n: number): string {\n if (n < 1024) return `${n}B`;\n if (n < 1024 ** 2) return `${(n / 1024).toFixed(1)}KB`;\n if (n < 1024 ** 3) return `${(n / 1024 ** 2).toFixed(1)}MB`;\n return `${(n / 1024 ** 3).toFixed(1)}GB`;\n}\n\nfunction fmtDur(ms: number): string {\n const s = Math.max(0, Math.round(ms / 1000));\n if (s < 60) return `${s}s`;\n const m = Math.round(s / 60);\n if (m < 60) return `${m}m`;\n const h = Math.floor(m / 60);\n return `${h}h${m % 60}m`;\n}\n\nfunction fmtAge(ms: number | null): string {\n return ms == null ? \"—\" : `${fmtDur(ms)} ago`;\n}\n\nfunction worst(states: AnyState[]): AnyState {\n let w: AnyState = \"alive\";\n for (const s of states) if (SEV[s] > SEV[w]) w = s;\n return w;\n}\n\n// ── Health tallies ────────────────────────────────────────────────────────────\ninterface Tally { alive: number; stale: number; gone: number; stopped: number; unknown: number; total: number }\n\nfunction tally(states: AnyState[]): Tally {\n const t: Tally = { alive: 0, stale: 0, gone: 0, stopped: 0, unknown: 0, total: states.length };\n for (const s of states) t[s]++;\n return t;\n}\n\n/** Master flight-status from an aggregate tally. gone → critical (red); stale →\n * degraded (amber); else nominal (green). Log errors map to `stale`, never gone,\n * so a noisy log can caution but never trips a CRITICAL master alarm. */\nfunction masterClass(t: Tally): \"ok\" | \"warn\" | \"crit\" {\n if (t.gone > 0) return \"crit\";\n if (t.stale > 0) return \"warn\";\n return \"ok\";\n}\nconst MASTER_WORD: Record<\"ok\" | \"warn\" | \"crit\", string> = { ok: \"NOMINAL\", warn: \"DEGRADED\", crit: \"CRITICAL\" };\n\n// ── Small presentational atoms ──────────────────────────────────────────────────\nfunction pill(state: AnyState, label: string): string {\n return `<span class=\"pill s-${state}\"><span class=\"pdot\"></span>${esc(label)}</span>`;\n}\n\n/** Status pill carrying the glyph + state word — used in component tables. */\nfunction statePill(state: AnyState): string {\n return pill(state, `${ICON[state]} ${STATE_WORD[state]}`);\n}\n\nfunction banner(kind: \"err\" | \"warn\", text: string): string {\n return `<div class=\"banner ${kind}\">${esc(text)}</div>`;\n}\n\nfunction remediation(text: string): string {\n // Copy-able text, NOT a button — read-only beta surface.\n return `<div class=\"rem\">remediation <code>${esc(text)}</code></div>`;\n}\n\nfunction probeCell(label: string, p: Probe): string {\n const detail = p.detail ? ` · ${esc(p.detail)}` : \"\";\n return `${pill(p.state, label)}<span class=\"cell-detail\">${detail}</span>`;\n}\n\n// ── Donut gauge (inline SVG) ────────────────────────────────────────────────────\nconst DONUT_ORDER: AnyState[] = [\"alive\", \"stale\", \"stopped\", \"gone\", \"unknown\"];\n\n/** The signature element: a four-segment health ring. Segment arc lengths are\n * proportional to the tally; everything is plain SVG math so it is deterministic\n * and testable. An empty tally shows a faint full track. */\nfunction donut(t: Tally): string {\n const cx = 64, cy = 64, r = 52, w = 14;\n const C = 2 * Math.PI * r;\n let acc = 0;\n const segs = DONUT_ORDER.map((k) => {\n const v = t[k];\n if (v <= 0) return \"\";\n const len = t.total ? (v / t.total) * C : 0;\n const rot = t.total ? (acc / t.total) * 360 : 0;\n acc += v;\n return `<circle class=\"seg s-${k}\" cx=\"${cx}\" cy=\"${cy}\" r=\"${r}\" fill=\"none\" stroke-width=\"${w}\" stroke-dasharray=\"${len.toFixed(2)} ${(C - len).toFixed(2)}\" transform=\"rotate(${(rot - 90).toFixed(2)} ${cx} ${cy})\"></circle>`;\n }).join(\"\");\n const track = `<circle class=\"donut-track\" cx=\"${cx}\" cy=\"${cy}\" r=\"${r}\" fill=\"none\" stroke-width=\"${w}\"></circle>`;\n return `<svg class=\"donut\" viewBox=\"0 0 128 128\" role=\"img\" aria-label=\"fleet health distribution\">${track}${segs}</svg>`;\n}\n\nfunction legendRow(state: AnyState, count: number): string {\n return `<div class=\"leg s-${state}\"><span class=\"pdot\"></span><span class=\"leg-n\" data-countup=\"leg-${state}\" data-value=\"${count}\">${count}</span><span class=\"leg-l\">${STATE_WORD[state]}</span></div>`;\n}\n\n/** A trend card: a label + a big readout value + an empty sparkline svg the\n * client fills from rolling history (data-spark key). */\nfunction trendCard(key: string, label: string, value: string, sub: string): string {\n return [\n `<div class=\"trend\">`,\n `<div class=\"trend-head\"><span class=\"trend-l\">${esc(label)}</span><span class=\"trend-v\">${esc(value)}</span></div>`,\n `<svg class=\"spark\" data-spark=\"${key}\" viewBox=\"0 0 100 28\" preserveAspectRatio=\"none\" aria-hidden=\"true\"></svg>`,\n `<div class=\"trend-sub\">${esc(sub)}</div>`,\n `</div>`,\n ].join(\"\");\n}\n\n/** Sum delivery lag across projects whose captain is alive (online only).\n * A captain that is offline with unread mail is not a live delivery problem. */\nfunction liveDeliveryBehind(d: DaemonSnapshot): number {\n return d.tier2.projects.reduce((sum, p) => {\n const captain = d.tier1.find((c) => c.kind === \"captain\" && c.project === p.project);\n const captainState = captain?.state ?? \"unknown\";\n return captainState === \"alive\" ? sum + p.delivery.behind : sum;\n }, 0);\n}\n\n// ── Aggregate collection (pure) ─────────────────────────────────────────────────\ninterface Collected {\n now: number;\n daemonT: Tally; projT: Tally; envT: Tally; overall: Tally;\n errors: number; behind: number; crewAgeMs: number;\n}\n\nfunction collect(snap: FullSnapshot): Collected {\n const now = snap.generatedAt;\n const env = snap.external;\n const envStates: AnyState[] = [\n env.cmux.state,\n ...env.agentClis.map((c) => c.state),\n env.vaults.hub.state,\n ...env.vaults.spokes.map((s) => s.state),\n env.config.parseable.state,\n env.config.sessions.state,\n ...env.config.projectPaths.map((p) => p.state),\n ];\n const daemonStates: AnyState[] = [];\n const projStates: AnyState[] = [];\n let errors = 0, behind = 0, crewAgeMs = 0;\n if (snap.daemon !== \"unreachable\") {\n const t0 = snap.daemon.tier0;\n daemonStates.push(\"alive\"); // the daemon process itself is up\n daemonStates.push(t0.build.state === \"fresh\" ? \"alive\" : \"stale\");\n daemonStates.push(t0.log.errorCount > 0 ? \"stale\" : \"alive\");\n errors = t0.log.errorCount;\n for (const c of snap.daemon.tier1) {\n projStates.push(c.state);\n if (c.kind === \"crew\" && c.lastSeenMs != null) crewAgeMs = Math.max(crewAgeMs, now - c.lastSeenMs);\n }\n for (const p of snap.daemon.tier2.projects) {\n if (p.delivery.behind > 0) projStates.push(\"stale\");\n if (p.store.corruptCount > 0) projStates.push(\"gone\");\n }\n behind = liveDeliveryBehind(snap.daemon);\n }\n return {\n now,\n daemonT: tally(daemonStates),\n projT: tally(projStates),\n envT: tally(envStates),\n overall: tally([...daemonStates, ...projStates, ...envStates]),\n errors, behind, crewAgeMs,\n };\n}\n\n// ── Tab: OVERVIEW ───────────────────────────────────────────────────────────────\n/** A titled section header: a short heading + a one-line plain-language caption,\n * so a first-time viewer knows what each block of widgets is showing. */\nfunction sectionHead(title: string, sub: string): string {\n return `<div class=\"section-head\"><h2 class=\"section-title\">${esc(title)}</h2><p class=\"section-sub\">${esc(sub)}</p></div>`;\n}\n\nfunction tierCard(name: string, t: Tally, desc: string): string {\n const w = t.total ? worst(([] as AnyState[]).concat(\n ...Array.from({ length: t.gone }, () => \"gone\" as AnyState),\n ...Array.from({ length: t.stopped }, () => \"stopped\" as AnyState),\n ...Array.from({ length: t.stale }, () => \"stale\" as AnyState),\n ...Array.from({ length: t.unknown }, () => \"unknown\" as AnyState),\n ...Array.from({ length: t.alive }, () => \"alive\" as AnyState),\n )) : \"unknown\";\n return [\n `<div class=\"tier-card\">`,\n `<div class=\"tier-top\"><span class=\"tier-name\">${esc(name)}</span>${statePill(w)}</div>`,\n `<p class=\"tier-desc\">${esc(desc)}</p>`,\n `<div class=\"tier-counts\">`,\n `<span class=\"tc s-alive\">${t.alive}<i>ok</i></span>`,\n `<span class=\"tc s-stale\">${t.stale}<i>caution</i></span>`,\n `<span class=\"tc s-gone\">${t.gone}<i>fault</i></span>`,\n ...(t.stopped > 0 ? [`<span class=\"tc s-stopped\">${t.stopped}<i>stopped</i></span>`] : []),\n `<span class=\"tc s-unknown\">${t.unknown}<i>unknown</i></span>`,\n `</div></div>`,\n ].join(\"\");\n}\n\nfunction renderOverview(snap: FullSnapshot, col: Collected): string {\n const linkLost = snap.daemon === \"unreachable\";\n const mc = linkLost ? \"crit\" : masterClass(col.overall);\n const word = linkLost ? \"LINK LOST\" : MASTER_WORD[mc];\n const out: string[] = [`<section class=\"panel\" data-panel=\"overview\" role=\"tabpanel\" aria-label=\"Overview\">`];\n\n out.push(sectionHead(\n \"System Health\",\n `${col.overall.alive} of ${col.overall.total} monitored components are alive — the ring shows the full breakdown by state.`,\n ));\n out.push(\n `<div class=\"hero a-${mc}\">`,\n `<div class=\"gauge\">`,\n donut(col.overall),\n `<div class=\"gauge-core\"><span class=\"gauge-n\" data-countup=\"monitored\" data-value=\"${col.overall.total}\">${col.overall.total}</span><span class=\"gauge-word\">${esc(word)}</span><span class=\"gauge-cap\">monitored</span></div>`,\n `</div>`,\n `<div class=\"legend\">`,\n legendRow(\"alive\", col.overall.alive),\n legendRow(\"stale\", col.overall.stale),\n legendRow(\"gone\", col.overall.gone),\n ...(col.overall.stopped > 0 ? [legendRow(\"stopped\", col.overall.stopped)] : []),\n legendRow(\"unknown\", col.overall.unknown),\n `</div>`,\n `</div>`,\n );\n\n out.push(sectionHead(\"Health by Tier\", \"How many components are healthy in each layer of the stack.\"));\n out.push(\n `<div class=\"tier-grid\">`,\n tierCard(\"Daemon\", col.daemonT, \"squadrantd process, build freshness & log volume (Tier 0)\"),\n tierCard(\"Projects\", col.projT, \"captains, crews & message data plane (Tier 1/2)\"),\n tierCard(\"Environment\", col.envT, \"agent CLIs, vaults & config integrity (Tier 3/4)\"),\n `</div>`,\n );\n\n out.push(sectionHead(\"Live Trends\", \"Magnitudes tracked over time — each sparkline builds as new updates arrive.\"));\n out.push(\n `<div class=\"trend-grid\">`,\n trendCard(\"errors\", \"Daemon log\", `${col.errors}`, \"errors the daemon logged in the last window\"),\n trendCard(\"behind\", \"Delivery lag\", `${col.behind}`, \"messages captains have not read yet\"),\n trendCard(\"crewAge\", \"Crew heartbeat\", linkLost ? \"—\" : fmtDur(col.crewAgeMs), \"time since the quietest crew was last seen\"),\n `</div>`,\n );\n\n out.push(`</section>`);\n return out.join(\"\");\n}\n\n// ── Tab: PROJECTS ───────────────────────────────────────────────────────────────\nfunction componentRow(c: ComponentHealth, now: number): string {\n const detail = c.detail ? esc(c.detail) : \"\";\n const row =\n `<tr>` +\n `<td>${statePill(c.state)}</td>` +\n `<td class=\"mono\">${esc(c.kind)}</td>` +\n `<td class=\"mono\">${esc(c.ref)}</td>` +\n `<td class=\"mono dim\">${esc(ageText(c.lastSeenMs, now))}</td>` +\n `<td class=\"dim\">${detail}</td>` +\n `</tr>`;\n const heal = healCmdFor(c);\n return heal ? row + `<tr class=\"rem-row\"><td colspan=\"5\">${remediation(heal)}</td></tr>` : row;\n}\n\nfunction deliveryBar(behind: number, maxSeq: number): string {\n const acked = Math.max(0, maxSeq - behind);\n const ackedPct = maxSeq > 0 ? (acked / maxSeq) * 100 : 100;\n const behindPct = maxSeq > 0 ? (behind / maxSeq) * 100 : 0;\n return [\n `<div class=\"dbar\" role=\"img\" aria-label=\"${acked} of ${maxSeq} delivered, ${behind} behind\">`,\n `<span class=\"dbar-acked\" style=\"width:${ackedPct.toFixed(1)}%\"></span>`,\n `<span class=\"dbar-behind\" style=\"width:${behindPct.toFixed(1)}%\"></span>`,\n `</div>`,\n ].join(\"\");\n}\n\nfunction renderProjects(snap: FullSnapshot, now: number): string {\n const out: string[] = [`<section class=\"panel\" data-panel=\"projects\" role=\"tabpanel\" aria-label=\"Projects\">`];\n out.push(sectionHead(\"Projects\", \"Per-project captains and crews, plus each project's mailbox delivery and task store.\"));\n if (snap.daemon === \"unreachable\") {\n out.push(`<div class=\"empty\">Telemetry link lost — per-project data is served by the daemon. Start it to restore: <code>squadrant heal daemon</code></div></section>`);\n return out.join(\"\");\n }\n const d = snap.daemon;\n const projects = new Set<string>([...d.tier1.map((c) => c.project), ...d.tier2.projects.map((p) => p.project)]);\n if (projects.size === 0) out.push(`<div class=\"empty\">No projects registered yet.</div>`);\n for (const project of projects) {\n const comps = d.tier1.filter((c) => c.project === project);\n const dp = d.tier2.projects.find((p) => p.project === project);\n // A stopped captain means the project is intentionally offline — its unread\n // mail is expected backlog, not a live caution, so the delivery lag does not\n // contribute a `stale` to the rollup (#324/#323). A genuine fault (corrupt\n // store) still bubbles `gone` and out-ranks the stopped headline.\n const captainStopped = comps.some((c) => c.kind === \"captain\" && c.state === \"stopped\");\n const rollupStates: AnyState[] = [\n ...comps.map((c) => c.state),\n !captainStopped && dp && dp.delivery.behind > 0 ? \"stale\" : \"alive\",\n dp && dp.store.corruptCount > 0 ? \"gone\" : \"alive\",\n ];\n const rollup = worst(rollupStates);\n out.push(`<article class=\"card\" data-rollup=\"${rollup}\">`);\n out.push(`<header class=\"card-head\"><span class=\"card-title\">${esc(project)}</span>${statePill(rollup)}</header>`);\n if (comps.length) {\n out.push(\n `<table class=\"grid\"><thead><tr><th>status</th><th>kind</th><th>ref</th><th>last seen</th><th>detail</th></tr></thead><tbody>`,\n ...comps.map((c) => componentRow(c, now)),\n `</tbody></table>`,\n );\n } else {\n out.push(`<div class=\"dim small\">no live components reported</div>`);\n }\n if (dp) {\n const counts = Object.entries(dp.store.byState).map(([s, n]) => pill(\"unknown\", `${n} ${s}`)).join(\"\");\n out.push(\n `<div class=\"dp-grid\">`,\n `<div class=\"dp-block\"><span class=\"dp-l\">mailbox</span><span class=\"dp-v\"><span class=\"mono\">${dp.mailbox.maxSeq}</span> entries · ${fmtBytes(dp.mailbox.sizeBytes)} · rotated ${dp.mailbox.rotationCount} · oldest ${fmtAge(dp.mailbox.oldestEntryAgeMs)}</span></div>`,\n `<div class=\"dp-block\"><span class=\"dp-l\">captain delivery</span>${deliveryBar(dp.delivery.behind, dp.mailbox.maxSeq)}<span class=\"dp-v\"><span class=\"mono\">${dp.delivery.behind}</span> behind</span></div>`,\n `<div class=\"dp-block\"><span class=\"dp-l\">task store</span><span class=\"chips\">${counts || `<span class=\"dim small\">no tasks</span>`}${dp.store.corruptCount > 0 ? pill(\"gone\", `${dp.store.corruptCount} corrupt`) : \"\"}</span></div>`,\n `</div>`,\n );\n }\n out.push(`</article>`);\n }\n out.push(`</section>`);\n return out.join(\"\");\n}\n\n// ── Tab: DAEMON ─────────────────────────────────────────────────────────────────\nfunction instr(label: string, value: string, extra = \"\"): string {\n return `<div class=\"instr\"><span class=\"instr-l\">${esc(label)}</span><span class=\"instr-v\">${value}</span>${extra}</div>`;\n}\n\nfunction renderDaemon(snap: FullSnapshot): string {\n const out: string[] = [`<section class=\"panel\" data-panel=\"daemon\" role=\"tabpanel\" aria-label=\"Daemon\">`];\n out.push(sectionHead(\"Daemon · Tier 0\", \"The squadrantd process at the root of everything — uptime, build freshness, sweep cadence, and log volume.\"));\n if (snap.daemon === \"unreachable\") {\n out.push(`<div class=\"empty\">Daemon unreachable — no Tier 0 telemetry. ${remediation(\"squadrant heal daemon\")}</div></section>`);\n return out.join(\"\");\n }\n const t0 = snap.daemon.tier0;\n const buildState: HealthState = t0.build.state === \"fresh\" ? \"alive\" : \"gone\";\n // #fix(a): a fresh daemon that has not run a sweep yet is \"awaiting first\n // sweep\" — not \"never swept\". A null age means the loop simply hasn't ticked.\n const sweep = t0.sweep.ageMs == null\n ? \"awaiting first sweep\"\n : `last ${fmtAge(t0.sweep.ageMs)} · ${fmtDur(t0.sweep.cadenceMs)} cadence`;\n const sweepState: AnyState = t0.sweep.ageMs == null ? \"unknown\" : \"alive\";\n // #fix(b): present the log error count as a calm, non-alarming metric — a\n // caution at most, with a trend sparkline, never a red master alarm.\n const logState: AnyState = t0.log.errorCount > 0 ? \"stale\" : \"alive\";\n\n out.push(\n `<div class=\"instr-grid\">`,\n instr(\"process\", `<span class=\"mono\">squadrantd</span> ${statePill(\"alive\")}`, `<span class=\"instr-sub\">pid ${t0.pid} · v${esc(t0.version)}</span>`),\n instr(\"uptime\", `<span class=\"mono\">${fmtDur(t0.uptimeMs)}</span>`),\n instr(\"build\", `${pill(buildState, t0.build.state)}`, t0.build.state === \"stale\" ? remediation(\"npm run build && squadrant heal daemon\") : \"\"),\n instr(\"sweep\", `${pill(sweepState, sweep)}`),\n `</div>`,\n );\n\n out.push(\n `<div class=\"trend-grid\">`,\n [\n `<div class=\"trend\">`,\n `<div class=\"trend-head\"><span class=\"trend-l\">Log errors</span><span class=\"trend-v\">${pill(logState, `${t0.log.errorCount}`)}</span></div>`,\n `<svg class=\"spark\" data-spark=\"errors\" viewBox=\"0 0 100 28\" preserveAspectRatio=\"none\" aria-hidden=\"true\"></svg>`,\n `<div class=\"trend-sub\">${t0.log.errorCount === 0 ? \"clean over the last\" : `over the last`} ${fmtDur(t0.log.windowMs)} · log ${fmtBytes(t0.log.sizeBytes)}</div>`,\n `</div>`,\n ].join(\"\"),\n trendCard(\"behind\", \"Delivery lag\", `${liveDeliveryBehind(snap.daemon)}`, \"summed across online projects only (offline excluded)\"),\n `</div>`,\n );\n\n out.push(`<div class=\"results\">global results · <span class=\"mono\">${snap.daemon.tier2.results.fileCount}</span> files · ${fmtBytes(snap.daemon.tier2.results.totalBytes)}</div>`);\n out.push(`</section>`);\n return out.join(\"\");\n}\n\n// ── Tab: ENVIRONMENT ────────────────────────────────────────────────────────────\nfunction probeTable(rows: Array<[string, Probe]>): string {\n return [\n `<table class=\"grid\"><thead><tr><th>status</th><th>component</th><th>detail</th></tr></thead><tbody>`,\n ...rows.map(([label, p]) =>\n `<tr><td>${statePill(p.state)}</td><td class=\"mono\">${esc(label)}</td><td class=\"dim\">${p.detail ? esc(p.detail) : \"\"}</td></tr>`,\n ),\n `</tbody></table>`,\n ].join(\"\");\n}\n\nfunction renderEnv(ext: ExternalProbes): string {\n const out: string[] = [`<section class=\"panel\" data-panel=\"environment\" role=\"tabpanel\" aria-label=\"Environment\">`];\n out.push(sectionHead(\"Environment · Tier 3 / 4\", \"External tools and on-disk state the squadrant depends on but does not own — agent CLIs, vaults, and config.\"));\n\n out.push(`<article class=\"card\"><header class=\"card-head\"><span class=\"card-title\">Runtime & CLIs</span></header>`);\n out.push(probeTable([\n [\"cmux\", ext.cmux],\n ...ext.agentClis.map((c) => [c.cli, c] as [string, Probe]),\n ]));\n out.push(`</article>`);\n\n out.push(`<article class=\"card\"><header class=\"card-head\"><span class=\"card-title\">Vaults</span></header>`);\n out.push(probeTable([\n [\"hub\", ext.vaults.hub],\n ...ext.vaults.spokes.map((s) => [`spoke · ${s.project}`, s] as [string, Probe]),\n ]));\n out.push(`</article>`);\n\n out.push(`<article class=\"card\"><header class=\"card-head\"><span class=\"card-title\">Config integrity</span></header>`);\n out.push(probeTable([\n [\"config.json\", ext.config.parseable],\n [\"sessions\", ext.config.sessions],\n ...ext.config.projectPaths.map((p) => [`path · ${p.project}`, p] as [string, Probe]),\n ]));\n out.push(`</article>`);\n\n out.push(`</section>`);\n return out.join(\"\");\n}\n\n// ── Tab nav + content assembly ──────────────────────────────────────────────────\nconst TABS: Array<[string, string]> = [\n [\"overview\", \"Overview\"],\n [\"projects\", \"Projects\"],\n [\"daemon\", \"Daemon\"],\n [\"environment\", \"Environment\"],\n];\n\nfunction tabNav(): string {\n const btns = TABS.map(([id, label], i) =>\n `<button class=\"tab${i === 0 ? \" on\" : \"\"}\" data-tab=\"${id}\" role=\"tab\" aria-selected=\"${i === 0 ? \"true\" : \"false\"}\">${esc(label)}</button>`,\n ).join(\"\");\n return `<nav class=\"tabs\" role=\"tablist\">${btns}</nav>`;\n}\n\nfunction metricsBlob(col: Collected, linkLost: boolean): string {\n const m = {\n t: col.now,\n errors: linkLost ? 0 : col.errors,\n behind: linkLost ? 0 : col.behind,\n crewAgeMs: linkLost ? 0 : col.crewAgeMs,\n alive: col.overall.alive, stale: col.overall.stale, gone: col.overall.gone, stopped: col.overall.stopped, unknown: col.overall.unknown,\n };\n // Escape `</` defensively so the JSON can never close the <script> early.\n const json = JSON.stringify(m).replace(/</g, \"\\\\u003c\");\n return `<script type=\"application/json\" id=\"squadrant-metrics\">${json}</script>`;\n}\n\n/** Pure. The live inner content (everything inside #content), re-pushed each tick. */\nexport function renderContent(snap: FullSnapshot): string {\n const col = collect(snap);\n const linkLost = snap.daemon === \"unreachable\";\n const mc = linkLost ? \"crit\" : masterClass(col.overall);\n const word = linkLost ? \"LINK LOST\" : MASTER_WORD[mc];\n\n const out: string[] = [\n `<header class=\"page-head\">`,\n `<h1 class=\"page-title\">SQUADRANT SYSTEM HEALTH</h1>`,\n `<p class=\"page-sub\">Live health of the squadrant daemon, sessions, message data plane, and environment — refreshed automatically every few seconds.</p>`,\n `</header>`,\n ];\n\n // Master annunciator (status summary) — glanceable on every tab.\n const stoppedPart = col.overall.stopped > 0 ? ` · ${col.overall.stopped} stopped` : \"\";\n const sumLine = `${col.overall.alive} nominal · ${col.overall.stale} caution · ${col.overall.gone} fault${stoppedPart} · ${col.overall.unknown} unknown`;\n out.push(\n `<section class=\"annunciator a-${mc}\" role=\"status\" aria-label=\"Status summary\">`,\n `<div class=\"ann-main\"><span class=\"ann-eyebrow\">Status summary</span><span class=\"ann-word\">${esc(word)}</span></div>`,\n `<div class=\"ann-meta\"><span class=\"ann-sum\">${sumLine}</span><span class=\"ann-cap\">worst current state across all ${col.overall.total} monitored components</span></div>`,\n `</section>`,\n );\n\n // Caution banners (loud, only when applicable).\n if (snap.daemon === \"unreachable\") {\n out.push(banner(\"err\", \"✘ DAEMON UNREACHABLE — start it: squadrant heal daemon (external checks below still live)\"));\n } else if (snap.daemon.tier0.build.state === \"stale\") {\n out.push(banner(\"warn\", \"⚠ DAEMON RUNNING STALE CODE — process started before the current dist build\"));\n out.push(remediation(\"npm run build && squadrant heal daemon\"));\n }\n\n out.push(tabNav());\n out.push(`<div class=\"panels\">`);\n out.push(renderOverview(snap, col));\n out.push(renderProjects(snap, col.now));\n out.push(renderDaemon(snap));\n out.push(renderEnv(snap.external));\n out.push(`</div>`);\n\n out.push(metricsBlob(col, linkLost));\n return out.join(\"\\n\");\n}\n\n/** Pure. The per-tick SSE payload: re-rendered content + the snapshot timestamp. */\nexport function renderTickJson(snap: FullSnapshot): string {\n return JSON.stringify({ contentHtml: renderContent(snap), generatedAt: snap.generatedAt });\n}\n\nconst STYLE = `\n:root{\n --bg:#f6f7f9;--panel:#ffffff;--panel-2:#eef1f6;--bezel:#e3e7ef;--track:#e9ecf2;\n --ink:#1b2333;--ink-dim:#5b6678;--hud:#0b6fc2;--hud-deep:#0b6fc2;\n --ok:#157f3c;--warn:#b45309;--crit:#c01f2e;--unk:#5f6b7d;--stopped:#7c5cbf;\n --shadow:0 1px 2px rgba(16,24,40,.05),0 4px 14px rgba(16,24,40,.06);\n}\n*{box-sizing:border-box}\nbody{margin:0;min-height:100vh;background:radial-gradient(1200px 760px at 50% -260px,#eaf1fb 0%,var(--bg) 58%);color:var(--ink);\n font:13px/1.55 ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;-webkit-font-smoothing:antialiased}\n\n/* Flight deck header (persistent shell) */\n.deck{display:flex;align-items:center;gap:18px;padding:14px 22px;border-bottom:1px solid var(--bezel);\n background:linear-gradient(180deg,rgba(255,255,255,.92),rgba(255,255,255,.62));position:sticky;top:0;z-index:5;backdrop-filter:blur(8px)}\n.brand{display:flex;align-items:center;gap:11px}\n.led{width:10px;height:10px;border-radius:50%;background:var(--unk);box-shadow:0 0 0 0 rgba(55,198,238,.5)}\n.led.live{background:var(--ok);animation:beat 2.2s ease-in-out infinite}\n.led.down{background:var(--crit);animation:blink 1s steps(2) infinite}\n.wordmark{font-family:system-ui,-apple-system,\"Segoe UI\",sans-serif;font-weight:800;letter-spacing:.34em;font-size:15px;text-transform:uppercase}\n.tagline{font-family:system-ui,sans-serif;text-transform:uppercase;letter-spacing:.26em;font-size:9.5px;color:var(--hud)}\n.deck-spacer{flex:1}\n.readout{display:flex;align-items:center;gap:16px;font-size:11px}\n.conn{font-family:system-ui,sans-serif;letter-spacing:.16em;text-transform:uppercase;color:var(--ink-dim)}\n.conn.live{color:var(--ok)}.conn.down{color:var(--crit)}\n.updated{color:var(--ink-dim)}\n.port{color:var(--hud)}\n\n#content{max-width:1080px;margin:0 auto;padding:18px 22px 64px;transition:opacity .18s ease}\n#content.swap{animation:fade .26s ease}\n\n/* Page heading + section headings */\n.page-head{margin:2px 0 16px}\n.page-title{margin:0;font-family:system-ui,-apple-system,\"Segoe UI\",sans-serif;font-weight:800;font-size:20px;letter-spacing:.06em;color:var(--ink)}\n.page-sub{margin:5px 0 0;color:var(--ink-dim);font-size:13px;max-width:74ch}\n.section-head{margin:20px 0 10px}\n.section-title{margin:0;font-family:system-ui,sans-serif;text-transform:uppercase;letter-spacing:.1em;font-size:12px;font-weight:700;color:var(--ink)}\n.section-sub{margin:3px 0 0;color:var(--ink-dim);font-size:12px}\n\n/* Annunciator */\n.annunciator{display:flex;align-items:center;justify-content:space-between;gap:18px;flex-wrap:wrap;padding:14px 18px;border-radius:12px;margin-bottom:6px;\n border:1px solid var(--bezel);background:var(--panel);box-shadow:var(--shadow);position:relative;overflow:hidden}\n.annunciator::before{content:\"\";position:absolute;inset:0 auto 0 0;width:4px}\n.ann-main{display:flex;flex-direction:column;gap:2px}\n.ann-eyebrow{font-family:system-ui,sans-serif;text-transform:uppercase;letter-spacing:.16em;font-size:9px;color:var(--ink-dim)}\n.ann-meta{display:flex;flex-direction:column;gap:2px;text-align:right;min-width:0}\n.ann-word{font-family:system-ui,sans-serif;font-weight:800;letter-spacing:.2em;font-size:21px}\n.ann-sum{color:var(--ink);letter-spacing:.04em;font-size:12px}\n.ann-cap{color:var(--ink-dim);font-size:11px}\n@media (max-width:560px){.ann-meta{text-align:left}}\n.a-ok .ann-word{color:var(--ok)}.a-ok::before{background:var(--ok);box-shadow:0 0 18px var(--ok)}\n.a-warn .ann-word{color:var(--warn)}.a-warn::before{background:var(--warn);box-shadow:0 0 18px var(--warn)}\n.a-crit .ann-word{color:var(--crit)}.a-crit::before{background:var(--crit);box-shadow:0 0 18px var(--crit);animation:pulseBar 1.4s ease-in-out infinite}\n\n/* Banners */\n.banner{padding:10px 14px;border-radius:10px;margin:10px 0;font-weight:700;letter-spacing:.02em;border:1px solid transparent}\n.banner.err{background:#fdecee;color:#b21f2c;border-color:#f3c3c9}\n.banner.warn{background:#fff5e1;color:#8a5806;border-color:#f0d8a4}\n.rem{color:var(--ink-dim);margin:6px 0;font-size:12px}\n.rem code,.empty code{background:var(--panel-2);padding:2px 7px;border-radius:5px;color:var(--hud);user-select:all;border:1px solid var(--bezel)}\n\n/* Tabs */\n.tabs{display:flex;gap:4px;margin:6px 0 16px;border-bottom:1px solid var(--bezel);flex-wrap:wrap}\n.tab{appearance:none;background:none;border:0;color:var(--ink-dim);cursor:pointer;padding:9px 16px;\n font-family:system-ui,sans-serif;text-transform:uppercase;letter-spacing:.16em;font-size:11px;font-weight:600;\n border-bottom:2px solid transparent;margin-bottom:-1px;transition:color .15s ease,border-color .15s ease}\n.tab:hover{color:var(--ink)}\n.tab.on{color:var(--hud);border-bottom-color:var(--hud)}\n.panel{animation:none}\n.panel.fade{animation:fade .28s ease}\n\n/* Overview hero */\n.hero{display:flex;gap:30px;align-items:center;flex-wrap:wrap;padding:22px;border-radius:14px;\n border:1px solid var(--bezel);background:linear-gradient(180deg,var(--panel-2),var(--panel));box-shadow:var(--shadow);margin-bottom:16px}\n.gauge{position:relative;width:172px;height:172px;flex:none}\n.donut{width:172px;height:172px;animation:rise .55s ease}\n.donut-track{stroke:var(--track)}\n.seg{transition:stroke-dasharray .5s ease}\n.seg.s-alive{stroke:var(--ok)}.seg.s-stale{stroke:var(--warn)}.seg.s-gone{stroke:var(--crit)}.seg.s-stopped{stroke:var(--stopped)}.seg.s-unknown{stroke:var(--unk)}\n.a-ok .seg.s-alive{filter:drop-shadow(0 0 4px var(--ok))}\n.gauge-core{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;gap:1px}\n.gauge-n{font-size:38px;font-weight:800;font-family:system-ui,sans-serif;line-height:1}\n.gauge-word{font-family:system-ui,sans-serif;text-transform:uppercase;letter-spacing:.14em;font-size:11px;color:var(--ink-dim)}\n.a-ok .gauge-word{color:var(--ok)}.a-warn .gauge-word{color:var(--warn)}.a-crit .gauge-word{color:var(--crit)}\n.gauge-cap{font-size:9px;letter-spacing:.2em;text-transform:uppercase;color:var(--ink-dim)}\n.legend{display:grid;grid-template-columns:1fr 1fr;gap:10px 22px;flex:1;min-width:200px}\n.leg{display:flex;align-items:center;gap:9px}\n.leg-n{font-size:20px;font-weight:700;font-family:system-ui,sans-serif;min-width:1.4em;text-align:right}\n.leg-l{color:var(--ink-dim);text-transform:uppercase;letter-spacing:.1em;font-size:10px;font-family:system-ui,sans-serif}\n.leg.s-alive .pdot{background:var(--ok)}.leg.s-stale .pdot{background:var(--warn)}\n.leg.s-gone .pdot{background:var(--crit)}.leg.s-stopped .pdot{background:var(--stopped)}.leg.s-unknown .pdot{background:var(--unk)}\n\n/* Tier + trend cards */\n.tier-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:12px;margin-bottom:16px}\n.tier-card{border:1px solid var(--bezel);border-radius:12px;background:var(--panel);padding:14px 16px;box-shadow:var(--shadow)}\n.tier-top{display:flex;align-items:center;justify-content:space-between;margin-bottom:6px}\n.tier-name{font-family:system-ui,sans-serif;text-transform:uppercase;letter-spacing:.12em;font-size:11px;color:var(--ink)}\n.tier-desc{margin:0 0 12px;color:var(--ink-dim);font-size:11px;min-height:2.2em}\n.tier-counts{display:flex;gap:14px}\n.tc{display:flex;flex-direction:column;font-size:21px;font-weight:700;font-family:system-ui,sans-serif;line-height:1.1}\n.tc i{font-size:9px;font-weight:600;font-style:normal;letter-spacing:.1em;text-transform:uppercase;color:var(--ink-dim)}\n.tc.s-alive{color:var(--ok)}.tc.s-stale{color:var(--warn)}.tc.s-gone{color:var(--crit)}.tc.s-stopped{color:var(--stopped)}.tc.s-unknown{color:var(--unk)}\n\n.trend-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));gap:12px;margin-bottom:16px}\n.trend{border:1px solid var(--bezel);border-radius:12px;background:var(--panel);padding:13px 15px;box-shadow:var(--shadow)}\n.trend-head{display:flex;align-items:center;justify-content:space-between;margin-bottom:8px}\n.trend-l{font-family:system-ui,sans-serif;text-transform:uppercase;letter-spacing:.12em;font-size:10px;color:var(--ink-dim)}\n.trend-v{font-size:18px;font-weight:700;font-family:system-ui,sans-serif;color:var(--hud)}\n.trend-sub{color:var(--ink-dim);font-size:11px;margin-top:7px}\n.spark{width:100%;height:34px;display:block}\n.spark-line{fill:none;stroke:var(--hud);stroke-width:1.6;vector-effect:non-scaling-stroke;stroke-linejoin:round}\n.spark-area{fill:var(--hud);opacity:.1}\n.spark-dot{fill:var(--hud)}\n\n/* Cards / tables */\n.card{border:1px solid var(--bezel);border-radius:12px;background:var(--panel);box-shadow:var(--shadow);padding:14px 16px;margin-bottom:14px;border-left:3px solid var(--bezel)}\n.card[data-rollup=\"gone\"]{border-left-color:var(--crit)}\n.card[data-rollup=\"stale\"]{border-left-color:var(--warn)}\n.card[data-rollup=\"stopped\"]{border-left-color:var(--stopped)}\n.card[data-rollup=\"alive\"]{border-left-color:var(--ok)}\n.card[data-rollup=\"unknown\"]{border-left-color:var(--unk)}\n.card-head{display:flex;align-items:center;justify-content:space-between;margin-bottom:12px}\n.card-title{font-family:system-ui,sans-serif;text-transform:uppercase;letter-spacing:.1em;font-size:12px;font-weight:600}\n.grid{width:100%;border-collapse:collapse;font-size:12px}\n.grid th{text-align:left;font-family:system-ui,sans-serif;text-transform:uppercase;letter-spacing:.1em;font-size:9px;\n color:var(--ink-dim);font-weight:600;padding:4px 10px 8px;border-bottom:1px solid var(--bezel)}\n.grid td{padding:6px 10px;border-bottom:1px solid var(--track);vertical-align:middle}\n.grid tr:last-child td{border-bottom:0}\n.rem-row td{padding-top:0;border-bottom:0}\n.mono{font-family:ui-monospace,monospace}\n.dim{color:var(--ink-dim)}.small{font-size:11px}\n\n/* Pills */\n.pill{display:inline-flex;align-items:center;gap:6px;padding:2px 9px;border-radius:999px;font-size:11px;\n border:1px solid var(--bezel);background:var(--panel-2);white-space:nowrap}\n.pdot{width:7px;height:7px;border-radius:50%;flex:none;background:var(--unk)}\n.pill.s-alive{color:var(--ok)}.pill.s-alive .pdot{background:var(--ok);box-shadow:0 0 6px var(--ok)}\n.pill.s-stale{color:var(--warn)}.pill.s-stale .pdot{background:var(--warn);box-shadow:0 0 6px var(--warn)}\n.pill.s-gone{color:var(--crit)}.pill.s-gone .pdot{background:var(--crit);box-shadow:0 0 6px var(--crit)}\n.pill.s-stopped{color:var(--stopped)}.pill.s-stopped .pdot{background:var(--stopped);box-shadow:0 0 6px var(--stopped)}\n.pill.s-unknown{color:var(--unk)}.pill.s-unknown .pdot{background:var(--unk)}\n.cell-detail{color:var(--ink-dim)}\n\n/* Project data-plane */\n.dp-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:12px;margin-top:14px;\n padding-top:13px;border-top:1px solid var(--bezel)}\n.dp-block{display:flex;flex-direction:column;gap:6px}\n.dp-l{font-family:system-ui,sans-serif;text-transform:uppercase;letter-spacing:.1em;font-size:9px;color:var(--ink-dim)}\n.dp-v{font-size:12px}\n.chips{display:flex;flex-wrap:wrap;gap:5px}\n.dbar{display:flex;height:9px;border-radius:5px;overflow:hidden;background:var(--track);border:1px solid var(--bezel)}\n.dbar-acked{background:var(--ok);transition:width .5s ease}\n.dbar-behind{background:var(--warn);transition:width .5s ease}\n.results{color:var(--ink-dim);font-size:12px;margin-top:8px}\n\n/* Daemon instruments */\n.instr-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:12px;margin-bottom:16px}\n.instr{border:1px solid var(--bezel);border-radius:12px;background:var(--panel);padding:13px 15px;box-shadow:var(--shadow);display:flex;flex-direction:column;gap:7px}\n.instr-l{font-family:system-ui,sans-serif;text-transform:uppercase;letter-spacing:.12em;font-size:9px;color:var(--ink-dim)}\n.instr-v{font-size:15px;display:flex;align-items:center;gap:9px;flex-wrap:wrap}\n.instr-sub{color:var(--ink-dim);font-size:11px}\n\n.empty{border:1px dashed var(--bezel);border-radius:12px;padding:24px;color:var(--ink-dim);text-align:center;background:var(--panel)}\n\n:focus-visible{outline:2px solid var(--hud);outline-offset:2px;border-radius:4px}\n\n@keyframes beat{0%,100%{box-shadow:0 0 0 0 rgba(58,210,159,.45)}50%{box-shadow:0 0 0 6px rgba(58,210,159,0)}}\n@keyframes blink{50%{opacity:.35}}\n@keyframes pulseBar{0%,100%{opacity:1}50%{opacity:.4}}\n@keyframes fade{from{opacity:0;transform:translateY(4px)}to{opacity:1;transform:none}}\n@keyframes rise{from{opacity:0;transform:scale(.92)}to{opacity:1;transform:none}}\n@media (prefers-reduced-motion:reduce){*{animation:none!important;transition:none!important}}\n@media (max-width:640px){.hero{gap:18px}.deck{padding:12px 14px;gap:10px}.tagline{display:none}#content{padding:14px}}\n`.trim();\n\n// Persistent client controller: tab switching (event-delegated), rolling history\n// for sparklines, count-ups, and the SSE wiring. Lives in the shell so it is set\n// up ONCE and survives every #content swap; `refresh()` reapplies tab + redraws\n// charts after each frame.\nconst CLIENT_JS = `\n(function(){\n var activeTab='overview';var hist={};var prev={};\n function pushHist(k,v,t){var a=hist[k]||(hist[k]=[]);if(a.length&&a[a.length-1].t===t)return;a.push({t:t,v:v});if(a.length>48)a.shift();}\n function ingest(){var el=document.getElementById('squadrant-metrics');if(!el)return;var m;try{m=JSON.parse(el.textContent);}catch(e){return;}pushHist('errors',m.errors,m.t);pushHist('behind',m.behind,m.t);pushHist('crewAge',Math.round(m.crewAgeMs/1000),m.t);}\n function sparkSVG(a){var W=100,H=28,p=2;if(!a.length)return'';var vs=a.map(function(x){return x.v;});var mx=Math.max.apply(null,vs),mn=Math.min.apply(null,vs);if(mx===mn)mx=mn+1;var n=a.length;var pts=a.map(function(x,i){var px=n>1?p+i/(n-1)*(W-2*p):W/2;var py=H-p-(x.v-mn)/(mx-mn)*(H-2*p);return[px,py];});var d=pts.map(function(pt,i){return(i?'L':'M')+pt[0].toFixed(1)+' '+pt[1].toFixed(1);}).join(' ');var last=pts[pts.length-1];var area=d+' L'+last[0].toFixed(1)+' '+H+' L'+pts[0][0].toFixed(1)+' '+H+' Z';return'<path class=\"spark-area\" d=\"'+area+'\"/><path class=\"spark-line\" d=\"'+d+'\"/><circle class=\"spark-dot\" cx=\"'+last[0].toFixed(1)+'\" cy=\"'+last[1].toFixed(1)+'\" r=\"2\"/>';}\n function drawSparks(){var ns=document.querySelectorAll('[data-spark]');for(var i=0;i<ns.length;i++){ns[i].innerHTML=sparkSVG(hist[ns[i].getAttribute('data-spark')]||[]);}}\n function applyTab(){var ts=document.querySelectorAll('[data-tab]');for(var i=0;i<ts.length;i++){var on=ts[i].getAttribute('data-tab')===activeTab;ts[i].setAttribute('aria-selected',on?'true':'false');ts[i].classList.toggle('on',on);}var ps=document.querySelectorAll('[data-panel]');for(var j=0;j<ps.length;j++){var on2=ps[j].getAttribute('data-panel')===activeTab;ps[j].hidden=!on2;}}\n function ease(k){return k<.5?2*k*k:1-Math.pow(-2*k+2,2)/2;}\n function countUps(){var ns=document.querySelectorAll('[data-countup]');for(var i=0;i<ns.length;i++){(function(el){var key=el.getAttribute('data-countup');var to=parseFloat(el.getAttribute('data-value'))||0;var from=prev[key]!=null?prev[key]:0;prev[key]=to;if(from===to){el.textContent=to;return;}var s=null;function step(ts){if(s===null)s=ts;var k=Math.min(1,(ts-s)/600);el.textContent=Math.round(from+(to-from)*ease(k));if(k<1)requestAnimationFrame(step);}requestAnimationFrame(step);})(ns[i]);}}\n function refresh(){ingest();applyTab();drawSparks();countUps();}\n document.addEventListener('click',function(e){var t=e.target&&e.target.closest?e.target.closest('[data-tab]'):null;if(t){activeTab=t.getAttribute('data-tab');applyTab();var c=document.getElementById('content');if(c){c.classList.remove('swap');void c.offsetWidth;c.classList.add('swap');}}});\n document.addEventListener('keydown',function(e){var ae=document.activeElement;if((e.key==='ArrowRight'||e.key==='ArrowLeft')&&ae&&ae.getAttribute&&ae.getAttribute('data-tab')){var o=['overview','projects','daemon','environment'];var i=o.indexOf(activeTab);i=(i+(e.key==='ArrowRight'?1:o.length-1))%o.length;activeTab=o[i];applyTab();var nt=document.querySelector('[data-tab=\"'+activeTab+'\"]');if(nt)nt.focus();e.preventDefault();}});\n var led=document.getElementById('led');var conn=document.getElementById('conn');var updated=document.getElementById('updated');\n function tickAge(){if(!generatedAt)return;var s=Math.max(0,Math.round((Date.now()-generatedAt)/1000));updated.textContent='updated '+s+'s ago';}\n setInterval(tickAge,1000);\n var es=new EventSource('/events');\n es.onopen=function(){conn.textContent='live';conn.className='conn live';led.className='led live';};\n es.onerror=function(){conn.textContent='reconnecting';conn.className='conn down';led.className='led down';};\n es.onmessage=function(e){try{var d=JSON.parse(e.data);document.getElementById('content').innerHTML=d.contentHtml;generatedAt=d.generatedAt;tickAge();refresh();}catch(_){}};\n refresh();tickAge();\n})();\n`.trim();\n\n/** Pure. The full HTML document for the initial GET / load (shell + content + SSE JS). */\nexport function renderHtml(snap: FullSnapshot, opts: { port?: number } = {}): string {\n const port = opts.port ? `:${opts.port}` : \"\";\n return [\n \"<!DOCTYPE html>\",\n '<html lang=\"en\"><head><meta charset=\"utf-8\">',\n '<meta name=\"viewport\" content=\"width=device-width,initial-scale=1\">',\n \"<title>squadrant · system health</title>\",\n `<style>${STYLE}</style></head><body class=\"theme-light\">`,\n `<header class=\"deck\">`,\n `<div class=\"brand\"><span class=\"led\" id=\"led\"></span><span class=\"wordmark\">Squadrant</span><span class=\"tagline\">Mission Control</span></div>`,\n `<span class=\"deck-spacer\"></span>`,\n `<div class=\"readout\"><span class=\"conn\" id=\"conn\">connecting</span><span class=\"updated\" id=\"updated\"></span><span class=\"port\">${esc(port)}</span></div>`,\n `</header>`,\n `<main id=\"content\">${renderContent(snap)}</main>`,\n `<script>let generatedAt=${snap.generatedAt};${CLIENT_JS}</script>`,\n \"</body></html>\",\n ].join(\"\");\n}\n","import { Command } from \"commander\";\nimport { execSync } from \"node:child_process\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport os from \"node:os\";\nimport chalk from \"chalk\";\nimport { loadConfig, resolveHome } from \"@squadrant/shared\";\nimport type { ModelRoutingConfig } from \"@squadrant/shared\";\nimport { createClaudeDriver, createCodexDriver, createGeminiDriver, createOpencodeDriver, CapabilityRegistry, buildAgentCmd } from \"@squadrant/agents\";\nimport type { AgentDriver } from \"@squadrant/agents\";\nimport { RuntimeRegistry, createCmuxDriver, createObsidianDriver, WorkspaceRegistry, isInsideCmux, cmuxLocal } from \"@squadrant/workspaces\";\nimport type { RuntimeDriver } from \"@squadrant/workspaces\";\nimport { ensureSpokeLayout } from \"@squadrant/shared\";\nimport { classifyStartupSurface } from \"@squadrant/workspaces\";\nimport { shouldStartFresh, recordSession } from \"@squadrant/core\";\n\nconst CMUX_APP = \"/Applications/cmux.app\";\nconst TEMPLATES_DIR = path.join(os.homedir(), \".config\", \"squadrant\", \"templates\");\nconst SESSIONS_PATH = path.join(os.homedir(), \".config\", \"squadrant\", \"sessions.json\");\n\nfunction ensureCmuxReady(): void {\n if (isInsideCmux()) return;\n\n console.log(chalk.yellow(\"\\n Not running inside cmux. Opening cmux app...\\n\"));\n execSync(`open \"${CMUX_APP}\"`, { stdio: \"inherit\" });\n console.log(chalk.bold(\" Run `squadrant launch` from inside a cmux workspace.\\n\"));\n process.exit(0);\n}\n\nexport interface StartupDeliveryOptions {\n /** Max time to wait for the surface to leave the cold-init splash. */\n readyTimeoutMs?: number;\n /** Pause after a send before checking whether the turn started. */\n settleMs?: number;\n /** Poll cadence while waiting for readiness. */\n pollMs?: number;\n /** Hard cap on (re)send attempts. */\n maxAttempts?: number;\n}\n\n/**\n * #292: deliver the captain/command startup prompt deterministically instead of\n * on a fixed 8s timer. CC cold-init takes 5–15s, so a fixed delay either wastes\n * boot time or — on a slow boot — drops the prompt on the splash screen (#235),\n * leaving the captain idle and the relay unbooted.\n *\n * The loop, per attempt: (1) poll until the surface is past the splash; (2) if a\n * turn is already running, stop — never queue a duplicate startup run; (3) send;\n * (4) after a short settle, re-check — a real submit flips the surface to\n * \"working\", so we re-send ONLY while it's still \"idle\" (keystrokes were dropped).\n * Re-sending strictly on observed-still-idle is what guards against duplicate\n * runs: a prompt that landed is never sent twice. Best-effort and never throws.\n */\nexport async function deliverStartupPrompt(\n runtime: Pick<RuntimeDriver, \"readScreen\" | \"send\">,\n refId: string,\n prompt: string,\n opts: StartupDeliveryOptions = {},\n): Promise<void> {\n const readyTimeoutMs = opts.readyTimeoutMs ?? 30_000;\n const settleMs = opts.settleMs ?? 2_500;\n const pollMs = opts.pollMs ?? 1_000;\n const maxAttempts = opts.maxAttempts ?? 3;\n const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms));\n const read = async () => runtime.readScreen(refId).catch(() => \"\");\n\n for (let attempt = 0; attempt < maxAttempts; attempt++) {\n // Phase 1 — wait out cold init (poll, don't guess with a fixed delay).\n // Keep the last-read screen as the pre-send baseline for the Phase-3 check.\n const deadline = Date.now() + readyTimeoutMs;\n let preSend = await read();\n let state = classifyStartupSurface(preSend);\n while (state === \"loading\" && Date.now() < deadline) {\n await sleep(pollMs);\n preSend = await read();\n state = classifyStartupSurface(preSend);\n }\n\n // A turn is already in flight (a prior attempt landed, or a resumed session\n // auto-continued). Never keystroke into it — that would queue a duplicate run.\n if (state === \"working\") return;\n\n // Phase 2 — deliver. We send on \"idle\" (input-ready) and, as a non-hanging\n // fallback, on a \"loading\" timeout (e.g. a non-Claude agent whose chrome we\n // don't recognize) so a launch is never left silently without its prompt.\n await runtime.send(refId, prompt).catch(() => { /* best-effort */ });\n\n // Timed out waiting for chrome — sent blind once; nothing to confirm, stop.\n if (state === \"loading\") return;\n\n // Phase 3 — confirm by whether the surface CHANGED, not by re-matching a\n // working-spinner. The old guard re-sent \"while still idle\", relying on\n // classifyStartupSurface → CC_WORKING_RE matching the live spinner. The newer\n // CC renders the early turn as a bare \"✽ Synthesizing…\" (no timer/token/shell\n // marker) and streams \"⏺ Thinking…\" with no spinner line at all — none of\n // which CC_WORKING_RE matches — so a captain that ALREADY accepted the prompt\n // and is busy thinking reads as \"idle\" at the +settleMs sample, and the loop\n // re-sends → duplicate startup run (cmux/CC render drift, audit A3; the code\n // is unchanged since v0.6.2). A LANDED prompt always mutates the surface (the\n // submitted message echoes into the transcript and the turn begins); DROPPED\n // keystrokes (#235) leave the surface byte-identical to the pre-send baseline.\n // Re-send only on no-change — robust to whatever the spinner renders as.\n await sleep(settleMs);\n const after = await read();\n if (after !== preSend) return;\n }\n}\n\nasync function launchWorkspace(\n runtime: RuntimeDriver,\n name: string,\n agentCmd: string,\n cwd?: string,\n navigate = false,\n forceFresh = false,\n pinToTop = false,\n initialPrompt?: string,\n): Promise<void> {\n ensureCmuxReady();\n\n const existing = await runtime.status(name);\n if (existing && forceFresh) {\n console.log(chalk.yellow(` Closing stale workspace '${name}' for fresh start`));\n await runtime.stop(existing.id);\n } else if (existing) {\n console.log(chalk.yellow(` Workspace '${name}' already exists — switching to it`));\n // TODO(runtime): select/focus not yet abstracted; direct cmux call retained intentionally\n cmuxLocal([\"select-workspace\", \"--workspace\", existing.id]);\n return;\n }\n\n let currentRef: string | undefined;\n try {\n // TODO(runtime): current-workspace not yet abstracted\n const cur = cmuxLocal([\"current-workspace\"]);\n currentRef = cur.match(/workspace:\\d+/)?.[0];\n } catch { /* ignore */ }\n\n const ref = await runtime.spawn({\n name,\n workdir: cwd ?? process.cwd(),\n command: agentCmd,\n pinToTop,\n });\n\n if (initialPrompt) {\n // #292: deterministic delivery — poll for input-readiness, send, and bounded\n // re-send if the first turn was dropped (replaces the racy fixed 8s delay\n // that dropped the prompt on slow 5–15s cold boots). Fire-and-forget, as the\n // old setTimeout was, so launch stays non-blocking and `--all` dispatches\n // captains in parallel; the loop's pending poll timers keep the CLI process\n // alive until delivery completes.\n void deliverStartupPrompt(runtime, ref.id, initialPrompt);\n }\n\n if (navigate) {\n // TODO(runtime): select not yet abstracted\n cmuxLocal([\"select-workspace\", \"--workspace\", ref.id]);\n } else if (currentRef) {\n // TODO(runtime): select not yet abstracted\n cmuxLocal([\"select-workspace\", \"--workspace\", currentRef]);\n }\n\n console.log(chalk.green(` ✔ Workspace '${name}' created`));\n}\n\nexport const launchCommand = new Command(\"launch\")\n .description(\n \"Launch a project captain (with project arg) or all captains (--all). Use `squadrant command` for one-shot Command tasks.\",\n )\n .argument(\"[project]\", \"Project name to launch captain for\")\n .option(\"--fresh\", \"Start a new session instead of resuming the last one\")\n .option(\"--all\", \"Launch all captain workspaces\")\n .action(async (project: string | undefined, opts: { fresh?: boolean; all?: boolean }) => {\n const config = loadConfig();\n\n // Build agent driver registry\n const drivers: Record<string, AgentDriver> = {\n claude: createClaudeDriver(),\n codex: createCodexDriver(),\n gemini: createGeminiDriver(),\n opencode: createOpencodeDriver(),\n };\n const registry = new CapabilityRegistry(drivers);\n\n // Build runtime driver registry\n const runtimes = new RuntimeRegistry({ cmux: createCmuxDriver() });\n\n async function launchOne(\n workspaceName: string,\n role: string,\n cwd: string,\n permissionMode: string,\n navigate: boolean,\n pinToTop = false,\n projectName?: string,\n ): Promise<void> {\n let forceFresh = !!opts.fresh;\n if (!forceFresh) {\n const auto = shouldStartFresh(workspaceName, role, { sessionsPath: SESSIONS_PATH, templatesDir: TEMPLATES_DIR });\n if (auto.fresh) {\n console.log(chalk.cyan(` ↻ ${auto.reason}`));\n forceFresh = true;\n }\n }\n\n const roleConfig = config.defaults.roles?.[role as keyof NonNullable<typeof config.defaults.roles>];\n const agentName = roleConfig?.agent || \"claude\";\n const model = roleConfig?.model || config.defaults.models?.[role as keyof ModelRoutingConfig];\n const agentCmd = buildAgentCmd(agentName, registry, role, forceFresh, permissionMode, model, TEMPLATES_DIR);\n recordSession(workspaceName, role, { sessionsPath: SESSIONS_PATH, templatesDir: TEMPLATES_DIR });\n\n // Auto-trigger startup checklist\n let initialPrompt: string | undefined;\n if (role === \"captain\") {\n initialPrompt = \"Run your startup checklist: use the squadrant:captain-ops skill, complete all startup steps, then report ready.\";\n } else if (role === \"command\") {\n initialPrompt = \"Run your startup checklist: use the squadrant:command-ops skill, complete your daily briefing, then report ready.\";\n }\n\n const runtime = projectName\n ? runtimes.forProject(projectName, config)\n : runtimes.global(config);\n\n try {\n await launchWorkspace(runtime, workspaceName, agentCmd, cwd, navigate, forceFresh, pinToTop, initialPrompt);\n } catch (err) {\n console.error(chalk.red(` ✘ Failed: ${(err as Error).message}`));\n }\n }\n\n if (opts.all) {\n // Launch all captains. Command is no longer auto-launched (#42).\n const hubPath = resolveHome(config.hubVault);\n fs.mkdirSync(hubPath, { recursive: true });\n\n console.log(chalk.bold(\"\\nLaunching all captain workspaces\\n\"));\n\n for (const [name, proj] of Object.entries(config.projects)) {\n const projPath = resolveHome(proj.path);\n const spokePath = resolveHome(proj.spokeVault);\n if (!fs.existsSync(spokePath)) {\n const spokeDriver = new WorkspaceRegistry({ obsidian: createObsidianDriver }).forProject(name, config);\n await ensureSpokeLayout(spokeDriver);\n console.log(chalk.cyan(` ✔ Created spoke vault at ${spokePath}`));\n }\n console.log(chalk.bold(`\\n Captain: ${proj.captainName} (${name})`));\n await launchOne(proj.captainName, \"captain\", projPath, config.defaults.permissions?.captain || \"auto\", false, true, name);\n }\n console.log(\"\");\n } else if (!project) {\n console.error(\n chalk.red(\n \"\\n ✘ Specify a project name, or pass --all to launch every captain.\\n\" +\n \" For one-shot Command tasks, use `squadrant command --task <briefing|learnings-review|wiki-aggregate>`.\\n\",\n ),\n );\n process.exit(1);\n } else {\n // Launch captain workspace for a project\n if (!config.projects[project]) {\n console.error(\n chalk.red(\n `\\n ✘ Project '${project}' not found. Run 'squadrant projects list' to see registered projects.\\n`,\n ),\n );\n process.exit(1);\n }\n\n const proj = config.projects[project];\n const projPath = resolveHome(proj.path);\n\n // Ensure spoke vault exists\n const spokePath = resolveHome(proj.spokeVault);\n if (!fs.existsSync(spokePath)) {\n const spokeDriver = new WorkspaceRegistry({ obsidian: createObsidianDriver }).forProject(project, config);\n await ensureSpokeLayout(spokeDriver);\n console.log(chalk.cyan(` ✔ Created spoke vault at ${spokePath}`));\n }\n\n console.log(\n chalk.bold(\n `\\nLaunching captain workspace for '${project}' (${proj.captainName})\\n`,\n ),\n );\n await launchOne(proj.captainName, \"captain\", projPath, config.defaults.permissions?.captain || \"auto\", false, true, project);\n }\n });\n","import { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport { loadConfig } from \"@squadrant/shared\";\nimport { createCmuxDriver, RuntimeRegistry } from \"@squadrant/workspaces\";\nimport type { RuntimeDriver } from \"@squadrant/workspaces\";\nimport { squadrantdCall } from \"./crew-control.js\";\nimport type { TaskRecord } from \"@squadrant/shared\";\nimport { TERMINAL_STATES } from \"@squadrant/shared\";\n\n// Captain workspaces gained the leading \"⚓ \" prefix partway through squadrant's\n// life. Workspaces created before that convention persist with the un-prefixed\n// name and shutdown needs to match both shapes.\nfunction nameVariants(name: string): string[] {\n const stripped = name.replace(/^⚓\\s+/, \"\").trim();\n return stripped === name ? [name] : [name, stripped];\n}\n\nasync function closeMatching(\n runtime: RuntimeDriver,\n variants: string[],\n label: string,\n): Promise<{ closed: string[]; failed: string[] }> {\n const workspaces = await runtime.list();\n const matches = workspaces.filter((w) => variants.includes(w.name));\n const closed: string[] = [];\n const failed: string[] = [];\n if (matches.length === 0) {\n console.log(\n chalk.yellow(` ⚠ Workspace '${label}' not found — already closed?`),\n );\n return { closed, failed };\n }\n for (const ws of matches) {\n try {\n await runtime.stop(ws.id);\n console.log(chalk.green(` ✔ Closed: ${ws.name}`));\n closed.push(ws.name);\n } catch {\n console.log(chalk.red(` ✘ Failed to close: ${ws.name}`));\n failed.push(ws.name);\n }\n }\n return { closed, failed };\n}\n\nexport const shutdownCommand = new Command(\"shutdown\")\n .description(\n \"Shutdown command + all captain workspaces (no args) or one captain workspace\",\n )\n .argument(\"[project]\", \"Project name to shut down captain for\")\n .action(async (project: string | undefined) => {\n const config = loadConfig();\n const runtimes = new RuntimeRegistry({ cmux: createCmuxDriver() });\n\n if (!project) {\n const globalRuntime = runtimes.global(config);\n const workspaces = await globalRuntime.list();\n const captainVariants = Object.values(config.projects).flatMap((p) =>\n nameVariants(p.captainName),\n );\n const commandName = config.commandName || \"command\";\n const commandVariants = nameVariants(commandName);\n const allVariants = new Set([...captainVariants, ...commandVariants]);\n const squadrantWorkspaces = workspaces.filter((w) => allVariants.has(w.name));\n\n if (squadrantWorkspaces.length === 0) {\n console.log(chalk.yellow(\"\\nNo squadrant workspaces found to close.\\n\"));\n return;\n }\n\n console.log(\n chalk.bold(\n `\\nShutting down ${squadrantWorkspaces.length} workspace(s)...\\n`,\n ),\n );\n // Terminalize all non-terminal crew tasks across every project before\n // closing workspaces — prevents ghost records from flooding on restart.\n for (const proj of Object.keys(config.projects)) {\n try {\n const tasks = (await squadrantdCall({ kind: \"list\", project: proj })) as TaskRecord[];\n for (const task of tasks) {\n if (!TERMINAL_STATES.has(task.state)) {\n await squadrantdCall({ kind: \"event\", project: proj, event: { type: \"task.cancelled\", id: task.id, reason: \"captain shutdown\" } });\n }\n }\n } catch { /* best-effort — daemon miss must not block workspace close */ }\n }\n for (const ws of squadrantWorkspaces) {\n try {\n await globalRuntime.stop(ws.id);\n console.log(chalk.green(` ✔ Closed: ${ws.name}`));\n } catch {\n console.log(chalk.red(` ✘ Failed to close: ${ws.name}`));\n }\n }\n console.log(\"\");\n return;\n }\n\n if (!config.projects[project]) {\n console.error(\n chalk.red(\n `\\n ✘ Project '${project}' not found. Run 'squadrant projects list' to see registered projects.\\n`,\n ),\n );\n process.exit(1);\n }\n\n const captainName = config.projects[project].captainName;\n const runtime = runtimes.forProject(project, config);\n console.log(\n chalk.bold(`\\nShutting down captain workspace for '${project}'...\\n`),\n );\n\n // Terminalize non-terminal crew tasks for this project before closing the\n // captain workspace — prevents ghost records from flooding on restart (#225).\n try {\n const tasks = (await squadrantdCall({ kind: \"list\", project })) as TaskRecord[];\n for (const task of tasks) {\n if (!TERMINAL_STATES.has(task.state)) {\n await squadrantdCall({ kind: \"event\", project, event: { type: \"task.cancelled\", id: task.id, reason: \"captain shutdown\" } });\n }\n }\n } catch { /* best-effort — daemon miss must not block workspace close */ }\n\n const { failed } = await closeMatching(\n runtime,\n nameVariants(captainName),\n captainName,\n );\n console.log(\"\");\n if (failed.length > 0) process.exit(1);\n });\n","import { Command } from \"commander\";\nimport fs from \"node:fs\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { execSync } from \"node:child_process\";\nimport chalk from \"chalk\";\nimport { loadConfig, readStamp } from \"@squadrant/shared\";\n\nconst REPO_URL = \"https://github.com/tu11aa/squadrant\";\n\n// Real running version. Path math is dist-relative and invariant to source\n// moves: the bundle lives at dist/index.js, so \"../package.json\" is the root\n// package.json (mirrors readPkgVersion in config.ts and index.ts).\nfunction readPkgVersion(): string {\n try {\n const pkgPath = path.join(path.dirname(fileURLToPath(import.meta.url)), \"..\", \"package.json\");\n return (JSON.parse(fs.readFileSync(pkgPath, \"utf-8\")).version as string) ?? \"unknown\";\n } catch {\n return \"unknown\";\n }\n}\n\ninterface Metrics {\n projects?: number;\n launches?: number;\n shutdowns?: number;\n lastUsed?: string;\n [key: string]: unknown;\n}\n\nfunction readMetrics(metricsPath: string): Metrics {\n try {\n return JSON.parse(fs.readFileSync(metricsPath, \"utf-8\")) as Metrics;\n } catch {\n return {};\n }\n}\n\nexport function buildIssueUrl(metrics: Metrics, squadrantVersion: string): string {\n const nodeVersion = process.versions.node;\n const platform = process.platform;\n\n const body = [\n \"## Feedback / Bug Report\",\n \"\",\n \"**Describe your feedback or issue:**\",\n \"\",\n \"<!-- Please describe what happened or what you'd like to see -->\",\n \"\",\n \"## Environment\",\n \"\",\n \"```\",\n `squadrant: ${squadrantVersion}`,\n `node: ${nodeVersion}`,\n `platform: ${platform}`,\n \"```\",\n \"\",\n \"## Usage Metrics\",\n \"\",\n \"```json\",\n JSON.stringify(metrics, null, 2),\n \"```\",\n ].join(\"\\n\");\n\n const params = new URLSearchParams({\n template: \"feedback.md\",\n title: \"[feedback] \",\n body,\n });\n\n return `${REPO_URL}/issues/new?${params.toString()}`;\n}\n\nexport const feedbackCommand = new Command(\"feedback\")\n .description(\"Open a pre-filled GitHub issue for feedback or bug reports\")\n .action(() => {\n const config = loadConfig();\n const metricsPath = config.metrics?.path || path.join(os.homedir(), \".config\", \"squadrant\", \"metrics.json\");\n const metrics = readMetrics(metricsPath);\n\n const version = readStamp(config) ?? readPkgVersion();\n const issueUrl = buildIssueUrl(metrics, version);\n\n console.log(chalk.bold(\"\\nOpening feedback issue in browser...\\n\"));\n console.log(chalk.dim(` URL: ${issueUrl.substring(0, 80)}...\\n`));\n\n try {\n execSync(`open \"${issueUrl}\"`, { stdio: \"ignore\" });\n console.log(chalk.green(\" ✔ Browser opened\\n\"));\n } catch {\n console.log(chalk.yellow(\" ⚠ Could not open browser automatically.\"));\n console.log(` Open manually: ${chalk.cyan(issueUrl)}\\n`);\n }\n });\n","import { Command } from \"commander\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport chalk from \"chalk\";\nimport matter from \"gray-matter\";\nimport { loadConfig, resolveHome, type ProjectConfig, type SquadrantConfig } from \"@squadrant/shared\";\nimport { readDailyLog, getGitCommits, iso, daysAgo } from \"@squadrant/shared\";\nimport { createObsidianDriver, WorkspaceRegistry } from \"@squadrant/workspaces\";\n\ninterface StatusFrontmatter {\n project?: string;\n captain_session?: string;\n last_updated?: string;\n active_crew?: number;\n tasks_total?: number;\n tasks_completed?: number;\n tasks_in_progress?: number;\n tasks_pending?: number;\n}\n\ninterface ProjectStandup {\n name: string;\n status: StatusFrontmatter;\n dailyLog: string | null;\n gitCommits: string[];\n blockers: string[];\n}\n\nfunction getDateStr(yesterday: boolean): string {\n return iso(daysAgo(yesterday ? 1 : 0));\n}\n\nasync function getProjectStandup(\n name: string,\n project: ProjectConfig,\n dateStr: string,\n registry: WorkspaceRegistry,\n config: SquadrantConfig,\n): Promise<ProjectStandup> {\n const workspace = registry.forProject(name, config);\n // TODO(workspace): status.md still read via raw fs — migrate to workspace driver (see #24)\n const spokeVault = resolveHome(project.spokeVault);\n const statusFile = path.join(spokeVault, \"status.md\");\n\n let status: StatusFrontmatter = {};\n if (fs.existsSync(statusFile)) {\n try {\n status = matter(fs.readFileSync(statusFile, \"utf-8\")).data as StatusFrontmatter;\n } catch { /* empty */ }\n }\n\n const log = await readDailyLog(workspace, dateStr);\n const gitCommits = getGitCommits(project.path, dateStr);\n\n return {\n name,\n status,\n dailyLog: log?.content ?? null,\n gitCommits,\n blockers: log?.blockers ?? [],\n };\n}\n\nfunction formatStandup(standups: ProjectStandup[], dateStr: string, raw: boolean): string {\n const lines: string[] = [];\n const header = `Standup — ${dateStr}`;\n\n if (!raw) {\n lines.push(chalk.bold(`\\n${header}\\n`));\n } else {\n lines.push(`# ${header}\\n`);\n }\n\n let hasBlockers = false;\n\n for (const s of standups) {\n const tasksDone = s.status.tasks_completed ?? 0;\n const tasksTotal = s.status.tasks_total ?? 0;\n const tasksInProgress = s.status.tasks_in_progress ?? 0;\n\n if (!raw) {\n lines.push(chalk.cyan.bold(`## ${s.name}`));\n } else {\n lines.push(`## ${s.name}`);\n }\n\n // What was done\n if (s.gitCommits.length > 0 || tasksDone > 0) {\n lines.push(!raw ? chalk.green(\"Done:\") : \"**Done:**\");\n for (const commit of s.gitCommits) {\n lines.push(` - ${commit}`);\n }\n if (tasksDone > 0 && s.gitCommits.length === 0) {\n lines.push(` - ${tasksDone}/${tasksTotal} tasks completed`);\n }\n }\n\n // In progress\n if (tasksInProgress > 0) {\n lines.push(!raw ? chalk.yellow(\"In Progress:\") : \"**In Progress:**\");\n lines.push(` - ${tasksInProgress} task(s) active`);\n }\n\n // Extract sections from daily log\n if (s.dailyLog) {\n const sections = [\"Completed\", \"In Progress\", \"Tomorrow\"];\n for (const section of sections) {\n const match = s.dailyLog.match(new RegExp(`## ${section}\\\\n([\\\\s\\\\S]*?)(?=\\\\n##|$)`));\n if (match) {\n const items = match[1].trim().split(\"\\n\").filter((l) => l.trim().startsWith(\"-\"));\n if (items.length > 0 && section === \"Tomorrow\") {\n lines.push(!raw ? chalk.blue(\"Next:\") : \"**Next:**\");\n for (const item of items) lines.push(` ${item.trim()}`);\n }\n }\n }\n }\n\n // Blockers\n if (s.blockers.length > 0) {\n hasBlockers = true;\n lines.push(!raw ? chalk.red(\"Blocked:\") : \"**Blocked:**\");\n for (const b of s.blockers) {\n lines.push(` - ${b}`);\n }\n }\n\n // No activity\n if (s.gitCommits.length === 0 && tasksDone === 0 && !s.dailyLog) {\n lines.push(!raw ? chalk.dim(\" (no activity)\") : \" (no activity)\");\n }\n\n lines.push(\"\");\n }\n\n // Summary line\n const totalCommits = standups.reduce((sum, s) => sum + s.gitCommits.length, 0);\n const totalDone = standups.reduce((sum, s) => sum + (s.status.tasks_completed ?? 0), 0);\n\n if (!raw) {\n lines.push(chalk.dim(`--- ${totalCommits} commits, ${totalDone} tasks done${hasBlockers ? \", HAS BLOCKERS\" : \"\"} ---\\n`));\n } else {\n lines.push(`---\\n*${totalCommits} commits, ${totalDone} tasks done${hasBlockers ? \", HAS BLOCKERS\" : \"\"}*\\n`);\n }\n\n return lines.join(\"\\n\");\n}\n\nexport const standupCommand = new Command(\"standup\")\n .description(\"Generate daily standup report from spoke vault data and git logs (zero tokens)\")\n .option(\"-p, --project <name>\", \"Show standup for a specific project only\")\n .option(\"-a, --all\", \"Show all projects (default)\")\n .option(\"-y, --yesterday\", \"Show yesterday's standup instead of today\")\n .option(\"-r, --raw\", \"Output raw markdown (for pasting into Slack/chat)\")\n .action(async (opts) => {\n const config = loadConfig();\n const registry = new WorkspaceRegistry({ obsidian: createObsidianDriver });\n const projects = Object.entries(config.projects);\n\n if (projects.length === 0) {\n console.log(chalk.yellow(\"\\nNo projects registered. Use: squadrant projects add <name> <path>\\n\"));\n return;\n }\n\n const dateStr = getDateStr(!!opts.yesterday);\n const raw = !!opts.raw;\n\n let targets: [string, ProjectConfig][];\n if (opts.project) {\n const match = projects.find(([name]) => name === opts.project);\n if (!match) {\n console.error(chalk.red(`Project \"${opts.project}\" not found.`));\n process.exit(1);\n }\n targets = [match];\n } else {\n targets = projects;\n }\n\n const standups = await Promise.all(\n targets.map(([name, proj]) => getProjectStandup(name, proj, dateStr, registry, config)),\n );\n const output = formatStandup(standups, dateStr, raw);\n console.log(output);\n });\n","import { Command } from \"commander\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport chalk from \"chalk\";\nimport matter from \"gray-matter\";\nimport { loadConfig, resolveHome, type ProjectConfig, type SquadrantConfig } from \"@squadrant/shared\";\nimport {\n readDailyLog,\n parseSection,\n getGitCommitsInRange,\n getMergedPRsInRange,\n enumerateDays,\n iso,\n daysAgo,\n} from \"@squadrant/shared\";\nimport { createObsidianDriver, WorkspaceRegistry } from \"@squadrant/workspaces\";\n\ninterface StatusFrontmatter {\n tasks_total?: number;\n tasks_completed?: number;\n tasks_in_progress?: number;\n}\n\ninterface ProjectRetro {\n name: string;\n shipped: string[];\n inProgress: string[];\n blocked: string[];\n decisions: string[];\n commits: string[];\n mergedPRs: string[];\n tasksCompletedNow: number;\n tasksInProgressNow: number;\n}\n\n// TODO(workspace): status.md still read via raw fs — migrate to workspace driver (see #24)\nfunction readStatus(spokeVault: string): StatusFrontmatter {\n const statusFile = path.join(spokeVault, \"status.md\");\n if (!fs.existsSync(statusFile)) return {};\n try {\n return matter(fs.readFileSync(statusFile, \"utf-8\")).data as StatusFrontmatter;\n } catch {\n return {};\n }\n}\n\nfunction dedupe(items: string[]): string[] {\n const seen = new Set<string>();\n const out: string[] = [];\n for (const it of items) {\n const key = it.toLowerCase();\n if (!seen.has(key)) {\n seen.add(key);\n out.push(it);\n }\n }\n return out;\n}\n\nasync function getProjectRetro(\n name: string,\n project: ProjectConfig,\n fromStr: string,\n toStr: string,\n registry: WorkspaceRegistry,\n config: SquadrantConfig,\n): Promise<ProjectRetro> {\n const workspace = registry.forProject(name, config);\n const spokeVault = resolveHome(project.spokeVault);\n const status = readStatus(spokeVault);\n\n const shipped: string[] = [];\n const inProgress: string[] = [];\n const blocked: string[] = [];\n const decisions: string[] = [];\n\n for (const day of enumerateDays(new Date(fromStr), new Date(toStr))) {\n const log = await readDailyLog(workspace, day);\n if (!log) continue;\n shipped.push(...parseSection(log.content, \"Completed\"));\n inProgress.push(...parseSection(log.content, \"In Progress\"));\n blocked.push(...log.blockers);\n decisions.push(...parseSection(log.content, \"Decisions\"));\n }\n\n const commits = getGitCommitsInRange(\n project.path,\n `${fromStr} 00:00:00`,\n `${toStr} 23:59:59`,\n );\n const mergedPRs = getMergedPRsInRange(\n project.path,\n `${fromStr} 00:00:00`,\n `${toStr} 23:59:59`,\n );\n\n return {\n name,\n shipped: dedupe(shipped),\n inProgress: dedupe(inProgress),\n blocked: dedupe(blocked),\n decisions: dedupe(decisions),\n commits,\n mergedPRs,\n tasksCompletedNow: status.tasks_completed ?? 0,\n tasksInProgressNow: status.tasks_in_progress ?? 0,\n };\n}\n\nfunction renderList(lines: string[], items: string[], raw: boolean, label: string, color: (s: string) => string) {\n if (items.length === 0) return;\n lines.push(raw ? `**${label}:**` : color(`${label}:`));\n for (const it of items) lines.push(` - ${it}`);\n}\n\nfunction formatRetro(retros: ProjectRetro[], fromStr: string, toStr: string, raw: boolean): string {\n const lines: string[] = [];\n const header = `Retro — ${fromStr} → ${toStr}`;\n lines.push(raw ? `# ${header}\\n` : chalk.bold(`\\n${header}\\n`));\n\n let totalCommits = 0;\n let totalPRs = 0;\n let totalShipped = 0;\n\n for (const r of retros) {\n totalCommits += r.commits.length;\n totalPRs += r.mergedPRs.length;\n totalShipped += r.shipped.length;\n\n lines.push(raw ? `## ${r.name}` : chalk.cyan.bold(`## ${r.name}`));\n\n renderList(lines, r.shipped, raw, \"Shipped\", chalk.green);\n if (r.mergedPRs.length > 0) {\n lines.push(raw ? `**PRs merged:**` : chalk.green(\"PRs merged:\"));\n for (const pr of r.mergedPRs) lines.push(` - ${pr}`);\n }\n renderList(lines, r.inProgress, raw, \"In Progress\", chalk.yellow);\n renderList(lines, r.blocked, raw, \"Blocked\", chalk.red);\n renderList(lines, r.decisions, raw, \"Key Decisions\", chalk.magenta);\n\n const metricBits = [\n `${r.commits.length} commits`,\n `${r.mergedPRs.length} PRs merged`,\n `${r.shipped.length} shipped`,\n ];\n lines.push(raw ? `*${metricBits.join(\" · \")}*` : chalk.dim(` ${metricBits.join(\" · \")}`));\n\n if (\n r.shipped.length === 0 &&\n r.commits.length === 0 &&\n r.mergedPRs.length === 0 &&\n r.inProgress.length === 0 &&\n r.blocked.length === 0\n ) {\n lines.push(raw ? \"_(no activity in this window)_\" : chalk.dim(\" (no activity in this window)\"));\n }\n\n lines.push(\"\");\n }\n\n const summary = `${totalShipped} items shipped · ${totalCommits} commits · ${totalPRs} PRs merged`;\n lines.push(raw ? `---\\n*${summary}*\\n` : chalk.dim(`--- ${summary} ---\\n`));\n\n return lines.join(\"\\n\");\n}\n\nexport const retroCommand = new Command(\"retro\")\n .description(\"Generate a retro (weekly/sprint summary) from daily logs and git (zero tokens)\")\n .option(\"-w, --week\", \"Trailing 7 days (default)\")\n .option(\"-s, --sprint [days]\", \"Custom window of N days (default 14 if N omitted)\")\n .option(\"-p, --project <name>\", \"Retro for a single project\")\n .option(\"-a, --all\", \"All projects (default)\")\n .option(\"-r, --raw\", \"Raw markdown output (for pasting into Slack/Obsidian)\")\n .action(async (opts) => {\n const config = loadConfig();\n const registry = new WorkspaceRegistry({ obsidian: createObsidianDriver });\n const projects = Object.entries(config.projects);\n\n if (projects.length === 0) {\n console.log(chalk.yellow(\"\\nNo projects registered. Use: squadrant projects add <name> <path>\\n\"));\n return;\n }\n\n let windowDays = 7;\n if (opts.sprint !== undefined) {\n const parsed = typeof opts.sprint === \"string\" ? parseInt(opts.sprint, 10) : NaN;\n windowDays = Number.isFinite(parsed) && parsed > 0 ? parsed : 14;\n } else if (opts.week) {\n windowDays = 7;\n }\n\n const toStr = iso(new Date());\n const fromStr = iso(daysAgo(windowDays - 1));\n const raw = !!opts.raw;\n\n let targets: [string, ProjectConfig][];\n if (opts.project) {\n const match = projects.find(([name]) => name === opts.project);\n if (!match) {\n console.error(chalk.red(`Project \"${opts.project}\" not found.`));\n process.exit(1);\n }\n targets = [match];\n } else {\n targets = projects;\n }\n\n const retros = await Promise.all(\n targets.map(([name, proj]) => getProjectRetro(name, proj, fromStr, toStr, registry, config)),\n );\n console.log(formatRetro(retros, fromStr, toStr, raw));\n });\n","import { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport { loadConfig } from \"@squadrant/shared\";\nimport { createCmuxDriver, RuntimeRegistry } from \"@squadrant/workspaces\";\nimport type { RuntimeDriver } from \"@squadrant/workspaces\";\nimport type { SquadrantConfig } from \"@squadrant/shared\";\n\nfunction buildRegistry(): RuntimeRegistry {\n return new RuntimeRegistry({\n cmux: createCmuxDriver(),\n });\n}\n\ninterface ResolvedTarget {\n driver: RuntimeDriver;\n workspaceName: string;\n}\n\nfunction resolveTarget(\n registry: RuntimeRegistry,\n config: SquadrantConfig,\n target: string | undefined,\n useCommand: boolean,\n): ResolvedTarget {\n if (useCommand) {\n return {\n driver: registry.global(config),\n workspaceName: config.commandName,\n };\n }\n if (!target) {\n throw new Error(\"Missing target: pass a project name or use --command\");\n }\n const proj = config.projects[target];\n if (!proj) {\n throw new Error(`Project '${target}' not found. Run 'squadrant projects list'.`);\n }\n return {\n driver: registry.forProject(target, config),\n workspaceName: proj.captainName,\n };\n}\n\nasync function needRef(resolved: ResolvedTarget): Promise<string> {\n const ref = await resolved.driver.status(resolved.workspaceName);\n if (!ref) {\n throw new Error(`Workspace '${resolved.workspaceName}' is not running`);\n }\n return ref.id;\n}\n\nexport const runtimeCommand = new Command(\"runtime\")\n .description(\"Interact with the runtime layer (workspaces). Bridges bash scripts to the RuntimeDriver.\");\n\nruntimeCommand\n .command(\"status\")\n .description(\"Print 'running' or 'stopped' for a target; exit 0 if running, 1 if not\")\n .argument(\"[target]\", \"Project name\")\n .option(\"--command\", \"Target the command workspace instead of a project captain\")\n .action(async (target: string | undefined, opts: { command?: boolean }) => {\n const config = loadConfig();\n const registry = buildRegistry();\n try {\n const resolved = resolveTarget(registry, config, target, !!opts.command);\n const ref = await resolved.driver.status(resolved.workspaceName);\n if (ref) {\n console.log(\"running\");\n process.exit(0);\n } else {\n console.log(\"stopped\");\n process.exit(1);\n }\n } catch (err) {\n console.error(chalk.red((err as Error).message));\n process.exit(2);\n }\n });\n\nruntimeCommand\n .command(\"send\")\n .description(\"Send a message to a target workspace AND commit with Enter. With --command, the first positional is the message.\")\n .argument(\"<arg1>\", \"Project name, or the message when --command is used\")\n .argument(\"[arg2]\", \"Message (when target is a project). Omit when using --command.\")\n .option(\"--command\", \"Target the command workspace\")\n .action(async (arg1: string, arg2: string | undefined, opts: { command?: boolean }) => {\n const config = loadConfig();\n const registry = buildRegistry();\n try {\n if (opts.command && arg2 !== undefined) {\n throw new Error(\"With --command, pass only the message (not a project name)\");\n }\n const target = opts.command ? undefined : arg1;\n const message = opts.command ? arg1 : arg2;\n if (!message) throw new Error(\"Message is required\");\n const resolved = resolveTarget(registry, config, target, !!opts.command);\n const ref = await needRef(resolved);\n await resolved.driver.send(ref, message);\n } catch (err) {\n console.error(chalk.red((err as Error).message));\n process.exit(1);\n }\n });\n\nruntimeCommand\n .command(\"send-key\")\n .description(\"Send a literal key press (e.g. Enter, Escape) to a target workspace. With --command, the first positional is the key.\")\n .argument(\"<arg1>\", \"Project name, or the key when --command is used\")\n .argument(\"[arg2]\", \"Key name (when target is a project). Omit when using --command.\")\n .option(\"--command\", \"Target the command workspace\")\n .action(async (arg1: string, arg2: string | undefined, opts: { command?: boolean }) => {\n const config = loadConfig();\n const registry = buildRegistry();\n try {\n if (opts.command && arg2 !== undefined) {\n throw new Error(\"With --command, pass only the key (not a project name)\");\n }\n const target = opts.command ? undefined : arg1;\n const key = opts.command ? arg1 : arg2;\n if (!key) throw new Error(\"Key is required\");\n const resolved = resolveTarget(registry, config, target, !!opts.command);\n const ref = await needRef(resolved);\n await resolved.driver.sendKey(ref, key);\n } catch (err) {\n console.error(chalk.red((err as Error).message));\n process.exit(1);\n }\n });\n\nruntimeCommand\n .command(\"list\")\n .description(\"List all workspaces from the global runtime\")\n .option(\"-j, --json\", \"Output as JSON\")\n .action(async (opts: { json?: boolean }) => {\n const config = loadConfig();\n const registry = buildRegistry();\n const driver = registry.global(config);\n const refs = await driver.list();\n if (opts.json) {\n console.log(JSON.stringify(refs, null, 2));\n } else {\n for (const r of refs) {\n console.log(`${r.id}\\t${r.name}\\t${r.status}`);\n }\n }\n });\n\nruntimeCommand\n .command(\"read-screen\")\n .description(\"Print a terminal snapshot of a target workspace\")\n .argument(\"[target]\", \"Project name\")\n .option(\"--command\", \"Target the command workspace\")\n .action(async (target: string | undefined, opts: { command?: boolean }) => {\n const config = loadConfig();\n const registry = buildRegistry();\n try {\n const resolved = resolveTarget(registry, config, target, !!opts.command);\n const ref = await needRef(resolved);\n const screen = await resolved.driver.readScreen(ref);\n process.stdout.write(screen);\n } catch (err) {\n console.error(chalk.red((err as Error).message));\n process.exit(1);\n }\n });\n\nruntimeCommand\n .command(\"stop\")\n .description(\"Stop a target workspace\")\n .argument(\"[target]\", \"Project name\")\n .option(\"--command\", \"Target the command workspace\")\n .action(async (target: string | undefined, opts: { command?: boolean }) => {\n const config = loadConfig();\n const registry = buildRegistry();\n try {\n const resolved = resolveTarget(registry, config, target, !!opts.command);\n const ref = await resolved.driver.status(resolved.workspaceName);\n if (!ref) {\n console.log(chalk.yellow(`Workspace '${resolved.workspaceName}' already stopped`));\n return;\n }\n await resolved.driver.stop(ref.id);\n console.log(chalk.green(`✔ Stopped ${resolved.workspaceName}`));\n } catch (err) {\n console.error(chalk.red((err as Error).message));\n process.exit(1);\n }\n });\n","import { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport { loadConfig, type SquadrantConfig } from \"@squadrant/shared\";\nimport { createObsidianDriver, WorkspaceRegistry } from \"@squadrant/workspaces\";\nimport type { WorkspaceDriver } from \"@squadrant/shared\";\n\nfunction buildRegistry(): WorkspaceRegistry {\n return new WorkspaceRegistry({\n obsidian: createObsidianDriver,\n });\n}\n\nfunction resolveDriver(\n registry: WorkspaceRegistry,\n config: SquadrantConfig,\n projectTarget: string | undefined,\n useHub: boolean,\n): WorkspaceDriver {\n if (useHub) return registry.hub(config);\n if (!projectTarget) throw new Error(\"Missing target: pass a project name or use --hub\");\n return registry.forProject(projectTarget, config);\n}\n\nasync function readStdin(): Promise<string> {\n const chunks: Buffer[] = [];\n for await (const chunk of process.stdin) {\n chunks.push(chunk as Buffer);\n }\n return Buffer.concat(chunks).toString(\"utf-8\");\n}\n\nexport const workspaceCommand = new Command(\"workspace\")\n .description(\"Interact with the workspace layer (vault storage). Bridges bash scripts to the WorkspaceDriver.\");\n\n// Reusable positional parser. The CLI convention:\n// <target> <path> → project workspace\n// --hub <path> → hub workspace\n// With commander we declare <arg1> [arg2] and in the action:\n// if --hub: arg1 is the path (target is implicit).\n// else: arg1 is the target, arg2 is the path.\nfunction resolveTargetAndPath(\n arg1: string,\n arg2: string | undefined,\n useHub: boolean,\n): { projectTarget: string | undefined; path: string } {\n if (useHub) {\n if (arg2 !== undefined) {\n throw new Error(\"With --hub, pass only the path (not a project name)\");\n }\n return { projectTarget: undefined, path: arg1 };\n }\n if (arg2 === undefined) {\n throw new Error(\"Missing path — usage: <project> <path> (or: --hub <path>)\");\n }\n return { projectTarget: arg1, path: arg2 };\n}\n\nworkspaceCommand\n .command(\"read\")\n .description(\"Print the contents of a scope-relative path to stdout\")\n .argument(\"<arg1>\", \"Project name, or the path when --hub is used\")\n .argument(\"[arg2]\", \"Scope-relative path (omit when using --hub)\")\n .option(\"--hub\", \"Target the hub workspace instead of a project spoke\")\n .action(async (arg1: string, arg2: string | undefined, opts: { hub?: boolean }) => {\n const config = loadConfig();\n const registry = buildRegistry();\n try {\n const { projectTarget, path } = resolveTargetAndPath(arg1, arg2, !!opts.hub);\n const driver = resolveDriver(registry, config, projectTarget, !!opts.hub);\n const content = await driver.read(path);\n process.stdout.write(content);\n } catch (err) {\n console.error(chalk.red((err as Error).message));\n process.exit(1);\n }\n });\n\nworkspaceCommand\n .command(\"write\")\n .description(\"Write content to a scope-relative path. Pass '-' as content to read from stdin.\")\n .argument(\"<arg1>\", \"Project name, or the path when --hub is used\")\n .argument(\"<arg2>\", \"Scope-relative path, or content when --hub is used\")\n .argument(\"[arg3]\", \"Content (omit when using --hub). Use '-' for stdin.\")\n .option(\"--hub\", \"Target the hub workspace\")\n .action(async (arg1: string, arg2: string, arg3: string | undefined, opts: { hub?: boolean }) => {\n const config = loadConfig();\n const registry = buildRegistry();\n try {\n let projectTarget: string | undefined;\n let path: string;\n let rawContent: string;\n if (opts.hub) {\n if (arg3 !== undefined) {\n throw new Error(\"With --hub, pass only the path and content\");\n }\n projectTarget = undefined;\n path = arg1;\n rawContent = arg2;\n } else {\n if (arg3 === undefined) {\n throw new Error(\"Missing content — usage: <project> <path> <content>\");\n }\n projectTarget = arg1;\n path = arg2;\n rawContent = arg3;\n }\n const driver = resolveDriver(registry, config, projectTarget, !!opts.hub);\n const payload = rawContent === \"-\" ? await readStdin() : rawContent;\n await driver.write(path, payload);\n } catch (err) {\n console.error(chalk.red((err as Error).message));\n process.exit(1);\n }\n });\n\nworkspaceCommand\n .command(\"list\")\n .description(\"List entries in a scope-relative directory\")\n .argument(\"<arg1>\", \"Project name, or the directory when --hub is used\")\n .argument(\"[arg2]\", \"Scope-relative directory (omit when using --hub)\")\n .option(\"--hub\", \"Target the hub workspace\")\n .action(async (arg1: string, arg2: string | undefined, opts: { hub?: boolean }) => {\n const config = loadConfig();\n const registry = buildRegistry();\n try {\n const { projectTarget, path } = resolveTargetAndPath(arg1, arg2, !!opts.hub);\n const driver = resolveDriver(registry, config, projectTarget, !!opts.hub);\n const entries = await driver.list(path);\n for (const entry of entries) console.log(entry);\n } catch (err) {\n console.error(chalk.red((err as Error).message));\n process.exit(1);\n }\n });\n\nworkspaceCommand\n .command(\"exists\")\n .description(\"Exit 0 if path exists, 1 if not\")\n .argument(\"<arg1>\", \"Project name, or the path when --hub is used\")\n .argument(\"[arg2]\", \"Scope-relative path (omit when using --hub)\")\n .option(\"--hub\", \"Target the hub workspace\")\n .action(async (arg1: string, arg2: string | undefined, opts: { hub?: boolean }) => {\n const config = loadConfig();\n const registry = buildRegistry();\n try {\n const { projectTarget, path } = resolveTargetAndPath(arg1, arg2, !!opts.hub);\n const driver = resolveDriver(registry, config, projectTarget, !!opts.hub);\n const ok = await driver.exists(path);\n process.exit(ok ? 0 : 1);\n } catch (err) {\n console.error(chalk.red((err as Error).message));\n process.exit(2);\n }\n });\n\nworkspaceCommand\n .command(\"mkdir\")\n .description(\"Recursively create a scope-relative directory\")\n .argument(\"<arg1>\", \"Project name, or the path when --hub is used\")\n .argument(\"[arg2]\", \"Scope-relative path (omit when using --hub)\")\n .option(\"--hub\", \"Target the hub workspace\")\n .action(async (arg1: string, arg2: string | undefined, opts: { hub?: boolean }) => {\n const config = loadConfig();\n const registry = buildRegistry();\n try {\n const { projectTarget, path } = resolveTargetAndPath(arg1, arg2, !!opts.hub);\n const driver = resolveDriver(registry, config, projectTarget, !!opts.hub);\n await driver.mkdir(path);\n } catch (err) {\n console.error(chalk.red((err as Error).message));\n process.exit(1);\n }\n });\n","import { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport { loadConfig } from \"@squadrant/shared\";\nimport { createCmuxNotifier, NotifierRegistry } from \"@squadrant/workspaces\";\n\nasync function readStdin(): Promise<string> {\n const chunks: Buffer[] = [];\n for await (const chunk of process.stdin) {\n chunks.push(chunk as Buffer);\n }\n return Buffer.concat(chunks).toString(\"utf-8\");\n}\n\nexport const notifyCommand = new Command(\"notify\")\n .description(\"Send a message to the user via the configured notifier\")\n .argument(\"<message>\", \"Message to send (use '-' to read from stdin)\")\n .action(async (message: string) => {\n const config = loadConfig();\n const registry = new NotifierRegistry({ cmux: createCmuxNotifier });\n try {\n const payload = message === \"-\" ? await readStdin() : message;\n if (!payload) throw new Error(\"Empty message\");\n await registry.get(config).notify(payload);\n } catch (err) {\n console.error(chalk.red((err as Error).message));\n process.exit(1);\n }\n });\n","import { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { loadConfig } from \"@squadrant/shared\";\nimport {\n createCursorEmitter,\n createCodexEmitter,\n createGeminiEmitter,\n createOpencodeEmitter,\n ProjectionRegistry,\n type ProjectionEmitter,\n type ProjectionSource,\n} from \"@squadrant/agents\";\nimport { createObsidianDriver } from \"@squadrant/workspaces\";\nimport type { WorkspaceDriver } from \"@squadrant/shared\";\nimport {\n readUserLevelSource,\n readProjectLevelSource,\n} from \"@squadrant/shared\";\n\ntype Opts = {\n scope?: \"user\" | \"project\";\n project?: string;\n target?: string;\n all?: boolean;\n};\n\nfunction parseScope(v: string): \"user\" | \"project\" {\n if (v !== \"user\" && v !== \"project\") {\n throw new Error(\"--scope must be 'user' or 'project'\");\n }\n return v;\n}\n\nfunction findPackageRoot(): string {\n let dir = path.dirname(fileURLToPath(import.meta.url));\n while (dir !== \"/\" && dir !== \"\") {\n if (fs.existsSync(path.join(dir, \"package.json\"))) return dir;\n dir = path.dirname(dir);\n }\n return process.cwd();\n}\n\nfunction buildRegistry(): ProjectionRegistry {\n return new ProjectionRegistry({\n cursor: createCursorEmitter,\n codex: createCodexEmitter,\n gemini: createGeminiEmitter,\n opencode: createOpencodeEmitter,\n });\n}\n\nfunction resolveTargets(cfg: ReturnType<typeof loadConfig>, opts: Opts): string[] {\n if (opts.target) return [opts.target];\n return cfg.projection?.targets ?? [\"cursor\", \"codex\", \"gemini\"];\n}\n\nasync function runEmit(opts: Opts & { dryRun?: boolean }) {\n if (opts.scope === \"user\" && opts.project) {\n throw new Error(\"--scope user cannot be combined with --project\");\n }\n if (opts.all && (opts.scope || opts.project)) {\n throw new Error(\"--all cannot be combined with --scope or --project\");\n }\n\n const cfg = loadConfig();\n const registry = buildRegistry();\n const workspace: WorkspaceDriver = createObsidianDriver({ root: process.cwd() });\n const targets = resolveTargets(cfg, opts);\n for (const name of targets) registry.get(name); // throws on unknown target\n\n const emittedCount = { written: 0, skipped: 0 };\n\n async function emitForTarget(\n emitter: ProjectionEmitter,\n scope: \"user\" | \"project\",\n source: ProjectionSource,\n projectRoot?: string,\n ) {\n for (const dest of emitter.destinations(scope, projectRoot)) {\n const result = await emitter.emit(source, dest, { dryRun: opts.dryRun });\n if (opts.dryRun) {\n console.log(chalk.cyan(`[${emitter.name}] ${dest.path}`));\n console.log(result.diff ?? \"(no diff)\");\n } else if (result.written) {\n console.log(\n chalk.green(\n `✔ ${emitter.name} → ${dest.path} (${result.bytesWritten} bytes)`,\n ),\n );\n emittedCount.written++;\n } else {\n console.log(chalk.gray(`- ${emitter.name} → ${dest.path} (skipped)`));\n emittedCount.skipped++;\n }\n }\n }\n\n const wantUser =\n opts.scope === \"user\" || opts.all || (!opts.project && !opts.scope);\n const wantProject = opts.scope === \"project\" || opts.all || !!opts.project;\n\n if (wantUser) {\n const source = await readUserLevelSource(workspace, { pkgRoot: findPackageRoot() });\n for (const name of targets) {\n await emitForTarget(registry.get(name), \"user\", source);\n }\n }\n\n if (wantProject) {\n const projectNames = opts.project ? [opts.project] : Object.keys(cfg.projects);\n for (const projectName of projectNames) {\n const proj = cfg.projects[projectName];\n if (!proj) {\n if (opts.project) {\n throw new Error(\n `Unknown project '${projectName}'. Available: ${Object.keys(cfg.projects).join(\", \") || \"(none)\"}`,\n );\n }\n console.error(chalk.yellow(`⚠ unknown project: ${projectName}`));\n continue;\n }\n const source = await readProjectLevelSource(\n createObsidianDriver({ root: proj.path }),\n );\n if (!source) {\n console.log(chalk.gray(`- ${projectName}: no AGENTS.md, skipping`));\n continue;\n }\n for (const name of targets) {\n await emitForTarget(registry.get(name), \"project\", source, proj.path);\n }\n }\n }\n\n if (!opts.dryRun) {\n console.log(\n chalk.bold(\n `\\nProjection complete — ${emittedCount.written} written, ${emittedCount.skipped} skipped.`,\n ),\n );\n }\n}\n\nexport const projectionCommand = new Command(\"projection\").description(\n \"Project squadrant instructions and skills to supported agent formats\",\n);\n\nprojectionCommand\n .command(\"emit\")\n .description(\"Emit projections to disk\")\n .option(\"--scope <scope>\", \"user or project\", parseScope)\n .option(\"--project <name>\", \"managed project name\")\n .option(\"--target <name>\", \"single target (cursor, codex, gemini, opencode)\")\n .option(\"--all\", \"emit user-level + every managed project\")\n .action(async (opts: Opts) => {\n try {\n await runEmit({ ...opts, dryRun: false });\n } catch (err) {\n console.error(chalk.red((err as Error).message));\n process.exit(1);\n }\n });\n\nprojectionCommand\n .command(\"diff\")\n .description(\"Preview changes without writing\")\n .option(\"--scope <scope>\", \"user or project\", parseScope)\n .option(\"--project <name>\", \"managed project name\")\n .option(\"--target <name>\", \"single target (cursor, codex, gemini, opencode)\")\n .option(\"--all\", \"dry-run across user-level + every managed project\")\n .action(async (opts: Opts) => {\n try {\n await runEmit({ ...opts, dryRun: true });\n } catch (err) {\n console.error(chalk.red((err as Error).message));\n process.exit(1);\n }\n });\n\nprojectionCommand\n .command(\"list\")\n .description(\"List registered projection targets\")\n .action(() => {\n const registry = buildRegistry();\n for (const name of registry.list()) {\n const emitter = registry.get(name);\n const userDests = emitter.destinations(\"user\").map((d) => d.path);\n const projectDests = emitter\n .destinations(\"project\", \"<project>\")\n .map((d) => d.path);\n console.log(chalk.bold(name));\n console.log(` user: ${userDests.join(\", \") || \"(none)\"}`);\n console.log(` project: ${projectDests.join(\", \") || \"(none)\"}`);\n }\n });\n","import { Command } from \"commander\";\nimport { AppServerClient } from \"@squadrant/agents\";\nimport { resolve } from \"node:path\";\n\nexport const codexChatSmokeCommand = new Command(\"codex-chat-smoke\")\n .description(\"Phase 1 gate: prove the codex app-server JSON-RPC path works end-to-end.\")\n .option(\"--cwd <dir>\", \"working dir for the codex thread\", process.cwd())\n .option(\"--model <m>\", \"model id (optional)\")\n .option(\n \"--approval\",\n \"include the approval round-trip (Phase 1 PASS requires this)\",\n false\n )\n .action(async (opts: { cwd: string; model?: string; approval: boolean }) => {\n const c = new AppServerClient({ clientInfo: { name: \"squadrant\", version: \"smoke\" } });\n const transcript: string[] = [];\n c.on(\"notification\", (n) =>\n transcript.push(`> ${n.method} ${JSON.stringify(n.params).slice(0, 200)}`)\n );\n c.on(\"stderr\", (s) => transcript.push(`[stderr] ${s.trim()}`));\n try {\n c.start();\n await c.initialize();\n const { threadId } = await c.startThread({\n cwd: resolve(opts.cwd),\n model: opts.model,\n sandbox: \"workspace-write\",\n // With --approval, force untrusted policy so codex requests approval\n // for any tool/shell invocation — proves the round-trip.\n ...(opts.approval ? { approvalPolicy: \"untrusted\" } : {}),\n });\n await c.sendTurn(threadId, \"Reply with exactly: PING-OK\");\n await assertSawText(transcript, \"PING-OK\");\n await c.sendTurn(threadId, \"Now reply with: PONG-OK\");\n await assertSawText(transcript, \"PONG-OK\");\n process.stdout.write(\"smoke: BASIC ok\\n\");\n if (!opts.approval) {\n c.kill();\n return;\n }\n\n // Approval round-trip — Phase-1 GATE.\n const pendingApprovals: Array<{ id: number; method: string }> = [];\n c.on(\"serverRequest\", (r) => {\n pendingApprovals.push({ id: r.id, method: r.method });\n // Approve every approval-shaped request automatically (PASS-by-affirm).\n c.respondToServerRequest(r.id, { decision: \"approve\" });\n });\n // Ask codex to do something that needs approval (writing a file).\n await c.sendTurn(threadId, `Write the text \"approval-ok\" to a file at ${resolve(opts.cwd)}/.squadrant-smoke.txt`);\n if (pendingApprovals.length === 0) {\n throw new Error(\"approval gate: expected at least one server-request (approval/input) during the turn\");\n }\n process.stdout.write(`smoke: APPROVAL ok (${pendingApprovals.length} request(s) handled)\\n`);\n c.kill();\n } catch (e) {\n process.stderr.write(\n `smoke FAIL: ${(e as Error).message}\\n${transcript.join(\"\\n\")}\\n`\n );\n c.kill();\n process.exit(1);\n }\n });\n\nasync function assertSawText(transcript: string[], needle: string): Promise<void> {\n const hit = transcript.some((l) => l.includes(needle));\n if (!hit)\n throw new Error(\n `expected to see '${needle}' in delta stream\\nTranscript:\\n${transcript.join(\"\\n\")}`\n );\n}\n","import { Command } from \"commander\";\nimport fs from \"node:fs\";\nimport { fileURLToPath } from \"node:url\";\nimport { dirname, join } from \"node:path\";\nimport chalk from \"chalk\";\nimport { DEFAULT_CONFIG_PATH, getDefaultConfig, loadConfig, saveConfig, type SquadrantConfig, isDaemonCachedKey } from \"@squadrant/shared\";\nimport { detectDrift, applySafeFixes, type DriftItem } from \"@squadrant/shared\";\nimport { withStamp } from \"@squadrant/shared\";\nimport { restartDaemonIfRunning, type RestartOutcome } from \"../control/restart-daemon.js\";\n\nexport interface ConfigCheckOptions {\n configPath: string;\n pkgVersion: string;\n fix: boolean;\n accept: boolean;\n}\n\nexport interface ConfigCheckResult {\n items: DriftItem[];\n applied: string[];\n remaining: DriftItem[];\n stamped: boolean;\n}\n\nexport function runConfigCheck(opts: ConfigCheckOptions): ConfigCheckResult {\n const raw = JSON.parse(fs.readFileSync(opts.configPath, \"utf-8\")) as SquadrantConfig;\n const def = getDefaultConfig();\n const items = detectDrift(raw, def);\n\n let working = raw;\n let applied: string[] = [];\n\n if (opts.fix) {\n const r = applySafeFixes(raw, items, def);\n working = r.config;\n applied = r.applied;\n }\n\n const remaining = detectDrift(working, def);\n\n let stamped = false;\n if (opts.accept || remaining.length === 0) {\n working = withStamp(working, opts.pkgVersion);\n stamped = true;\n }\n\n if (opts.fix || opts.accept || stamped) {\n fs.writeFileSync(opts.configPath, JSON.stringify(working, null, 2) + \"\\n\");\n }\n\n return { items, applied, remaining, stamped };\n}\n\n/** Read a value at a dotted path (e.g. \"defaults.effort\"). Throws if the path\n * does not resolve. Returns the raw value (stringified by the caller for display). */\nexport function runConfigGet(key: string, configPath = DEFAULT_CONFIG_PATH): unknown {\n const config = loadConfig(configPath);\n const parts = key.split(\".\");\n let node: unknown = config;\n for (const p of parts) {\n if (node === null || typeof node !== \"object\" || !(p in (node as Record<string, unknown>))) {\n throw new Error(`config key not found: ${key}`);\n }\n node = (node as Record<string, unknown>)[p];\n }\n return node;\n}\n\n/** Write a value at a dotted path, creating intermediate objects as needed.\n * The value is JSON-parsed when it parses (numbers/bools/arrays); otherwise the\n * raw string is kept (so `low` stays \"low\", not a parse error). Persists to disk.\n * NOTE: this is a generic local CLI surface; the Telegram channel restricts which\n * keys may be set via WRITABLE_CONFIG_KEYS, so secrets can't be written remotely. */\nexport function runConfigSet(key: string, value: string, configPath = DEFAULT_CONFIG_PATH): void {\n let parsed: unknown;\n try { parsed = JSON.parse(value); } catch { parsed = value; }\n const config = loadConfig(configPath) as unknown as Record<string, unknown>;\n const parts = key.split(\".\");\n let node = config;\n for (let i = 0; i < parts.length - 1; i++) {\n const p = parts[i];\n if (node[p] === null || typeof node[p] !== \"object\") node[p] = {};\n node = node[p] as Record<string, unknown>;\n }\n node[parts[parts.length - 1]] = parsed;\n saveConfig(config as unknown as SquadrantConfig, configPath);\n}\n\nfunction printRestartOutcome(outcome: RestartOutcome): void {\n if (outcome === \"skipped-not-running\") {\n console.log(chalk.dim(\"(daemon not running — change applies on next start)\"));\n } else if (outcome === \"skipped-opt-out\") {\n console.log(chalk.dim(\"(run 'squadrant heal daemon' to apply)\"));\n }\n}\n\nexport function runConfigSetAction(opts: {\n key: string;\n value: string;\n noRestart?: boolean;\n doRestart?: (o: { reason: string; noRestart?: boolean }) => RestartOutcome;\n configPath?: string;\n}): void {\n runConfigSet(opts.key, opts.value, opts.configPath);\n console.log(chalk.green(`✔ set ${opts.key} = ${opts.value}`));\n if (isDaemonCachedKey(opts.key)) {\n const doRestart = opts.doRestart ?? restartDaemonIfRunning;\n const outcome = doRestart({ reason: `config ${opts.key}`, noRestart: opts.noRestart });\n printRestartOutcome(outcome);\n }\n}\n\nconst SEV_COLOR: Record<string, (s: string) => string> = {\n info: chalk.green,\n advisory: chalk.yellow,\n warn: chalk.red,\n};\nconst KIND_GLYPH: Record<string, string> = {\n missing: \"+\",\n deprecated: \"-\",\n \"changed-default\": \"~\",\n invalid: \"\\u2717\",\n};\n\nfunction printItems(items: DriftItem[]): void {\n for (const i of items) {\n const color = SEV_COLOR[i.severity] ?? ((s: string) => s);\n const detail = i.note ? ` (${i.note})` : i.suggested !== undefined ? ` \\u2192 ${JSON.stringify(i.suggested)}` : \"\";\n console.log(\" \" + color(`${KIND_GLYPH[i.kind]} ${i.kind}: ${i.path}`) + chalk.dim(detail));\n }\n}\n\nexport const configCommand = new Command(\"config\").description(\"Inspect and reconcile squadrant config\");\n\nconfigCommand\n .command(\"check\")\n .description(\"Detect config drift vs the current default schema\")\n .option(\"--fix\", \"Apply the safe tier (add missing, remove deprecated)\", false)\n .option(\"--accept\", \"Stamp the current version without changing config (dismiss advisories)\", false)\n .option(\"--json\", \"Output drift items as JSON\", false)\n .action((opts: { fix: boolean; accept: boolean; json: boolean }) => {\n const pkgVersion = readPkgVersion();\n if (!fs.existsSync(DEFAULT_CONFIG_PATH)) {\n console.log(chalk.yellow(\"No config found \\u2014 run `squadrant init` first.\"));\n return;\n }\n const res = runConfigCheck({ configPath: DEFAULT_CONFIG_PATH, pkgVersion, fix: opts.fix, accept: opts.accept });\n\n if (opts.json) {\n console.log(JSON.stringify(res.items, null, 2));\n return;\n }\n\n if (res.items.length === 0) {\n console.log(chalk.green(\"\\u2714 Config is in sync with the current schema.\"));\n return;\n }\n\n console.log(chalk.bold(\"\\nConfig drift:\\n\"));\n printItems(res.items);\n\n if (opts.fix && res.applied.length) {\n console.log(chalk.green(`\\n\\u2714 Applied ${res.applied.length} safe item(s): ${res.applied.join(\", \")}`));\n }\n const judgment = res.remaining.filter((i) => i.kind === \"changed-default\" || i.kind === \"invalid\");\n if (judgment.length) {\n console.log(chalk.yellow(`\\n${judgment.length} item(s) need review \\u2014 run the config-doctor skill, or \\`squadrant config check --accept\\` to keep your values.`));\n } else if (res.stamped) {\n console.log(chalk.green(\"\\n\\u2714 Config reconciled and stamped.\"));\n }\n });\n\nconfigCommand\n .command(\"get\")\n .description(\"Read a config value by dotted key (e.g. defaults.effort)\")\n .argument(\"<key>\", \"dotted config key\")\n .action((key: string) => {\n try {\n const value = runConfigGet(key);\n console.log(typeof value === \"string\" ? value : JSON.stringify(value));\n } catch (e) {\n console.error(chalk.red((e as Error).message));\n process.exit(1);\n }\n });\n\nconfigCommand\n .command(\"set\")\n .description(\"Write a config value by dotted key (e.g. defaults.effort low)\")\n .argument(\"<key>\", \"dotted config key\")\n .argument(\"<value>\", \"value (JSON-parsed when possible, else a bare string)\")\n .option(\"--no-restart\", \"skip daemon restart even if the key is daemon-cached\")\n .action((key: string, value: string, opts: { restart?: boolean }) => {\n try {\n runConfigSetAction({ key, value, noRestart: opts.restart === false });\n } catch (e) {\n console.error(chalk.red((e as Error).message));\n process.exit(1);\n }\n });\n\nfunction readPkgVersion(): string {\n const pkgPath = join(dirname(fileURLToPath(import.meta.url)), \"..\", \"package.json\");\n return JSON.parse(fs.readFileSync(pkgPath, \"utf-8\")).version as string;\n}\n","// src/commands/heal.ts\n//\n// squadrant heal <component> — targeted, idempotent, machine-readable remediation\n// surface for the detect → notify → remediate loop (#234).\n//\n// Subcommands:\n// heal status — dry-run: print unhealthy components + the exact heal command\n// heal daemon — restart squadrantd via the existing launchd kickstart path\n//\n// DEFERRED: heal crew <id> — re-attach a stuck crew task (overlaps #100, more\n// complex; explicitly out of MVP scope).\nimport { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport { queryHealth } from \"./health-view.js\";\nimport { healCmdFor } from \"@squadrant/core\";\nimport type { ComponentHealth, HealthState } from \"@squadrant/core\";\nimport { restartDaemonIfRunning } from \"../control/restart-daemon.js\";\n\n// ── pure helpers (fully unit-testable, no I/O) ────────────────────────────────\n\n// Re-exported so existing consumers (tests + external code) that import from\n// this module continue to work without changes.\nexport { healCmdFor };\n\nexport interface HealComponent {\n kind: ComponentHealth[\"kind\"];\n project: string;\n ref: string;\n state: HealthState;\n healCmd: string | null;\n}\n\nexport interface HealStatusResult {\n healthy: boolean;\n daemonUnreachable?: boolean;\n components: HealComponent[];\n}\n\n/**\n * Pure. Assemble the HealStatusResult from a raw liveness snapshot.\n * null input = daemon unreachable.\n */\nexport function buildHealStatus(components: ComponentHealth[] | null): HealStatusResult {\n if (components === null) {\n return { healthy: false, daemonUnreachable: true, components: [] };\n }\n const out: HealComponent[] = components.map((c) => ({\n kind: c.kind,\n project: c.project,\n ref: c.ref,\n state: c.state,\n healCmd: healCmdFor(c),\n }));\n const healthy = out.every((c) => c.healCmd === null);\n return { healthy, components: out };\n}\n\n// ── injectable runners (used by Commander actions + tests) ────────────────────\n\nexport interface HealStatusOpts {\n project: string | undefined;\n json: boolean;\n queryHealth: typeof queryHealth;\n stdout: NodeJS.WritableStream;\n stderr: NodeJS.WritableStream;\n}\n\n/** Returns exit code: 0=all healthy, 1=error/daemon-unreachable, 2=unhealthy */\nexport async function runHealStatus(opts: HealStatusOpts): Promise<number> {\n const { project, json, stdout, stderr } = opts;\n let rows: ComponentHealth[] | null;\n try {\n rows = await opts.queryHealth(project);\n } catch (e) {\n stderr.write(`heal status: ${(e as Error).message}\\n`);\n return 1;\n }\n\n const result = buildHealStatus(rows);\n\n if (result.daemonUnreachable) {\n if (json) {\n stdout.write(JSON.stringify({ healthy: false, daemonUnreachable: true, components: [] }) + \"\\n\");\n } else {\n stderr.write(\"daemon unreachable — start the daemon first (squadrant heal daemon)\\n\");\n }\n return 1;\n }\n\n if (json) {\n stdout.write(JSON.stringify(result) + \"\\n\");\n return result.healthy ? 0 : 2;\n }\n\n if (result.healthy) {\n stdout.write(chalk.green(\"✔ all components healthy\\n\"));\n return 0;\n }\n\n stdout.write(chalk.bold(\"Unhealthy components:\\n\\n\"));\n for (const c of result.components) {\n if (c.healCmd) {\n stdout.write(` ${chalk.red(\"✘\")} ${c.kind.padEnd(8)} ${c.ref.padEnd(16)} ${chalk.red(c.state.padEnd(8))} ${c.project}\\n`);\n stdout.write(` heal: ${chalk.cyan(c.healCmd)}\\n`);\n }\n }\n return 2;\n}\n\nexport interface HealDaemonOpts {\n ensureDaemon: () => void;\n stdout: NodeJS.WritableStream;\n stderr: NodeJS.WritableStream;\n}\n\n/** Returns exit code: 0=success, 1=error */\nexport async function runHealDaemon(opts: HealDaemonOpts): Promise<number> {\n const { stdout, stderr } = opts;\n stdout.write(\"restarting squadrantd via launchd kickstart...\\n\");\n try {\n opts.ensureDaemon();\n stdout.write(chalk.green(\"✔ daemon kickstart complete\\n\"));\n return 0;\n } catch (e) {\n stderr.write(`heal daemon failed: ${(e as Error).message}\\n`);\n return 1;\n }\n}\n\n// ── Commander command tree ────────────────────────────────────────────────────\n\nexport const healCommand = new Command(\"heal\")\n .description(\"Targeted, idempotent remediation for squadrant components (daemon, health)\")\n .addHelpText(\"after\", \"\\nDeferred: 'squadrant heal crew <id>' (re-attach) — see issue #100.\")\n .addCommand(\n new Command(\"status\")\n .description(\"Dry-run: print unhealthy components and the exact heal command for each\")\n .option(\"-p, --project <project>\", \"scope to one project\")\n .option(\"--json\", \"output machine-readable JSON (exit 0=healthy, 1=error, 2=unhealthy)\")\n .action(async (opts: { project?: string; json?: boolean }) => {\n const code = await runHealStatus({\n project: opts.project,\n json: opts.json ?? false,\n queryHealth,\n stdout: process.stdout,\n stderr: process.stderr,\n });\n process.exit(code);\n }),\n )\n .addCommand(\n new Command(\"daemon\")\n .description(\"Restart squadrantd via the idempotent launchd kickstart path\")\n .action(async () => {\n const code = await runHealDaemon({\n ensureDaemon: () => restartDaemonIfRunning({ reason: \"heal\", isRunning: () => true }),\n stdout: process.stdout,\n stderr: process.stderr,\n });\n process.exit(code);\n }),\n );\n","// src/commands/group.ts\n//\n// #246: cross-project intra-group delegation. `squadrant group dispatch`\n// sends a task to a sibling project in the same group. The target's captain\n// is woken via the existing mailbox/relay path. A dispatches-and-yields;\n// the origin captain is auto-woken when the task settles (report-back).\n\nimport { Command } from \"commander\";\nimport { execSync } from \"node:child_process\";\nimport { randomUUID } from \"node:crypto\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport chalk from \"chalk\";\nimport { loadConfig, resolveHome, type SquadrantConfig } from \"@squadrant/shared\";\nimport { sendRequest } from \"@squadrant/core\";\nimport type { TaskRecord, Provider, Mode } from \"@squadrant/shared\";\n\nconst SOCK = join(homedir(), \".config\", \"squadrant\", \"squadrant.sock\");\n// #288: 30s was too short — cold captain boot + relay supervisor startup takes\n// 45-90s. 120s gives the full chain (Claude init + checklist + relay register)\n// comfortable headroom while still failing fast on a genuinely broken launch.\nconst WARMUP_TIMEOUT_MS = 120_000;\nconst WARMUP_POLL_MS = 1_000;\n\n/** Resolve the current project name by matching cwd against config paths. */\nexport function resolveCurrentProject(config: SquadrantConfig): string | null {\n const cwd = process.cwd();\n for (const [name, proj] of Object.entries(config.projects)) {\n const resolvedPath = resolveHome(proj.path);\n if (cwd.startsWith(resolvedPath)) return name;\n }\n return null;\n}\n\n/** Check via the daemon health endpoint whether a project's captain is up. */\nasync function isCaptainAlive(project: string): Promise<boolean> {\n try {\n const health = (await sendRequest(SOCK, { kind: \"health\", project }, 5000)) as Array<{\n kind: string; project: string; state: string;\n }>;\n const captain = health?.find((h) => h.kind === \"captain\" && h.project === project);\n return captain != null && captain.state !== \"gone\" && captain.state !== \"unknown\";\n } catch {\n return false;\n }\n}\n\n/** Poll the daemon health endpoint until the target project's captain is up,\n * or the hard timeout expires. Returns true if warmup succeeded. */\nexport async function waitForWarmup(\n project: string,\n timeoutMs = WARMUP_TIMEOUT_MS,\n pollMs = WARMUP_POLL_MS,\n): Promise<boolean> {\n const deadline = Date.now() + timeoutMs;\n while (Date.now() < deadline) {\n if (await isCaptainAlive(project)) return true;\n await new Promise((r) => setTimeout(r, pollMs));\n }\n return false;\n}\n\nexport interface GroupDispatchOpts {\n fromProject: string;\n toProject: string;\n task: string;\n provider?: Provider;\n mode?: Mode;\n warmupTimeoutMs?: number;\n warmupPollMs?: number;\n}\n\n/** Pure-ish dispatch function (extracted for testability). */\nexport async function runGroupDispatch(opts: GroupDispatchOpts): Promise<TaskRecord> {\n const config = loadConfig();\n const fromCfg = config.projects[opts.fromProject];\n const toCfg = config.projects[opts.toProject];\n\n if (!toCfg) {\n throw new Error(`target project '${opts.toProject}' not found in config`);\n }\n\n // #246: same-group gate — hard boundary\n if (!fromCfg.group || !toCfg.group || fromCfg.group !== toCfg.group) {\n throw new Error(\n `cannot dispatch: '${opts.toProject}' (group: ${toCfg.group ?? \"none\"}) ` +\n `is not in the same group as '${opts.fromProject}' (group: ${fromCfg.group ?? \"none\"})`,\n );\n }\n\n // #246: acceptDelegations check\n if (toCfg.acceptDelegations === false) {\n throw new Error(\n `cannot dispatch to '${opts.toProject}': project has acceptDelegations set to false`,\n );\n }\n\n // Ensure B's captain is up\n const alive = await isCaptainAlive(opts.toProject);\n if (!alive) {\n try {\n execSync(`squadrant launch ${opts.toProject}`, { stdio: \"ignore\", timeout: 15_000 });\n } catch {\n throw new Error(`failed to launch captain for '${opts.toProject}' — is squadrant installed?`);\n }\n\n const warmed = await waitForWarmup(opts.toProject, opts.warmupTimeoutMs, opts.warmupPollMs);\n if (!warmed) {\n throw new Error(\n `dispatch to '${opts.toProject}' timed out waiting for captain warmup ` +\n `(>${(opts.warmupTimeoutMs ?? WARMUP_TIMEOUT_MS) / 1000}s)`,\n );\n }\n }\n\n // Record the task via the daemon\n const now = Date.now();\n const attemptId = randomUUID();\n const record: TaskRecord = {\n id: randomUUID(),\n project: opts.toProject,\n originProject: opts.fromProject,\n provider: opts.provider ?? \"claude\",\n mode: opts.mode ?? \"headless\",\n state: \"submitted\",\n task: opts.task,\n createdAt: now,\n lastHeartbeat: now,\n lastEvent: \"dispatch\",\n heartbeatBudgetMs: 300000,\n attempts: [{ attemptId, startedAt: now, lastHeartbeatAt: now }],\n };\n\n const result = await sendRequest(SOCK, { kind: \"dispatch\", record }) as TaskRecord;\n return result;\n}\n\n// ── CLI command ──────────────────────────────────────────────────────────────\n\nexport const groupCommand = new Command(\"group\")\n .description(\"Cross-project intra-group operations (Phase 1: dispatch)\")\n .addCommand(\n new Command(\"dispatch\")\n .description(\"Dispatch a task to a sibling project in the same group\")\n .argument(\"<to-project>\", \"Target project name (must be in the same group)\")\n .argument(\"<task>\", \"Task description to dispatch\")\n .option(\"--provider <p>\", \"claude|opencode|codex\", \"claude\")\n .option(\"--mode <m>\", \"headless|interactive\", \"headless\")\n .option(\"--warmup-timeout <s>\", \"seconds to wait for target captain relay to boot (default: 120)\", (v) => parseInt(v, 10) * 1000)\n .action(async (toProject: string, task: string, opts: { provider?: Provider; mode?: Mode; warmupTimeout?: number }) => {\n const fromProject = resolveCurrentProject(loadConfig());\n if (!fromProject) {\n console.error(chalk.red(\"Could not determine current project from cwd. Run from inside a registered project directory.\"));\n process.exit(1);\n }\n\n try {\n const result = await runGroupDispatch({\n fromProject,\n toProject,\n task,\n provider: opts.provider,\n mode: opts.mode,\n warmupTimeoutMs: opts.warmupTimeout,\n });\n console.log(chalk.green(`✔ Dispatched to '${toProject}' (task ${result.id.slice(0, 8)})`));\n console.log(chalk.dim(` originProject: ${result.originProject ?? \"none\"}`));\n console.log(chalk.dim(\" You will be notified when the task settles (done/blocked/failed).\"));\n } catch (e) {\n console.error(chalk.red(`✘ ${(e as Error).message}`));\n process.exit(1);\n }\n }),\n );\n","// src/commands/cmux.ts\n//\n// squadrant cmux autoconfig — #348 (part of #332). User-facing surface for the\n// cmux socket auto-config: write the comment-preserving automation config, probe\n// the live socket from a non-cmux process, and tell the user whether a cmux\n// restart is needed to enable daemon-direct delivery.\n//\n// See docs/specs/2026-06-16-cmux-socket-auth-daemon-direct-design.md §4.\nimport { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport { ensureCmuxAutoConfig, type AutoConfigResult } from \"@squadrant/shared\";\n\nexport interface CmuxAutoconfigOpts {\n json: boolean;\n stdout: NodeJS.WritableStream;\n stderr: NodeJS.WritableStream;\n /** Injectable for tests. Default = ensureCmuxAutoConfig (real I/O). */\n run?: () => Promise<AutoConfigResult>;\n}\n\n/** Returns exit code: 0=reachable, 1=unknown/error, 2=restart needed. */\nexport async function runCmuxAutoconfig(opts: CmuxAutoconfigOpts): Promise<number> {\n const { json, stdout, stderr } = opts;\n let r: AutoConfigResult;\n try {\n r = await (opts.run ?? ensureCmuxAutoConfig)();\n } catch (e) {\n stderr.write(`cmux autoconfig failed: ${(e as Error).message}\\n`);\n return 1;\n }\n\n if (json) {\n stdout.write(JSON.stringify(r) + \"\\n\");\n return r.verdict === \"reachable\" ? 0 : r.needsRestart ? 2 : 1;\n }\n\n if (r.configChanged) {\n stdout.write(`wrote cmux automation config → ${r.configPath}\\n`);\n } else {\n stdout.write(chalk.dim(`cmux automation config already in place (${r.configPath})\\n`));\n }\n\n if (r.verdict === \"reachable\") {\n stdout.write(chalk.green(\"✔ daemon-direct delivery is reachable — cmux control socket accepts the daemon\\n\"));\n return 0;\n }\n\n if (r.needsRestart) {\n stdout.write(\n chalk.yellow(\"⚠ cmux is still on the old socket mode — restart cmux to enable daemon-direct delivery.\\n\"),\n );\n if (r.promptedThisRun) {\n stdout.write(chalk.dim(\" (one-time prompt — you won't be nagged again)\\n\"));\n }\n return 2;\n }\n\n // unknown — fail soft.\n stderr.write(\n \"could not reach the cmux control socket (is cmux installed and running?) — staying on the relay.\\n\",\n );\n return 1;\n}\n\nexport const cmuxCommand = new Command(\"cmux\")\n .description(\"cmux integration helpers\")\n .addCommand(\n new Command(\"autoconfig\")\n .description(\n \"Write the cmux automation socket config and probe whether daemon-direct\\n\" +\n \"delivery is reachable. Idempotent; prompts once if a cmux restart is needed.\",\n )\n .option(\"--json\", \"output machine-readable JSON (exit 0=reachable, 1=unknown, 2=restart-needed)\")\n .action(async (opts: { json?: boolean }) => {\n const code = await runCmuxAutoconfig({\n json: opts.json ?? false,\n stdout: process.stdout,\n stderr: process.stderr,\n });\n process.exit(code);\n }),\n );\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport { loadConfig, saveConfig, resolveEffort, DEFAULT_CONFIG_PATH } from \"@squadrant/shared\";\nimport type { SquadrantConfig, Effort } from \"@squadrant/shared\";\n\nconst VALID_EFFORTS: Effort[] = [\"max\", \"balance\", \"low\"];\n\nconst EFFORT_MEANING: Record<Effort, string> = {\n max: \"tokens are plentiful — bias crew spawns toward claude/opus\",\n balance: \"normal routing — use default crew routing rules unchanged\",\n low: \"conserve tokens — bias crew spawns toward opencode/sonnet; reserve opus for work that genuinely needs it\",\n};\n\nexport interface EffortGetResult {\n effort: Effort;\n description: string;\n}\n\nexport function runEffortGet(configPath = DEFAULT_CONFIG_PATH): EffortGetResult {\n const config = loadConfig(configPath);\n const effort = resolveEffort(config);\n const description = `${effort}: ${EFFORT_MEANING[effort]}`;\n return { effort, description };\n}\n\nexport function runEffortSet(value: string, configPath = DEFAULT_CONFIG_PATH): void {\n if (!(VALID_EFFORTS as string[]).includes(value)) {\n throw new Error(\n `Invalid effort '${value}'. Valid values: ${VALID_EFFORTS.join(\" | \")}`,\n );\n }\n const config = loadConfig(configPath);\n config.defaults.effort = value as Effort;\n saveConfig(config, configPath);\n}\n\n/** Minimal slice of RuntimeDriver used to notify a captain. */\ninterface EffortNotifyDriver {\n status(nameOrId: string): Promise<{ id: string } | null>;\n send(ref: string, message: string): Promise<void>;\n}\n\n/** Resolve a path through symlinks; fall back to a plain resolve if it\n * doesn't exist on disk (e.g. a stale/unmounted project entry). */\nfunction canonical(p: string): string {\n try {\n return fs.realpathSync(p);\n } catch {\n return path.resolve(p);\n }\n}\n\n/**\n * Send the effort-change notice to every running captain EXCEPT the one in the\n * current working directory. The captain that ran `squadrant effort` already saw\n * the stdout '✔ effort → ...' confirmation, so injecting the notice into its own\n * pane is a duplicate self-notification. Other running captains still get it.\n */\nexport async function notifyCaptainsOfEffort(\n effort: Effort,\n config: SquadrantConfig,\n driver: EffortNotifyDriver,\n cwd: string = process.cwd(),\n): Promise<void> {\n const here = canonical(cwd);\n const notice = `🎚️ effort → ${effort}: ${EFFORT_MEANING[effort]}`;\n for (const [, proj] of Object.entries(config.projects)) {\n // Skip the captain running in this same directory — it already saw stdout.\n if (canonical(proj.path) === here) continue;\n try {\n const ref = await driver.status(proj.captainName);\n if (ref) {\n await driver.send(ref.id, notice);\n }\n } catch {\n // individual project captain unreachable — skip\n }\n }\n}\n\nexport const effortCommand = new Command(\"effort\")\n .description(\"Get or set the global crew tokenomics dial (max | balance | low)\")\n .argument(\"[value]\", \"effort level to set: max | balance | low\")\n .action(async (value: string | undefined) => {\n if (value === undefined) {\n const { effort, description } = runEffortGet();\n console.log(chalk.bold(\"Current effort:\"), chalk.cyan(effort));\n console.log(chalk.dim(EFFORT_MEANING[effort]));\n return;\n }\n\n try {\n runEffortSet(value);\n } catch (err) {\n console.error(chalk.red((err as Error).message));\n process.exit(1);\n }\n\n const effort = value as Effort;\n console.log(chalk.green(`✔ effort → ${effort}`));\n console.log(chalk.dim(EFFORT_MEANING[effort]));\n\n // Best-effort active notify: send a one-line notice to any running captain.\n // Never hard-fails — config is already written above.\n try {\n const { createCmuxDriver, RuntimeRegistry } = await import(\"@squadrant/workspaces\");\n const config = loadConfig();\n const registry = new RuntimeRegistry({ cmux: createCmuxDriver() });\n const driver = registry.global(config);\n await notifyCaptainsOfEffort(effort, config, driver);\n } catch {\n // runtime unavailable — config already written, change applies on next launch\n console.log(chalk.dim(\"(no running captain detected — change applies on next launch)\"));\n }\n });\n","import { join, dirname } from \"node:path\";\nimport { emitKeypressEvents } from \"node:readline\";\nimport { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport { loadConfig, DEFAULT_CONFIG_PATH, saveProjectOverride, resolveNotify, loadProjectOverride, isQuieter } from \"@squadrant/shared\";\nimport type { SquadrantConfig, TelegramConfig, NotifyConfig, CrewTier } from \"@squadrant/shared\";\nimport { createTelegramClient, loadState, setTopic, topicKey, topicName, detectGroupAndUser, writeTelegramConfig, maskToken, isNotifyActive, setNotify, BOT_COMMANDS, resolveSetupGroup } from \"@squadrant/core\";\nimport type { TelegramClient } from \"@squadrant/core\";\nimport { restartDaemonIfRunning, type RestartOutcome } from \"../control/restart-daemon.js\";\n\n/** Daemon state root (mirrors buildContext): ~/.config/squadrant/state. */\nfunction defaultStateRoot(): string {\n return join(dirname(DEFAULT_CONFIG_PATH), \"state\");\n}\n\nexport interface TelegramStatusResult {\n tokenSet: boolean;\n supergroupId: number | null;\n links: Array<{ project: string; scope: string; topicId: number }>;\n}\n\nexport function runTelegramStatus(opts: {\n config: SquadrantConfig;\n stateRoot: string;\n env?: NodeJS.ProcessEnv;\n}): TelegramStatusResult {\n const tg = opts.config.telegram;\n const env = opts.env ?? process.env;\n const tokenSet = !!(tg?.botToken ?? env.TELEGRAM_BOT_TOKEN);\n const links = Object.entries(loadState(opts.stateRoot).topics).map(([key, topicId]) => {\n const sep = key.indexOf(\"::\");\n return { project: key.slice(0, sep), scope: key.slice(sep + 2), topicId };\n });\n return { tokenSet, supergroupId: tg?.supergroupId ?? null, links };\n}\n\n/** Send a message to a project's linked Telegram topic. */\nexport async function runTelegramSend(opts: {\n project: string;\n message: string;\n cfg: TelegramConfig;\n client: TelegramClient;\n stateRoot: string;\n}): Promise<{ chatId: number; topicId: number }> {\n const topicId = loadState(opts.stateRoot).topics[topicKey(opts.project)];\n if (topicId === undefined) {\n throw new Error(`project \"${opts.project}\" is not linked — run: squadrant telegram link ${opts.project}`);\n }\n await opts.client.sendMessage(opts.cfg.supergroupId, topicId, opts.message);\n return { chatId: opts.cfg.supergroupId, topicId };\n}\n\n/** Set a project's notification flag in telegram-state.json. */\nexport function runTelegramNotifySet(opts: { project: string; active: boolean; stateRoot: string }): void {\n setNotify(opts.stateRoot, opts.project, opts.active);\n}\n\n/** Write a deliberate per-project notification preference (crew tier / cap) to\n * projects/<name>.json. Distinct from live on|off state (telegram-state.json). */\nexport function runTelegramNotifyPref(\n args: { project: string; dimension: \"crew\" | \"cap\"; value: string; root?: string },\n): { ok: true } | { ok: false; message: string } {\n const { project, dimension, value, root } = args;\n if (dimension === \"crew\") {\n if (![\"all\", \"alert_only\", \"done_only\", \"none\"].includes(value))\n return { ok: false, message: \"crew must be all|alert_only|done_only|none\" };\n saveProjectOverride(project, { telegram: { notify: { crew: value as any } } }, root);\n return { ok: true };\n }\n if (value !== \"on\" && value !== \"off\") return { ok: false, message: \"cap must be on|off\" };\n saveProjectOverride(project, { telegram: { notify: { cap: value === \"on\" } } }, root);\n return { ok: true };\n}\n\n/** Resolved `cap` for a project — whether explicit captain messages may be sent.\n * `cap=false` is the deliberate \"don't let the captain DM me\" switch; live\n * idle-mute (active) is intentionally NOT consulted here (an explicit push\n * shouldn't be dropped just because the topic is idle-muted). */\nexport function capAllowed(project: string, globalNotify: TelegramConfig[\"notify\"], root?: string): boolean {\n return resolveNotify(globalNotify, loadProjectOverride(project, root)).cap;\n}\n\n/** List every known project (union of linked topics and notify keys) with its state. */\nexport function runTelegramNotifyStatus(opts: { stateRoot: string }): Array<{ project: string; active: boolean }> {\n const s = loadState(opts.stateRoot);\n const projects = new Set<string>();\n for (const key of Object.keys(s.topics)) {\n const sep = key.indexOf(\"::\");\n projects.add(sep === -1 ? key : key.slice(0, sep));\n }\n for (const p of Object.keys(s.notify)) projects.add(p);\n return [...projects].map((project) => ({ project, active: s.notify[project] === true }));\n}\n\n/** Bind a project to a forum topic, creating it on first link. Idempotent. */\nexport async function runTelegramLink(opts: {\n project: string;\n cfg: TelegramConfig;\n client: TelegramClient;\n stateRoot: string;\n}): Promise<{ topicId: number; created: boolean }> {\n const existing = loadState(opts.stateRoot).topics[topicKey(opts.project)];\n if (existing !== undefined) return { topicId: existing, created: false };\n const topicId = await opts.client.createForumTopic(opts.cfg.supergroupId, topicName(opts.project));\n setTopic(opts.stateRoot, opts.project, topicId);\n return { topicId, created: true };\n}\n\n// Reads a secret from stdin, printing \"*\" per character. The caller must print\n// the visible label before calling this — raw mode is active only during input.\nexport async function questionMasked(): Promise<string> {\n return new Promise<string>((resolve) => {\n emitKeypressEvents(process.stdin);\n process.stdin.setRawMode(true);\n process.stdin.resume();\n\n let answer = \"\";\n\n const onKeypress = (_str: string | undefined, key: { name: string; ctrl: boolean; meta: boolean; sequence: string }) => {\n if (key.ctrl && key.name === \"c\") {\n process.stdin.removeListener(\"keypress\", onKeypress as any);\n process.stdin.setRawMode(false);\n process.stdin.pause();\n process.stdout.write(\"\\n\");\n process.exit(130);\n } else if (key.name === \"return\" || key.name === \"enter\") {\n process.stdin.removeListener(\"keypress\", onKeypress as any);\n process.stdin.setRawMode(false);\n process.stdin.pause();\n process.stdout.write(\"\\n\");\n resolve(answer);\n } else if (key.name === \"backspace\") {\n if (answer.length > 0) {\n answer = answer.slice(0, -1);\n process.stdout.write(\"\\b \\b\");\n }\n } else if (!key.ctrl && !key.meta && key.sequence) {\n answer += key.sequence;\n process.stdout.write(\"*\");\n }\n };\n\n process.stdin.on(\"keypress\", onKeypress as any);\n });\n}\n\n// Visible yes/no prompt (default No). Used for opt-ins where masking is wrong.\n// Pauses stdin afterward so the process can exit cleanly (prior wizard-hang fix).\nasync function questionYesNo(prompt: string): Promise<boolean> {\n const { createInterface } = await import(\"node:readline\");\n const rl = createInterface({ input: process.stdin, output: process.stdout });\n return new Promise<boolean>((resolve) => {\n rl.question(prompt, (ans) => {\n rl.close();\n process.stdin.pause();\n resolve(/^y(es)?$/i.test(ans.trim()));\n });\n });\n}\n\nfunction confirmationText(project: string, before: NotifyConfig, after: NotifyConfig, dim: \"active\" | \"cap\" | \"crew\"): string {\n if (dim === \"active\") return `🔕 ${project} — all notifications muted here. Unmute: squadrant telegram notify ${project} on`;\n if (dim === \"cap\") return `🔕 ${project} — captain messages muted here. Re-enable: squadrant telegram notify ${project} cap on`;\n return `🔕 ${project} — crew notifications now '${after.crew}' (was '${before.crew}'). Re-enable: squadrant telegram notify ${project} crew ${before.crew}`;\n}\n\n/** Send a one-time mute confirmation directly to the project topic, bypassing all delivery gates.\n * Returns true if the message was sent, false if skipped (not quieter / no topic) or failed. */\nexport async function runNotifyConfirmation(opts: {\n project: string;\n before: NotifyConfig;\n after: NotifyConfig;\n cfg: TelegramConfig;\n client: TelegramClient;\n stateRoot: string;\n}): Promise<boolean> {\n const { quieter, dim } = isQuieter(opts.before, opts.after);\n if (!quieter || dim === null) return false;\n const topicId = loadState(opts.stateRoot).topics[topicKey(opts.project)];\n if (topicId === undefined) return false;\n const text = confirmationText(opts.project, opts.before, opts.after, dim);\n try {\n await opts.client.sendMessage(opts.cfg.supergroupId, topicId, text);\n return true;\n } catch {\n console.warn(`[squadrant] mute-confirmation send failed for ${opts.project} — notification preference was still saved`);\n return false;\n }\n}\n\nexport function resolveSetupToken(\n existingToken: string | undefined,\n opts: { resetToken: boolean },\n): \"prompt\" | \"try-reuse\" {\n if (opts.resetToken || !existingToken) return \"prompt\";\n return \"try-reuse\";\n}\n\n/**\n * Precedence: explicit --user-id flag > detected userId (first-run getUpdates) >\n * lastUserId persisted in telegram-state.json by the bridge poll (passive capture).\n */\nexport function resolveSetupUserId(\n flagUserId: number | undefined,\n detectedUserId: number | undefined,\n stateRoot: string,\n): number | undefined {\n return flagUserId ?? detectedUserId ?? loadState(stateRoot).lastUserId;\n}\n\nexport async function runRegisterCommands(opts: { client: TelegramClient }): Promise<void> {\n await opts.client.setMyCommands(BOT_COMMANDS);\n}\n\nexport function runTelegramPostSetup(opts: {\n doRestart?: (o: { reason: string }) => RestartOutcome;\n}): void {\n const doRestart = opts.doRestart ?? restartDaemonIfRunning;\n const outcome = doRestart({ reason: \"telegram config\" });\n if (outcome === \"skipped-not-running\") {\n console.log(chalk.dim(\"(daemon not running — change applies on next start)\"));\n } else if (outcome === \"skipped-opt-out\") {\n console.log(chalk.dim(\"(run 'squadrant heal daemon' to apply)\"));\n }\n}\n\nexport const telegramCommand = new Command(\"telegram\")\n .description(\"Two-way Telegram integration: push crew events to a topic and reply into the captain pane\");\n\ntelegramCommand\n .command(\"status\")\n .description(\"Show Telegram config and linked projects\")\n .action(() => {\n const { tokenSet, supergroupId, links } = runTelegramStatus({ config: loadConfig(), stateRoot: defaultStateRoot() });\n console.log(`token: ${tokenSet ? chalk.green(\"set\") : chalk.yellow(\"unset\")}`);\n console.log(`supergroup: ${supergroupId ?? chalk.yellow(\"unset\")}`);\n if (links.length === 0) {\n console.log(\"no projects linked\");\n return;\n }\n for (const l of links) console.log(` ${l.project} (${l.scope}) → topic ${l.topicId}`);\n });\n\ntelegramCommand\n .command(\"link\")\n .argument(\"<project>\", \"project to bind to a Telegram topic\")\n .description(\"Create (or reuse) a forum topic for a project and bind it\")\n .action(async (project: string) => {\n const cfg = loadConfig().telegram;\n if (!cfg) {\n console.error(chalk.red(\"telegram config absent — add a `telegram` block to ~/.config/squadrant/config.json\"));\n process.exit(1);\n }\n const token = cfg.botToken ?? process.env.TELEGRAM_BOT_TOKEN;\n if (!token) {\n console.error(chalk.red(\"no botToken in config and TELEGRAM_BOT_TOKEN is unset\"));\n process.exit(1);\n }\n const client = createTelegramClient({ token });\n const { topicId, created } = await runTelegramLink({ project, cfg, client, stateRoot: defaultStateRoot() });\n console.log(chalk.green(`${created ? \"linked\" : \"already linked\"}: ${project} → topic ${topicId}`));\n });\n\ntelegramCommand\n .command(\"setup\")\n .description(\"Interactive wizard — bot token, validate, auto-detect supergroup, write config\")\n .option(\"--reset-token\", \"force re-entry of the bot token even if one already exists\")\n .option(\"--redetect\", \"force group re-detection even when a supergroup is already configured\")\n .option(\"--user-id <id>\", \"allowlist user-id — enables remote control on a re-run without getUpdates detection\", (v: string) => parseInt(v, 10))\n .action(async (opts: { resetToken?: boolean; redetect?: boolean; userId?: number }) => {\n if (!process.stdin.isTTY) {\n console.error(chalk.red(\"setup requires a TTY — pipe input is not supported\"));\n process.exit(1);\n }\n\n // Banner\n console.log();\n console.log(chalk.bold(\"Telegram setup\") + \" — connect squadrant to a Telegram bot for notifications + remote control\");\n console.log();\n console.log(\"Before you start you need:\");\n console.log(\" 1. A bot token from @BotFather (send /newbot)\");\n console.log(\" 2. A forum supergroup with the bot added as an admin (Topics enabled)\");\n console.log(\" 3. Bot privacy mode set to OFF (@BotFather → /setprivacy → Disable)\");\n console.log();\n\n // Step 1/3 — Bot token (reuse if present unless --reset-token)\n console.log(chalk.bold(\"Step 1/3 — Bot token\"));\n const existingCfg = loadConfig().telegram;\n const existingToken = existingCfg?.botToken ?? process.env.TELEGRAM_BOT_TOKEN;\n const decision = resolveSetupToken(existingToken, { resetToken: opts.resetToken ?? false });\n\n let token: string;\n let client: TelegramClient;\n let botUser: { id: number; username: string };\n\n if (decision === \"try-reuse\") {\n client = createTelegramClient({ token: existingToken! });\n try {\n botUser = await client.getMe();\n token = existingToken!;\n console.log(chalk.green(`Using existing bot token (@${botUser.username})`));\n console.log();\n } catch {\n console.log(chalk.yellow(\"Existing token is invalid — please enter a new one.\"));\n console.log(\"Paste your bot token then press Enter (input is hidden):\");\n token = await questionMasked();\n if (!token) { console.error(chalk.red(\"token required\")); process.exit(1); }\n client = createTelegramClient({ token });\n try {\n botUser = await client.getMe();\n } catch (e) {\n console.error(chalk.red(`token rejected: ${(e as Error).message}`));\n process.exit(1);\n }\n console.log(chalk.green(`Connected as @${botUser.username}`));\n console.log();\n }\n } else {\n console.log(\"Paste your bot token then press Enter (input is hidden):\");\n token = await questionMasked();\n if (!token) { console.error(chalk.red(\"token required\")); process.exit(1); }\n client = createTelegramClient({ token });\n try {\n botUser = await client.getMe();\n } catch (e) {\n console.error(chalk.red(`token rejected: ${(e as Error).message}`));\n process.exit(1);\n }\n console.log(chalk.green(`Connected as @${botUser.username}`));\n console.log();\n }\n\n // Step 2/3 — Supergroup (reuse if already configured and --redetect not passed)\n console.log(chalk.bold(\"Step 2/3 — Supergroup\"));\n const groupDecision = resolveSetupGroup(existingCfg?.supergroupId, { redetect: opts.redetect ?? false });\n let supergroupId: number;\n let detectedUserId: number | undefined;\n\n if (groupDecision === \"reuse\") {\n supergroupId = existingCfg!.supergroupId;\n console.log(chalk.green(`Using existing group: ${supergroupId}`));\n console.log();\n } else {\n console.log(\"Add the bot to your forum supergroup, then send any message in it.\");\n console.log(chalk.dim(\"Waiting for a message (up to 60s)…\"));\n try {\n ({ supergroupId, userId: detectedUserId } = await detectGroupAndUser(client, { timeoutMs: 60_000 }));\n } catch {\n console.error(chalk.red(\"Timed out — no supergroup message received within 60s.\"));\n console.error(chalk.yellow(\"Check: bot is an admin in the group · privacy mode is OFF · Topics enabled\"));\n process.exit(1);\n }\n console.log(chalk.green(`Found group: ${supergroupId}`));\n console.log();\n }\n\n // Step 3/3 — Remote control (opt-in, #321) + Save\n // Precedence for userId: --user-id flag > detected (detect mode only) > lastUserId from state\n console.log(chalk.bold(\"Step 3/3 — Remote control + Save\"));\n console.log(chalk.dim(\"Remote control enables auto-launching captains and the General command channel\"));\n console.log(chalk.dim(\"from your phone — gated to your Telegram user-id only (fail-closed).\"));\n\n const finalUserId = resolveSetupUserId(opts.userId, detectedUserId, defaultStateRoot());\n let users: number[] | undefined;\n let remoteControl: boolean | undefined;\n let printedRemoteControlState = false;\n\n if (finalUserId !== undefined) {\n const enable = await questionYesNo(\n `Enable remote control for your user-id ${finalUserId}? [y/N] `,\n );\n if (enable) {\n users = [finalUserId];\n remoteControl = true;\n }\n } else if (groupDecision === \"detect\") {\n // Detection ran but no userId came back from the message\n console.log(chalk.yellow(\"Could not read your user-id from that message — skipping remote control.\"));\n console.log(chalk.yellow(\"Re-run with --user-id <id> to enable, or edit telegram.users in config manually.\"));\n printedRemoteControlState = true;\n } else {\n // Reuse mode, no --user-id: existing users/remoteControl preserved by writeTelegramConfig\n const existingUsers = existingCfg?.users;\n if (existingUsers && existingUsers.length > 0) {\n console.log(chalk.dim(`Remote control: already configured (user-id ${existingUsers[0]}). Use --user-id to update.`));\n } else {\n console.log(chalk.dim(\"Remote control: off. Re-run with --user-id <id> to enable.\"));\n }\n printedRemoteControlState = true;\n }\n\n writeTelegramConfig(DEFAULT_CONFIG_PATH, { token, supergroupId, users, remoteControl });\n console.log(chalk.green(`Wrote telegram config — token: ${maskToken(token)} group: ${supergroupId}`));\n\n if (!printedRemoteControlState) {\n if (remoteControl) {\n console.log(chalk.green(`Remote control: ON (allowlisted user-id ${users![0]})`));\n } else {\n console.log(chalk.dim(\"Remote control: off (default). Re-run with --user-id <id> to enable.\"));\n }\n }\n\n try {\n await runRegisterCommands({ client });\n console.log(chalk.dim(\"Registered the /command menu.\"));\n } catch (e) {\n console.log(chalk.yellow(`command-menu registration skipped: ${(e as Error).message}`));\n }\n\n // Topic summary — show existing links so re-running setup is informative\n const topics = loadState(defaultStateRoot()).topics;\n const topicEntries = Object.entries(topics);\n if (topicEntries.length > 0) {\n const summary = topicEntries\n .map(([key, id]) => {\n const project = key.slice(0, key.indexOf(\"::\"));\n return `${project}→${id}`;\n })\n .join(\", \");\n console.log(chalk.dim(`Existing topics: ${summary} (already created — not recreated)`));\n } else {\n console.log(chalk.dim(\"No project topics yet — they're created on first delivery or via: squadrant telegram link <project>\"));\n }\n\n runTelegramPostSetup({});\n console.log();\n console.log(`Next: ${chalk.cyan(\"squadrant telegram link <project>\")}`);\n });\n\ntelegramCommand\n .command(\"register-commands\")\n .description(\"Register (or re-register) the bot's / command menu with Telegram\")\n .action(async () => {\n const cfg = loadConfig().telegram;\n if (!cfg) {\n console.error(chalk.red(\"telegram config absent — run: squadrant telegram setup\"));\n process.exit(1);\n }\n const token = cfg.botToken ?? process.env.TELEGRAM_BOT_TOKEN;\n if (!token) {\n console.error(chalk.red(\"no botToken in config and TELEGRAM_BOT_TOKEN is unset\"));\n process.exit(1);\n }\n const client = createTelegramClient({ token });\n await runRegisterCommands({ client });\n console.log(chalk.green(`registered ${BOT_COMMANDS.length} bot commands`));\n });\n\ntelegramCommand\n .command(\"notify\")\n .argument(\"[project]\", \"project to toggle\")\n .argument(\"[state]\", \"on | off | crew | cap\")\n .argument(\"[value]\", \"tier for crew (all|alert_only|done_only|none) or on|off for cap\")\n .option(\"--status\", \"list notification state for all projects\")\n .description(\"Live on|off (state), or crew <tier> / cap <on|off> preference (per-project config)\")\n .action(async (project: string | undefined, state: string | undefined, value: string | undefined, opts: { status?: boolean }) => {\n const stateRoot = defaultStateRoot();\n if (opts.status || !project) {\n const rows = runTelegramNotifyStatus({ stateRoot });\n if (rows.length === 0) {\n console.log(\"no projects linked\");\n return;\n }\n for (const r of rows) {\n console.log(` ${r.project}: ${r.active ? chalk.green(\"on\") : chalk.dim(\"off (muted)\")}`);\n }\n return;\n }\n\n const tgCfg = loadConfig().telegram;\n const globalNotify = tgCfg?.notify;\n const token = tgCfg?.botToken ?? process.env.TELEGRAM_BOT_TOKEN;\n\n // Deliberate preference (per-project config file): crew tier / cap.\n if (state === \"crew\" || state === \"cap\") {\n if (value === undefined) {\n console.error(chalk.red(`usage: squadrant telegram notify <project> ${state} <value>`));\n process.exit(1);\n }\n const resolved = resolveNotify(globalNotify, loadProjectOverride(project));\n const before: NotifyConfig = { ...resolved, active: isNotifyActive(stateRoot, project) };\n const res = runTelegramNotifyPref({ project, dimension: state, value });\n if (!res.ok) {\n console.error(chalk.red(res.message));\n process.exit(1);\n }\n console.log(chalk.green(`${project} ${state} = ${value}`));\n const after: NotifyConfig = state === \"crew\"\n ? { ...before, crew: value as CrewTier }\n : { ...before, cap: value === \"on\" };\n if (tgCfg && token) {\n const client = createTelegramClient({ token });\n const sent = await runNotifyConfirmation({ project, before, after, cfg: tgCfg, client, stateRoot });\n if (sent) console.log(chalk.dim(`→ notified ${project} topic`));\n }\n return;\n }\n\n // Live session toggle (telegram-state.json), unchanged.\n if (state !== \"on\" && state !== \"off\") {\n console.error(chalk.red(\"usage: squadrant telegram notify <project> <on|off|crew <tier>|cap <on|off>>\"));\n process.exit(1);\n }\n const resolved = resolveNotify(globalNotify, loadProjectOverride(project));\n const before: NotifyConfig = { ...resolved, active: isNotifyActive(stateRoot, project) };\n const after: NotifyConfig = { ...before, active: state === \"on\" };\n runTelegramNotifySet({ project, active: state === \"on\", stateRoot });\n console.log(chalk.green(`${project} notifications ${state === \"on\" ? \"ON\" : \"OFF\"}`));\n if (tgCfg && token) {\n const client = createTelegramClient({ token });\n const sent = await runNotifyConfirmation({ project, before, after, cfg: tgCfg, client, stateRoot });\n if (sent) console.log(chalk.dim(`→ notified ${project} topic`));\n }\n });\n\ntelegramCommand\n .command(\"send\")\n .argument(\"<project>\", \"project whose topic receives the message\")\n .argument(\"[message...]\", \"message text (omit to read from stdin)\")\n .description(\"Send a message to a project's linked Telegram topic\")\n .action(async (project: string, messageParts: string[]) => {\n const cfg = loadConfig().telegram;\n if (!cfg) {\n console.error(chalk.red(\"telegram config absent — add a `telegram` block to ~/.config/squadrant/config.json\"));\n process.exit(1);\n }\n const token = cfg.botToken ?? process.env.TELEGRAM_BOT_TOKEN;\n if (!token) {\n console.error(chalk.red(\"no botToken in config and TELEGRAM_BOT_TOKEN is unset\"));\n process.exit(1);\n }\n\n if (!capAllowed(project, cfg.notify)) {\n console.log(chalk.dim(`${project}: captain messages muted (cap=off) — not sent`));\n return;\n }\n\n let message: string;\n if (messageParts.length > 0) {\n message = messageParts.join(\" \");\n } else if (!process.stdin.isTTY) {\n const { createInterface } = await import(\"node:readline\");\n const lines: string[] = [];\n const rl = createInterface({ input: process.stdin });\n for await (const line of rl) lines.push(line);\n message = lines.join(\"\\n\").trimEnd();\n if (!message) {\n console.error(chalk.red(\"no message provided (stdin was empty)\"));\n process.exit(1);\n }\n } else {\n console.error(chalk.red(\"message required — pass as argument or pipe via stdin\"));\n process.exit(1);\n }\n\n const client = createTelegramClient({ token });\n try {\n const { chatId, topicId } = await runTelegramSend({ project, message, cfg, client, stateRoot: defaultStateRoot() });\n console.log(chalk.green(`sent to group ${chatId} topic ${topicId}`));\n } catch (e) {\n console.error(chalk.red((e as Error).message));\n process.exit(1);\n }\n });\n"],"mappings":"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","names":["fs","os","path","path","existsSync","readFileSync","homedir","join","existsSync","readFileSync","writeFileSync","join","existsSync","readFileSync","writeFileSync","mkdirSync","rmSync","homedir","dirname","join","path","statePath","execFileSync","path","fs","readFile","readStdin","fs","path","fs","path","fs","path","fs","join","existsSync","resolve","mkdirSync","readFileSync","writeFileSync","existsSync","rmSync","join","execFileSync","mkdirSync","writeFileSync","readFileSync","existsSync","unlinkSync","homedir","dirname","join","path","homedir","join","writeFileSync","mkdirSync","randomUUID","fileURLToPath","join","statSync","openSync","closeSync","readdirSync","readFileSync","join","dirname","fs","path","resolve","fs","path","os","path","fs","sleep","init_dist","execFileSync","resolve","init_dist","execFileSync","execSync","init_cmux","init_registry","init_cmux","init_registry","fs","existsSync","path","init_registry","init_workspaces","init_registry","bin","args","sleep","resolve","resolve","init_dist","init_dist","init_workspaces","execSync","execSync","execSync","execSync","init_registry","fs","path","roleFile","init_registry","path","os","sep","mkdir","readFile","writeFile","path","os","readExisting","init_codex","mkdir","readFile","writeFile","path","os","renderMarkdown","readExisting","init_gemini","mkdir","readFile","writeFile","path","os","renderMarkdown","readExisting","init_opencode","init_registry","init_projection","init_codex","init_gemini","init_opencode","init_registry","nodeSpawn","resolve","readFile","homedir","join","init_config","resolve","init_config","sleep","execSync","readFileSync","homedir","join","path","init_claude","init_claude","init_registry","init_claude","init_types","init_types","init_claude","init_types","init_opencode","init_types","init_codex","init_types","ADAPTERS","init_registry","init_claude","init_opencode","init_codex","resolve","init_registry","dist_exports","init_dist","init_projection","init_claude","init_registry","init_types","init_dist","Command","readFileSync","existsSync","writeFileSync","fileURLToPath","dirname","join","homedir","init_dist","execSync","fs","path","chalk","init_dist","homedir","join","chalk","init_dist","execSync","fs","chalk","path","createClaudeDriver","createCodexDriver","createGeminiDriver","createOpencodeDriver","CapabilityRegistry","init_dist","Command","fs","path","os","chalk","Command","fs","path","chalk","init_dist","execFileSync","existsSync","homedir","join","chalk","findPackageRoot","path","fs","copyDirRecursive","Command","init_dist","Command","chalk","matter","chalk","Command","matter","init_dist","Command","execSync","path","os","chalk","Command","fs","path","os","chalk","rule","init_dist","init_dist","Command","createConnection","randomUUID","homedir","join","mkdirSync","writeFileSync","init_dist","Command","chalk","createConnection","homedir","join","chalk","Command","createConnection","Command","Command","SOCK","join","homedir","resolve","createConnection","randomUUID","mkdirSync","writeFileSync","r","Command","init_dist","mkdirSync","readFileSync","writeFileSync","join","join","mkdirSync","readFileSync","writeFileSync","init_dist","TEMPLATES_DIR","path","os","chalk","fs","cliCommand","direction","title","pane","Command","init_dist","Command","fs","path","os","chalk","TEMPLATES_DIR","shellQuote","titleFor","nameFromTitle","nextAutoName","init_dist","Command","execSync","homedir","join","chalk","firstLine","chalk","fs","path","writeFile","mkdir","init_dist","createServer","join","homedir","existsSync","readFileSync","execFile","withTimeout","cmux","resolve","init_dist","ICON","createServer","resolve","SOCK","join","homedir","detectCurrentWorkspace","execSync","chalk","Command","init_dist","Command","execSync","fs","path","os","chalk","TEMPLATES_DIR","SESSIONS_PATH","sleep","init_dist","Command","chalk","chalk","Command","Command","fs","os","path","fileURLToPath","execSync","chalk","init_dist","Command","fs","path","chalk","matter","init_dist","Command","fs","path","chalk","matter","init_dist","Command","chalk","init_dist","Command","chalk","buildRegistry","path","init_dist","Command","chalk","readStdin","init_dist","Command","chalk","fs","path","fileURLToPath","findPackageRoot","buildRegistry","init_dist","Command","resolve","Command","fs","fileURLToPath","dirname","join","chalk","fs","chalk","Command","readPkgVersion","join","dirname","fileURLToPath","Command","chalk","init_dist","chalk","Command","init_dist","Command","execSync","randomUUID","homedir","join","chalk","SOCK","Command","chalk","fs","path","Command","chalk","effort","createCmuxDriver","RuntimeRegistry","init_dist","join","dirname","Command","chalk","join","dirname","sep","resolve","createInterface","chalk","Command","resolved","before","after","dirname","fileURLToPath","readFileSync","join","homedir","existsSync","writeFileSync","Command"]}