@noir-ai/cli 1.14.0 → 1.15.0-beta.1
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/README.md +2 -2
- package/dist/bin.d.ts +10 -3
- package/dist/bin.js +1240 -365
- package/dist/bin.js.map +1 -1
- package/dist/index.d.ts +39 -12
- package/dist/index.js +1258 -383
- package/dist/index.js.map +1 -1
- package/dist/{output-BNE9htEm.d.ts → output-2T2lGR7a.d.ts} +3 -3
- package/dist/tui/{chunk-6LO4LXEH.js → chunk-5KWETEMF.js} +1191 -352
- package/dist/tui/chunk-5KWETEMF.js.map +1 -0
- package/dist/tui/{chunk-ESZTOQEC.js → chunk-KETMM3BA.js} +25 -3
- package/dist/tui/chunk-KETMM3BA.js.map +1 -0
- package/dist/tui/{chunk-2RK6AFZQ.js → chunk-TPNJEN4B.js} +2 -2
- package/dist/tui/chunk-TPNJEN4B.js.map +1 -0
- package/dist/tui/{create-FD4E626Z.js → create-6KDIFPUL.js} +10 -6
- package/dist/tui/create-6KDIFPUL.js.map +1 -0
- package/dist/tui/index.js +994 -120
- package/dist/tui/index.js.map +1 -1
- package/dist/tui/{install-YGTUSLRO.js → install-KA35ONQP.js} +2 -2
- package/dist/tui/{sync-N633SQSS.js → sync-AII5WCRO.js} +8 -4
- package/dist/tui/sync-AII5WCRO.js.map +1 -0
- package/dist/tui/{update-LET5BWOU.js → update-XGKJ4KBR.js} +3 -3
- package/package.json +11 -11
- package/dist/tui/chunk-2RK6AFZQ.js.map +0 -1
- package/dist/tui/chunk-6LO4LXEH.js.map +0 -1
- package/dist/tui/chunk-ESZTOQEC.js.map +0 -1
- package/dist/tui/create-FD4E626Z.js.map +0 -1
- package/dist/tui/sync-N633SQSS.js.map +0 -1
- /package/dist/tui/{install-YGTUSLRO.js.map → install-KA35ONQP.js.map} +0 -0
- /package/dist/tui/{update-LET5BWOU.js.map → update-XGKJ4KBR.js.map} +0 -0
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/commands/status.ts","../../src/daemon-client.ts","../../src/bin.ts","../../src/commands/context.ts","../../src/commands/daemon.ts","../../src/commands/workspace.ts","../../src/workspace-mcp.ts","../../src/commands/doctor.ts","../../src/commands/env.ts","../../src/commands/handoff.ts","../../src/commands/task.ts","../../src/commands/home.ts","../../src/banner.ts","../../src/tui/commands/registry.ts","../../src/tui/commands/sections.ts","../../src/commands/memory.ts","../../src/commands/release.ts","../../src/commands/run.ts","../../src/orchestrator.ts","../../src/shell-bridge.ts","../../src/run-profiles.ts","../../src/commands/skills.ts","../../src/init.ts","../../src/conflict.ts","../../src/dedup-write.ts","../../src/serve.ts"],"sourcesContent":["// S9 t4 — `noir status [--json]`.\n//\n// Aggregates a project + daemon + store + context + workflow + memory snapshot.\n// Project info (id/name/host/version) is assembled IN-PROCESS from\n// `loadProjectInfo` + `NOIR_VERSION` — no daemon round-trip just to name the\n// project. Daemon state comes from a read-only {@link probeDaemon} (liveness\n// probe of `~/.noir/daemon.json` + pid + GET /health) that NEVER starts a daemon\n// (spec F2 amendment: `status` is probe-only and works daemon-down — a down\n// daemon is reported honestly + exit 0, never auto-started). When the probe finds\n// a running daemon, the optional count tools are fetched over one connection via\n// {@link withRunningDaemon} (which reuses the running daemon and also never\n// starts one); if the daemon is down, those sections are simply `null` and the\n// snapshot still renders.\n//\n// Graceful degradation (spec F2 / \"some engines optional\"): every count tool —\n// `host_status` (enriches `daemon.transport`), `store_status`, `context_status`,\n// `workflow_status`, `memory_sessions` — is wrapped in {@link tryTool} and\n// contributes `null` when absent or when its engine is not wired. One missing\n// engine never fails the snapshot; even the daemon being down doesn't (it is the\n// one piece of information `status` exists to report). A tool's own\n// logical-failure envelope (e.g. `workflow_status` returning\n// `{ok:false,error:'no active task'}`) is data, not a transport failure, and is\n// normalized to `null`.\n//\n// Active commands (`context *`, `memory *`, `task *`) do real work and KEEP using\n// `withDaemon` (auto-start acceptable for commands that perform writes/reads with\n// side-effects); their daemon-down path is the same clean exit-4 envelope. Only\n// `status` is probe-only — in-process read fallback for the active commands is\n// deferred to v1.x.\n//\n// Stream discipline (S9): `--json` emits the versioned `{ok,data}` envelope\n// to STDOUT (the only stdout write); the human table + banner go to STDERR via\n// the centralized `table()` / `log()` helpers (auto-stripped under NO_COLOR /\n// non-TTY / --json).\n\nimport { loadProjectInfo, NOIR_VERSION, type ProjectInfo } from '@noir-ai/core';\nimport {\n type DaemonClientOptions,\n type DaemonProbe,\n type DaemonToolCaller,\n probeDaemon,\n withRunningDaemon,\n} from '../daemon-client.js';\nimport { type CliOptions, definitionList, EXIT, fail, log, tip } from '../output.js';\nimport { badge } from '../theme.js';\nimport { DEFAULT_UPDATE_CONFIG, runAsyncUpdateCheck } from './update.js';\n\n/** Options accepted by `status` (global flags + daemon-client knobs). */\nexport interface StatusOptions extends CliOptions, DaemonClientOptions {}\n\n// ---------------------------------------------------------------------------\n// Tool result shapes (the relevant slices of the daemon's payloads). The daemon\n// returns these as JSON text; daemon-client parses them to `unknown`, so each\n// reader below treats a missing/foreign field as `undefined` and the section is\n// reported `null`. Keeping these local (rather than importing the daemon's\n// internal types) means the CLI depends only on the MCP wire contract.\n// ---------------------------------------------------------------------------\ninterface HostStatusResult {\n noir: string;\n project: { id: string; name: string };\n host: string;\n transport: string;\n daemon: boolean;\n pid?: number;\n uptimeSec?: number;\n}\n\ninterface StoreStatusResult {\n ok: boolean;\n projectId: string;\n docCount: number;\n vecCount: number;\n dbPath: string | null;\n degraded: boolean;\n}\n\ninterface ContextStatusResult {\n ok: boolean;\n projectId: string;\n docCount: number;\n vecCount: number;\n indexedFiles: number;\n embedder: { kind: string; model?: string; dim: number };\n degraded: boolean;\n}\n\ninterface WorkflowStatusResult {\n ok: boolean;\n taskId: string;\n phase: string;\n state: string;\n mode: string;\n nextGate: string | null;\n degraded: boolean;\n}\n\ninterface MemorySessionsResult {\n ok: boolean;\n sessions: Array<{ id: string; count: number; lastTs: number }>;\n}\n\n// ---------------------------------------------------------------------------\n// Normalized payload (the `data` of the `--json` envelope + the source for the\n// human table). Every optional section is `null` when its engine is absent, so\n// a `--json` consumer can branch with a simple null check.\n// ---------------------------------------------------------------------------\nexport interface StatusPayload {\n noir: string;\n project: { id: string; name: string };\n host: string;\n daemon: {\n running: boolean;\n transport?: string;\n pid?: number;\n uptimeSec?: number;\n };\n store: {\n docCount: number;\n vecCount: number;\n dbPath: string | null;\n degraded: boolean;\n } | null;\n context: {\n docCount: number;\n vecCount: number;\n indexedFiles: number;\n embedder: string;\n degraded: boolean;\n } | null;\n workflow: {\n taskId: string;\n phase: string;\n state: string;\n mode: string;\n nextGate: string | null;\n degraded: boolean;\n } | null;\n memory: { sessions: number; observations: number } | null;\n}\n\n/**\n * Call an optional daemon tool, returning `null` on ANY failure. The daemon\n * registers `store_status` / `context_status` / `workflow_status` /\n * `memory_sessions` only when it wired the matching engine, so a missing engine\n * surfaces as a tool-call failure that we fold to `null` rather than failing\n * the snapshot. A tool's own `{ok:false,…}` envelope is returned as data (the\n * caller normalizes it) — only transport / parse / not-registered failures map\n * to `null` here.\n *\n * Exported so `noir handoff` reuses the SAME fold-to-null pattern for its\n * bounded `context_search` / `memory_recall` extraction — a missing embedder or\n * a daemon-down degrades to `null` instead of failing the handoff artifact.\n */\nexport async function tryTool<T>(\n caller: DaemonToolCaller,\n name: string,\n args?: Record<string, unknown>,\n): Promise<T | null> {\n try {\n return await caller.callTool<T>(name, args);\n } catch {\n // Engine absent (tool not registered), transport hiccup, or non-JSON text.\n // All are non-fatal for an optional section; report it as unavailable.\n return null;\n }\n}\n\nfunction pickStore(s: StoreStatusResult | null): StatusPayload['store'] {\n if (s?.ok !== true) return null;\n return {\n docCount: s.docCount,\n vecCount: s.vecCount,\n dbPath: s.dbPath,\n degraded: s.degraded === true,\n };\n}\n\nfunction describeEmbedder(e: ContextStatusResult['embedder']): string {\n if (!e || e.kind === 'none') return 'none (BM25-only)';\n const model = typeof e.model === 'string' && e.model.length > 0 ? e.model : '<unset>';\n return `${e.kind} · ${model} (${e.dim}-dim)`;\n}\n\nfunction pickContext(c: ContextStatusResult | null): StatusPayload['context'] {\n if (c?.ok !== true) return null;\n return {\n docCount: c.docCount,\n vecCount: c.vecCount,\n indexedFiles: c.indexedFiles,\n embedder: describeEmbedder(c.embedder),\n degraded: c.degraded === true,\n };\n}\n\nfunction pickWorkflow(w: WorkflowStatusResult | null): StatusPayload['workflow'] {\n // `workflow_status` returns `{ok:false,error:'no active task'}` (data) when no\n // task is active — normalize that to `null` so the payload's `workflow` field\n // cleanly means \"active task snapshot present\".\n if (w?.ok !== true) return null;\n return {\n taskId: w.taskId,\n phase: w.phase,\n state: w.state,\n mode: w.mode,\n nextGate: w.nextGate,\n degraded: w.degraded === true,\n };\n}\n\nfunction pickMemory(m: MemorySessionsResult | null): StatusPayload['memory'] {\n if (m?.ok !== true || !Array.isArray(m.sessions)) return null;\n let observations = 0;\n for (const s of m.sessions) observations += s.count;\n return { sessions: m.sessions.length, observations };\n}\n\n/**\n * Build the normalized payload from in-process project info + the daemon probe\n * + the (all-optional) count-tool results. Daemon `running`/`pid`/`uptimeSec`\n * come from the probe (the honest liveness source); `transport` is enriched from\n * `host_status` when that tool is reachable, else omitted. Every other section is\n * `null` when its engine is absent OR the daemon is down.\n */\nfunction buildPayload(\n project: ProjectInfo,\n probe: DaemonProbe,\n host: HostStatusResult | null,\n store: StoreStatusResult | null,\n context: ContextStatusResult | null,\n workflow: WorkflowStatusResult | null,\n memory: MemorySessionsResult | null,\n): StatusPayload {\n return {\n noir: NOIR_VERSION,\n project: { id: project.id, name: project.name },\n host: project.config.host,\n daemon: {\n running: probe.running,\n ...(probe.pid !== undefined ? { pid: probe.pid } : {}),\n ...(probe.uptimeSec !== undefined ? { uptimeSec: probe.uptimeSec } : {}),\n ...(host && typeof host.transport === 'string' ? { transport: host.transport } : {}),\n },\n store: pickStore(store),\n context: pickContext(context),\n workflow: pickWorkflow(workflow),\n memory: pickMemory(memory),\n };\n}\n\n// ---------------------------------------------------------------------------\n// Human rendering (stderr). A two-column Field/Value table is the leanest\n// readable shape for a status snapshot; cli-table3 is auto-stripped under\n// NO_COLOR / non-TTY and the whole call is a no-op under --json.\n// ---------------------------------------------------------------------------\nfunction formatDuration(sec?: number): string {\n if (typeof sec !== 'number' || sec < 0) return 'unknown';\n if (sec < 60) return `${sec}s`;\n if (sec < 3600) return `${Math.floor(sec / 60)}m ${sec % 60}s`;\n return `${Math.floor(sec / 3600)}h ${Math.floor((sec % 3600) / 60)}m`;\n}\n\nexport function describeDaemon(d: StatusPayload['daemon']): string {\n if (!d.running) return 'not running (start with `noir daemon start`)';\n const pid = typeof d.pid === 'number' ? `pid ${d.pid}` : 'pid unknown';\n const up = typeof d.uptimeSec === 'number' ? `, up ${formatDuration(d.uptimeSec)}` : '';\n const transport = typeof d.transport === 'string' ? `, ${d.transport}` : '';\n return `running (${pid}${up}${transport})`;\n}\n\nexport function describeStore(s: StatusPayload['store']): string {\n if (!s) return 'unavailable (store engine not wired)';\n const flag = s.degraded ? ` ${badge('warn', 'degraded: read-only')}` : '';\n return `${s.docCount} docs / ${s.vecCount} vecs${flag}`;\n}\n\nexport function describeContext(c: StatusPayload['context']): string {\n if (!c) return 'unavailable (context engine not wired)';\n const flag = c.degraded ? ` ${badge('warn', 'degraded')}` : '';\n return `${c.docCount} docs, ${c.vecCount} vecs, ${c.indexedFiles} files · embedder ${c.embedder}${flag}`;\n}\n\nexport function describeWorkflow(w: StatusPayload['workflow']): string {\n if (!w) return 'no active task';\n const gate = w.nextGate ? ` → next gate: ${w.nextGate}` : '';\n const flag = w.degraded ? ` ${badge('warn', 'degraded')}` : '';\n return `${w.phase} (${w.state}, ${w.mode}) · task ${w.taskId}${gate}${flag}`;\n}\n\nexport function describeMemory(m: StatusPayload['memory']): string {\n if (!m) return 'unavailable (memory engine not wired)';\n return `${m.observations} observations across ${m.sessions} session${m.sessions === 1 ? '' : 's'}`;\n}\n\nfunction renderHuman(p: StatusPayload, opts: CliOptions): void {\n // Banner + definition list both go to stderr (rendering is a no-op under\n // --json; we only render human when opts.json is false, but passing opts\n // keeps --quiet honest).\n log(`noir status — ${p.project.name} (${p.project.id})`, opts);\n definitionList(\n [\n { label: 'Project', value: `${p.project.name} (${p.project.id})` },\n { label: 'Host', value: p.host },\n { label: 'Noir', value: p.noir },\n { label: 'Daemon', value: describeDaemon(p.daemon) },\n { label: 'Store', value: describeStore(p.store) },\n { label: 'Context', value: describeContext(p.context) },\n { label: 'Workflow', value: describeWorkflow(p.workflow) },\n { label: 'Memory', value: describeMemory(p.memory) },\n ],\n opts,\n );\n // Resume hint (c4-surface-wiring S2): when a resumable (non-terminal) task is\n // present, surface the resume command git-status-style. `--no-tips`/`--json`\n // silence it (renderHuman is only called when !json; tip() honors --no-tips).\n if (p.workflow && p.workflow.state !== 'done' && p.workflow.state !== 'abandoned') {\n tip('resume: `noir task resume`', opts);\n }\n}\n\n/**\n * Gather the live snapshot into the normalized {@link StatusPayload}. Extracted\n * so `noir handoff` reuses the SAME aggregation path as `noir status`\n * (single source for the multi-engine snapshot). Project info is read in-process\n * (uninitialized → exit 1 propagated to the caller); daemon state comes from a\n * {@link probeDaemon} (NEVER auto-starts). When the daemon is up, the optional\n * count tools are fetched over one {@link withRunningDaemon} connection; when it\n * is down, those sections are `null` and `daemon:{running:false}` — this function\n * never throws on a down daemon (the handoff command degrades gracefully).\n */\nexport async function gatherStatusPayload(opts: StatusOptions): Promise<StatusPayload> {\n // In-process project info — no daemon round-trip. Uninitialized → exit 1\n // (both `status` and `handoff` treat an uninitialized project as a hard error\n // — there is no project to snapshot). Route through fail() so --json emits the\n // canonical {ok:false,error} envelope (a plain Error would leave stdout empty).\n let project: ProjectInfo;\n try {\n project = loadProjectInfo(process.cwd());\n } catch {\n fail(EXIT.ERROR, 'Noir is not initialized in this directory. Run `noir init` first.', opts);\n }\n // Probe — never starts a daemon. A down daemon is reported honestly.\n const probe = await probeDaemon(opts);\n\n let host: HostStatusResult | null = null;\n let store: StoreStatusResult | null = null;\n let context: ContextStatusResult | null = null;\n let workflow: WorkflowStatusResult | null = null;\n let memory: MemorySessionsResult | null = null;\n\n if (probe.running) {\n // Reuse the already-running daemon — withRunningDaemon NEVER auto-starts\n // (probe-only). Pass the probe we already computed so it doesn't GET /health\n // a second time. Every tool is optional (tryTool folds a missing engine /\n // logical-failure envelope to null); host_status now only enriches\n // daemon.transport. If the daemon dies mid-snapshot (probe→connect race),\n // withRunningDaemon returns null and the sections stay null while the probe\n // data still populates the daemon section.\n await withRunningDaemon(\n opts,\n async (caller: DaemonToolCaller): Promise<void> => {\n host = await tryTool<HostStatusResult>(caller, 'host_status');\n store = await tryTool<StoreStatusResult>(caller, 'store_status');\n context = await tryTool<ContextStatusResult>(caller, 'context_status');\n workflow = await tryTool<WorkflowStatusResult>(caller, 'workflow_status');\n memory = await tryTool<MemorySessionsResult>(caller, 'memory_sessions');\n },\n probe,\n );\n }\n\n return buildPayload(project, probe, host, store, context, workflow, memory);\n}\n\n/**\n * `noir status`: aggregate the snapshot and render it.\n *\n * Project info is read in-process; daemon state comes from a {@link probeDaemon}\n * (NEVER auto-starts). When the daemon is up, the optional count tools are\n * fetched over one {@link withRunningDaemon} connection; when it is down, those\n * sections are `null` and `daemon:{running:false}` is rendered with exit 0\n * (status is informational — a down daemon is not an error).\n *\n * `--json` emits `{ok:true, data: StatusPayload}` to stdout. The human path\n * renders a two-column table on stderr. Uninitialized project → exit 1 from\n * `loadProjectInfo` (same as every other command).\n */\nexport async function status(opts: StatusOptions): Promise<void> {\n // fire-and-forget; never blocks, never prints under --json/--quiet/CI/non-TTY.\n void runAsyncUpdateCheck({\n env: process.env,\n configUpdate: (() => {\n try {\n const info = loadProjectInfo(process.cwd());\n return info.config.update ?? DEFAULT_UPDATE_CONFIG;\n } catch {\n return DEFAULT_UPDATE_CONFIG;\n }\n })(),\n quiet: opts.json === true || opts.quiet === true || !process.stdout.isTTY,\n });\n\n const payload = await gatherStatusPayload(opts);\n if (opts.json === true) {\n // Single stdout write — the versioned S9 F11 success envelope.\n process.stdout.write(`${JSON.stringify({ ok: true, data: payload })}\\n`);\n return;\n }\n renderHuman(payload, opts);\n}\n","// S9 t3 — Daemon MCP client.\n//\n// Store-touching commands (`status`, `context *`, `memory *`, `task *`) are thin\n// MCP clients over the running Noir daemon rather than opening the store\n// in-process: that preserves the daemon's single-writer discipline and reuses\n// the MCP tool surface built in S6. This module is the single bridge from\n// the CLI to that daemon — every command module calls {@link callDaemonTool} (or\n// the multi-call {@link withDaemon}) instead of importing the store directly.\n//\n// Flow: {@link ensureDaemonRunning} (from @noir-ai/daemon) reads THIS project's\n// daemon record (`~/.noir/daemons/<projectId>.json`, NOIR_DAEMON_DIR override\n// for tests) and STARTS a foreground daemon if no healthy one is present,\n// returning its URL + a `stop()` tear-down. We connect a\n// @modelcontextprotocol/client `Client` over\n// Streamable HTTP to that URL (127.0.0.1 only — daemon §4), initialize, and\n// `callTool(name, args)`; the daemon's tools always return a single text content\n// block whose `text` is `JSON.stringify(payload)` (see `textResult` in\n// packages/daemon/src/server.ts), so we parse it back into the payload object.\n//\n// Failure handling (S9 exit-code contract): ANY failure to reach or use the\n// daemon — record missing/stale, ensure-start error, transport, connect,\n// protocol, or a tool call that rejects / returns no parseable text — maps to\n// exit code `4` (DAEMON_DOWN) with a stable remediation hint. `--verbose` surfaces\n// the underlying cause on stderr; `--json` shapes the failure as the S9\n// `{ok:false,error:{code,message}}` envelope ON STDOUT via `output.ts:fail`\n// (data→stdout discipline — the single canonical envelope is shaped once there;\n// `failDaemonDown` passes the PLAIN hint as the message, never a pre-stringified\n// inner envelope, which would doubly-encode `error.message`). A tool that returns\n// a logical-failure envelope (`{ok:false, degraded:true, …}`) is NOT a transport\n// failure — it parses cleanly and is returned to the caller as data.\n//\n// Auth (spec 6.1): the HTTP transport requires a bearer token, regenerated by\n// the daemon on every start and stored 0600 at `~/.noir/daemons/<scopeKey>.token`\n// (`readDaemonToken`). The scope key is the daemon's IDENTITY: a project daemon's\n// projectId, a workspace daemon's workspace NAME (spec §6.3). Every `/mcp`\n// connect below sends the token for the daemon it is addressing via\n// `httpTransport` — never another identity's; `/health` is token-free, so the\n// liveness probe and the daemon record are unaffected. The stdio transport never\n// uses a token (no network surface, no header trust).\n\nimport { Client, StreamableHTTPClientTransport } from '@modelcontextprotocol/client';\nimport { ContextEngine, createEmbedFn, resolveEmbedderConfig } from '@noir-ai/context';\nimport {\n loadProjectInfo,\n NOIR_VERSION,\n type ProjectInfo,\n readWorkspaceMarker,\n workspaceStoreDbPath,\n} from '@noir-ai/core';\nimport {\n ensureDaemonRunning,\n pidAlive,\n readDaemonToken,\n readProjectDaemonRecord,\n readWorkspaceDaemonRecord,\n resolveGateConfig,\n tokenPath,\n} from '@noir-ai/daemon';\nimport { createMemoryEngine, type MemoryEngine } from '@noir-ai/memory';\nimport { openStore, type Store } from '@noir-ai/store';\nimport { WorkflowEngine } from '@noir-ai/workflow';\nimport { EXIT, fail } from './bin.js';\n\n/** Options shared by every daemon-client entry point. */\nexport interface DaemonClientOptions {\n /** Emit the daemon-down failure as a JSON `{ok,error}` envelope (S9 --json). */\n readonly json?: boolean;\n /** Surface transport / connection detail on stderr (S9 --verbose). */\n readonly verbose?: boolean;\n /**\n * Project used to resolve the daemon idle timeout. Defaults to\n * `loadProjectInfo(process.cwd())` — the bin's `--cwd` preAction hook has\n * already chdir'd, so process.cwd() honors `--cwd`.\n */\n readonly project?: ProjectInfo;\n /** Override the daemon idle timeout (sec). Defaults to the project's config. */\n readonly idleTimeoutSec?: number;\n}\n\n/** A handle for calling daemon MCP tools over an already-connected client. */\nexport interface DaemonToolCaller {\n /**\n * Call a daemon MCP tool and parse its text-JSON result. Transport / parse\n * failures throw an S9 {@link NoirCliError} (exit 4); a tool's own logical\n * failure envelope (`{ok:false,…}`) is returned as-is.\n */\n callTool<T = unknown>(name: string, args?: Record<string, unknown>): Promise<T>;\n /**\n * List the names of the tools the connected daemon currently exposes.\n * Required so a command can tell \"the daemon is up but does not register\n * tool X\" (an opt-in / engine-not-wired condition, e.g. `memory_consolidate`\n * when consolidation is disabled) apart from \"the daemon is down\" — calling\n * an unregistered tool would otherwise mis-map onto exit 4 (DAEMON_DOWN).\n * Transport failures throw exit 4 exactly like {@link callTool}.\n */\n listTools(): Promise<string[]>;\n}\n\n/** Daemon-down remediation hint (S9). Stable across releases. */\nexport const DAEMON_DOWN_HINT = 'daemon not reachable — try `noir daemon start`';\n\n/**\n * Bounded /health probe window (ms). A probe must never hang: a stale daemon\n * record can point at a port bound by an unrelated process that accepts TCP but\n * never answers, and the probe is now the FIRST hop for every read command's\n * fallback decision. A timeout is treated as \"not running\" (reads degrade to the\n * read-only engine); the bound also keeps the daemon-up fast path snappy.\n */\nexport const PROBE_TIMEOUT_MS = 1500;\n\nfunction describeCause(cause: unknown): string {\n if (cause instanceof Error) return `${cause.name}: ${cause.message}`;\n try {\n return JSON.stringify(cause);\n } catch {\n return String(cause);\n }\n}\n\n/**\n * Map any daemon / transport failure onto the S9 DAEMON_DOWN exit code. Always\n * throws (via {@link fail}); the `never` return lets callers use it as a\n * diverging expression inside parsed result handling.\n */\nfunction failDaemonDown(opts: DaemonClientOptions, cause: unknown): never {\n if (opts.verbose) {\n process.stderr.write(`noir: daemon transport detail: ${describeCause(cause)}\\n`);\n }\n // Pass the PLAIN hint + opts and let `output.ts:fail` shape the single S9\n // `{ok:false,error:{code:EXIT.DAEMON_DOWN,message:hint}}` envelope ONCE. The\n // prior branch pre-stringified an inner `{ok,error}` and passed it as `message`,\n // which `fail` then wrapped AGAIN → `error.message` was a JSON string\n // (doubly-encoded). `opts` carries `--json`/`--verbose` so `fail` selects the\n // stdout envelope vs. the plain stderr line.\n fail(EXIT.DAEMON_DOWN, DAEMON_DOWN_HINT, opts);\n}\n\n// ---------------------------------------------------------------------------\n// Liveness probe (read-only). `noir status` uses this to report daemon state\n// HONESTLY without auto-starting one: it reads the daemon record + checks the\n// pid + GETs /health, and returns {running:false} on any miss. It NEVER calls\n// ensureDaemonRunning. Active commands keep using {@link withDaemon} (which may\n// start a daemon); only the informational `status` command is probe-only.\n// ---------------------------------------------------------------------------\n\n/** Outcome of a read-only daemon liveness probe (never starts a daemon). */\nexport interface DaemonProbe {\n running: boolean;\n pid?: number;\n port?: number;\n uptimeSec?: number;\n}\n\n/**\n * Probe whether a healthy daemon is currently running, WITHOUT starting one.\n * Resolves the CALLER's project id first (that id IS the record lookup key),\n * reads the per-project record via {@link readProjectDaemonRecord}, checks\n * {@link pidAlive}, and GETs `http://127.0.0.1:<port>/health`. Any miss (no\n * project, no record, stale pid, non-200, unreachable, malformed body) →\n * `{running:false}` — this function NEVER throws and NEVER starts a daemon.\n * Under `--verbose` the reason for a miss is logged to stderr (NF5: honest\n * degradation).\n */\nexport async function probeDaemon(opts: DaemonClientOptions = {}): Promise<DaemonProbe> {\n // Resolve the project FIRST — with per-project records the ProjectId IS the\n // lookup key, so the record cannot be read before it is known.\n const expectedProject =\n opts.project?.id ??\n (() => {\n try {\n return loadProjectInfo(process.cwd()).id;\n } catch {\n return undefined; // uninitialized — no caller project to look up\n }\n })();\n if (expectedProject === undefined) {\n if (opts.verbose) process.stderr.write('noir: daemon probe: no project (uninitialized)\\n');\n return { running: false };\n }\n const rec = readProjectDaemonRecord(expectedProject);\n if (!rec) {\n if (opts.verbose) process.stderr.write('noir: daemon probe: no daemon record\\n');\n return { running: false };\n }\n if (!pidAlive(rec.pid)) {\n if (opts.verbose) process.stderr.write(`noir: daemon probe: pid ${rec.pid} not alive\\n`);\n return { running: false };\n }\n try {\n // Bounded probe: a stale daemon record pointing at a port held by an\n // unrelated process that accepts TCP but never responds (a blackhole) must\n // NOT hang the probe (or any read command that probes first). Treat a\n // timeout as \"not running\" so reads fall back to the read-only engine.\n const res = await fetch(`http://127.0.0.1:${rec.port}/health`, {\n signal: AbortSignal.timeout(PROBE_TIMEOUT_MS),\n });\n if (!res.ok) {\n if (opts.verbose) process.stderr.write(`noir: daemon probe: /health → HTTP ${res.status}\\n`);\n return { running: false };\n }\n const body = (await res.json().catch(() => null)) as {\n ok?: boolean;\n pid?: number;\n uptimeSec?: number;\n } | null;\n // PID-reuse guard (same invariant as @noir-ai/daemon ensure.ts isHealthy +\n // commands/daemon.ts isHealthy): the responding /health must carry OUR\n // recorded pid — a missing or mismatched pid means a foreign process holds\n // the port; report NOT running. (The record is already scoped to the caller's\n // project, so there is no cross-project body check left to perform.)\n const pidOk = typeof body?.pid === 'number' && body.pid === rec.pid;\n if (body?.ok !== true || !pidOk) {\n if (opts.verbose)\n process.stderr.write(\n !pidOk\n ? 'noir: daemon probe: pid missing/mismatched (foreign process on recorded port)\\n'\n : 'noir: daemon probe: /health body not ok\\n',\n );\n return { running: false };\n }\n return {\n running: true,\n pid: typeof body.pid === 'number' ? body.pid : rec.pid,\n port: rec.port,\n uptimeSec: typeof body.uptimeSec === 'number' ? body.uptimeSec : undefined,\n };\n } catch (err) {\n if (opts.verbose)\n process.stderr.write(`noir: daemon probe: unreachable (${describeCause(err)})\\n`);\n return { running: false };\n }\n}\n\n/**\n * Resolve a CONNECTED daemon client for the caller's project, plus the\n * tear-down for any daemon this call started. Maps any start / connect error\n * onto exit 4.\n *\n * Ordering is CONNECT-FIRST (spec 7.1). When `daemon.port` gives a stable\n * address we attempt the MCP session against it BEFORE spawning anything, so a\n * daemon starts because a connection was genuinely attempted rather than as a\n * side effect of running a command. Only when that attempt fails — a refused\n * connection is the common case — do we fall through to\n * {@link ensureDaemonRunning} (still the single spawn primitive; only the\n * DECISION POINT moved) and connect to whatever it returns. Without a\n * configured `daemon.port` there is no address to probe, so the previous\n * ensure-first ordering is retained verbatim (spec 7.1: D depends on B).\n *\n * The failure path is BOUNDED, in both senses. Structurally: at most one direct\n * attempt, one ensure, and one retry connect — never a loop. In time: the direct\n * probe is raced against {@link PROBE_TIMEOUT_MS}, so a port that accepts TCP\n * and never answers (\"blackhole\") costs the probe window, not a multi-minute\n * stall. A permanently dead port therefore ends in the S9 exit-4 DAEMON_DOWN\n * envelope via {@link failDaemonDown}, not a hang.\n *\n * This function cleans up after ITSELF before any throw: every client it created\n * is closed, and a daemon it started (an ensure result's `stop`) is torn down —\n * because throwing from here means `withDaemon`'s `finally` never runs, so the\n * caller's tear-down cannot be relied on for this leg.\n */\nasync function resolveDaemon(\n opts: DaemonClientOptions,\n): Promise<{ client: Client; stop: () => Promise<void> }> {\n // Lazy default: when the caller didn't inject a project (the common case from\n // command modules, which only forward --json/--verbose), resolve one here.\n // An uninitialized project (`loadProjectInfo` throws \"Run `noir init` first\")\n // is a USAGE error (exit 1), not a daemon-down (exit 4) — so route it through\n // fail() BEFORE the ensureDaemonRunning try, which maps errors to exit 4. This\n // keeps exit-1 semantics AND emits the canonical {ok:false,error} envelope on\n // stdout under --json (a plain Error would leave stdout EMPTY). It also runs\n // BEFORE any connect attempt: a project id is the daemon scope key, so there\n // is nothing to address (and no token to present) without one.\n let project: ProjectInfo;\n try {\n project = opts.project ?? loadProjectInfo(process.cwd());\n } catch {\n fail(EXIT.ERROR, 'Noir is not initialized in this directory. Run `noir init` first.', opts);\n }\n const idleTimeoutSec = opts.idleTimeoutSec ?? project.config.daemon.idleTimeoutSec;\n const preferred = project.config.daemon.port;\n\n // Connect-first when a stable address exists. `0` is a configured PREFERENCE\n // for an ephemeral port, i.e. explicitly NOT a stable address — it takes the\n // ensure-first path below, which still forwards the preference to the spawn.\n if (preferred !== undefined && preferred !== 0) {\n const direct = `http://127.0.0.1:${preferred}/mcp`;\n const probe = newClient();\n let probeTimer: ReturnType<typeof setTimeout> | undefined;\n try {\n // Raw connect, NOT connectClient: a failure here is the SIGNAL TO SPAWN,\n // not a command-fatal error, so it must never be mapped onto exit 4.\n //\n // BOUNDED, exactly like every other address probe in this module: a\n // configured port is a BLIND address — unlike the port\n // `ensureDaemonRunning` has just verified via `/health`, a foreign process\n // may hold it and accept TCP without ever answering. `connect()` carries\n // no deadline of its own (the only backstop would be undici's ~300s\n // headersTimeout), so the probe is raced against the same\n // {@link PROBE_TIMEOUT_MS} window the `/health` probe uses and a timeout\n // is treated as \"no daemon here\", i.e. fall through to the spawn.\n await Promise.race([\n probe.connect(httpTransport(direct, project.id)),\n new Promise<never>((_, reject) => {\n probeTimer = setTimeout(\n () => reject(new Error(`no response within ${PROBE_TIMEOUT_MS}ms`)),\n PROBE_TIMEOUT_MS,\n );\n }),\n ]);\n // A daemon was already answering at the configured address. Nothing was\n // started, so tear-down is a no-op — `stop` must stay inert (there is no\n // ensure result to defer to, and stopping a daemon we did not start would\n // kill the user's).\n return { client: probe, stop: async () => {} };\n } catch (err) {\n // Refused connection (nothing listening), no answer inside the probe\n // window (a blackhole port), a stale token from a before-restart daemon,\n // or a foreign process holding the port — each means \"no USABLE daemon at\n // this address\". Discard the probe and fall through to ensure + one retry;\n // the token is re-read at retry connect time, so a stale-token case\n // self-heals against the same (still healthy) daemon.\n if (opts.verbose) {\n process.stderr.write(\n `noir: no daemon at the configured port ${preferred} (${describeCause(err)})\\n`,\n );\n }\n await probe.close().catch(() => {\n /* the probe connection is already unusable; never mask the spawn path */\n });\n } finally {\n // Release the loser: on success the pending timer must not hold the event\n // loop open, and on failure it has already fired. (A connect that settles\n // AFTER the timeout is ignored by the settled race — and `close()` above\n // has already torn its transport down.)\n if (probeTimer !== undefined) clearTimeout(probeTimer);\n }\n }\n\n let url: string;\n let stop: () => Promise<void>;\n try {\n const ensured = await ensureDaemonRunning({\n project,\n idleTimeoutSec,\n ...(preferred !== undefined ? { port: preferred } : {}),\n });\n url = ensured.url;\n stop = ensured.stop;\n } catch (err) {\n failDaemonDown(opts, err);\n }\n\n // The retry (or the direct path when no port is configured). A failure HERE\n // is genuinely fatal — ensure already succeeded, so there is no further\n // recovery and the S9 exit-4 mapping applies (unlike the probe above).\n const client = newClient();\n try {\n await connectClient(client, url, opts, project.id);\n } catch (err) {\n // This function is about to THROW, so `withDaemon`'s finally — the one that\n // tears down a daemon we started — never runs. Tear down BOTH here, or a\n // daemon `ensureDaemonRunning` just spawned is stranded (running, with no\n // caller left to stop it) behind an exit-4 failure. Reachable on the plain\n // ensure-first path too, not just connect-first: ensure succeeds, then the\n // connect to the daemon it returned fails.\n await client.close().catch(() => {\n /* never mask the connect failure with a close failure */\n });\n await stop().catch(() => {\n /* ditto for the tear-down — the connect failure is the real error */\n });\n throw err;\n }\n return { client, stop };\n}\n\n/**\n * Build a Streamable HTTP transport for `url`, carrying the daemon's bearer\n * token when one is on disk for `scopeKey`. The daemon regenerates its token\n * on every start (spec 6.1), so the header is resolved at CONNECT time — never\n * cached across commands — and an absent token file simply means \"send no\n * header\" (a stdio-only or pre-auth daemon); the request then fails as any\n * other unauthorized request does (exit 4 with the daemon's own remediation).\n * `scopeKey` is the daemon identity: a project daemon's projectId, a workspace\n * daemon's name.\n */\nfunction httpTransport(url: string, scopeKey: string | null): StreamableHTTPClientTransport {\n const token = scopeKey === null ? null : readDaemonToken(scopeKey);\n return new StreamableHTTPClientTransport(\n new URL(url),\n // Verified present: StreamableHTTPClientTransportOptions.requestInit?: RequestInit\n token ? { requestInit: { headers: { Authorization: `Bearer ${token}` } } } : {},\n );\n}\n\n/**\n * The daemon scope key for the caller's project (its projectId), or `null` when\n * the project cannot be resolved. `null` ⇒ connect without a token header; the\n * daemon then answers 401 and the caller maps it to exit 4 exactly like any\n * other unreachable daemon (the caller has no project to scope a token to).\n */\nfunction callerScopeKey(opts: DaemonClientOptions): string | null {\n try {\n return (opts.project ?? loadProjectInfo(process.cwd())).id;\n } catch {\n return null;\n }\n}\n\n/**\n * Build an unconnected MCP client for the CLI. One client per connection: the\n * SDK's `connect` binds a transport to the client, so a client is never reused\n * across two daemons (the connect-first probe discards its own on failure).\n */\nfunction newClient(): Client {\n return new Client(\n { name: 'noir-cli', version: NOIR_VERSION },\n { versionNegotiation: { mode: 'auto' } },\n );\n}\n\n/** Connect a Client over Streamable HTTP, rethrowing the RAW transport error so\n * the caller owns the failure mapping. Used by {@link withWorkspaceDaemon},\n * which can read more out of a connect failure than \"the daemon is down\" (a\n * 401 means it is up and reachable but rejected our credential). Everything\n * else goes through {@link connectClient}, which maps onto exit 4. */\nasync function connectRaw(client: Client, url: string, scopeKey: string | null): Promise<void> {\n await client.connect(httpTransport(url, scopeKey));\n}\n\n/** Connect a Client over Streamable HTTP; map transport failure to exit 4. */\nasync function connectClient(\n client: Client,\n url: string,\n opts: DaemonClientOptions,\n scopeKey: string | null,\n): Promise<void> {\n try {\n await connectRaw(client, url, scopeKey);\n } catch (err) {\n failDaemonDown(opts, err);\n }\n}\n\n/**\n * Map a WORKSPACE connect failure onto exit 4 with an accurate message.\n *\n * A 401 is not \"the daemon is down\": the daemon answered, so it IS reachable —\n * it rejected our bearer token (a stale token file, or one we cannot read). The\n * generic {@link DAEMON_DOWN_HINT} sends the user to `noir daemon start`, which\n * fixes nothing. Name the token file (the workspace scope key is the workspace\n * NAME) and the remedy instead. Conservative by construction: only the MESSAGE\n * differs for the recognizable-401 case — the exit code and every non-401\n * failure keep the exact previous behaviour.\n */\nfunction failWorkspaceConnect(\n opts: DaemonClientOptions,\n routing: WorkspaceRouting,\n cause: unknown,\n): never {\n const text = String(cause).toLowerCase();\n if (text.includes('401') || text.includes('unauthorized')) {\n if (opts.verbose) {\n process.stderr.write(`noir: daemon transport detail: ${describeCause(cause)}\\n`);\n }\n // Names only, never a value: the token file's path, never its contents.\n fail(\n EXIT.DAEMON_DOWN,\n `workspace ${JSON.stringify(routing.name)} daemon is running but rejected this client's token (HTTP 401) — its token file is ${tokenPath(routing.name)}; make sure it is readable, or restart the workspace daemon with \\`noir daemon start --workspace ${routing.name}\\` to mint a fresh one.`,\n opts,\n );\n }\n failDaemonDown(opts, cause);\n}\n\n/**\n * Call one daemon tool and parse its text-JSON result. A tool's own\n * logical-failure envelope is returned as data; transport / parse failures\n * throw exit 4.\n */\nasync function callToolParse<T>(\n client: Client,\n opts: DaemonClientOptions,\n name: string,\n args: Record<string, unknown>,\n): Promise<T> {\n // `.catch` whose handler returns `never` (failDaemonDown always throws) keeps\n // `result` typed as the callTool payload — no evolving-any `let`, and the only\n // way past this line is a successful call.\n const result = await client\n .callTool({ name, arguments: args })\n .catch((err: unknown) => failDaemonDown(opts, err));\n // The daemon's tools always return `{content:[{type:'text', text: JSON}]}` via\n // `textResult`. Read defensively: any non-text / empty / non-JSON block means\n // the MCP surface is unusable → exit 4 (not a tool's logical error).\n const block = (result.content as readonly unknown[] | undefined)?.[0] as\n | { type?: string; text?: unknown }\n | undefined;\n if (block?.type !== 'text' || typeof block.text !== 'string') {\n failDaemonDown(opts, new Error(`tool '${name}' returned no text content`));\n }\n const text: string = block.text;\n try {\n return JSON.parse(text) as T;\n } catch (err) {\n failDaemonDown(opts, err);\n }\n}\n\n/**\n * Build a {@link DaemonToolCaller} over an already-connected {@link Client}.\n * Shared by {@link withDaemon} (active commands — failures map to exit 4) and\n * {@link withRunningDaemon} (status — connect failures degrade to null, caught\n * by its outer try). `callTool`/`listTools` still route transport / parse\n * failures through {@link failDaemonDown}; {@link withRunningDaemon} wraps the\n * connect+fn body so those become a null result instead of an exit.\n */\nfunction buildCaller(client: Client, opts: DaemonClientOptions): DaemonToolCaller {\n return {\n callTool: <U = unknown>(name: string, args: Record<string, unknown> = {}): Promise<U> =>\n callToolParse<U>(client, opts, name, args),\n listTools: async (): Promise<string[]> => {\n // `listTools()` is the standard MCP capability discovery method; the\n // daemon's McpServer answers with every registered tool name. Any\n // transport failure maps to exit 4 (DAEMON_DOWN) exactly like callTool;\n // a defensive read of `.tools` keeps a surprising payload from crashing.\n const res = await client.listTools().catch((err: unknown) => failDaemonDown(opts, err));\n const tools = (res as { tools?: unknown } | null)?.tools;\n if (!Array.isArray(tools)) return [];\n const names: string[] = [];\n for (const t of tools) {\n const name = (t as { name?: unknown } | null)?.name;\n if (typeof name === 'string') names.push(name);\n }\n return names;\n },\n };\n}\n\n/**\n * Connect to the daemon and run `fn` against a {@link DaemonToolCaller} that\n * shares one MCP connection across any number of tool calls.\n *\n * {@link resolveDaemon} owns the CONNECT-FIRST ordering (spec 7.1) and returns\n * a connection it has already established, so this body only has to run `fn`\n * and tear down. The client is closed and any daemon this call started is torn\n * down in `finally`, even when `fn` throws — so a one-shot CLI command never\n * strands a server or leaks a connection, while a reused (already-running)\n * daemon is left untouched (both `ensureDaemonRunning`'s `stop` for a reused\n * daemon and the connect-first path's `stop` are no-ops in that case).\n *\n * That `finally` is reached only once `resolveDaemon` has RETURNED. A throw from\n * `resolveDaemon` itself (exit 4) skips it entirely, so the same tear-down is\n * performed inside `resolveDaemon` before it throws — the two legs must stay in\n * step, or a spawned daemon is stranded. See the retry-failure catch there.\n *\n * `fn`'s own errors propagate untouched (the command module owns their exit\n * code); only transport / connection / tool-parse failures map to exit 4 here.\n */\nexport async function withDaemon<T>(\n opts: DaemonClientOptions,\n fn: (caller: DaemonToolCaller) => Promise<T>,\n): Promise<T> {\n const { client, stop } = await resolveDaemon(opts);\n try {\n return await fn(buildCaller(client, opts));\n } finally {\n await client.close().catch(() => {\n /* a close error must not mask the real failure / swallowed result */\n });\n await stop().catch(() => {\n /* ditto: tear-down failures never override the command's outcome */\n });\n }\n}\n\n/**\n * Connect to an ALREADY-RUNNING daemon (located via {@link probeDaemon}) and run\n * `fn` over one MCP connection. NEVER starts a daemon — returns `null` when the\n * probe finds none. This is the read-only, best-effort path `noir status` uses:\n * a down daemon is reported honestly (the caller renders `daemon:{running:false}`\n * and exits 0 — status is informational, not a write), and any connect failure\n * that crops up after a successful probe (the daemon died mid-snapshot) degrades\n * to `null` rather than escalating to exit 4 (DAEMON_DOWN). Active commands that\n * NEED a daemon use {@link withDaemon} (which auto-starts + maps failures to\n * exit 4); only `status` is probe-only.\n *\n * `fn` should wrap its own tool calls in a try/catch (status uses `tryTool`) so a\n * single missing engine folds to `null` instead of failing the snapshot.\n *\n * `probe` lets a caller that has ALREADY probed (status, to populate the daemon\n * section whether up or down) pass the result in so we don't GET /health twice.\n */\nexport async function withRunningDaemon<T>(\n opts: DaemonClientOptions,\n fn: (caller: DaemonToolCaller) => Promise<T>,\n probe?: DaemonProbe,\n): Promise<T | null> {\n const p = probe ?? (await probeDaemon(opts));\n if (!p.running) return null;\n const url = `http://127.0.0.1:${p.port}/mcp`;\n let client: Client | undefined;\n try {\n client = newClient();\n const connected: Client = client;\n // Connect directly to the probed port — NO ensureDaemonRunning. If the daemon\n // died between probe and connect (a race), this throws and we degrade to null\n // (the probe already supplied pid/uptime for the snapshot). The bearer header\n // is required here too: /health is token-free (the probe above passed without\n // one), but the /mcp snapshot connect is authenticated like every other one.\n await connected.connect(httpTransport(url, callerScopeKey(opts)));\n return await fn(buildCaller(connected, opts));\n } catch {\n // Best-effort: probe said up but connect/transport failed mid-snapshot.\n // Report the probe data + null sections instead of exit 4.\n return null;\n } finally {\n if (client) {\n await client.close().catch(() => {\n /* a close error must not mask the degraded result */\n });\n }\n }\n}\n\n/**\n * Call a single daemon MCP tool and return its parsed JSON payload. The\n * convenience most command modules use; built on {@link withDaemon} so connect\n * + close + tear-down are handled once.\n */\nexport async function callDaemonTool<T = unknown>(\n opts: DaemonClientOptions,\n name: string,\n args: Record<string, unknown> = {},\n): Promise<T> {\n return withDaemon<T>(opts, (caller) => caller.callTool<T>(name, args));\n}\n\n// ---------------------------------------------------------------------------\n// In-process read-only fallback (S9 DS-5). READS only — the single-writer\n// invariant is preserved because the store is opened READ-ONLY and every engine\n// built over it (context retriever, memory recall/sessions, workflow status) is\n// a pure reader. Writes keep the daemon-required path (exit 4 when down).\n// ---------------------------------------------------------------------------\n\n/** Engines constructed in-process by {@link withInProcessRead} (reads only). */\nexport interface InProcessEngines {\n /** Hybrid-retrieval engine over the read-only store handle. */\n context: ContextEngine;\n /** Cross-session memory engine over the same handle (recall/sessions read). */\n memory: MemoryEngine;\n /** Workflow engine over the same handle (status read). */\n workflow: WorkflowEngine;\n}\n\n/**\n * Open the project's store READ-ONLY, build the context + memory + workflow\n * engines in-process over that one handle, run `fn`, and close the store in\n * `finally`. This is the daemon-down fallback for READ commands (`context\n * search`, `memory recall`, `memory sessions`, `task status`): a read-only\n * handle preserves the daemon's single-writer discipline (the store is never\n * opened for writes here), and reads (FTS, kNN, counts, KV) keep working on it\n * exactly as they do for a degraded daemon handle.\n *\n * Construction mirrors {@link openStoreForDaemon} + the daemon's stdio/http\n * seams: the context engine resolves its embedder from the project's\n * `context:` config via {@link resolveEmbedderConfig} (a pure projection —\n * construction never touches the network or the native runtime; a `kind:'none'`\n * or unavailable embedder degrades reads to BM25-only, F8); the memory engine\n * shares the SAME embed; the workflow engine reads the store KV. All three\n * reuse the injected handle — no second connection.\n *\n * `storeDegraded: true` is threaded into both engines so their persistent\n * `degraded` flag is honest (a read-only handle) and any accidental write\n * refuses with the daemon's \"store is read-only (daemon down)\" error rather\n * than silently succeeding.\n *\n * The store is ALWAYS closed in `finally`, even when `fn` throws (a one-shot\n * CLI command never strands a handle).\n *\n * @param opts Daemon-client options. `project` resolves the store path + the\n * embedder config; when absent it is resolved from `process.cwd()`\n * (uninitialized project → throws the \"Run `noir init` first\" exit-1 hint,\n * mirroring {@link resolveDaemon}).\n */\nexport async function withInProcessRead<T>(\n opts: DaemonClientOptions,\n fn: (engines: InProcessEngines) => Promise<T>,\n): Promise<T> {\n let project: ProjectInfo;\n try {\n project = opts.project ?? loadProjectInfo(process.cwd());\n } catch {\n fail(EXIT.ERROR, 'Noir is not initialized in this directory. Run `noir init` first.', opts);\n }\n // Route a store-open failure through fail() so --json emits {ok:false,error}\n // (a raw throw would leave stdout empty).\n let store: Store;\n try {\n store = await openStore({ projectId: project.id, root: project.root, readonly: true });\n } catch (err) {\n fail(\n EXIT.ERROR,\n `could not open the store read-only: ${err instanceof Error ? err.message : String(err)}`,\n opts,\n );\n }\n try {\n // READ-ONLY handle: `storeDegraded` is threaded so status/degraded flags are\n // honest and any accidental write refuses cleanly (single writer preserved).\n const embedderCfg = resolveEmbedderConfig(project.config.context);\n const embed = createEmbedFn(embedderCfg).embed;\n const context = new ContextEngine({\n store,\n root: project.root,\n projectId: project.id,\n embedderCfg,\n storeDegraded: true,\n });\n const memory = createMemoryEngine({\n store,\n root: project.root,\n projectId: project.id,\n embed,\n storeDegraded: true,\n });\n const workflow = new WorkflowEngine(\n store,\n project.root,\n project.id,\n resolveGateConfig(project.config),\n );\n return await fn({ context, memory, workflow });\n } finally {\n await store.close().catch(() => {\n /* a close error must not mask the command's outcome */\n });\n }\n}\n\n// ---------------------------------------------------------------------------\n// Workspace-aware routing (ADR-0009). In a repo that joined a workspace (a\n// `.noir/workspace.json` marker), `memory *` commands route to the WORKSPACE\n// daemon (`?p=<projectId>`), not the per-project daemon. The read fallback opens\n// the workspace store read-only (single-writer preserved). Context/workflow/task\n// commands keep the project daemon (spec §6).\n// ---------------------------------------------------------------------------\n\n/** A repo's workspace membership (name + this repo's project id), or null. */\nexport interface WorkspaceRouting {\n name: string;\n projectId: string;\n}\n\nexport function workspaceRoutingTarget(root: string): WorkspaceRouting | null {\n const name = readWorkspaceMarker(root);\n if (name === null) return null;\n try {\n return { name, projectId: loadProjectInfo(root).id };\n } catch {\n return null;\n }\n}\n\n/** Read-only probe of a workspace daemon (never starts one). */\nexport async function probeWorkspaceDaemon(routing: WorkspaceRouting): Promise<DaemonProbe> {\n const rec = readWorkspaceDaemonRecord(routing.name);\n if (rec === null || !pidAlive(rec.pid)) return { running: false };\n try {\n const res = await fetch(`http://127.0.0.1:${rec.port}/health`, {\n signal: AbortSignal.timeout(PROBE_TIMEOUT_MS),\n });\n if (!res.ok) return { running: false };\n const body = (await res.json().catch(() => null)) as {\n ok?: boolean;\n pid?: number;\n workspace?: string;\n } | null;\n if (body?.ok !== true || body.workspace !== routing.name || body.pid !== rec.pid) {\n return { running: false };\n }\n return { running: true, pid: rec.pid, port: rec.port };\n } catch {\n return { running: false };\n }\n}\n\n/** Connect to the workspace daemon (`?p=<projectId>`) and run `fn` (active path). */\nexport async function withWorkspaceDaemon<T>(\n opts: DaemonClientOptions,\n routing: WorkspaceRouting,\n fn: (caller: DaemonToolCaller) => Promise<T>,\n): Promise<T> {\n // Spec §11: a write/read against a workspace whose daemon is DOWN must fail\n // with clear guidance, NOT silently auto-start a fresh daemon (which would\n // look identical to \"up\" but surprise the user). Probe-only — no ensure.\n const probe = await probeWorkspaceDaemon(routing);\n if (!probe.running || probe.port === undefined) {\n fail(\n EXIT.DAEMON_DOWN,\n `workspace ${JSON.stringify(routing.name)} daemon is not running — start it with \\`noir daemon start --workspace ${routing.name}\\` (or run \\`noir workspace status\\`).`,\n opts,\n );\n }\n const url = `http://127.0.0.1:${probe.port}/mcp?p=${routing.projectId}`;\n let client: Client | undefined;\n try {\n client = newClient();\n const connected: Client = client;\n // The workspace daemon's token scope key is the workspace NAME — its own\n // secret, resolved from disk at connect time like every other token. In\n // particular the CALLER's project token is never handed to a workspace\n // server: the two scope keys are different identities, so a repo can only\n // ever present the credential of the daemon it is actually addressing.\n // `connectRaw` (not `connectClient`) so a 401 rejection reaches\n // `failWorkspaceConnect` with its cause intact, instead of being flattened\n // into the generic \"daemon not reachable\" hint.\n await connectRaw(connected, url, routing.name).catch((err: unknown) =>\n failWorkspaceConnect(opts, routing, err),\n );\n return await fn(buildCaller(connected, opts));\n } finally {\n if (client) {\n await client.close().catch(() => {\n /* a close error must not mask the real failure */\n });\n }\n }\n}\n\n/** Open the workspace store read-only and run `fn` over a memory engine (read fallback). */\nexport async function withWorkspaceMemoryRead<T>(\n opts: DaemonClientOptions,\n routing: WorkspaceRouting,\n project: ProjectInfo,\n fn: (memory: MemoryEngine) => Promise<T>,\n): Promise<T> {\n let store: Store;\n try {\n store = await openStore({\n projectId: `ws-${routing.name}`,\n root: project.root,\n dbPath: workspaceStoreDbPath(routing.name),\n readonly: true,\n });\n } catch (err) {\n // Reached only when the workspace daemon is already down (this is its read\n // fallback). The dominant cause is a store that was never created, so give\n // the same actionable guidance + DAEMON_DOWN exit code the active path uses\n // rather than a bare store-open error — the caller's next step is the same\n // either way: start the daemon.\n fail(\n EXIT.DAEMON_DOWN,\n `workspace ${JSON.stringify(routing.name)} store is unavailable (${err instanceof Error ? err.message : String(err)}) — start its daemon with \\`noir daemon start --workspace ${routing.name}\\` (or run \\`noir workspace status\\`).`,\n opts,\n );\n }\n const embedderCfg = resolveEmbedderConfig(project.config.context);\n const embed = createEmbedFn(embedderCfg).embed;\n const memory = createMemoryEngine({\n store,\n root: project.root,\n projectId: `ws-${routing.name}`,\n embed,\n storeDegraded: true,\n softForget: true,\n });\n try {\n return await fn(memory);\n } finally {\n await store.close().catch(() => {\n /* a close error must not mask the command's outcome */\n });\n }\n}\n","// `noir` bin entry. Migrated from the hand-rolled `parseArgs` dispatcher onto a\n// commander Command tree (S9 t1). Behavior of init / sync / mcp serve / daemon\n// start|stop / doctor is preserved flag-for-flag; the only change is the dispatch\n// path and the new global flags + exit-code contract.\n//\n// Testability: commander is configured with `.exitOverride()` so it NEVER calls\n// `process.exit`. The exported `createProgram()` factory returns a fresh, fully\n// wired program for unit tests; `run(argv)` is the bin's own entry and maps any\n// thrown error to `process.exitCode` (Node then exits naturally with that code).\n// A main-module guard prevents auto-running when bin.ts is imported by tests.\n\nimport { realpathSync } from 'node:fs';\nimport { pathToFileURL } from 'node:url';\nimport { type HostId, SUPPORTED_HOSTS } from '@noir-ai/adapters';\nimport { applyNoirEnv, NOIR_VERSION } from '@noir-ai/core';\nimport { Command, Option } from 'commander';\nimport { contextIndex, contextSearch, contextStatus } from './commands/context.js';\nimport {\n daemonRestart,\n daemonStart,\n daemonStatus,\n daemonStop,\n daemonToken,\n} from './commands/daemon.js';\nimport { doctor } from './commands/doctor.js';\nimport { captureAmbientEnv, env } from './commands/env.js';\nimport { type HandoffOptions, handoff } from './commands/handoff.js';\nimport { type HomeDeps, home } from './commands/home.js';\nimport {\n memoryCapture,\n memoryConsolidate,\n memoryForget,\n memoryRecall,\n memorySave,\n memorySessions,\n} from './commands/memory.js';\nimport { release } from './commands/release.js';\nimport { type RunOptions, run as runHostCommand } from './commands/run.js';\nimport { skillsLint, skillsList, skillsRegistry, skillsSync } from './commands/skills.js';\nimport { type StatusOptions, status } from './commands/status.js';\nimport {\n taskAbandon,\n taskAdvance,\n taskBlock,\n taskDecompose,\n taskNew,\n taskNext,\n taskResearch,\n taskResearchRecord,\n taskResume,\n taskStatus,\n taskVerify,\n} from './commands/task.js';\nimport {\n daemonJoin,\n workspaceLeave,\n workspaceList,\n workspaceStatus,\n workspaceStop,\n} from './commands/workspace.js';\nimport { init } from './init.js';\nimport {\n type CliOptions,\n EXIT,\n fail,\n handleError,\n inferExitCode,\n info,\n json,\n NoirCliError,\n requireInteractive,\n table,\n tip,\n} from './output.js';\nimport { listProfiles, loadRunConfig } from './run-profiles.js';\nimport { serve } from './serve.js';\nimport { buildPaletteCommands } from './tui/commands/registry.js';\nimport type { PaletteCommand } from './tui/palette/types.js';\n\n// Exit-code contract, error type, `fail`, and exit-code mapping live in\n// `./output.js` (S9 t2 central output infra). Re-exported here so existing\n// imports from `./bin.js` (bin.test.ts, future commands) keep working without\n// a second source of truth.\nexport { EXIT, fail, inferExitCode, NoirCliError };\n\n/**\n * The TUI palette source (B3). Walks a FRESH {@link createProgram} at `noir tui`\n * launch and projects every leaf subcommand into a {@link PaletteCommand}.\n * Defined here (not in the tui) so the palette derives from the REAL command\n * tree without the tui graph importing the bin (which would be circular).\n */\nexport function buildPaletteCommandsForTui(): PaletteCommand[] {\n return buildPaletteCommands(createProgram());\n}\n\n// ---------------------------------------------------------------------------\n// Program factory. Each call returns a fresh, independently-parseable Command\n// (commander parse state is mutable, so tests should drive a fresh program).\n// ---------------------------------------------------------------------------\n\n// ---------------------------------------------------------------------------\n// Action-option bridge. Commander passes each action handler the positional\n// args + options + the action's Command as the LAST argument. The global flags\n// (`--json/--no-input/--quiet/--verbose/--cwd`, registered `` on\n// the program) land on `command.optsWithGlobals()`. The two helpers below read\n// those globals off the trailing Command without depending on how many params\n// commander injected in front of it (it varies with the command's arity), so a\n// single pattern works for every action.\n// ---------------------------------------------------------------------------\nfunction actionGlobals(args: readonly unknown[]): Record<string, unknown> {\n // `noUncheckedIndexedAccess` → element access yields `unknown`; the optional\n // chain + cast handles the undefined case without a runtime branch.\n const last = args[args.length - 1];\n return (last as Command | undefined)?.optsWithGlobals() ?? {};\n}\n\n/**\n * The trailing {@link Command} commander always passes as the LAST action\n * argument. Used by the context/memory/task actions to read their own options\n * (`cmd.opts()`) + globals (`cmd.optsWithGlobals()`) without depending on how\n * many positional args commander injected in front of it. Positional values are\n * read off the FRONT of `args` (commander puts positionals first, then the\n * options object, then the command). Throws on a malformed call rather than\n * silently coercing `undefined`.\n */\nfunction trailingCmd(args: readonly unknown[]): Command {\n const last = args[args.length - 1];\n if (!(last instanceof Command)) {\n throw new NoirCliError(\n EXIT.ERROR,\n 'internal: commander action callback received no trailing Command',\n );\n }\n return last;\n}\n\n/** Map commander's parsed global-flag bag onto the CLI's {@link CliOptions}. */\nfunction toCliOptions(g: Record<string, unknown>): CliOptions {\n // `--no-input` is stored under `input` (commander strips the `no-` prefix);\n // default `true`, so `input !== false` ⇒ input allowed.\n return {\n json: g.json === true,\n quiet: g.quiet === true,\n verbose: g.verbose === true,\n input: g.input !== false,\n // TUI policy — additive only. `--tui`/`--no-tui` land on `tui`\n // (true/false; absent when neither flag is given). Spread conditionally so\n // the default-args case (no flag) does NOT add a `tui` key — keeps the\n // exact-shape assertions in bin.test.ts green.\n ...(g.tui === true || g.tui === false ? { tui: g.tui === true } : {}),\n // `--no-tips` is stored under `tips` (default true; flag ⇒ false). Map to\n // the additive `noTips` spelling used by CliOptions + `tip()`.\n ...(g.tips === false ? { noTips: true } : {}),\n };\n}\n\n/** {@link toCliOptions} + the daemon-client knobs `status` needs. */\nfunction toStatusOptions(g: Record<string, unknown>): StatusOptions {\n return {\n json: g.json === true,\n quiet: g.quiet === true,\n verbose: g.verbose === true,\n input: g.input !== false,\n ...(g.tips === false ? { noTips: true } : {}),\n };\n}\n\n/**\n * S10 — narrow commander's `string | undefined` host option to `HostId |\n * undefined`. Commander's `.choices(SUPPORTED_HOSTS)` already rejects unknown\n * values at parse time (usage=2), so by the time the action runs any string\n * present IS one of `SUPPORTED_HOSTS`. The cast is therefore total — but kept\n * explicit (not a type assertion) so a future change to the choices wiring\n * surfaces here rather than silently coercing. Returns `undefined` for an\n * unset flag so callers can conditional-spread (preserves the exact-arg-shape\n * assertions in bin.test.ts).\n */\nfunction parseHost(raw: string | undefined): HostId | undefined {\n if (raw === undefined) return undefined;\n // The cast is safe: commander's `.choices` enforces it pre-action.\n return raw as HostId;\n}\n\n// ---------------------------------------------------------------------------\n// TUI policy + deprecation / redirect infrastructure.\n//\n// Approach B (locked): TUI-primary UX, but NEVER hard-gate any subcommand. The\n// bare `noir` home menu is the documented human entry point; every subcommand\n// stays 100% scriptable. `--json` is the headless contract. The deprecation\n// registry below is the formal \"warn for N → redirect for N → never silently\n// remove\" channel; ZERO entries today (no command is deprecated).\n// ---------------------------------------------------------------------------\n\n/** One entry in the {@link DEPRECATIONS} registry. */\nexport interface DeprecationEntry {\n /** Old command form as a path prefix, e.g. `['legacy-status']` or\n * `['context','legacy']`. Matched against the dispatched command's path\n * (program name `noir` stripped). */\n readonly oldArgv: readonly string[];\n /** Replacement command form, e.g. `['status']`. Shown in the redirect hint. */\n readonly newArgv: readonly string[];\n /** Version the deprecation started in, e.g. `'1.4.0'`. */\n readonly since: string;\n}\n\n/**\n * Deprecation registry. **Empty today** — no `noir` command is deprecated.\n * When adding an entry, update the CHANGELOG + `docs/reference/cli.md` (and,\n * if the old form still routes, add a redirect). {@link emitDeprecationHintsFor}\n * scans this on every dispatch and emits one `tip()` per match; `--no-tips` /\n * `--json` suppress the hint (see {@link tip}).\n */\nexport const DEPRECATIONS: DeprecationEntry[] = [];\n\n/**\n * Build the dispatched command's path (e.g. `['noir','context','search']`) by\n * walking `.parent` up to the program root. Used by {@link emitDeprecationHintsFor}\n * to match an {@link DeprecationEntry.oldArgv} prefix (program name stripped).\n */\nfunction commandPath(cmd: Command): string[] {\n const path: string[] = [];\n let c: Command | null = cmd;\n while (c !== null) {\n path.unshift(c.name());\n c = c.parent;\n }\n return path;\n}\n\n/**\n * Emit one redirect hint per matching {@link DEPRECATIONS} entry for the\n * dispatched command. Respects `--no-tips` and `--json` via {@link tip} (a CI\n * run's stderr stays quiet and its stdout envelope stays pristine). Exported so\n * tests can drive it with a temporarily-populated registry without going\n * through commander.\n */\nexport function emitDeprecationHintsFor(cmd: Command, opts: CliOptions): void {\n if (DEPRECATIONS.length === 0) return; // common case (no entries today)\n // Strip the leading program name ('noir') for matching.\n const rel = commandPath(cmd).slice(1);\n for (const d of DEPRECATIONS) {\n if (d.oldArgv.every((a, i) => rel[i] === a)) {\n tip(\n `\\`noir ${d.oldArgv.join(' ')}\\` is deprecated since v${d.since}; use \\`noir ${d.newArgv.join(' ')}\\`.`,\n opts,\n );\n }\n }\n}\n\nexport function createProgram(): Command {\n const program = new Command();\n\n program\n .name('noir')\n .description('Noir — discipline, context, and memory layer for agentic CLIs.')\n .version(NOIR_VERSION, '-v, --version')\n // Global flags (S9). makeGlobal() propagates each to every subcommand so\n // they parse in any position (e.g. `noir status --json` as well as `noir\n // --json status`) and appear on subcommand --help.\n .addOption(new Option('--json', 'emit machine-readable JSON to stdout'))\n .addOption(new Option('--no-input', 'never prompt; error if input is required'))\n .addOption(new Option('--quiet', 'suppress non-essential diagnostics'))\n .addOption(new Option('--verbose', 'show additional diagnostic detail'))\n .addOption(new Option('--cwd <path>', 'run as if started in <path>'))\n // TUI policy — advisory routing for bare `noir` only (never hard-gates a\n // subcommand). `--tui`/`--no-tui` are a commander negatable pair: parsed\n // onto a single `tui` attribute (true / false / absent=auto). Bare `noir`\n // in a TTY runs the home menu by default; `--no-tui` forces the\n // non-interactive `status` path even in a TTY; `--tui` is a hint that still\n // requires a TTY (so it never blocks in CI / a pipe). See home.ts + CLAUDE.md.\n .addOption(\n new Option('--tui', 'prefer the interactive home menu for bare `noir` (advisory; TTY-only)'),\n )\n .addOption(\n new Option(\n '--no-tui',\n 'route bare `noir` to the non-interactive `status` path even in a TTY',\n ),\n )\n // Deprecation / redirect hints — `--no-tips` silences the `tip()` helper\n // for CI / log-friendly runs. No command is deprecated today; the flag is\n // the headless contract for quieting future notices.\n .addOption(new Option('--no-tips', 'suppress redirect / deprecation hints on stderr'))\n .exitOverride((err) => {\n // Never process.exit; surface to the caller (run()/test) instead.\n throw err;\n })\n .configureOutput({\n // Stream discipline: --help/--version → stdout (conventional; users pipe\n // them), errors → stderr. --json data is emitted by command actions via\n // process.stdout directly, NOT by commander's writeOut, so routing help/\n // version to stdout does not conflict with --json payloads.\n writeOut: (str) => process.stdout.write(str),\n writeErr: (str) => process.stderr.write(str),\n });\n\n // --cwd: chdir before the action runs so the existing modules (which read\n // process.cwd()) honor it. actionCmd.optsWithGlobals() works on whichever\n // program instance is being parsed, so createProgram() isolates correctly.\n program.hook('preAction', (_thisCmd, actionCmd) => {\n const opts = actionCmd.optsWithGlobals();\n const cwd = opts.cwd;\n if (typeof cwd === 'string' && cwd.length > 0) {\n try {\n process.chdir(cwd);\n } catch (err) {\n throw new NoirCliError(\n EXIT.USAGE,\n `--cwd: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n }\n // Load project-local .noir/.env AFTER the --cwd chdir so the .env root\n // matches the effective project (a `--cwd /other` run must never inherit the\n // launch dir's tokens into the host subprocess). Idempotent — and spec 12.1\n // inverts the usual dotenv rule: a key the file DEFINES wins, and the real\n // environment is the fallback for keys the file omits. The overlay is\n // confined to this process tree (see applyNoirEnv), so a sibling shell and\n // the user's own manual `claude` invocations are untouched.\n //\n // `noir env` is the ONE command that must also see the AMBIENT environment\n // as it was before that overlay: reporting \"the file's value won, and the\n // one you exported is being ignored\" needs the pre-overlay values, which are\n // indistinguishable from the file's own afterwards. Capture it for that\n // command only — every other command just applies the overlay.\n if (actionCmd.name() === 'env') captureAmbientEnv();\n applyNoirEnv(process.cwd());\n // SP-G: propagate --json / --no-input to the deep conflict resolver via env\n // so a regenerate conflict never prompts under those flags (the @clack\n // prompt writes to stdout — it would corrupt --json output and violate\n // --no-input). Done here centrally so init/create/sync need no arg changes\n // (no bin.test.ts arg-pin cascade). buildConflictOpts reads this flag.\n const nonInteractive = opts.json === true || opts.input === false;\n if (nonInteractive) process.env.NOIR_NON_INTERACTIVE = '1';\n else delete process.env.NOIR_NON_INTERACTIVE;\n // Deprecation / redirect hints. Scans {@link DEPRECATIONS} against the\n // dispatched command path; emits via `tip()` (suppressed by --no-tips /\n // --json). Empty registry today — no-op until an entry is added.\n emitDeprecationHintsFor(actionCmd, toCliOptions(opts));\n });\n\n // ----- migrated commands (behavior-preserving) -----\n\n program\n .command('init')\n .description('scaffold Noir in the current project (.noir/, .mcp.json, CLAUDE.md, skills)')\n .option('--transport <transport>', 'stdio | streamable-http (default: stdio)', 'stdio')\n .option('--url <url>', 'streamable-http daemon URL (localhost only)')\n .option(\n '--upgrade',\n 'run scaffold migrations before re-emitting (re-run on an existing project)',\n )\n .option('--force', 're-scaffold even if already initialized (bypasses the already-init no-op)')\n .option('--dry-run', 'report planned writes without writing anything')\n .option('--preview', 'alias for --dry-run')\n .addOption(\n // S10: target host. Defaults to `'claude'` (the regression anchor). The\n // chosen host is forwarded to scaffold() + skills emission via\n // resolveAdapter. The choice list mirrors `SUPPORTED_HOSTS` so a new host\n // lands here automatically; commander rejects anything else as usage=2.\n new Option(\n '--host <id>',\n 'target agentic CLI (default: claude) — drives host-side emission',\n ).choices(SUPPORTED_HOSTS),\n )\n .action(\n async (\n opts: {\n transport?: string;\n url?: string;\n upgrade?: boolean;\n force?: boolean;\n host?: string;\n dryRun?: boolean;\n preview?: boolean;\n },\n cmd: Command,\n ) => {\n // Preserve the parseArgs coercion exactly: only 'streamable-http' is\n // special; any other value (incl. typos / future transports) → 'stdio'.\n const transport: 'stdio' | 'streamable-http' =\n opts.transport === 'streamable-http' ? 'streamable-http' : 'stdio';\n // `upgrade`/`host` are conditionally spread so an UNSET flag does NOT add\n // an `upgrade: false` / `host: …` key to the opts object — that would\n // break the toEqual-based arg assertions in bin.test.ts (which expects\n // exactly `{transport, url}` for the default-invocation cases). Matches\n // the conditional-spread pattern used for task/memory options elsewhere.\n const upgrade = opts.upgrade === true;\n const force = opts.force === true;\n const host = parseHost(opts.host);\n // F1: --dry-run/--preview collapse to a single dryRun boolean (the\n // command modules read both spellings, but the bin normalizes).\n const dryRun = opts.dryRun === true || opts.preview === true;\n const result = await init(process.cwd(), {\n transport,\n url: opts.url,\n ...(upgrade ? { upgrade } : {}),\n ...(force ? { force } : {}),\n ...(host !== undefined ? { host } : {}),\n ...(dryRun ? { dryRun } : {}),\n });\n // ScaffoldResult gap close: surface the structured ScaffoldResult (with\n // `conflicts[]`) on stdout under `--json`, wrapped in the versioned\n // `{ok, data}` envelope so it matches the headless contract every read\n // command uses. The args passed to init() are UNCHANGED (bin.test.ts\n // arg pins still hold); only the return value is captured + emitted.\n // `init` returns `undefined` on the already-initialized no-op — skip.\n if (cmd.optsWithGlobals().json === true && result !== undefined) {\n json({ ok: true, data: result });\n }\n },\n );\n\n // `noir create [dir]` — greenfield AI-layer bootstrap (slice S). Lazy import\n // mirrors sync's dispatcher so the create module isn't loaded for unrelated\n // commands. Optional `[dir]` defaults to process.cwd() inside the action.\n program\n .command('create [dir]')\n .description('bootstrap the Noir AI layer in a new or empty directory')\n .option('--transport <transport>', 'stdio | streamable-http (default: stdio)', 'stdio')\n .option('--url <url>', 'streamable-http daemon URL (localhost only)')\n .option('--force', 're-scaffold even if already initialized (bypasses the already-init no-op)')\n .option('--dry-run', 'report planned writes without writing anything')\n .option('--preview', 'alias for --dry-run')\n .addOption(\n new Option(\n '--host <id>',\n 'target agentic CLI (default: claude) — drives host-side emission',\n ).choices(SUPPORTED_HOSTS),\n )\n .action(\n async (\n dir: string | undefined,\n opts: {\n transport?: string;\n url?: string;\n force?: boolean;\n host?: string;\n dryRun?: boolean;\n preview?: boolean;\n },\n cmd: Command,\n ) => {\n const transport: 'stdio' | 'streamable-http' =\n opts.transport === 'streamable-http' ? 'streamable-http' : 'stdio';\n const force = opts.force === true;\n const host = parseHost(opts.host);\n // F1: --dry-run/--preview collapse to a single dryRun boolean.\n const dryRun = opts.dryRun === true || opts.preview === true;\n const { create } = await import('./commands/create.js');\n const result = await create(dir, {\n transport,\n url: opts.url,\n ...(force ? { force } : {}),\n ...(host !== undefined ? { host } : {}),\n ...(dryRun ? { dryRun } : {}),\n });\n // ScaffoldResult gap close: surface the structured ScaffoldResult (with\n // `conflicts[]`) on stdout under `--json`, wrapped in the `{ok, data}`\n // envelope (headless contract). Skipped on the no-op return.\n if (cmd.optsWithGlobals().json === true && result !== undefined) {\n json({ ok: true, data: result });\n }\n },\n );\n\n program\n .command('sync')\n .description(\n 're-emit Noir managed files (.mcp.json, CLAUDE.md blocks, NOIR.md brief, ignores) + skills',\n )\n .option(\n '--force',\n 'overwrite differing regenerated files without prompting (bypasses the conflict menu)',\n )\n .option(\n '--merge',\n 'three-way merge managed regions (default since 1.3.0; flag kept for compatibility)',\n )\n .option('--dry-run', 'report planned writes without writing anything')\n .option('--preview', 'alias for --dry-run')\n .addOption(\n // Opt OUT of managed-region merge (restore strip-replace). Commander\n // stores `--no-merge-regions` under `mergeRegions` (default true; flag →\n // false). Bare `noir sync` keeps the merge default (true).\n new Option(\n '--no-merge-regions',\n 'strip-replace managed regions (discard hand-edits inside <!-- noir:* --> markers)',\n ),\n )\n .addOption(\n // S10: optional `--host` override. When omitted, sync reads host from\n // `.noir/config.yml` (whatever `noir init --host <id>` persisted). The\n // override is rarely needed — documented as advanced.\n new Option(\n '--host <id>',\n 'override the configured host (advanced; default reads .noir/config.yml)',\n ).choices(SUPPORTED_HOSTS),\n )\n .action(\n async (\n opts: {\n host?: string;\n force?: boolean;\n merge?: boolean;\n mergeRegions?: boolean;\n dryRun?: boolean;\n preview?: boolean;\n },\n cmd: Command,\n ) => {\n // Lazy import preserves the original dispatcher's deferred module load.\n const { sync } = await import('./sync.js');\n const host = parseHost(opts.host);\n const force = opts.force === true;\n const merge = opts.merge === true;\n // `--no-merge-regions` → commander stores `mergeRegions: false`.\n const noMergeRegions = opts.mergeRegions === false;\n // F1: --dry-run/--preview collapse to a single dryRun boolean.\n const dryRun = opts.dryRun === true || opts.preview === true;\n // Single-positional regression anchor: when no `--host`/`--force`/`--merge`/\n // `--no-merge-regions`/`--dry-run` is given, call `sync(cwd)` exactly\n // (bin.test.ts pins this). Only spread the opts bag when a flag was\n // explicit so the default-args snapshot stays green.\n const result =\n host === undefined && !force && !merge && !noMergeRegions && !dryRun\n ? await sync(process.cwd())\n : await sync(process.cwd(), {\n ...(host !== undefined ? { host } : {}),\n ...(force ? { force } : {}),\n ...(merge ? { merge } : {}),\n ...(noMergeRegions ? { mergeManagedRegions: false } : {}),\n ...(dryRun ? { dryRun } : {}),\n });\n // ScaffoldResult gap close: surface the structured ScaffoldResult (with\n // `conflicts[]`) on stdout under `--json`, wrapped in the `{ok, data}`\n // envelope (headless contract). sync() always returns a ScaffoldResult\n // (never undefined), so the guard is the json flag only.\n if (cmd.optsWithGlobals().json === true) {\n json({ ok: true, data: result });\n }\n },\n );\n\n // `mcp` group — preserve legacy bare-`mcp` usage error.\n const mcpCmd = program.command('mcp').description('MCP server control');\n mcpCmd\n .command('serve')\n .description('run the Noir MCP server (stdio, or via the shared daemon)')\n .option('--stdio', 'force the stdio transport')\n .action(async (opts: { stdio?: boolean }) => {\n await serve({ stdio: opts.stdio === true });\n });\n mcpCmd.action(() => {\n throw new NoirCliError(EXIT.USAGE, 'Usage: noir mcp serve [--stdio]');\n });\n\n // `daemon` group — start/stop/status/restart (S9).\n // `start` runs the daemon in the FOREGROUND by default; `--detach` forks a\n // detached child (D1). `--_detached-child` is the hidden marker the detached\n // child carries (D2): it tells the child it IS the daemon (run in-process),\n // so it is never shown in `--help` and never meant for users.\n const daemonGrp = program.command('daemon').description('control the Noir daemon');\n daemonGrp\n .command('start')\n .description('start the Noir daemon (foreground, or background with --detach)')\n .option('--detach', 'run the daemon in the background and exit')\n .option('--workspace <name>', 'start a shared cross-repo workspace daemon instead')\n .option('--force', 'overwrite a non-Noir .mcp.json entry (--workspace only)')\n .addOption(\n new Option('--_detached-child', 'reserved: detached daemon child (internal)').hideHelp(),\n )\n .action(async (...args: unknown[]) => {\n const cmd = trailingCmd(args);\n const g = cmd.optsWithGlobals();\n const detach = g.detach === true;\n const detachChild = g._detachedChild === true;\n const workspace = typeof g.workspace === 'string' ? g.workspace : undefined;\n await daemonStart({\n ...toCliOptions(g),\n ...(detach ? { detach } : {}),\n ...(detachChild ? { detachChild } : {}),\n ...(workspace !== undefined ? { workspace } : {}),\n ...(g.force === true ? { force: true } : {}),\n });\n });\n daemonGrp\n .command('join')\n .description('join a shared workspace from this repo')\n .argument('<name>', 'workspace name')\n .option('--force', 'overwrite a non-Noir .mcp.json entry')\n .action(async (...args: unknown[]) => {\n const cmd = trailingCmd(args);\n const g = cmd.optsWithGlobals();\n const name = typeof args[0] === 'string' ? (args[0] as string) : '';\n await daemonJoin({ ...toCliOptions(g), name, ...(g.force === true ? { force: true } : {}) });\n });\n daemonGrp\n .command('stop')\n .description('stop the Noir daemon')\n .action(async (...args: unknown[]) => {\n await daemonStop(toCliOptions(trailingCmd(args).optsWithGlobals()));\n });\n daemonGrp\n .command('status')\n .description('report daemon pid/uptime/mode (exit 4 if not running)')\n .action(async (...args: unknown[]) => {\n await daemonStatus(toCliOptions(trailingCmd(args).optsWithGlobals()));\n });\n daemonGrp\n .command('token')\n .description('print the daemon bearer token to stdout (for a host headersHelper)')\n .action(async (...args: unknown[]) => {\n await daemonToken(toCliOptions(trailingCmd(args).optsWithGlobals()));\n });\n daemonGrp\n .command('restart')\n .description('stop then start the daemon')\n .option('--detach', 'run the daemon in the background and exit')\n .action(async (...args: unknown[]) => {\n const cmd = trailingCmd(args);\n const g = cmd.optsWithGlobals();\n await daemonRestart({\n ...toCliOptions(g),\n ...(g.detach === true ? { detach: true } : {}),\n });\n });\n daemonGrp.action(() => {\n throw new NoirCliError(EXIT.USAGE, 'Usage: noir daemon start|join|stop|status|restart|token');\n });\n daemonGrp.addHelpText(\n 'after',\n [\n '',\n 'Shared workspaces (two repos, one product — e.g. backend + frontend):',\n ' noir daemon start --workspace <name> --detach found a workspace from this repo',\n ' noir daemon join <name> join it from the other repo',\n '',\n 'Guide: docs/how-to/shared-workspaces.md',\n ].join('\\n'),\n );\n\n const workspaceGrp = program.command('workspace').description('shared cross-repo workspaces');\n workspaceGrp\n .command('list')\n .description('list workspaces on this machine')\n .action(async (...args: unknown[]) => {\n await workspaceList(toCliOptions(trailingCmd(args).optsWithGlobals()));\n });\n workspaceGrp\n .command('status')\n .description('members + daemon liveness for a workspace')\n .argument('[name]', \"workspace name (defaults to this repo's joined workspace)\")\n .action(async (...args: unknown[]) => {\n const cmd = trailingCmd(args);\n const name =\n typeof args[0] === 'string' && (args[0] as string).length > 0\n ? (args[0] as string)\n : undefined;\n await workspaceStatus({\n ...toCliOptions(cmd.optsWithGlobals()),\n ...(name !== undefined ? { name } : {}),\n });\n });\n workspaceGrp\n .command('leave')\n .description('leave the workspace this repo joined (restore stdio)')\n .option('--force', 'overwrite a non-Noir .mcp.json entry')\n .action(async (...args: unknown[]) => {\n const cmd = trailingCmd(args);\n const g = cmd.optsWithGlobals();\n await workspaceLeave({\n ...toCliOptions(g),\n ...(g.force === true ? { force: true } : {}),\n });\n });\n workspaceGrp\n .command('stop')\n .description('stop a workspace daemon (membership retained)')\n .argument('[name]', \"workspace name (defaults to this repo's joined workspace)\")\n .action(async (...args: unknown[]) => {\n const cmd = trailingCmd(args);\n const name =\n typeof args[0] === 'string' && (args[0] as string).length > 0\n ? (args[0] as string)\n : undefined;\n await workspaceStop({\n ...toCliOptions(cmd.optsWithGlobals()),\n ...(name !== undefined ? { name } : {}),\n });\n });\n workspaceGrp.addHelpText(\n 'after',\n [\n '',\n 'This group only inspects and leaves workspaces. To CREATE or JOIN one:',\n ' noir daemon start --workspace <name> --detach found it (from the first repo)',\n ' noir daemon join <name> join it (from the second repo)',\n '',\n 'Guide: docs/how-to/shared-workspaces.md',\n ].join('\\n'),\n );\n workspaceGrp.action(() => {\n throw new NoirCliError(EXIT.USAGE, 'Usage: noir workspace list|status|leave|stop');\n });\n\n program\n .command('doctor')\n .description('environment + project health')\n .option(\n '--dedup',\n 'scan host-context + .noir/ docs for semantic near-duplicates (loads the local embedder)',\n )\n .action(async (...args: unknown[]) => {\n const g = actionGlobals(args);\n const dedup = trailingCmd(args).opts().dedup === true;\n await doctor({ ...toCliOptions(g), ...(dedup ? { dedup: true } : {}) });\n });\n\n // ----- new subcommand groups (wired by t4) -----\n // Signatures match S9 §7 so --help is accurate; every action dispatches to\n // its command module in ./commands/*.js.\n\n program\n .command('status')\n .description('project + daemon + workflow + store snapshot')\n .action(async (...args: unknown[]) => {\n // Global flags (`--json`/`--verbose`/…) reach status via the trailing\n // Command; the action itself owns no command-specific options.\n await status(toStatusOptions(actionGlobals(args)));\n });\n\n // `noir env` — which configuration is in effect and where each value comes\n // from. READ-ONLY, and names-and-shapes only: never a value (spec 12.4).\n program\n .command('env')\n .description('which configuration is in effect and where each value comes from')\n .action(async (...args: unknown[]) => {\n await env(toCliOptions(actionGlobals(args)));\n });\n\n const contextGrp = program.command('context').description('context engine');\n contextGrp\n .command('search')\n .description('hybrid search over the indexed context')\n .argument('<query>', 'search query')\n .option('--limit <n>', 'max results', '10')\n .action(async (...args: unknown[]) => {\n const cmd = trailingCmd(args);\n const g = cmd.optsWithGlobals();\n // Positional `<query>` is always the leading action arg.\n const query = typeof args[0] === 'string' ? (args[0] as string) : '';\n const limit = typeof g.limit === 'string' ? (g.limit as string) : undefined;\n await contextSearch({\n ...toCliOptions(g),\n query,\n ...(limit === undefined ? {} : { limit }),\n });\n });\n contextGrp\n .command('index')\n .description('(re)index project files into the context store')\n // Repeatable: the `(val, acc) => [...acc, val]` coercion accumulates each\n // `--path` into an array (commander's idiomatic collect pattern), so\n // `--path a --path b` → `['a','b']` instead of last-wins.\n .option(\n '--path <p>',\n 'path to index (repeatable)',\n (val: string, acc: string[]) => [...acc, val],\n [] as string[],\n )\n .option('--force', 'force a full reindex (drop all chunks+vectors, re-index from scratch)')\n .action(async (...args: unknown[]) => {\n const cmd = trailingCmd(args);\n const g = cmd.optsWithGlobals();\n const rawPaths = Array.isArray(g.path)\n ? (g.path as unknown[]).filter((p): p is string => typeof p === 'string')\n : [];\n const force = g.force === true;\n await contextIndex({\n ...toCliOptions(g),\n ...(rawPaths.length === 0 ? {} : { paths: rawPaths }),\n ...(force ? { force } : {}),\n });\n });\n contextGrp\n .command('status')\n .description('index freshness + counts')\n .action(async (...args: unknown[]) => {\n await contextStatus(toCliOptions(trailingCmd(args).optsWithGlobals()));\n });\n contextGrp.action(() => {\n throw new NoirCliError(EXIT.USAGE, 'Usage: noir context search|index|status');\n });\n\n const memoryGrp = program.command('memory').description('memory engine');\n memoryGrp\n .command('recall')\n .description('recall memories for a query')\n .argument('<query>', 'recall query')\n .option('--limit <n>', 'max results', '10')\n .action(async (...args: unknown[]) => {\n const cmd = trailingCmd(args);\n const g = cmd.optsWithGlobals();\n const query = typeof args[0] === 'string' ? (args[0] as string) : '';\n const limit = typeof g.limit === 'string' ? (g.limit as string) : undefined;\n await memoryRecall({\n ...toCliOptions(g),\n query,\n ...(limit === undefined ? {} : { limit }),\n });\n });\n memoryGrp\n .command('save')\n .description('save an observation to long-term memory')\n // Both optional: `--content` is prompted interactively when absent (memory.ts),\n // or the command fails exit 2 under non-interactive / --no-input / --json.\n .option('--content <text>', 'memory content (prompted interactively if omitted)')\n .option(\n '--type <type>',\n 'observation type (pattern | preference | architecture | bug | workflow | fact | decision)',\n )\n .option('--files <files>', 'comma-separated related file paths')\n .action(async (...args: unknown[]) => {\n const cmd = trailingCmd(args);\n const g = cmd.optsWithGlobals();\n const content = typeof g.content === 'string' ? (g.content as string) : undefined;\n const type = typeof g.type === 'string' ? (g.type as string) : undefined;\n const files = typeof g.files === 'string' ? (g.files as string) : undefined;\n await memorySave({\n ...toCliOptions(g),\n ...(content === undefined ? {} : { content }),\n ...(type === undefined ? {} : { type }),\n ...(files === undefined ? {} : { files }),\n });\n });\n memoryGrp\n .command('sessions')\n .description('list recent memory sessions')\n .action(async (...args: unknown[]) => {\n await memorySessions(toCliOptions(trailingCmd(args).optsWithGlobals()));\n });\n memoryGrp\n .command('forget')\n .description('delete one or more memories by id')\n .argument('<ids...>', 'observation id(s)')\n .action(async (...args: unknown[]) => {\n const cmd = trailingCmd(args);\n const g = cmd.optsWithGlobals();\n // Variadic positional → commander passes a string[] as the leading arg.\n const rawIds = Array.isArray(args[0]) ? (args[0] as unknown[]) : [];\n const ids = rawIds.filter((x): x is string => typeof x === 'string');\n await memoryForget({ ...toCliOptions(g), ids });\n });\n memoryGrp\n .command('consolidate')\n .description('consolidate memories into a derived lesson (provider-explicit)')\n .option('--types <types>', 'comma-separated observation types to consolidate')\n .option('--limit <n>', 'cap on candidate observations')\n .action(async (...args: unknown[]) => {\n const cmd = trailingCmd(args);\n const g = cmd.optsWithGlobals();\n const types = typeof g.types === 'string' ? (g.types as string) : undefined;\n const limit = typeof g.limit === 'string' ? (g.limit as string) : undefined;\n await memoryConsolidate({\n ...toCliOptions(g),\n ...(types === undefined ? {} : { types }),\n ...(limit === undefined ? {} : { limit }),\n });\n });\n memoryGrp\n .command('capture')\n .description('distill a transcript/notes file (or stdin) into a memory (manual)')\n .argument('[file]', 'transcript/notes file (or pipe stdin)')\n .option('--content <text>', 'inline distilled content')\n .option('--event-type <type>', 'capture hook label (defaults to Stop)')\n .action(async (...args: unknown[]) => {\n const cmd = trailingCmd(args);\n const g = cmd.optsWithGlobals();\n const file =\n typeof args[0] === 'string' && (args[0] as string).length > 0\n ? (args[0] as string)\n : undefined;\n const content = typeof g.content === 'string' ? (g.content as string) : undefined;\n const eventType = typeof g.eventType === 'string' ? (g.eventType as string) : undefined;\n await memoryCapture({\n ...toCliOptions(g),\n ...(file === undefined ? {} : { file }),\n ...(content === undefined ? {} : { content }),\n ...(eventType === undefined ? {} : { eventType }),\n });\n });\n memoryGrp.action(() => {\n throw new NoirCliError(\n EXIT.USAGE,\n 'Usage: noir memory recall|save|capture|sessions|forget|consolidate',\n );\n });\n\n // `skills` group — list/sync the builtin pack in-process (S9, S5).\n const skillsGrp = program.command('skills').description('builtin skills');\n skillsGrp\n .command('list')\n .description('list installed Noir skills')\n .action(async (...args: unknown[]) => {\n await skillsList(toCliOptions(actionGlobals(args)));\n });\n skillsGrp\n .command('sync')\n .description('re-emit skills to the host skills dir')\n .action(async (...args: unknown[]) => {\n await skillsSync(toCliOptions(actionGlobals(args)));\n });\n skillsGrp\n .command('lint')\n .description('structural quality gate over the shipped pack')\n .action(async (...args: unknown[]) => {\n await skillsLint(toCliOptions(actionGlobals(args)));\n });\n skillsGrp\n .command('registry')\n .description('emit the runtime-derived skill registry')\n .action(async (...args: unknown[]) => {\n await skillsRegistry(toCliOptions(actionGlobals(args)));\n });\n skillsGrp.action(() => {\n throw new NoirCliError(EXIT.USAGE, 'Usage: noir skills list|sync|lint|registry');\n });\n\n const taskGrp = program.command('task').description('workflow task control');\n taskGrp\n .command('new')\n .description('start a new workflow task')\n .requiredOption('--slug <slug>', 'task slug')\n .option('--mode <mode>', 'full | quick')\n .option(\n '--class <taskClass>',\n 'task class (feature/epic/enhancement/bugfix/spike/quick-task/refactor) — drives the PRD gate',\n )\n .action(async (...args: unknown[]) => {\n const cmd = trailingCmd(args);\n const g = cmd.optsWithGlobals();\n const slug = typeof g.slug === 'string' ? (g.slug as string) : '';\n const mode = typeof g.mode === 'string' ? (g.mode as string) : undefined;\n const taskClass = typeof g.class === 'string' ? (g.class as string) : undefined;\n await taskNew({\n ...toCliOptions(g),\n slug,\n ...(mode === undefined ? {} : { mode }),\n ...(taskClass === undefined ? {} : { taskClass }),\n });\n });\n taskGrp\n .command('status')\n .description('active (or named) task status')\n .argument('[id]', 'task id (defaults to active)')\n .action(async (...args: unknown[]) => {\n const cmd = trailingCmd(args);\n const g = cmd.optsWithGlobals();\n // Optional positional: only a string at args[0] is the task id.\n const first = args[0];\n const id = typeof first === 'string' ? first : undefined;\n await taskStatus({\n ...toCliOptions(g),\n ...(id === undefined ? {} : { id }),\n });\n });\n taskGrp\n .command('advance')\n .description('advance the active task to the next phase')\n .option('--to <phase>', 'target phase')\n .option('--force <reason>', 'force the gate with a reason')\n .option('--skip', 'record the landing gate as skipped (advance continues)')\n .option('--no-artifacts', 'skip the document-phase artifact writes at done')\n .action(async (...args: unknown[]) => {\n const cmd = trailingCmd(args);\n const g = cmd.optsWithGlobals();\n const to = typeof g.to === 'string' ? (g.to as string) : undefined;\n const force = typeof g.force === 'string' ? (g.force as string) : undefined;\n await taskAdvance({\n ...toCliOptions(g),\n ...(to === undefined ? {} : { to }),\n ...(force === undefined ? {} : { force }),\n ...(g.skip === true ? { skip: true } : {}),\n ...(g.artifacts === false ? { noArtifacts: true } : {}),\n });\n });\n taskGrp\n .command('next')\n .description('suggest the next phase + applicable skill')\n .action(async (...args: unknown[]) => {\n await taskNext(toCliOptions(trailingCmd(args).optsWithGlobals()));\n });\n taskGrp\n .command('decompose')\n .description('decompose a capability into an implementation plan')\n .argument('<capability>', 'capability id')\n .option('--out <path>', 'output path for the plan JSON')\n .action(async (...args: unknown[]) => {\n const cmd = trailingCmd(args);\n const g = cmd.optsWithGlobals();\n const capability = typeof args[0] === 'string' ? (args[0] as string) : '';\n await taskDecompose({\n ...toCliOptions(g),\n capability,\n ...(typeof g.out === 'string' && g.out.length > 0 ? { out: g.out } : {}),\n });\n });\n taskGrp\n .command('verify')\n .description('run configured verify checks and submit evidence to the verify gate')\n .option(\n '--check <name>',\n 'restrict to a named check (repeatable)',\n (val: string, acc: string[]) => [...acc, val],\n [],\n )\n .action(async (...args: unknown[]) => {\n const cmd = trailingCmd(args);\n const g = cmd.optsWithGlobals();\n const check = Array.isArray(g.check) ? (g.check as string[]) : undefined;\n await taskVerify({\n ...toCliOptions(g),\n ...(check === undefined || check.length === 0 ? {} : { check }),\n });\n });\n taskGrp\n .command('research')\n .description('list research findings for the active (or named) task')\n .argument('[id]', 'task id (defaults to active)')\n .action(async (...args: unknown[]) => {\n const cmd = trailingCmd(args);\n const g = cmd.optsWithGlobals();\n const first = args[0];\n const id = typeof first === 'string' ? first : undefined;\n await taskResearch({\n ...toCliOptions(g),\n ...(id === undefined ? {} : { id }),\n });\n });\n taskGrp\n .command('research-record')\n .description('record a research finding for the active (or named) task')\n .requiredOption('--type <type>', 'assumption | discovery | decision | grounding-fact')\n .requiredOption('--text <text>', 'finding text (capped)')\n .option('--source <ref>', 'evidence/citation (required unless grounding-fact)')\n .option('--task <id>', 'task id (defaults to active)')\n .action(async (...args: unknown[]) => {\n const cmd = trailingCmd(args);\n const g = cmd.optsWithGlobals();\n await taskResearchRecord({\n ...toCliOptions(g),\n type: String(g.type ?? ''),\n text: String(g.text ?? ''),\n ...(typeof g.source === 'string' && g.source.length > 0 ? { source: g.source } : {}),\n ...(typeof g.task === 'string' && g.task.length > 0 ? { task: g.task } : {}),\n });\n });\n taskGrp\n .command('resume')\n .description('resume the active (or named) in-flight/blocked task')\n .argument('[id]', 'task id (defaults to active)')\n .option('--prompt <text>', 'a continue instruction to surface in the briefing')\n .action(async (...args: unknown[]) => {\n const cmd = trailingCmd(args);\n const g = cmd.optsWithGlobals();\n const first = args[0];\n const id = typeof first === 'string' ? first : undefined;\n const prompt = typeof g.prompt === 'string' ? (g.prompt as string) : undefined;\n await taskResume({\n ...toCliOptions(g),\n ...(id === undefined ? {} : { id }),\n ...(prompt === undefined ? {} : { prompt }),\n });\n });\n taskGrp\n .command('block')\n .description('mark the active (or named) task blocked with a reason')\n .argument('<reason>', 'why the task is stuck (non-empty)')\n .option('--task <id>', 'task id (defaults to active)')\n .action(async (...args: unknown[]) => {\n const cmd = trailingCmd(args);\n const g = cmd.optsWithGlobals();\n const reason = typeof args[0] === 'string' ? (args[0] as string) : '';\n const task = typeof g.task === 'string' ? (g.task as string) : undefined;\n await taskBlock({\n ...toCliOptions(g),\n reason,\n ...(task === undefined ? {} : { task }),\n });\n });\n taskGrp\n .command('abandon')\n .description('abandon the active (or named) task (terminal, confirmed)')\n .option('--task <id>', 'task id (defaults to active)')\n .action(async (...args: unknown[]) => {\n const cmd = trailingCmd(args);\n const g = cmd.optsWithGlobals();\n const task = typeof g.task === 'string' ? (g.task as string) : undefined;\n await taskAbandon({\n ...toCliOptions(g),\n ...(task === undefined ? {} : { task }),\n });\n });\n taskGrp.action(() => {\n throw new NoirCliError(\n EXIT.USAGE,\n 'Usage: noir task new|status|advance|next|verify|research|research-record|resume|block|abandon',\n );\n });\n\n // C1 -- `noir install` / `noir migrate`: move to the native install path,\n // preserving all settings. `migrate` is an alias (mirrors claude migrate-installer).\n const installCmd = program\n .command('install')\n .description(\n 'install Noir via the native managed-Node path (or migrate from another install method)',\n )\n .option('--list', 'list detected install methods')\n .option('--uninstall-prev', 'after a successful migrate, uninstall the previous install method')\n .option(\n '--dismiss',\n 'dismiss the migration banner for the current version (persists in install.json)',\n )\n .argument('[spec]', \"channel ('latest'|'beta') or exact version (default: latest)\")\n .action(\n async (\n spec: string | undefined,\n opts: { list?: boolean; uninstallPrev?: boolean; dismiss?: boolean },\n cmd: Command,\n ) => {\n const { install } = await import('./commands/install.js');\n const cli = cmd.optsWithGlobals() as CliOptions;\n await install({\n ...cli,\n spec,\n list: opts.list === true,\n uninstallPrev: opts.uninstallPrev === true,\n dismiss: opts.dismiss === true,\n });\n },\n );\n // `migrate` alias -- same behavior.\n installCmd.alias('migrate');\n\n // C1 --- `noir update`: self-update via the active install method.\n program\n .command('update')\n .description('update Noir to the latest version via the active install method')\n .option('--check', 'check for a new version without changing anything')\n .argument('[spec]', \"channel ('latest'|'beta') or exact version (default: latest)\")\n .action(async (spec: string | undefined, opts: { check?: boolean }, cmd: Command) => {\n const { update } = await import('./commands/update.js');\n const cli = cmd.optsWithGlobals() as CliOptions;\n await update({ ...cli, spec, check: opts.check === true });\n });\n\n // `noir handoff` + the `noir wrap` session-end alias. Both dispatch the\n // SAME handler; the artifact reuses `gatherStatusPayload` (status.ts) +\n // `PHASE_SKILL` (task.ts) for the snapshot, does a bounded context/memory\n // extraction, and renders a pasteable host-handoff markdown block to STDOUT.\n // `--write` persists to `.noir/handoff/HO-<NNNN>-<id>.md` (gitignored); `--json` emits\n // the structured payload. Doctrine: the host-launch directive is TEXT ONLY —\n // Noir never spawns the host.\n function buildHandoffOptions(g: Record<string, unknown>): HandoffOptions {\n return { ...toCliOptions(g), ...(g.write === true ? { write: true } : {}) };\n }\n program\n .command('handoff')\n .description('emit a ready-to-paste host handoff prompt')\n .option('--write', 'persist to .noir/handoff/HO-<NNNN>-<id>.md (gitignored)')\n .action(async (...args: unknown[]) => {\n await handoff(buildHandoffOptions(trailingCmd(args).optsWithGlobals()));\n });\n // `noir wrap` — session-end alias (same handler, friendlier name at the end of\n // a session). Same options; no separate code path.\n program\n .command('wrap')\n .description('session-end alias for `noir handoff`')\n .option('--write', 'persist to .noir/handoff/HO-<NNNN>-<id>.md (gitignored)')\n .action(async (...args: unknown[]) => {\n await handoff(buildHandoffOptions(trailingCmd(args).optsWithGlobals()));\n });\n\n // `noir release <version> [--channel beta|stable] [--dry-run]` — guided\n // orchestrator over the patch-release flow (c4-release-phase S2). Hands off\n // at the human-approval gates; NEVER auto-approves the GitHub publish job.\n program\n .command('release')\n .description('guided release orchestrator over the patch-release flow')\n .argument('[version]', 'target version, e.g. 1.10.0')\n .option('--channel <channel>', 'beta (default) | stable')\n .option('--dry-run', 'print the checklist without executing any steps')\n .action(async (...args: unknown[]) => {\n const cmd = trailingCmd(args);\n const g = cmd.optsWithGlobals();\n await release({\n ...toCliOptions(g),\n ...(typeof args[0] === 'string' && (args[0] as string).length > 0\n ? { version: args[0] as string }\n : {}),\n ...(typeof g.channel === 'string' && (g.channel as string).length > 0\n ? { channel: g.channel as string }\n : {}),\n ...(g.dryRun === true ? { dryRun: true } : {}),\n });\n });\n\n // `noir tui` — the interactive Ink dashboard. LAZY-loaded: the Ink app\n // (React) is imported ONLY inside this action via `await import('./tui/…')`,\n // so React + Ink never enter the main CLI startup path. `noir status`,\n // `noir doctor`, a bare `noir`, etc. stay fast and React-free. The dispatch\n // seam is the SAME shape `home(opts, deps)` uses (a fresh commander program\n // per dispatch, with its own error → exit-code mapping) — command routing is\n // NOT reimplemented in the TUI; `/`-prefixed inputs are routed through it.\n // Interactive-only: requires a TTY; under `--json` / `--no-input` / non-TTY\n // / CI / NO_COLOR it errors cleanly via `requireInteractive` (exit 2).\n program\n .command('tui')\n .description('interactive Ink dashboard (host · phase · daemon + /command dispatch)')\n .action(async (...args: unknown[]) => {\n const g = actionGlobals(args);\n const opts = toCliOptions(g);\n // requireInteractive honors all the non-interactive conditions (no TTY,\n // --no-input, --json, CI, NO_COLOR) and fails exit 2 with a clear message.\n requireInteractive(opts, '`noir tui`');\n // LAZY load the Ink dashboard. The import path is computed at runtime\n // (not a string literal) so esbuild cannot statically follow it into the\n // tui graph during the bin build — that static analysis is what hoists\n // bin.ts's entry body (incl. the `isMainModule` realpath guard) into a\n // shared chunk, turning dist/bin.js into a facade and breaking a global\n // `noir` install under its symlink. The tui is built as a sibling entry\n // (see the second tsup config) so its react/ink dependency tree never\n // enters the main CLI graph; React stays out of `noir status` etc.\n const tuiUrl = new URL('./tui/index.js', import.meta.url).href;\n // React/Ink are external (resolved from node_modules at runtime), so the\n // react-reconciler DEV build is selected unless NODE_ENV is 'production'.\n // The dev build calls performance.measure() on every render, filling\n // Node's 1M-entry performance buffer and OOMing the TUI after a few\n // minutes (QwenLM PR #4462). Force production BEFORE the TUI loads.\n process.env.NODE_ENV ||= 'production';\n const { runTui } = await import(/* @vite-ignore */ tuiUrl);\n // Same dispatch seam as homeDeps.dispatch above — a fresh program per\n // dispatched argv, errors mapped to process.exitCode (never thrown out).\n const dispatch = async (argv: readonly string[]): Promise<void> => {\n const sub = createProgram();\n try {\n await sub.parseAsync([...argv], { from: 'user' });\n } catch (err) {\n handleError(err);\n }\n };\n await runTui(opts, dispatch);\n });\n\n // `noir palette` — the fuzzy command palette opened directly (home-consolidation\n // S3). Same lazy Ink mount as `noir tui` but renders the App palette-first\n // (`{ kind: 'palette' }` initial mode), so the user can fuzzy-run any command\n // without first entering the dashboard. Interactive-only (requireInteractive →\n // exit 2 under non-TTY/--json/--no-input/CI/NO_COLOR), exactly like `noir tui`.\n program\n .command('palette')\n .description('fuzzy command palette — run any noir command (Ink)')\n .action(async (...args: unknown[]) => {\n const g = actionGlobals(args);\n const opts = toCliOptions(g);\n requireInteractive(opts, '`noir palette`');\n const tuiUrl = new URL('./tui/index.js', import.meta.url).href;\n process.env.NODE_ENV ||= 'production'; // see the `noir tui` action above\n const { runPalette } = await import(/* @vite-ignore */ tuiUrl);\n const dispatch = async (argv: readonly string[]): Promise<void> => {\n const sub = createProgram();\n try {\n await sub.parseAsync([...argv], { from: 'user' });\n } catch (err) {\n handleError(err);\n }\n };\n await runPalette(opts, dispatch);\n });\n\n // `noir run <prompt>` — drive the host CLI headless and render its\n // stream-json (v2 orchestrator, Archetype B). Streams the host's output and\n // reports token/cost from the `result` event. `--command <binary>` overrides\n // the per-host default so users with multiple profiles (claude vs claude-work)\n // can point at their own binary (D2a). Scriptable under `--json`.\n program\n .command('run')\n .description('ask the host agent a question and print the answer')\n .argument('[prompt...]', 'prompt to send to the host')\n .addOption(new Option('--host <id>', 'host to drive (default claude)').choices(SUPPORTED_HOSTS))\n .option('--command <binary>', 'custom host binary (e.g. claude-work)')\n .option('--profile <name>', 'use a named run profile (run.profiles in .noir/config.yml)')\n .option('--list-profiles', 'list configured run profiles and exit')\n .action(async (...args: unknown[]) => {\n const cmd = trailingCmd(args);\n const g = cmd.optsWithGlobals();\n // A variadic `[prompt...]` argument arrives as a SINGLE array value in the\n // action's positional args, so read the parsed positional args off the\n // trailing Command (`cmd.args`) rather than filtering the raw `args`.\n const prompt = cmd.args.join(' ').trim();\n const opts: RunOptions = {\n ...toCliOptions(g),\n ...(typeof g.host === 'string' ? { host: g.host } : {}),\n ...(typeof g.command === 'string' ? { command: g.command } : {}),\n ...(typeof g.profile === 'string' ? { profile: g.profile } : {}),\n };\n if (g.listProfiles === true) {\n listProfilesCommand(opts);\n return;\n }\n await runHostCommand(prompt, opts);\n });\n\n /** `noir run --list-profiles`: show the configured run profiles (NAME / DEFAULT / BINARY).\n * Under --json the rows go to stdout as one {ok,data} envelope (S9 contract —\n * the table/info helpers are silenced in json mode, so json is handled FIRST). */\n function listProfilesCommand(opts: CliOptions): void {\n const config = loadRunConfig(process.cwd());\n const rows = config ? listProfiles(config) : [];\n if (opts.json === true) {\n json({ ok: true, data: rows });\n return;\n }\n if (rows.length === 0) {\n info('(no run profiles configured — add a run.profiles block to .noir/config.yml)', opts);\n return;\n }\n table(rows, ['NAME', 'DEFAULT', 'BINARY'], opts);\n }\n\n program.action(async (...args: unknown[]) => {\n const cmd = trailingCmd(args);\n // Bare `noir` (no subcommand) → the home router. But a leftover positional\n // here is an UNKNOWN command: every registered subcommand consumes its own\n // leading arg via its own action, so anything still in `cmd.args` didn't\n // match. Reject it exit 3 (NOT_FOUND) per the S9 contract instead of\n // silently routing the typo through home (which would exit 0).\n const leftovers = cmd.args;\n if (leftovers.length > 0) {\n fail(\n EXIT.NOT_FOUND,\n `unknown command '${leftovers[0]}' (no such subcommand). Run \\`noir --help\\` for the list.`,\n toCliOptions(cmd.optsWithGlobals()),\n );\n }\n await home(toCliOptions(actionGlobals(args)), homeDeps);\n });\n\n return program;\n}\n\n/** Singleton program used by the bin entry (`run`) and re-exported for convenience. */\nexport const program: Command = createProgram();\n\n// Home-menu deps, built ONCE at module scope (home-consolidation S2). Defined\n// OUTSIDE createProgram so the palette commands are computed a single time and\n// never recurse (createProgram → homeDeps → createProgram → …). The bare-`noir`\n// action inside createProgram closes over this module-level const.\nconst homeDeps: HomeDeps = {\n dispatch: async (argv: readonly string[]): Promise<void> => {\n const sub = createProgram();\n try {\n await sub.parseAsync([...argv], { from: 'user' });\n } catch (err) {\n // Map the sub-command's failure to process.exitCode (never throw out\n // of dispatch — home returns and the outer program exit reflects this).\n handleError(err);\n }\n },\n // The grouped home menu resolves its sections against the LIVE palette\n // registry (home-consolidation S1/S2) — the same source the TUI palette\n // uses — so the menu cannot drift from the commander tree.\n commands: buildPaletteCommands(createProgram()),\n};\n\n// ---------------------------------------------------------------------------\n// Error → exit-code mapping lives in `./output.js` (`handleError`); it never\n// throws and never calls `process.exit` (commander's `exitOverride` already\n// prevented that for commander's own errors).\n// ---------------------------------------------------------------------------\n\n/**\n * Parse `argv` (user-form: NO node/script prefix) on the singleton program and\n * return the resulting exit code. Sets `process.exitCode` for the real bin;\n * tests can either call this or drive `createProgram().parseAsync` directly.\n */\nexport async function run(argv: readonly string[] = []): Promise<number> {\n try {\n await program.parseAsync([...argv], { from: 'user' });\n } catch (err) {\n handleError(err);\n }\n return typeof process.exitCode === 'number' ? process.exitCode : EXIT.OK;\n}\n\n// Auto-invoke only when bin.ts is the entry point (real `noir` bin, or a tsx\n// subprocess as in gate1-stdio). When vitest imports bin.js as a module,\n// process.argv[1] is the runner, so this is skipped and the program stays idle.\nconst isMainModule = (() => {\n try {\n const entry = process.argv[1];\n if (typeof entry !== 'string' || entry.length === 0) return false;\n // Resolve symlinks: a global npm install invokes the bin via a symlink\n // (.../bin/noir -> .../lib/node_modules/@noir-ai/cli/dist/bin.js), so argv[1]\n // is the symlink path while import.meta.url is the RESOLVED real path. Compare\n // the REAL paths so `noir` runs under BOTH direct + symlinked invocation.\n // (Without this, a global `noir` install silently exits 0 — main() never runs.)\n return pathToFileURL(realpathSync(entry)).href === import.meta.url;\n } catch {\n return false;\n }\n})();\n\nif (isMainModule) {\n void run(process.argv.slice(2));\n}\n","// S9 — `noir context {search,index,status}`.\n//\n// Thin MCP-client commands over the running daemon's S6 context engine. Every\n// read/write here is a single `callDaemonTool` round-trip; the daemon is the\n// sole writer (blueprint §2), so the CLI never opens the store in-process. If\n// the daemon can't be reached, `callDaemonTool` maps the failure onto exit 4\n// (DAEMON_DOWN) with the stable remediation hint — see daemon-client.ts.\n//\n// A daemon tool's OWN logical-failure envelope (`{ok:false, degraded:true,\n// error}` — e.g. a read-only store refusing `context_index`, or the embedder\n// throwing inside `context_search`) is DATA, not a transport failure: it parses\n// cleanly, so this module surfaces it honestly as exit 1 (ERROR) with the\n// daemon's message, rather than re-packaging it as daemon-down.\n//\n// Stream discipline (S9): `--json` emits the versioned `{ok:true,data}`\n// envelope to STDOUT (the only stdout write); human tables / snippets go to\n// STDERR via the centralized `table()` / `log()` helpers (auto-stripped under\n// NO_COLOR / non-TTY / --json). `--limit` is coerced here; an invalid value is a\n// USAGE error (exit 2) before we touch the daemon.\n\nimport {\n callDaemonTool,\n type DaemonClientOptions,\n type DaemonProbe,\n probeDaemon,\n withInProcessRead,\n} from '../daemon-client.js';\nimport { type CliOptions, definitionList, EXIT, fail, info, log, table } from '../output.js';\nimport { badge } from '../theme.js';\n\n/** Options accepted by every `context` sub-command (globals + daemon knobs). */\nexport interface ContextOptions extends CliOptions, DaemonClientOptions {}\n\n// ---------------------------------------------------------------------------\n// Tool result shapes (the relevant slices of the daemon's wire payloads). The\n// daemon returns these as JSON text; daemon-client parses to `unknown`, so each\n// reader treats a foreign field as undefined and the command degrades to a clear\n// error rather than crashing. Local types = the CLI depends only on the MCP\n// wire contract (mirrors status.ts).\n// ---------------------------------------------------------------------------\n\n/** Normalized search hit rendered to humans + emitted in the JSON payload. */\nexport interface ContextHit {\n path: string;\n score: number;\n snippet: string;\n source: string;\n}\n\n/** `context_search` success payload (SearchResult + the echoed query). */\nexport interface ContextSearchData {\n query: string;\n hits: ContextHit[];\n consumedTokens: number;\n truncated: boolean;\n degraded: boolean;\n mode: string;\n}\n\n/** `context_index` success payload (IndexResult). */\nexport interface ContextIndexData {\n indexed: number;\n skipped: number;\n deleted: number;\n failed: number;\n totalChunks: number;\n degraded: boolean;\n}\n\n/** `context_status` payload (ContextStatus). `ok` is a literal so the success /\n * failure union narrows cleanly against {@link ToolFailure} (ok:false). */\nexport interface ContextStatusData {\n ok: true;\n projectId: string;\n docCount: number;\n vecCount: number;\n indexedFiles: number;\n embedder: { kind: string; model?: string; dim: number };\n degraded: boolean;\n}\n\n/** A daemon logical-failure envelope (`{ok:false,…}`) — read generically. */\ninterface ToolFailure {\n ok: false;\n degraded?: boolean;\n error?: string;\n reason?: string;\n}\n\n/** The raw `context_search` wire payload (success branch). */\ninterface ContextSearchResult {\n ok: true;\n results?: unknown;\n consumedTokens?: number;\n truncated?: boolean;\n degraded?: boolean;\n mode?: string;\n}\n\n/** The raw `context_index` wire payload (success branch). */\ninterface ContextIndexResult {\n ok: true;\n indexed?: number;\n skipped?: number;\n deleted?: number;\n failed?: number;\n totalChunks?: number;\n degraded?: boolean;\n}\n\n// ---------------------------------------------------------------------------\n// Small shared helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Coerce a commander `--limit <n>` string into a positive int, or fail with\n * exit 2 (USAGE) naming the flag — mirrors the daemon's zod\n * `number().int().positive()` but at the CLI edge so a bad value never starts a\n * daemon round-trip.\n */\nfunction parseLimit(raw: string | undefined, label: string, opts: CliOptions): number | undefined {\n if (raw === undefined) return undefined;\n const n = Number(raw);\n if (!Number.isInteger(n) || n <= 0) {\n fail(EXIT.USAGE, `${label}: --limit must be a positive integer (got '${raw}')`, opts);\n }\n return n;\n}\n\n/**\n * Normalize a daemon logical-failure envelope into a thrown exit-1 ERROR. The\n * envelope is data (it parsed cleanly), so this is NOT daemon-down; we surface\n * the daemon's own `error`/`reason` verbatim so the user sees the real cause\n * (e.g. \"store is read-only (daemon down) — context_index is unavailable\").\n */\nfunction failTool(label: string, envelope: ToolFailure, opts: CliOptions): never {\n const detail = envelope.error ?? envelope.reason ?? 'unknown failure';\n fail(EXIT.ERROR, `${label}: ${detail}`, opts);\n}\n\n/** Narrow a raw wire hit (RetrieverHit) into the rendered {@link ContextHit}. */\nfunction toHit(raw: unknown): ContextHit {\n const h = (raw ?? {}) as Record<string, unknown>;\n return {\n path: typeof h.path === 'string' ? h.path : '<unknown>',\n score: typeof h.score === 'number' ? h.score : 0,\n snippet: typeof h.snippet === 'string' ? h.snippet : '',\n source: typeof h.source === 'string' ? h.source : '',\n };\n}\n\n// ---------------------------------------------------------------------------\n// `noir context search <query> [--limit N]`\n// ---------------------------------------------------------------------------\nexport interface ContextSearchOptions extends ContextOptions {\n query: string;\n /** Raw `--limit` string from commander; parsed + validated here. */\n limit?: string;\n}\n\n/**\n * Run `context_search` against the daemon when it is up, or fall back to the\n * IN-PROCESS read-only engine when the daemon probe reports it down (S9 DS-5).\n *\n * A daemon-down probe is a READ degradation, not a write failure: the read-only\n * store keeps working, so instead of exit 4 the search runs against a fresh\n * in-process {@link withInProcessRead} ContextEngine over the same project\n * store (BM25-only when the embedder is unavailable — F8). Writes (`context\n * index`) keep the daemon-required exit-4 path. When the daemon IS up, the\n * probe result is ignored and the normal daemon round-trip proceeds unchanged\n * (the probe only ever short-circuits on a CONFIRMED down).\n *\n * The probe is best-effort and CONSERVATIVE: an unavailable probe (a host that\n * stubs the daemon-client without a `probeDaemon` export, or a probe transport\n * hiccup) is treated as \"daemon may be up\" so the command proceeds down the\n * normal daemon path (which maps a genuinely-down daemon to exit 4). The\n * fallback only engages on a CONFIRMED `{running:false}`.\n */\nexport async function contextSearch(opts: ContextSearchOptions): Promise<void> {\n const limit = parseLimit(opts.limit, 'context search', opts);\n let probe: DaemonProbe;\n try {\n probe = await probeDaemon(opts);\n } catch {\n // Conservative: can't confirm the daemon is down → use the daemon path.\n probe = { running: true };\n }\n if (!probe.running) {\n await withInProcessRead(opts, async (engines) => {\n const result = await engines.context.search(opts.query, {\n ...(limit === undefined ? {} : { limit }),\n });\n const data: ContextSearchData = {\n query: opts.query,\n hits: result.results.map((h) => ({\n path: h.path,\n score: h.score,\n snippet: h.snippet,\n source: h.source,\n })),\n consumedTokens: result.consumedTokens,\n truncated: result.truncated,\n degraded: result.degraded,\n mode: result.mode,\n };\n if (opts.json === true) {\n process.stdout.write(`${JSON.stringify({ ok: true, data })}\\n`);\n return;\n }\n renderSearch(data, opts);\n });\n return;\n }\n const res = await callDaemonTool<ContextSearchResult | ToolFailure>(opts, 'context_search', {\n query: opts.query,\n ...(limit === undefined ? {} : { limit }),\n });\n if (res.ok !== true) failTool('context search', res, opts);\n\n const data: ContextSearchData = {\n query: opts.query,\n hits: Array.isArray(res.results) ? (res.results as unknown[]).map(toHit) : [],\n consumedTokens: typeof res.consumedTokens === 'number' ? res.consumedTokens : 0,\n truncated: res.truncated === true,\n degraded: res.degraded === true,\n mode: typeof res.mode === 'string' ? res.mode : 'unknown',\n };\n\n if (opts.json === true) {\n process.stdout.write(`${JSON.stringify({ ok: true, data })}\\n`);\n return;\n }\n renderSearch(data, opts);\n}\n\nfunction renderSearch(data: ContextSearchData, opts: CliOptions): void {\n const flag = data.degraded ? ` ${badge('warn', 'degraded: BM25-only')}` : '';\n const trunc = data.truncated ? ' (budget hit — results truncated)' : '';\n log(\n `context search — ${data.hits.length} hit${data.hits.length === 1 ? '' : 's'} · ${data.mode} · ${data.consumedTokens} tokens${flag}${trunc}`,\n opts,\n );\n table(\n data.hits.map((h, i) => ({\n '#': i + 1,\n Path: h.path,\n Score: h.score.toFixed(4),\n Snippet: h.snippet,\n })),\n ['#', 'Path', 'Score', 'Snippet'],\n opts,\n );\n}\n\n// ---------------------------------------------------------------------------\n// `noir context index [--path ...] [--force]`\n// ---------------------------------------------------------------------------\nexport interface ContextIndexOptions extends ContextOptions {\n /** Raw repeated `--path` values from commander (`undefined` ⇒ index root). */\n paths?: string[];\n /** Force a full reindex (drop all chunks+vectors, re-index from scratch). */\n force?: boolean;\n}\n\nexport async function contextIndex(opts: ContextIndexOptions): Promise<void> {\n // force:true → the daemon drops every indexed chunk + vector and re-indexes\n // the registered roots from scratch (spec F1); otherwise the content-hash\n // incremental walk. Omit the key entirely when not forced so the incremental\n // contract (and any daemon defaulting) stays unambiguous on the wire.\n const args: Record<string, unknown> =\n opts.paths && opts.paths.length > 0 ? { paths: opts.paths } : {};\n if (opts.force === true) args.force = true;\n const res = await callDaemonTool<ContextIndexResult | ToolFailure>(opts, 'context_index', args);\n if (res.ok !== true) failTool('context index', res, opts);\n\n const data: ContextIndexData = {\n indexed: typeof res.indexed === 'number' ? res.indexed : 0,\n skipped: typeof res.skipped === 'number' ? res.skipped : 0,\n deleted: typeof res.deleted === 'number' ? res.deleted : 0,\n failed: typeof res.failed === 'number' ? res.failed : 0,\n totalChunks: typeof res.totalChunks === 'number' ? res.totalChunks : 0,\n degraded: res.degraded === true,\n };\n\n if (opts.json === true) {\n process.stdout.write(`${JSON.stringify({ ok: true, data })}\\n`);\n return;\n }\n renderIndex(data, opts.paths, opts);\n}\n\nfunction renderIndex(data: ContextIndexData, paths: string[] | undefined, opts: CliOptions): void {\n const scope = paths && paths.length > 0 ? paths.join(', ') : '.';\n const flag = data.degraded ? ` ${badge('warn', 'degraded: vectors skipped')}` : '';\n log(`context index — ${scope}${flag}`, opts);\n definitionList(\n [\n { label: 'Indexed (new)', value: data.indexed },\n { label: 'Skipped (unchanged)', value: data.skipped },\n { label: 'Deleted (removed)', value: data.deleted },\n { label: 'Failed', value: data.failed },\n { label: 'Total chunks', value: data.totalChunks },\n ],\n opts,\n );\n if (data.failed > 0) {\n info(`${data.failed} file(s) could not be indexed (binary / IO / encoding).`, opts);\n }\n}\n\n// ---------------------------------------------------------------------------\n// `noir context status`\n// ---------------------------------------------------------------------------\nexport async function contextStatus(opts: ContextOptions): Promise<void> {\n const res = await callDaemonTool<ContextStatusData | ToolFailure>(opts, 'context_status');\n if (res.ok !== true) failTool('context status', res, opts);\n // `context_status` already carries its own `ok:true`; reuse it as the payload.\n const data = res;\n\n if (opts.json === true) {\n process.stdout.write(`${JSON.stringify({ ok: true, data })}\\n`);\n return;\n }\n renderStatus(data, opts);\n}\n\nfunction describeEmbedder(e: ContextStatusData['embedder']): string {\n if (!e || e.kind === 'none') return 'none (BM25-only)';\n const model = typeof e.model === 'string' && e.model.length > 0 ? e.model : '<unset>';\n return `${e.kind} · ${model} (${e.dim}-dim)`;\n}\n\nfunction renderStatus(data: ContextStatusData, opts: CliOptions): void {\n const flag = data.degraded ? ` ${badge('warn', 'degraded')}` : '';\n log(`context status — ${data.projectId}${flag}`, opts);\n definitionList(\n [\n { label: 'Project', value: data.projectId },\n { label: 'Docs', value: data.docCount },\n { label: 'Vectors', value: data.vecCount },\n { label: 'Indexed files', value: data.indexedFiles },\n { label: 'Embedder', value: describeEmbedder(data.embedder) },\n { label: 'Degraded', value: data.degraded ? 'yes' : 'no' },\n ],\n opts,\n );\n}\n","// S9 — `noir daemon {start,stop,status,restart}` (+ `token`, spec 6.1).\n//\n// Honest daemon UX (S9 / spec §8). `noir daemon start` runs the daemon either\n// FOREGROUND or DETACHED, depending on flags:\n// - default (foreground): `ensureDaemonRunning` (from @noir-ai/daemon) starts\n// a fresh in-process HTTP server — whose listen handle + idle timer +\n// SIGINT/SIGTERM handlers (installed inside `startHttpServer`) keep this CLI\n// process alive until idle-stop or a signal — or reuses an already-healthy\n// one and exits.\n// - `--detach` (parent path, D1): `spawnDetachedDaemon` forks a detached child\n// `noir daemon start --_detached-child` (unref'd + silent stdio), waits for\n// the child's daemon record + `/health` to confirm it is serving, reports\n// `{mode:'detached', pid, port}`, and the PARENT exits — the child keeps the\n// daemon alive in the background.\n// - `--_detached-child` (child path, D2; hidden, set by the parent's spawn):\n// we ARE the detached child — run `ensureDaemonRunning` in-process (the HTTP\n// server keeps THIS process alive) and emit `{mode:'detached'}`. The child\n// is the SINGLE writer of the daemon record (its own pid), so the parent\n// discovers the port by polling that record.\n// Both detached paths guard double-spawn: an already-healthy daemon is reported\n// `{mode:'detached', reused:true}` and never spawned twice.\n//\n// Stream discipline (S9): `--json` emits the versioned `{ok,data}` envelope\n// to stdout (the only stdout write); every human diagnostic goes to stderr via\n// the centralized helpers. Exit codes follow the S9 contract: a missing/stale\n// daemon record on `status` → exit 4 (DAEMON_DOWN); an uninitialized project\n// (`loadProjectInfo` throws) → exit 1 with the hint.\n\nimport { loadProjectInfo, type ProjectInfo } from '@noir-ai/core';\nimport {\n clearProjectDaemonRecord,\n ensureDaemonRunning,\n pidAlive,\n readDaemonToken,\n readProjectDaemonRecord,\n spawnDetachedDaemon,\n} from '@noir-ai/daemon';\nimport { PROBE_TIMEOUT_MS } from '../daemon-client.js';\nimport { type CliOptions, EXIT, fail, info, log, spinner } from '../output.js';\nimport { daemonStartWorkspace } from './workspace.js';\n\n/** Options accepted by `daemon` sub-commands (the global flags only). */\nexport interface DaemonOptions extends CliOptions {}\n\n/** `daemon start` adds the real `--detach` flag (D1) plus the hidden\n * `--_detached-child` marker (D2) the detached child carries. */\nexport interface DaemonStartOptions extends DaemonOptions {\n /** `--detach`: parent path — fork a detached child and exit. */\n detach?: boolean;\n /** `--_detached-child` (hidden, reserved): we ARE the detached child. */\n detachChild?: boolean;\n /** `--workspace <name>`: start a shared cross-repo workspace daemon instead. */\n workspace?: string;\n /** `--force`: overwrite a non-Noir `.mcp.json` entry (the `--workspace` join). */\n force?: boolean;\n}\n\n/** Human label for the detached mode in `status` output. */\nconst MODE = 'foreground' as const;\n\n/** Shape of the `/health` body the daemon's HTTP server serves. */\ninterface HealthBody {\n ok?: boolean;\n pid?: number;\n projectId?: string;\n uptimeSec?: number;\n}\n\nfunction formatUptime(sec: number): string {\n if (!Number.isFinite(sec) || sec < 0) return 'unknown';\n if (sec < 60) return `${sec}s`;\n if (sec < 3600) return `${Math.floor(sec / 60)}m ${sec % 60}s`;\n return `${Math.floor(sec / 3600)}h ${Math.floor((sec % 3600) / 60)}m`;\n}\n\n/** Resolve the CALLER's project id — the lookup key for this project's daemon\n * record (the record is per-project). `undefined` when uninitialized: there is\n * no project whose daemon we could legitimately report or stop. */\nfunction resolveCallerProjectId(): string | undefined {\n try {\n return loadProjectInfo(process.cwd()).id;\n } catch {\n return undefined;\n }\n}\n\n/** Best-effort `/health` probe (never throws). Bounded — a blackhole socket that\n * accepts TCP but never answers must not hang `noir daemon start/status/stop`\n * indefinitely. When `expectedPid` is given, the probe ALSO requires the\n * responding daemon's own pid to match (the PID-reuse guard: a foreign process\n * that recycled the recorded pid must never be signalled as \"our daemon\"). */\nasync function isHealthy(\n port: number,\n expectedPid?: number,\n expectedProjectId?: string,\n): Promise<boolean> {\n try {\n const res = await fetch(`http://127.0.0.1:${port}/health`, {\n signal: AbortSignal.timeout(PROBE_TIMEOUT_MS),\n });\n if (res.status !== 200) return false;\n if (expectedPid === undefined) return true;\n const body = (await res.json()) as HealthBody | undefined;\n if (body?.ok !== true || body.pid !== expectedPid) return false;\n // Cross-project isolation: only reuse a daemon that serves the expected\n // project (absent /health projectId — a pre-1.12 daemon — is not trusted).\n if (expectedProjectId !== undefined && body.projectId !== expectedProjectId) return false;\n return true;\n } catch {\n return false;\n }\n}\n\n// ---------------------------------------------------------------------------\n// `noir daemon start` (foreground default; `--detach` + `--_detached-child`)\n// ---------------------------------------------------------------------------\n/**\n * Start the Noir daemon — foreground by default, or detached via `--detach`.\n *\n * Three modes, chosen by the flags (all three guard double-spawn: an\n * already-healthy daemon is reported `{mode:'detached', reused:true}` / the\n * foreground `reused:true` envelope and never started twice):\n *\n * 1. `--_detached-child` (D2; hidden, only ever set by `spawnDetachedDaemon`'s\n * child argv): we ARE the detached daemon. Run `ensureDaemonRunning`\n * in-process — the started HTTP server + idle timer + signal handlers keep\n * THIS process alive as the background daemon — emit `{mode:'detached'}`\n * (or `{mode:'detached', reused:true}` when a healthy daemon is reused, in\n * which case the redundant child exits) and return. The child is the SINGLE\n * writer of the daemon record (its own pid), which is how the parent learns\n * the port. We deliberately do NOT call `ensured.stop()` — that would undo\n * the daemon we just started (or tear down a reused one owned elsewhere).\n * 2. `--detach` (D1; parent path): `spawnDetachedDaemon` forks the detached\n * child, waits until the child's record + `/health` confirm it is serving,\n * emits `{mode:'detached', pid, port}`, and the PARENT returns (and thus\n * exits — it never blocks). Guard first: if a daemon is ALREADY healthy,\n * report `{mode:'detached', reused:true}` and return WITHOUT spawning.\n * 3. Foreground (default): `ensureDaemonRunning` in-process. When it STARTS a\n * daemon, the HTTP server keeps this process alive until\n * SIGINT/SIGTERM/idle-timeout (the function returns but the process does not\n * exit); when it REUSES a healthy daemon, this process reports and exits.\n *\n * `--json` emits the one envelope to stdout before the process blocks/returns.\n */\nexport async function daemonStart(opts: DaemonStartOptions): Promise<void> {\n // Workspace mode: `--workspace <name>` founds/joins a cross-repo workspace and\n // starts its daemon (a separate daemon kind — never the project daemon).\n if (opts.workspace !== undefined) {\n await daemonStartWorkspace({\n ...opts,\n name: opts.workspace,\n ...(opts.detach === true ? { detach: true } : {}),\n ...(opts.detachChild === true ? { detachChild: true } : {}),\n });\n return;\n }\n // A throw from loadProjectInfo on an uninitialized project must route through\n // fail() — otherwise under --json stdout stays EMPTY (the raw error only\n // reaches stderr), violating the S9 `{ok:false}` envelope contract.\n let project: ProjectInfo;\n try {\n project = loadProjectInfo(process.cwd());\n } catch {\n fail(EXIT.ERROR, 'Noir is not initialized in this directory. Run `noir init` first.', opts);\n }\n\n // D2 — detached CHILD path. The parent forked us via `--_detached-child`;\n // run the daemon in-process (the HTTP server keeps THIS process alive).\n if (opts.detachChild === true) {\n const child = await ensureDaemonRunning({\n project,\n idleTimeoutSec: project.config.daemon.idleTimeoutSec,\n ...(project.config.daemon.port !== undefined ? { port: project.config.daemon.port } : {}),\n });\n if (child.started) {\n if (opts.json === true) {\n process.stdout.write(`${JSON.stringify({ ok: true, data: { mode: 'detached' } })}\\n`);\n return;\n }\n // The HTTP server + idle timer + signal handlers inside startHttpServer\n // keep this child process alive past `return` — it IS the daemon now.\n info('noir daemon: detached foreground. Ctrl+C to stop.', opts);\n log(`Noir daemon listening at ${child.url}`, opts);\n return;\n }\n // An already-healthy daemon was reused — this redundant child reports and\n // exits (the parent's double-spawn guard should have caught this, but the\n // child re-checks so two racing spawns can never start two daemons).\n if (opts.json === true) {\n process.stdout.write(\n `${JSON.stringify({ ok: true, data: { mode: 'detached', reused: true } })}\\n`,\n );\n return;\n }\n info('Noir daemon already running; detached child exiting.', opts);\n return;\n }\n\n // D1 — `--detach` PARENT path. Fork a detached child and let it own the\n // daemon; the parent reports the backgrounded daemon and exits.\n if (opts.detach === true) {\n // Double-spawn guard: only spawn a child if no daemon is already healthy\n // (the child would merely reuse it and exit — a wasted detached process).\n // Scoped read: THIS project's record, so a daemon serving another project\n // is neither adopted nor counted as ours.\n const existing = readProjectDaemonRecord(project.id);\n if (\n existing &&\n pidAlive(existing.pid) &&\n (await isHealthy(existing.port, existing.pid, project.id))\n ) {\n if (opts.json === true) {\n process.stdout.write(\n `${JSON.stringify({ ok: true, data: { mode: 'detached', reused: true } })}\\n`,\n );\n return;\n }\n info(\n `Noir daemon already running at http://127.0.0.1:${existing.port}/mcp (detach not needed).`,\n opts,\n );\n return;\n }\n let spawned: Awaited<ReturnType<typeof spawnDetachedDaemon>>;\n try {\n spawned = await spawnDetachedDaemon({ project });\n } catch (err) {\n fail(\n EXIT.ERROR,\n `noir daemon start --detach failed: ${err instanceof Error ? err.message : String(err)}`,\n opts,\n );\n }\n if (opts.json === true) {\n process.stdout.write(\n `${JSON.stringify({ ok: true, data: { mode: 'detached', pid: spawned.pid, port: spawned.port } })}\\n`,\n );\n return;\n }\n info(`Noir daemon started in the background (pid ${spawned.pid}, port ${spawned.port}).`, opts);\n // The parent returns (and exits); the detached child owns the daemon.\n return;\n }\n\n // Foreground (default) — run the daemon in-process.\n const ds = spinner('Starting Noir daemon...', opts).start();\n let ensured: Awaited<ReturnType<typeof ensureDaemonRunning>>;\n try {\n ensured = await ensureDaemonRunning({\n project,\n idleTimeoutSec: project.config.daemon.idleTimeoutSec,\n ...(project.config.daemon.port !== undefined ? { port: project.config.daemon.port } : {}),\n });\n } catch (err) {\n ds.fail('Daemon failed to start');\n fail(\n EXIT.ERROR,\n `noir daemon start failed: ${err instanceof Error ? err.message : String(err)}`,\n opts,\n );\n }\n\n if (ensured.started) {\n ds.succeed('Daemon started');\n if (opts.json === true) {\n process.stdout.write(\n `${JSON.stringify({\n ok: true,\n data: {\n url: ensured.url,\n port: ensured.port,\n pid: process.pid,\n mode: MODE,\n reused: false,\n },\n })}\\n`,\n );\n return;\n }\n info('noir daemon: foreground mode. Ctrl+C to stop.', opts);\n log(`Noir daemon listening at ${ensured.url}`, opts);\n // NOTE: the started HTTP server + idle timer + signal handlers installed\n // inside startHttpServer keep this process alive past `return`. We\n // intentionally do NOT call ensured.stop(): that would undo the start.\n return;\n }\n\n // Reused an already-running daemon — this process exits after reporting.\n ds.succeed('Daemon already running');\n if (opts.json === true) {\n process.stdout.write(\n `${JSON.stringify({ ok: true, data: { url: ensured.url, port: ensured.port, reused: true } })}\\n`,\n );\n return;\n }\n log(`Noir daemon already running at ${ensured.url}`, opts);\n}\n\n// ---------------------------------------------------------------------------\n// `noir daemon stop`\n// ---------------------------------------------------------------------------\n/**\n * Stop the recorded daemon (SIGTERM its pid) and clear the record.\n *\n * Best-effort exit 0: a missing record (\"not running\") and a signal failure\n * both report and succeed, matching the pre-migration behavior. `--json` emits\n * `{ok:true, data:{running, stopped, pid?}}` to stdout.\n */\nexport async function daemonStop(opts: DaemonOptions): Promise<void> {\n // The record is keyed by ProjectId, so the caller's project IS the scope: a\n // daemon serving another project is simply not visible here (no\n // cross-project guard needed — the foreign record is a different file). When\n // the caller has no project there is no record to name, and guessing would\n // mean either stopping nothing or signalling a stranger's daemon.\n const callerProject = resolveCallerProjectId();\n if (callerProject === undefined) {\n if (opts.json === true) {\n process.stdout.write(\n `${JSON.stringify({ ok: true, data: { running: false, stopped: false } })}\\n`,\n );\n return;\n }\n info('No Noir daemon is running for this directory (not a Noir project).', opts);\n return;\n }\n\n const rec = readProjectDaemonRecord(callerProject);\n if (!rec) {\n if (opts.json === true) {\n process.stdout.write(\n `${JSON.stringify({ ok: true, data: { running: false, stopped: false } })}\\n`,\n );\n return;\n }\n info('No Noir daemon is running.', opts);\n return;\n }\n\n const ds = spinner(`Stopping daemon (pid ${rec.pid})...`, opts).start();\n let signalled = false;\n let errMsg: string | undefined;\n // Guard PID reuse: only SIGTERM the recorded pid if it still answers as OUR\n // daemon on the recorded port. If the daemon crashed and the pid was recycled\n // by an unrelated process, a blind `process.kill(pid)` would signal an\n // innocent process — so probe `/health` first and clear the stale record if it\n // does not answer.\n const healthy = pidAlive(rec.pid) && (await isHealthy(rec.port, rec.pid, callerProject));\n if (healthy) {\n try {\n process.kill(rec.pid, 'SIGTERM');\n signalled = true;\n } catch (err) {\n // Process may have already exited between the probe and the signal.\n errMsg = err instanceof Error ? err.message : String(err);\n }\n }\n // Our own record only — unconditionally, now that it is unambiguously ours.\n clearProjectDaemonRecord(callerProject);\n\n if (opts.json === true) {\n process.stdout.write(\n `${JSON.stringify({\n ok: true,\n data: {\n running: signalled,\n stopped: signalled,\n pid: rec.pid,\n ...(errMsg !== undefined ? { error: errMsg } : {}),\n },\n })}\\n`,\n );\n return;\n }\n if (signalled) {\n ds.succeed(`Stopped Noir daemon (pid ${rec.pid})`);\n } else {\n // Two non-signalled cases: a healthy probe whose signal failed (errMsg set),\n // or a pid that no longer answers as our daemon.\n const reason =\n errMsg !== undefined\n ? errMsg\n : 'the recorded pid did not answer as our daemon (stale record cleared)';\n ds.warn(`Daemon (pid ${rec.pid}) could not be signalled: ${reason}`);\n info(`Noir daemon (pid ${rec.pid}) could not be signalled: ${reason}`, opts);\n }\n}\n\n// ---------------------------------------------------------------------------\n// `noir daemon status`\n// ---------------------------------------------------------------------------\n/**\n * Report daemon liveness: read the record, confirm the pid is alive, and ping\n * `/health` for a live uptime. A missing/stale/unresponsive record maps to\n * exit 4 (DAEMON_DOWN) — the \"probed by script\" contract.\n *\n * `--json` emits `{ok:true, data:{running,pid,port,startedAt,uptimeSec,mode}}`\n * on success; failure goes through `fail()` (structured `{ok:false,error}` on\n * stdout under `--json`, plain message on stderr otherwise) with exit 4.\n */\nexport async function daemonStatus(opts: DaemonOptions): Promise<void> {\n // The record is keyed by ProjectId, so the caller's project IS the scope: a\n // daemon serving another project is a different file, invisible here (no\n // cross-project exit-4 block left to perform).\n const callerProject = resolveCallerProjectId();\n if (callerProject === undefined) {\n fail(EXIT.DAEMON_DOWN, 'Noir daemon is not running (not a Noir project).', opts);\n }\n const rec = readProjectDaemonRecord(callerProject);\n if (!rec) {\n fail(EXIT.DAEMON_DOWN, 'Noir daemon is not running (start with `noir daemon start`).', opts);\n }\n // `fail` returns `never` → TS narrows `rec` to ProjectDaemonRecord below.\n\n if (!pidAlive(rec.pid)) {\n clearProjectDaemonRecord(callerProject);\n fail(EXIT.DAEMON_DOWN, 'Noir daemon is not running (stale record removed).', opts);\n }\n\n // Live liveness probe: the daemon's HTTP server answers GET /health with\n // `{ok, pid, uptimeSec}`. A dead port / non-200 / unreachable host ⇒ stale.\n // Bounded like the other probes — a blackhole socket must not hang `noir\n // daemon status` (the \"probed by script\" exit-4 contract).\n const hs = spinner('Probing daemon health...', opts).start();\n let health: HealthBody | null = null;\n try {\n const res = await fetch(`http://127.0.0.1:${rec.port}/health`, {\n signal: AbortSignal.timeout(PROBE_TIMEOUT_MS),\n });\n if (res.status === 200) {\n health = (await res.json()) as HealthBody;\n }\n } catch {\n // ECONNREFUSED / DNS / timeout — treat as not-running below.\n health = null;\n }\n // PID-reuse guard (same invariant as @noir-ai/daemon ensure.ts isHealthy +\n // this file's isHealthy): the responding /health must carry OUR recorded pid —\n // a MISSING or mismatched pid means a foreign process (or one that recycled\n // the pid) holds the port. Report stale, never \"running\" with the wrong\n // process's uptime. Distinguish \"no health body at all\" (port unresponsive)\n // from \"body present but pid missing/mismatched\" (foreign process).\n const pidOk = typeof health?.pid === 'number' && health.pid === rec.pid;\n if (health?.ok !== true || !pidOk) {\n hs.fail('Daemon not responding');\n clearProjectDaemonRecord(callerProject);\n fail(\n EXIT.DAEMON_DOWN,\n health !== null && !pidOk\n ? 'Noir daemon is not running (pid missing/mismatched — a foreign process holds the recorded port; stale record removed).'\n : 'Noir daemon is not running (port unresponsive; stale record removed).',\n opts,\n );\n }\n\n hs.succeed('Daemon healthy');\n\n // Prefer the daemon's own uptime count; fall back to the record's startedAt.\n const uptimeSec =\n typeof health?.uptimeSec === 'number'\n ? health.uptimeSec\n : Math.max(0, Math.floor((Date.now() - rec.startedAt) / 1000));\n const data = {\n running: true,\n pid: rec.pid,\n port: rec.port,\n startedAt: rec.startedAt,\n uptimeSec,\n // Honest ownership: the detached child writes `mode:'detached'`; anything\n // else (a record written before the field existed, foreground start)\n // reports 'foreground'.\n mode: rec.mode ?? MODE,\n };\n\n if (opts.json === true) {\n process.stdout.write(`${JSON.stringify({ ok: true, data })}\\n`);\n return;\n }\n log(\n `Noir daemon: running (pid ${data.pid}, port ${data.port}, up ${formatUptime(uptimeSec)}, ${data.mode})`,\n opts,\n );\n}\n\n// ---------------------------------------------------------------------------\n// `noir daemon token`\n// ---------------------------------------------------------------------------\n/**\n * Print this project's daemon bearer token (spec 6.1) — the command a host's\n * MCP `headersHelper` runs at connect time so no secret lives in a config file.\n *\n * stdout carries the token and NOTHING else: no banner, no decoration, no\n * second line — the command's whole purpose is to be consumed by a program.\n * `--json` emits the S9 `{ok:true,data:{token}}` envelope instead (the same data\n * channel, self-describing). Every diagnostic goes to stderr.\n *\n * Every \"no usable token\" outcome is exit 4 (DAEMON_DOWN), like `daemon status`:\n * an uninitialized project, no daemon record, a record whose daemon is gone, or\n * a record with no token file beside it. A token is a credential for a LIVE\n * daemon — printing the token of a daemon that is not running would authenticate\n * nothing while looking like success, which is exactly the silent failure the\n * `headersHelper` contract must not have.\n *\n * The token is read from disk at CALL time (`~/.noir/daemons/<projectId>.token`)\n * and never cached: the daemon regenerates it on every start, so a remembered\n * copy is a 401.\n */\nexport async function daemonToken(opts: DaemonOptions): Promise<void> {\n // Same caller-scope resolution as status/stop: the project id IS the record\n // (and token) lookup key, so a daemon serving another project is invisible\n // here rather than mis-reported.\n const callerProject = resolveCallerProjectId();\n if (callerProject === undefined) {\n fail(EXIT.DAEMON_DOWN, 'Noir daemon is not running (not a Noir project).', opts);\n }\n const rec = readProjectDaemonRecord(callerProject);\n if (!rec) {\n fail(\n EXIT.DAEMON_DOWN,\n 'Noir daemon is not running (no daemon record — start it with `noir daemon start`).',\n opts,\n );\n }\n // A record whose process is gone is stale, and liveness alone is not enough:\n // an unrelated process can recycle the recorded pid. /health must answer with\n // THIS pid (and project) — the same ownership proof `daemon status` demands —\n // so a recycled pid cannot mint a token for a daemon that is not there.\n if (!pidAlive(rec.pid) || !(await isHealthy(rec.port, rec.pid, callerProject))) {\n fail(\n EXIT.DAEMON_DOWN,\n 'Noir daemon is not running (stale record — start it with `noir daemon start`).',\n opts,\n );\n }\n const token = readDaemonToken(callerProject);\n if (token === null) {\n fail(\n EXIT.DAEMON_DOWN,\n 'Noir daemon is not running (the record has no token beside it — restart it with `noir daemon start`).',\n opts,\n );\n }\n\n if (opts.json === true) {\n process.stdout.write(`${JSON.stringify({ ok: true, data: { token } })}\\n`);\n return;\n }\n // The ONLY stdout write on the human path — a headersHelper reads exactly this.\n process.stdout.write(`${token}\\n`);\n}\n\n// ---------------------------------------------------------------------------\n// `noir daemon restart`\n// ---------------------------------------------------------------------------\n/**\n * Stop any running daemon, then start a fresh one (foreground by default,\n * detached when `--detach` is forwarded through).\n *\n * The stop sub-step is silenced (no separate envelope / message) so that under\n * `--json` a restart emits exactly ONE stdout envelope (the start result), and\n * so the human output's headline is the new daemon, not the torn-down old one.\n * Foreground `start` blocks once it brings up a daemon, so a foreground restart\n * blocks too — the honest behavior; with `--detach` the parent exits after the\n * detached child is confirmed serving.\n */\nexport async function daemonRestart(opts: DaemonOptions & { detach?: boolean }): Promise<void> {\n // Force the stop to be quiet + non-JSON: its output would either duplicate\n // the start envelope (--json) or noise up the headline (human). The verbose\n // flag is forwarded so a `--verbose` caller still sees stop diagnostics.\n await daemonStop({ ...opts, json: false, quiet: true });\n await daemonStart(opts);\n}\n","// `noir workspace *` + the `--workspace` branch of `noir daemon start` + `noir daemon join`.\n//\n// A workspace is a named cross-repo sharing unit. `daemon start --workspace <name>`\n// founds/joins it from the current repo and starts the detached workspace daemon;\n// `daemon join <name>` joins it from another repo. `workspace list/status/leave/stop`\n// manage membership. Joining writes a `.noir/workspace.json` marker + rewrites the\n// repo's `.mcp.json` `noir` entry to the workspace daemon URL (`?p=<projectId>`);\n// leaving reverses both. Default transport (stdio) and project behavior are\n// untouched unless a repo explicitly joins.\nimport { readdirSync } from 'node:fs';\nimport {\n clearWorkspaceMarker,\n ensureWorkspaceRegistry,\n isValidWorkspaceName,\n isWorkspaceMember,\n loadProjectInfo,\n type ProjectInfo,\n readWorkspaceMarker,\n readWorkspaceRegistry,\n removeWorkspaceMember,\n upsertWorkspaceMember,\n workspaceHomeDir,\n writeWorkspaceMarker,\n} from '@noir-ai/core';\nimport {\n clearWorkspaceDaemonRecord,\n ensureWorkspaceDaemonRunning,\n pidAlive,\n readWorkspaceDaemonRecord,\n spawnDetachedWorkspaceDaemon,\n} from '@noir-ai/daemon';\nimport { type CliOptions, EXIT, fail, info, log } from '../output.js';\nimport { writeStdioEntry, writeWorkspaceHttpEntry } from '../workspace-mcp.js';\n\nexport interface WorkspaceStartOptions extends CliOptions {\n name: string;\n detach?: boolean;\n detachChild?: boolean;\n force?: boolean;\n}\nexport interface WorkspaceJoinOptions extends CliOptions {\n name: string;\n force?: boolean;\n}\nexport interface WorkspaceStatusOptions extends CliOptions {\n name?: string;\n}\nexport interface WorkspaceLeaveOptions extends CliOptions {\n force?: boolean;\n}\n\nfunction loadProjectOrFail(opts: CliOptions): ProjectInfo {\n try {\n return loadProjectInfo(process.cwd());\n } catch {\n fail(EXIT.ERROR, 'Noir is not initialized in this directory. Run `noir init` first.', opts);\n }\n}\n\nfunction finishJoin(\n project: ProjectInfo,\n name: string,\n url: string,\n opts: CliOptions & { force?: boolean },\n): void {\n writeWorkspaceMarker(project.root, name);\n writeWorkspaceHttpEntry(project.root, project.config.host, url, project.id, opts);\n}\n\n/** `noir daemon start --workspace <name>` — found a workspace + start its daemon. */\nexport async function daemonStartWorkspace(opts: WorkspaceStartOptions): Promise<void> {\n const project = loadProjectOrFail(opts);\n if (!isValidWorkspaceName(opts.name)) {\n fail(\n EXIT.USAGE,\n `invalid workspace name ${JSON.stringify(opts.name)} (lowercase letters, digits, and dashes).`,\n opts,\n );\n }\n // Found/join: register THIS repo as a member (idempotent by projectId).\n upsertWorkspaceMember(ensureWorkspaceRegistry(opts.name), {\n projectId: project.id,\n root: project.root,\n joinedAt: Date.now(),\n });\n\n // Detached-child path (set by spawnDetachedWorkspaceDaemon): run in-process.\n if (opts.detachChild === true) {\n const ensured = await ensureWorkspaceDaemonRunning({\n name: opts.name,\n project,\n idleTimeoutSec: project.config.workspace.idleTimeoutSec,\n });\n if (opts.json === true) {\n process.stdout.write(`${JSON.stringify({ ok: true, data: { mode: 'detached' } })}\\n`);\n return;\n }\n info('noir workspace daemon: detached foreground. Ctrl+C to stop.', opts);\n log(`workspace daemon listening at ${ensured.url}`, opts);\n return;\n }\n\n // --detach: fork a detached child; the parent writes the marker + .mcp.json.\n if (opts.detach === true) {\n const spawned = await spawnDetachedWorkspaceDaemon({ name: opts.name, project });\n finishJoin(project, opts.name, `http://127.0.0.1:${spawned.port}/mcp`, opts);\n if (opts.json === true) {\n process.stdout.write(\n `${JSON.stringify({ ok: true, data: { mode: 'detached', pid: spawned.pid, port: spawned.port } })}\\n`,\n );\n return;\n }\n info(\n `workspace \"${opts.name}\" daemon started (pid ${spawned.pid}, port ${spawned.port}).`,\n opts,\n );\n return;\n }\n\n // Foreground: the workspace server keeps this process alive.\n const ensured = await ensureWorkspaceDaemonRunning({\n name: opts.name,\n project,\n idleTimeoutSec: project.config.workspace.idleTimeoutSec,\n });\n finishJoin(project, opts.name, ensured.url, opts);\n if (opts.json === true) {\n process.stdout.write(\n `${JSON.stringify({ ok: true, data: { url: ensured.url, port: ensured.port, reused: !ensured.started } })}\\n`,\n );\n return;\n }\n info('noir workspace daemon: foreground mode. Ctrl+C to stop.', opts);\n log(`workspace daemon listening at ${ensured.url}`, opts);\n}\n\n/** `noir daemon join <name>` — join an existing workspace from this repo. */\nexport async function daemonJoin(opts: WorkspaceJoinOptions): Promise<void> {\n const project = loadProjectOrFail(opts);\n if (!isValidWorkspaceName(opts.name)) {\n fail(EXIT.USAGE, `invalid workspace name ${JSON.stringify(opts.name)}.`, opts);\n }\n const reg = readWorkspaceRegistry(opts.name);\n if (!reg) {\n fail(\n EXIT.ERROR,\n `workspace ${JSON.stringify(opts.name)} not found — start it from a member repo with \\`noir daemon start --workspace ${opts.name}\\`.`,\n opts,\n );\n }\n const ensured = await ensureWorkspaceDaemonRunning({\n name: opts.name,\n project,\n idleTimeoutSec: project.config.workspace.idleTimeoutSec,\n });\n upsertWorkspaceMember(reg, { projectId: project.id, root: project.root, joinedAt: Date.now() });\n finishJoin(project, opts.name, ensured.url, opts);\n if (opts.json === true) {\n process.stdout.write(\n `${JSON.stringify({ ok: true, data: { joined: true, url: ensured.url, port: ensured.port } })}\\n`,\n );\n return;\n }\n info(`joined workspace ${JSON.stringify(opts.name)} (${ensured.url}).`, opts);\n}\n\n/** `noir workspace list` — every workspace on this machine + member count. */\nexport async function workspaceList(opts: CliOptions): Promise<void> {\n let names: string[] = [];\n try {\n names = readdirSync(workspaceHomeDir(), { withFileTypes: true })\n .filter((e) => e.isDirectory())\n .map((e) => e.name);\n } catch {\n names = [];\n }\n const rows = names.map((n) => {\n const reg = readWorkspaceRegistry(n);\n return {\n name: n,\n members: reg?.members.length ?? 0,\n // A record file whose pid is dead (daemon killed without cleanup) must not\n // read as \"running\" — mirror the pidAlive liveness `workspace status` uses.\n running: (() => {\n const rec = readWorkspaceDaemonRecord(n);\n return rec !== null && pidAlive(rec.pid);\n })(),\n };\n });\n if (opts.json === true) {\n process.stdout.write(`${JSON.stringify({ ok: true, data: { workspaces: rows } })}\\n`);\n return;\n }\n if (rows.length === 0) {\n info('No workspaces yet.', opts);\n return;\n }\n for (const r of rows) {\n log(`${r.name} — ${r.members} member(s)${r.running ? ', running' : ''}`, opts);\n }\n}\n\n/** `noir workspace status [name]` — members + daemon liveness. */\nexport async function workspaceStatus(opts: WorkspaceStatusOptions): Promise<void> {\n const name = opts.name ?? readWorkspaceMarker(process.cwd()) ?? undefined;\n if (name === undefined) {\n fail(EXIT.USAGE, 'workspace status requires a name (or run from a joined repo).', opts);\n }\n if (!isValidWorkspaceName(name)) {\n fail(EXIT.USAGE, `invalid workspace name ${JSON.stringify(name)}.`, opts);\n }\n const reg = readWorkspaceRegistry(name);\n const rec = readWorkspaceDaemonRecord(name);\n const running = rec !== null && pidAlive(rec.pid);\n const data = {\n name,\n members: reg?.members.map((m) => m.projectId) ?? [],\n running,\n ...(rec ? { pid: rec.pid, port: rec.port } : {}),\n };\n if (opts.json === true) {\n process.stdout.write(`${JSON.stringify({ ok: true, data })}\\n`);\n return;\n }\n log(\n `workspace ${name}: ${running ? `running (pid ${rec?.pid}, port ${rec?.port})` : 'not running'}`,\n opts,\n );\n for (const m of data.members) log(` member: ${m}`, opts);\n}\n\n/** `noir workspace leave` — remove this repo from membership + restore stdio. */\nexport async function workspaceLeave(opts: WorkspaceLeaveOptions): Promise<void> {\n const project = loadProjectOrFail(opts);\n const name = readWorkspaceMarker(project.root);\n if (name === null) {\n fail(EXIT.USAGE, 'this repo is not joined to a workspace.', opts);\n }\n // Restore stdio FIRST — it is the one step that can fail (a non-Noir .mcp.json\n // is refused without `--force`). Doing it last would strand the repo mid-leave:\n // membership removed + marker cleared, but .mcp.json still pointed at a\n // workspace the repo no longer belongs to.\n writeStdioEntry(project.root, project.config.host, opts);\n const reg = readWorkspaceRegistry(name);\n if (reg && isWorkspaceMember(reg, project.id)) {\n removeWorkspaceMember(reg, project.id);\n }\n clearWorkspaceMarker(project.root);\n if (opts.json === true) {\n process.stdout.write(`${JSON.stringify({ ok: true, data: { left: name } })}\\n`);\n return;\n }\n info(`left workspace ${JSON.stringify(name)}.`, opts);\n}\n\n/** `noir workspace stop [name]` — stop the workspace daemon (membership retained). */\nexport async function workspaceStop(opts: WorkspaceStatusOptions): Promise<void> {\n const name = opts.name ?? readWorkspaceMarker(process.cwd()) ?? undefined;\n if (name === undefined) {\n fail(EXIT.USAGE, 'workspace stop requires a name (or run from a joined repo).', opts);\n }\n if (!isValidWorkspaceName(name)) {\n fail(EXIT.USAGE, `invalid workspace name ${JSON.stringify(name)}.`, opts);\n }\n const rec = readWorkspaceDaemonRecord(name);\n if (rec === null || !pidAlive(rec.pid)) {\n if (opts.json === true) {\n process.stdout.write(\n `${JSON.stringify({ ok: true, data: { running: false, stopped: false } })}\\n`,\n );\n return;\n }\n info('workspace daemon is not running.', opts);\n return;\n }\n try {\n process.kill(rec.pid, 'SIGTERM');\n } catch {\n // already exited between the probe and the signal\n }\n clearWorkspaceDaemonRecord(name);\n if (opts.json === true) {\n process.stdout.write(\n `${JSON.stringify({ ok: true, data: { running: false, stopped: true, pid: rec.pid } })}\\n`,\n );\n return;\n }\n info(`stopped workspace daemon (pid ${rec.pid}).`, opts);\n}\n","// `.mcp.json` rewrite/restore for workspace membership — the ONLY user-facing\n// file a join/leave touches. It rewrites just the `noir` server entry (preserving\n// every other server the user added) and refuses to clobber a config that does\n// not look Noir-emitted unless `--force` (never a silent overwrite).\nimport { existsSync, readFileSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { type HostId, resolveAdapter } from '@noir-ai/adapters';\nimport { atomicWriteFile, resolveNoirCommand } from '@noir-ai/core';\nimport { type CliOptions, EXIT, fail } from './output.js';\n\nfunction mcpPathFor(root: string, host: HostId): string {\n return resolveAdapter(host).mcpConfigPath?.({ root }) ?? join(root, '.mcp.json');\n}\n\n/** Read + parse an existing host MCP config, or `null` when the file is absent. */\nfunction readJson(path: string): { mcpServers?: Record<string, unknown> } | null {\n if (!existsSync(path)) return null; // absent → fresh write is fine\n // Unparseable (JSONC/commented/trailing-comma) THROWS so the caller can refuse —\n // never silently clobber a user-edited file that happens to not be strict JSON.\n return JSON.parse(readFileSync(path, 'utf8')) as { mcpServers?: Record<string, unknown> };\n}\n\n/** Load an existing config, refusing (exit 1) on an unparseable file unless --force. */\nfunction loadExisting(\n path: string,\n opts: CliOptions & { force?: boolean },\n): { mcpServers?: Record<string, unknown> } | null {\n let existing: { mcpServers?: Record<string, unknown> } | null;\n try {\n existing = readJson(path);\n } catch {\n if (opts.force !== true) {\n fail(\n EXIT.ERROR,\n `Refusing to rewrite ${path}: it is not valid JSON (add --force to overwrite).`,\n opts,\n );\n }\n existing = null; // --force: overwrite the unparseable file\n }\n if (existing !== null && !isNoirEmitted(existing.mcpServers) && opts.force !== true) {\n fail(\n EXIT.ERROR,\n `Refusing to rewrite ${path}: it does not look like a Noir-emitted config (add --force to overwrite).`,\n opts,\n );\n }\n return existing;\n}\n\nfunction isNoirEmitted(mcpServers: Record<string, unknown> | undefined): boolean {\n const noir = mcpServers?.noir as { command?: unknown; type?: unknown } | undefined;\n if (!noir) return false;\n if (typeof noir.command === 'string') return true;\n return noir.type === 'http';\n}\n\n/** Point the repo's `noir` MCP entry at the workspace daemon (with the member `?p=` identity). */\nexport function writeWorkspaceHttpEntry(\n root: string,\n host: HostId,\n url: string,\n projectId: string,\n opts: CliOptions & { force?: boolean },\n): void {\n const path = mcpPathFor(root, host);\n const existing = loadExisting(path, opts);\n const next = {\n ...(existing ?? {}),\n mcpServers: {\n ...(existing?.mcpServers ?? {}),\n noir: { type: 'http', url: `${url}?p=${projectId}` },\n },\n };\n atomicWriteFile(path, `${JSON.stringify(next, null, 2)}\\n`);\n}\n\n/** Restore the repo's `noir` MCP entry to stdio (used by `workspace leave`). */\nexport function writeStdioEntry(\n root: string,\n host: HostId,\n opts: CliOptions & { force?: boolean },\n): void {\n const path = mcpPathFor(root, host);\n const existing = loadExisting(path, opts);\n const noir = { command: resolveNoirCommand(), args: ['mcp', 'serve', '--stdio'] };\n const next = { ...(existing ?? {}), mcpServers: { ...(existing?.mcpServers ?? {}), noir } };\n atomicWriteFile(path, `${JSON.stringify(next, null, 2)}\\n`);\n}\n","// S9 — `noir doctor`.\n//\n// Environment + project health. Runs a fixed set of checks and renders a\n// results table (human, stderr) or the versioned `{ok,data}` envelope (--json,\n// stdout). Exit 1 if any CRITICAL (fail) check is unhealthy, else 0.\n//\n// Severity model (S9 spec F8):\n// - ok — healthy.\n// - warn — degraded but usable (daemon down, onnx missing, provider key\n// missing, project not initialized). NEVER triggers exit 1.\n// - fail — CRITICAL: the product is broken on this host. Only `config` (parse\n// error), `native deps` (better-sqlite3 / sqlite-vec will not load),\n// and `store` (open fails) can fail. Exit 1 if any fail.\n//\n// Honesty rules: provider status uses `resolveModelConfig` — a PURE projection\n// of the user's config + env-var NAME presence; it makes NO live call (blueprint\n// D5). Native-dep probes are best-effort try/catch (the store's native\n// binaries are probed via `vecAvailability`, the single cross-package surface;\n// onnxruntime-node is the context engine's own dep and is probed separately).\n//\n// Cold-start (NF6): the @noir-ai/store import (which loads better-sqlite3) is\n// DYNAMIC, inside the action, so merely running `noir status` / `noir --help`\n// never pays the native-bindings cost. @noir-ai/model is imported eagerly — its\n// provider self-registration is light (SDKs load lazily inside `complete()`).\n//\n// Stream discipline (S9): `--json` writes `{ok:true, data:{checks,summary}}`\n// to stdout (the only stdout write). Doctor always emits `ok:true` because the\n// COMMAND succeeded in producing a diagnosis; the system-health pass/fail is\n// signaled by the EXIT CODE (0 healthy / 1 critical failure) — the same shape\n// `npm audit --json` uses (valid JSON out, non-zero exit when issues found).\n\nimport { spawnSync } from 'node:child_process';\nimport { existsSync, readdirSync, readFileSync, type Stats, statSync } from 'node:fs';\nimport { dirname, join, relative } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { type HostId, resolveAdapter } from '@noir-ai/adapters';\nimport {\n detectActiveMethod,\n type InstallMethod,\n type LoadedEnv,\n latestVersionFromCache,\n loadNoirEnv,\n loadProjectInfo,\n NOIR_VERSION,\n type ProjectInfo,\n paths,\n readInstallRecord,\n readUpdateCache,\n} from '@noir-ai/core';\nimport { CURRENT_SCAFFOLD_VERSION, readScaffoldVersion } from '@noir-ai/create';\nimport { pidAlive, readProjectDaemonRecord } from '@noir-ai/daemon';\nimport { resolveModelConfig } from '@noir-ai/model';\nimport { PROBE_TIMEOUT_MS } from '../daemon-client.js';\nimport {\n type CliOptions,\n EXIT,\n error as err,\n log,\n NoirCliError,\n success,\n table,\n warn,\n} from '../output.js';\nimport { type BadgeState, badge } from '../theme.js';\n\n/** Options accepted by `doctor`: the global flags + the opt-in `--dedup`. */\nexport interface DoctorOptions extends CliOptions {\n /** `--dedup`: scan host-context + `.noir/` docs for semantic near-duplicates.\n * Opt-in (loads the local embedder) so a default `noir doctor` stays fast. */\n dedup?: boolean;\n}\n\ntype Severity = 'ok' | 'warn' | 'fail';\n\n/** One row of the doctor report (table cell + `--json` element). */\nexport interface CheckResult {\n name: string;\n status: Severity;\n detail: string;\n}\n\n/** The `data` payload of `noir doctor --json`. */\nexport interface DoctorPayload {\n noir: string;\n checks: CheckResult[];\n summary: { ok: number; warn: number; fail: number };\n /** Scaffold-version drift (slice S). `onDisk` is null when the stamp is\n * absent (uninitialized or pre-Slice-S project); `drift` is true only when\n * a stamp is present AND differs from the engine's current version. */\n scaffold: { onDisk: string | null; current: string; drift: boolean };\n /** RULES.md budget measurement. `null` when the project isn't\n * initialized OR `.noir/rules/RULES.md` is absent — in either case there\n * is nothing to measure and the check row stays informational (warn skip\n * or ok \"no RULES.md\"). Never drives `fail` — over-budget is a `warn`. */\n rules: {\n onDisk: { bytes: number; lines: number };\n budget: { kb: number; maxLines: number };\n over: boolean;\n } | null;\n /** S10 host report. `null` when the project isn't initialized (no resolved\n * host); otherwise carries the active `host` + the list of repo-relative\n * primary artifact paths the doctor verified (AGENTS.md for agents-md/\n * cursor/opencode; the host's native context file when distinct from\n * AGENTS.md (claude → CLAUDE.md, gemini → GEMINI.md); the host's MCP\n * config). The check row is `ok` when\n * all present, `warn` (NEVER `fail`) when any are missing — re-running\n * `noir sync` restores them. */\n host: { active: HostId; expected: string[]; missing: string[] } | null;\n /** S11 publish-readiness report (repo-developer-facing, advisory). `null`\n * when doctor is NOT running from a monorepo checkout (a global install has\n * no workspace package.json set to validate → the row reports `ok`\n * \"skipped\"). Otherwise carries the count of workspace `package.json` files\n * validated + the list of advisory issues found (bad semver, missing\n * `files`, cli missing `bin`, …). The row severity is `warn` when any issues\n * are present, `ok` otherwise — NEVER `fail` (a missing field does not break\n * the local install). */\n publish: { checked: number; issues: string[] } | null;\n /** C1 install-method report. `method` from ~/.noir/install.json (fallback\n * unknown); `latestKnown` from the update cache (never a live call). */\n install: {\n method: InstallMethod;\n installedVersion: string | null;\n latestKnown: string | null;\n } | null;\n}\n\n// ---------------------------------------------------------------------------\n// Small helpers\n// ---------------------------------------------------------------------------\n\n/** Best-effort probe of the `onnxruntime-node` native binding. */\nasync function probeOnnx(): Promise<{ ok: boolean; reason: string }> {\n try {\n // Variable specifier (not a string literal) so tsc does NOT try to resolve\n // a module the CLI package does not directly depend on — onnxruntime-node\n // is the context engine's dep and resolves through ITS node_modules at\n // runtime. Best-effort: hosts that hoist it resolve; otherwise not-loadable.\n const spec = 'onnxruntime-node';\n await import(spec);\n return { ok: true, reason: 'loadable' };\n } catch (e) {\n return { ok: false, reason: e instanceof Error ? e.message : String(e) };\n }\n}\n\n/** Human label for the onnx probe outcome (hides confusing module-not-found noise). */\nfunction describeOnnx(o: { ok: boolean; reason: string }): string {\n if (o.ok) return 'loadable';\n if (/Cannot find (module|package)/i.test(o.reason)) {\n return 'not resolvable from CLI probe (best-effort)';\n }\n const r = o.reason.length > 60 ? `${o.reason.slice(0, 59)}…` : o.reason;\n return `probe failed: ${r}`;\n}\n\nfunction fmtUptime(sec: number): string {\n if (!Number.isFinite(sec) || sec < 0) return 'unknown';\n if (sec < 60) return `${sec}s`;\n if (sec < 3600) return `${Math.floor(sec / 60)}m ${sec % 60}s`;\n return `${Math.floor(sec / 3600)}h ${Math.floor((sec % 3600) / 60)}m`;\n}\n\nfunction msg(e: unknown): string {\n return e instanceof Error ? e.message : String(e);\n}\n\n// ---------------------------------------------------------------------------\n// Checks. Each appends to `checks`; project-dependent ones short-circuit to a\n// `warn` \"skipped\" row when the project isn't initialized (so the table still\n// accounts for them, but a pre-init `noir doctor` never exit-1s on them).\n// ---------------------------------------------------------------------------\n\nasync function checkRuntime(checks: CheckResult[]): Promise<void> {\n checks.push({\n name: 'runtime',\n status: 'ok',\n detail: `noir ${NOIR_VERSION} · node ${process.version} · ${process.platform}`,\n });\n}\n\nfunction checkConfig(root: string): { project: ProjectInfo | undefined; result: CheckResult } {\n const configPath = paths.config(root);\n if (!existsSync(configPath)) {\n return {\n project: undefined,\n result: {\n name: 'config',\n status: 'warn',\n detail: `no .noir/config.yml in ${root} — run \\`noir init\\``,\n },\n };\n }\n try {\n const project = loadProjectInfo(root);\n return {\n project,\n result: {\n name: 'config',\n status: 'ok',\n detail: `host=${project.config.host} · mode=${project.config.mode}`,\n },\n };\n } catch (e) {\n return {\n project: undefined,\n result: { name: 'config', status: 'fail', detail: `config parse error: ${msg(e)}` },\n };\n }\n}\n\nasync function checkDaemon(checks: CheckResult[], project: ProjectInfo | undefined): Promise<void> {\n // The record is per-project; without a project id there is no record to look\n // up, so report honestly rather than reading (and implicitly claiming) a\n // daemon that belongs to some unknown project.\n if (project === undefined) {\n checks.push({\n name: 'daemon',\n status: 'warn',\n detail: 'skipped — project not initialized',\n });\n return;\n }\n const rec = readProjectDaemonRecord(project.id);\n if (!rec) {\n checks.push({\n name: 'daemon',\n status: 'warn',\n detail: 'not running (start with `noir daemon start`)',\n });\n return;\n }\n if (!pidAlive(rec.pid)) {\n checks.push({\n name: 'daemon',\n status: 'warn',\n detail: `stale record (pid ${rec.pid} not alive)`,\n });\n return;\n }\n try {\n // Bounded probe — a stale record pointing at a blackhole socket (TCP\n // accepted, HTTP never answered) must not hang `noir doctor` for minutes.\n const res = await fetch(`http://127.0.0.1:${rec.port}/health`, {\n signal: AbortSignal.timeout(PROBE_TIMEOUT_MS),\n });\n const body =\n res.status === 200\n ? ((await res.json()) as { ok?: boolean; pid?: number; uptimeSec?: number })\n : null;\n // PID-reuse guard (mirrors daemonStatus): require the responding /health to\n // carry OUR recorded pid — a foreign process serving /health is not our daemon.\n const pidOk = typeof body?.pid === 'number' && body.pid === rec.pid;\n if (body && body.ok === true && pidOk) {\n checks.push({\n name: 'daemon',\n status: 'ok',\n detail: `running (pid ${rec.pid}, port ${rec.port}, up ${fmtUptime(body.uptimeSec ?? 0)})`,\n });\n return;\n }\n checks.push({\n name: 'daemon',\n status: 'warn',\n detail: `record present but /health unreachable on port ${rec.port}`,\n });\n } catch {\n checks.push({\n name: 'daemon',\n status: 'warn',\n detail: `record present but /health unreachable on port ${rec.port}`,\n });\n }\n}\n\nasync function checkNativeDeps(checks: CheckResult[]): Promise<{ vecOk: boolean }> {\n // vecAvailability probes better-sqlite3 + sqlite-vec together (the store opens\n // a Database and loads sqlite-vec). Dynamic import keeps the native bindings\n // out of cold-start for every other command.\n const { vecAvailability } = await import('@noir-ai/store');\n const vec = vecAvailability();\n const onnx = await probeOnnx();\n const vecOk = vec.ok === true;\n const onnxOk = onnx.ok === true;\n // The sqlite side is CRITICAL (the store cannot open without it). onnx only\n // backs local embeddings, so its absence is a warning (search → BM25-only).\n const status: Severity = vecOk ? (onnxOk ? 'ok' : 'warn') : 'fail';\n checks.push({\n name: 'native deps',\n status,\n detail: `better-sqlite3+sqlite-vec: ${vecOk ? 'loadable' : vec.ok === false ? vec.reason : 'unknown'} · onnxruntime-node: ${describeOnnx(onnx)}`,\n });\n return { vecOk };\n}\n\nasync function checkStore(\n checks: CheckResult[],\n project: ProjectInfo | undefined,\n root: string,\n): Promise<void> {\n if (!project) {\n checks.push({ name: 'store', status: 'warn', detail: 'skipped — not initialized' });\n return;\n }\n const dbPath = paths.storeDb(root, project.id);\n if (!existsSync(dbPath)) {\n // Fresh project: the store DB is created LAZILY when the daemon first runs\n // (or when content is indexed) — `noir init`/`create` does not pre-create it.\n // Its absence on an otherwise-initialized project is EXPECTED, not a failure:\n // surfacing it as `fail` would alarm every new user on their first `noir doctor`.\n // Warn (never exit-1) with the action that materializes the store.\n checks.push({\n name: 'store',\n status: 'warn',\n detail: `not created yet — the store DB is created when the daemon first runs (\\`noir daemon start\\` or index content); expected at ${dbPath}`,\n });\n return;\n }\n const { openStore } = await import('@noir-ai/store');\n let store: { close(): Promise<void> | void } | undefined;\n try {\n store = await openStore({ projectId: project.id, root, readonly: true });\n checks.push({\n name: 'store',\n status: 'ok',\n detail: `opens readonly (db: ${paths.storeDb(root, project.id)})`,\n });\n } catch (e) {\n checks.push({ name: 'store', status: 'fail', detail: `open failed: ${msg(e)}` });\n } finally {\n if (store) {\n try {\n await Promise.resolve(store.close());\n } catch {\n /* a close error must not mask the open result */\n }\n }\n }\n}\n\n/**\n * The tracked-file refusal line emitted by `loadNoirEnv` (spec 12.2). Matched by\n * its stable PREFIX: @noir-ai/core owns the wording, and this warning is the one\n * signal the loader returns that a `.noir/.env` was refused outright rather than\n * loaded (a refused file yields `overlay: {}` + `sources: {}` + this one line).\n */\nconst ENV_REFUSAL_PREFIX = '.noir/.env: refusing to load';\n\n/**\n * `.noir/.env` rows (names only, never values).\n *\n * Three concerns, in the order the user should read them:\n *\n * 1. REFUSAL (spec 12.2) — a git-tracked file contributes NOTHING. Reporting\n * only its permissions here would tell the user everything is fine while\n * every key in it is being ignored, which is precisely the \"I edited\n * `.noir/.env` and nothing changed\" confusion this check exists to kill.\n * The permissions advisory is skipped for a refused file, mirroring the\n * loader, which refuses before it even parses (so it emits no other\n * diagnostic either).\n * 2. PERMISSION advisory — a group/world-readable file can leak tokens\n * (ssh/aws-credentials convention). Warn, never fail.\n * 3. PROVENANCE — one `ok` row per key the file DEFINES, naming the side that\n * won. The file is the user's own short list, so this is not an\n * enumeration of the environment (see `noir env` for the curated view);\n * the value is never read, only the key name.\n */\nfunction checkNoirEnv(checks: CheckResult[], root: string, loaded: LoadedEnv): void {\n const path = join(paths.noirDir(root), '.env');\n let st: Stats;\n try {\n st = statSync(path);\n } catch {\n return; // no .env file — nothing to check\n }\n if (loaded.warnings.some((w) => w.startsWith(ENV_REFUSAL_PREFIX))) {\n checks.push({\n name: 'noir-env',\n status: 'warn',\n detail: `${path} is tracked by git — refused, so NONE of its keys are in effect. Fix: add \\`.noir/.env\\` to .gitignore and run \\`git rm --cached .noir/.env\\`.`,\n });\n return;\n }\n const mode = st.mode & 0o777;\n const tooOpen = (st.mode & 0o077) !== 0;\n checks.push(\n tooOpen\n ? {\n name: 'noir-env',\n status: 'warn',\n detail: `${path} is ${mode.toString(8)} — readable by others; run chmod 600`,\n }\n : { name: 'noir-env', status: 'ok', detail: `${path} permissions ok (${mode.toString(8)})` },\n );\n // Provenance rows. Named `noir-env:<KEY>` so they group under the permission\n // row in the table and stay uniquely addressable in the `--json` payload.\n for (const [key, source] of Object.entries(loaded.sources)) {\n if (source !== 'file') continue;\n checks.push({ name: `noir-env:${key}`, status: 'ok', detail: 'from .noir/.env' });\n }\n}\n\nfunction checkEmbedder(\n checks: CheckResult[],\n project: ProjectInfo | undefined,\n vecOk: boolean,\n): void {\n if (!project) {\n checks.push({ name: 'embedder', status: 'warn', detail: 'skipped — not initialized' });\n return;\n }\n const emb = project.config.context.embedder;\n const kind = emb.kind;\n const model = typeof emb.model === 'string' && emb.model.length > 0 ? emb.model : '<unset>';\n if (kind === 'none') {\n checks.push({\n name: 'embedder',\n status: 'ok',\n detail: `kind=none (BM25-only) · dim=${emb.dim}`,\n });\n return;\n }\n if (!vecOk) {\n // vec native layer is the embedder's hard prereq (vecs write into vec0).\n checks.push({\n name: 'embedder',\n status: 'warn',\n detail: `${kind}/${model} (${emb.dim}-dim) configured but vec native layer unavailable — search degrades to BM25`,\n });\n return;\n }\n checks.push({\n name: 'embedder',\n status: 'ok',\n detail: `${kind}/${model} (${emb.dim}-dim) · vec backend available`,\n });\n}\n\nfunction checkProvider(\n checks: CheckResult[],\n project: ProjectInfo | undefined,\n sources: LoadedEnv['sources'],\n): void {\n if (!project) {\n checks.push({ name: 'provider', status: 'warn', detail: 'skipped — not initialized' });\n return;\n }\n // PURE projection — resolveModelConfig reads config + env-var NAMES only; it\n // NEVER makes a live call and NEVER infers a provider from env-var presence.\n const resolved = resolveModelConfig(project.config.model);\n const names = Object.keys(resolved.providers);\n if (names.length === 0) {\n checks.push({\n name: 'provider',\n status: 'ok',\n detail: 'none configured (offline mode; drafting degrades to templates)',\n });\n return;\n }\n const parts: string[] = [];\n let missing = false;\n for (const name of names) {\n const p = resolved.providers[name];\n if (!p) continue;\n // Provenance (spec 12.3): when the winning source for the key is\n // `.noir/.env`, say so — \"key present\" alone leaves the user staring at an\n // empty shell export wondering where the key came from. The NAME only; the\n // value is never read here, let alone printed.\n const fromFile = p.apiKeyEnv !== undefined && sources[p.apiKeyEnv] === 'file';\n const key = p.hasKey\n ? fromFile\n ? 'key present (from .noir/.env)'\n : 'key present'\n : p.apiKeyEnv\n ? `missing ${p.apiKeyEnv}`\n : 'anonymous';\n if (!p.hasKey && p.apiKeyEnv) missing = true;\n parts.push(`${name}/${p.model ?? '?'} (${key})`);\n }\n // Provider readiness is never CRITICAL — the model layer degrades to `null`\n // (templates) when a key is missing, so this is an ok/warn signal only.\n checks.push({\n name: 'provider',\n status: missing ? 'warn' : 'ok',\n detail: parts.join(' · '),\n });\n}\n\n// ---------------------------------------------------------------------------\n// C1 — doctor install row (advisory; ok/warn only, never fail, cache-only).\n// ---------------------------------------------------------------------------\n\nexport interface InstallCheckOutcome {\n name: 'install';\n status: 'ok' | 'warn';\n detail: string;\n method: InstallMethod;\n installedVersion: string | null;\n latestKnown: string | null;\n}\n\n/** Pure: build the doctor `install` row. NEVER `fail` — an install method issue\n * is advisory, not a broken host. Reads the cache only; no network. */\nexport function buildInstallCheck(opts: {\n method: InstallMethod;\n version: string | null;\n latestKnown: string | null;\n}): InstallCheckOutcome {\n const { method, version, latestKnown } = opts;\n const parts: string[] = [`method=${method}`];\n if (version) parts.push(`v${version}`);\n const advisory: string[] = [];\n if (method !== 'native') advisory.push('native recommended');\n if (latestKnown && version && latestKnown !== version) advisory.push('update available');\n const status: 'ok' | 'warn' = advisory.length > 0 ? 'warn' : 'ok';\n if (advisory.length > 0) parts.push(advisory.join(' + '));\n return {\n name: 'install',\n status,\n detail: parts.join(' · '),\n method,\n installedVersion: version,\n latestKnown,\n };\n}\n\nfunction checkScaffoldVersion(\n checks: CheckResult[],\n root: string,\n): {\n onDisk: string | null;\n current: string;\n drift: boolean;\n} {\n // readScaffoldVersion never throws — it returns null on an absent/malformed\n // stamp, so doctor keeps reporting even on a partially-initialized project.\n const onDisk = readScaffoldVersion(root);\n const current = CURRENT_SCAFFOLD_VERSION;\n const drift = onDisk !== null && onDisk !== current;\n // Drift is NEVER critical: a stale scaffold still works (the manifest entries\n // are forward-compatible), it just means `noir init --upgrade` will run\n // pending migrations. Absent stamp on an uninitialized project → warn (parity\n // with the other project-dependent checks that skip-with-warn pre-init).\n const status: Severity = onDisk === null || drift ? 'warn' : 'ok';\n const detail =\n onDisk === null\n ? 'no .noir/scaffold-version stamp (run `noir init`)'\n : drift\n ? `on-disk ${onDisk} ≠ current ${current} (run \\`noir init --upgrade\\`)`\n : `${onDisk} (up to date)`;\n checks.push({ name: 'scaffold version', status, detail });\n return { onDisk, current, drift };\n}\n\n/**\n * Soft RULES.md budget cap. Mirrors the Failure-Backed Rules doctrine:\n * an over-budget RULES.md tends to accumulate stale / speculative clauses, so\n * doctor warns (NEVER fails — purely a hygiene nudge) when the file exceeds\n * the configured `lengthBudgetKb` (default 6 KB) OR a 150-line ceiling. The\n * check is honest about the three \"nothing to measure\" cases:\n *\n * • project not initialized → skip-warn (parity with store/embedder/provider)\n * • RULES.md absent → ok informational (no file = no budget problem)\n * • RULES.md unreadable → warn (treat like a malformed-stamp: surface it)\n *\n * Returns the structured measurement for the `--json` envelope's `data.rules`,\n * or `null` when there is nothing to measure (absent / skipped).\n */\nfunction checkRulesMdBudget(\n checks: CheckResult[],\n root: string,\n project: ProjectInfo | undefined,\n): {\n onDisk: { bytes: number; lines: number };\n budget: { kb: number; maxLines: number };\n over: boolean;\n} | null {\n if (!project) {\n checks.push({ name: 'rules budget', status: 'warn', detail: 'skipped — not initialized' });\n return null;\n }\n const rulesPath = paths.rulesMd(root);\n if (!existsSync(rulesPath)) {\n // No RULES.md is fine — most projects don't have one yet. Informational ok\n // so a green run stays green without forcing a file creation.\n checks.push({\n name: 'rules budget',\n status: 'ok',\n detail: 'no .noir/rules/RULES.md',\n });\n return null;\n }\n // Read + measure. A read/decode failure surfaces as a warn (parallel to the\n // malformed-stamp handling in checkScaffoldVersion): the doctor keeps\n // reporting rather than crashing, and the user sees a clear hint.\n let content: string;\n try {\n content = readFileSync(rulesPath, 'utf8');\n } catch (e) {\n checks.push({\n name: 'rules budget',\n status: 'warn',\n detail: `RULES.md unreadable: ${msg(e)}`,\n });\n return null;\n }\n // bytes = UTF-8 file size on disk (the natural unit for a KB budget). lines\n // uses wc-style counting: count of '\\n' chars, +1 if the last line has no\n // trailing newline; 0 only for an empty file.\n const bytes = Buffer.byteLength(content, 'utf8');\n const lineCount =\n content.length === 0 ? 0 : content.split('\\n').length - (content.endsWith('\\n') ? 1 : 0);\n const lengthBudgetKb = project.config.rules.lengthBudgetKb;\n const budgetBytes = lengthBudgetKb * 1024;\n const maxLines = 150;\n const overBytes = bytes > budgetBytes;\n const overLines = lineCount > maxLines;\n const over = overBytes || overLines;\n const status: Severity = over ? 'warn' : 'ok';\n const kb = (n: number): string => (n / 1024).toFixed(1);\n const detail = over\n ? `OVER: ${kb(bytes)} KB / ${lengthBudgetKb} KB · ${lineCount}/${maxLines} lines — trim RULES.md (failure-backed clauses only) or raise rules.lengthBudgetKb`\n : `${kb(bytes)} KB / ${lengthBudgetKb} KB · ${lineCount}/${maxLines} lines (within budget)`;\n checks.push({ name: 'rules budget', status, detail });\n return {\n onDisk: { bytes, lines: lineCount },\n budget: { kb: lengthBudgetKb, maxLines },\n over,\n };\n}\n\nfunction summarize(checks: CheckResult[]): DoctorPayload['summary'] {\n let ok = 0;\n let warnN = 0;\n let fail = 0;\n for (const c of checks) {\n if (c.status === 'ok') ok++;\n else if (c.status === 'warn') warnN++;\n else fail++;\n }\n return { ok, warn: warnN, fail };\n}\n\n/**\n * S10 — host-artifacts presence check. Reports the ACTIVE host (read from\n * `project.config.host`) + verifies the host's primary emission paths exist on\n * disk. The expected set mirrors `buildHostArtifacts` in @noir-ai/create:\n *\n * - AGENTS.md for the hosts that emit it (agents-md/cursor/opencode — their\n * native context surface IS AGENTS.md). claude/gemini do NOT emit AGENTS.md\n * (their CLAUDE.md/GEMINI.md @-import the canonical .noir/ sources; a root\n * AGENTS.md would double-import them — fix-wave I1 removed that delta).\n * - The host's native context file when distinct from AGENTS.md\n * (claude → CLAUDE.md; gemini → GEMINI.md; agents-md/cursor/opencode →\n * none, AGENTS.md IS the context). Cursor's working-rules ride AGENTS.md's\n * `@.noir/rules/RULES.md` import — NO separate `.cursor/rules/noir-contract.mdc`\n * host-rules pointer (it was `noir-`-prefixed and the C3 cursor flat-skill\n * prune deleted it on every sync).\n * - The host's MCP config (.mcp.json / .gemini/mcp.json / .cursor/mcp.json /\n * opencode.json).\n *\n * Severity is `ok` when every expected path exists, `warn` when any are\n * missing (NEVER `fail` — a missing host artifact is restored by `noir sync`,\n * not a critical product failure). Mirrors the policy of the other\n * presence/projection checks (scaffold-version drift, RULES.md budget): warn,\n * surface the remediation, never block.\n *\n * Returns the structured payload for the `--json` envelope's `data.host`, or\n * `null` when the project isn't initialized (no resolved host).\n */\nfunction checkHostArtifacts(\n checks: CheckResult[],\n root: string,\n project: ProjectInfo | undefined,\n): { active: HostId; expected: string[]; missing: string[] } | null {\n if (!project) {\n checks.push({ name: 'host artifacts', status: 'warn', detail: 'skipped — not initialized' });\n return null;\n }\n const host = project.config.host;\n const adapter = resolveAdapter(host);\n const ectx = { root };\n\n // Build the expected repo-relative path list. Mirrors buildHostArtifacts in\n // @noir-ai/create so a missing row maps 1:1 to a manifest entry the user can\n // restore with `noir sync`. Kept inline (not imported) so doctor stays a\n // READ-ONLY health probe with zero write-side coupling.\n const expected: string[] = [];\n // AGENTS.md — only for hosts whose emitContext IS the AGENTS.md (I1: claude/\n // gemini skip it — their native context file already covers .noir/).\n const emitsAgentsMd = host === 'agents-md' || host === 'cursor' || host === 'opencode';\n if (emitsAgentsMd) {\n expected.push(relOr(adapter.agentsMdPath?.(ectx) ?? 'AGENTS.md', root));\n }\n // Host-native context file (when distinct from AGENTS.md).\n if (host === 'claude') expected.push('CLAUDE.md');\n else if (host === 'gemini') expected.push('GEMINI.md');\n // Cursor has NO separate host-rules .mdc — the prior `noir-contract.mdc`\n // pointer was REMOVED (it was `noir-`-prefixed, so the C3 cursor flat-skill\n // prune in emitSkillsToDir deleted it on every noir init/create/sync).\n // Cursor's rules ride AGENTS.md's `@.noir/rules/RULES.md` import instead.\n // Host MCP config (fallback .mcp.json for claude/agents-md).\n expected.push(relOr(adapter.mcpConfigPath?.(ectx) ?? '.mcp.json', root));\n\n const missing = expected.filter((p) => !existsSync(joinRoot(root, p)));\n const status: Severity = missing.length === 0 ? 'ok' : 'warn';\n const detail =\n missing.length === 0\n ? `host=${host} · all ${expected.length} primary artifacts present`\n : `host=${host} · missing ${missing.join(', ')} (run \\`noir sync\\` to restore)`;\n checks.push({ name: 'host artifacts', status, detail });\n return { active: host, expected, missing };\n}\n\n// ---------------------------------------------------------------------------\n// SP-A — nested-`.noir` detection (read-only).\n// ---------------------------------------------------------------------------\n\n/**\n * Detects the fingerprint of a `noir init`/`create` run from INSIDE `.noir/`\n * (now PREVENTED by `assertSafeRoot` in @noir-ai/create, but legacy/already-\n * nested projects still carry the damage): a nested `<root>/.noir/.noir/` store\n * and/or host artifacts emitted into `.noir/` as if it were a project root\n * (`.noir/CLAUDE.md`, `.noir/.mcp.json`, `.noir/.claude/`, and the ignore files\n * `.noir/.gitignore` / `.dockerignore` / `.npmignore` / `.prettierignore`).\n * Read-only `warn` —\n * doctor never mutates; remediation is manual removal (a future follow-up\n * slice can automate it). Never `fail`: a nested store wastes space + confuses\n * tooling but does not break the outer project.\n */\nexport function checkNestedNoir(\n checks: CheckResult[],\n root: string,\n): { detected: boolean; paths: string[] } {\n const candidates = [\n '.noir/.noir',\n '.noir/CLAUDE.md',\n '.noir/.mcp.json',\n '.noir/.claude',\n '.noir/.gitignore',\n '.noir/.dockerignore',\n '.noir/.npmignore',\n '.noir/.prettierignore',\n ];\n const found = candidates.filter((rel) => existsSync(join(root, rel)));\n const detected = found.length > 0;\n checks.push({\n name: 'nested .noir',\n status: detected ? 'warn' : 'ok',\n detail: detected\n ? `nested Noir artifacts inside .noir/ (${found.join(', ')}) — likely from running \\`noir init\\` inside .noir/. Remove them; the real project is at ${root}.`\n : 'no nested .noir/ artifacts',\n });\n return { detected, paths: found };\n}\n\n// ---------------------------------------------------------------------------\n// SP-C deferred — semantic duplicate detection (`--dedup`; loads the embedder).\n// ---------------------------------------------------------------------------\n\n/** Local embedder shape (@noir-ai/context's `EmbedFn`). */\ntype EmbedLike = (text: string) => Promise<Float32Array>;\n\n/**\n * Collect dedup candidates: the host context files that exist at the root\n * (CLAUDE.md / AGENTS.md / GEMINI.md — the hand-mirrored-overlap case) plus\n * `.noir/rules/RULES.md`. `.noir/NOIR.md` is EXCLUDED because host context\n * files `@import` it by design (their similarity is intentional, not a dup).\n */\nexport function collectDedupCandidates(root: string): { path: string; text: string }[] {\n const rels = ['CLAUDE.md', 'AGENTS.md', 'GEMINI.md', '.noir/rules/RULES.md'];\n const out: { path: string; text: string }[] = [];\n for (const rel of rels) {\n const abs = join(root, rel);\n if (!existsSync(abs)) continue;\n let text: string;\n try {\n text = readFileSync(abs, 'utf8');\n } catch {\n continue;\n }\n if (text.trim().length === 0) continue;\n out.push({ path: rel, text });\n }\n return out;\n}\n\n/**\n * `noir doctor --dedup`: embed the host-context + RULES.md candidates and\n * report near-duplicate pairs (cosine ≥ 0.90). The ONLY mechanism that catches\n * cross-file SEMANTIC overlap (e.g. a hand-mirrored CLAUDE.md ≈ AGENTS.md) —\n * exact content-hash cannot. Opt-in so a default `noir doctor` never pays the\n * embedder-load cost; degrades to a `warn` skip when the embedder is\n * unavailable (kind=none / native layer missing). `opts.embed` is a testability\n * seam — tests inject a deterministic fake; production omits it and the local\n * embedder is lazy-loaded via `@noir-ai/context`.\n */\nexport async function checkSemanticDupDoctor(\n checks: CheckResult[],\n root: string,\n project: ProjectInfo | undefined,\n opts: { embed?: EmbedLike } = {},\n): Promise<void> {\n if (!project) {\n checks.push({ name: 'semantic dup', status: 'warn', detail: 'skipped — not initialized' });\n return;\n }\n const candidates = collectDedupCandidates(root);\n if (candidates.length < 2) {\n checks.push({\n name: 'semantic dup',\n status: 'ok',\n detail: `${candidates.length} candidate file(s); nothing to compare`,\n });\n return;\n }\n const ctx = await import('@noir-ai/context');\n let embed: EmbedLike | undefined = opts.embed;\n if (!embed) {\n const cfg = ctx.resolveEmbedderConfig(project.config.context);\n if (cfg.kind === 'none') {\n checks.push({\n name: 'semantic dup',\n status: 'warn',\n detail: 'embedder kind=none — set context.embedder.kind=local to enable semantic dedup',\n });\n return;\n }\n try {\n embed = ctx.createEmbedFn(cfg).embed as EmbedLike;\n } catch (e) {\n checks.push({\n name: 'semantic dup',\n status: 'warn',\n detail: `embedder unavailable — skipped (${msg(e)})`,\n });\n return;\n }\n }\n if (!embed) return;\n const pairs = await ctx.findSemanticDuplicates(candidates, embed, ctx.DEFAULT_DUP_THRESHOLD);\n checks.push({\n name: 'semantic dup',\n status: pairs.length > 0 ? 'warn' : 'ok',\n detail:\n pairs.length === 0\n ? `no near-duplicates across ${candidates.length} file(s)`\n : `${pairs.length} near-duplicate pair${pairs.length === 1 ? '' : 's'}: ${pairs\n .map((p) => `${p.a}≈${p.b} (${p.similarity.toFixed(2)})`)\n .join('; ')}`,\n });\n}\n\n// ---------------------------------------------------------------------------\n// S11 — publish-readiness check (advisory, repo-developer-facing).\n// ---------------------------------------------------------------------------\n\n/**\n * Resolve the workspace `packages/` directory from the CLI's own location —\n * walk up from `import.meta.url` to the nearest `package.json` named\n * `@noir-ai/cli`, then return its PARENT dir (the `packages/` root) IF that\n * dir's parent carries the monorepo marker (`pnpm-workspace.yaml`). Returns\n * `null` when not running from a monorepo checkout (a global `npm install -g`\n * has no `packages/*` workspace to validate → the publish check skips).\n *\n * The walk is robust across layouts: source (`packages/cli/src/commands/`),\n * built (`packages/cli/dist/`), and bundled-chunk (`packages/cli/dist/`) all\n * walk up to `packages/cli/package.json`. In a global install the same walk\n * lands on `node_modules/@noir-ai/cli/package.json`, whose parent\n * (`node_modules/@noir-ai/`) has NO `pnpm-workspace.yaml` parent → null.\n */\nfunction resolveWorkspacePackagesDir(): string | null {\n let here = dirname(fileURLToPath(import.meta.url));\n // Bound the walk so a pathological layout never loops the filesystem.\n for (let i = 0; i < 8; i++) {\n const pkgPath = join(here, 'package.json');\n if (existsSync(pkgPath)) {\n try {\n const pkg = JSON.parse(readFileSync(pkgPath, 'utf8')) as { name?: string };\n if (pkg.name === '@noir-ai/cli') {\n // `here` is the cli package dir; `dirname(here)` is `packages/`.\n const packagesDir = dirname(here);\n // Monorepo gate: the repo root (`dirname(packagesDir)`) carries\n // `pnpm-workspace.yaml`. A global install fails this gate.\n if (existsSync(join(dirname(packagesDir), 'pnpm-workspace.yaml'))) {\n return packagesDir;\n }\n return null;\n }\n } catch {\n // Malformed package.json — keep walking.\n }\n }\n const parent = dirname(here);\n if (parent === here) break; // filesystem root\n here = parent;\n }\n return null;\n}\n\n/**\n * Permissive semver-ish regex for the advisory check. Accepts release and\n * pre-release/build forms (`1.0.0`, `1.1.0-beta.1`, `1.2.0+build.4`). Strict\n * enough to catch the obvious foot-guns (a git SHA, a literal \"latest\", a\n * missing patch) without pulling in the `semver` package for a warn-level\n * check. `npm publish` itself enforces rigor at pack time.\n */\nconst SEMVER_ISH = /^\\d+\\.\\d+\\.\\d+(?:-[0-9A-Za-z.-]+)?(?:\\+[0-9A-Za-z.-]+)?$/;\n\n/** Best-effort `npm pack --dry-run` on the cli package — read-only (it does\n * NOT write the tarball). Returns `{ fileCount, distIncluded }` parsed from\n * npm's notice output, or `{ error }` when npm is unavailable / the pack\n * fails. Gated on npm being on PATH (the spec's expensive-but-optional leg):\n * we probe `npm --version` first and skip-with-note if it isn't resolvable. */\nfunction npmPackDryRun(\n cliPkgDir: string,\n): { fileCount: number | null; distIncluded: boolean | null } | { error: string } {\n // Probe npm availability first (cheap). shell:true so Windows finds npm.cmd.\n const probe = spawnSync('npm', ['--version'], { encoding: 'utf8', shell: true });\n if (probe.status !== 0 || probe.error) {\n return { error: probe.error ? probe.error.message : 'npm not on PATH' };\n }\n // `npm pack --dry-run` lists the tarball contents without writing the file.\n // It IS read-only (npm's own docs: \"--dry-run ... does not write anything\").\n const res = spawnSync('npm', ['pack', '--dry-run'], {\n cwd: cliPkgDir,\n encoding: 'utf8',\n shell: true,\n });\n if (res.status !== 0 || res.error) {\n return { error: res.error ? res.error.message : `npm pack exited ${res.status ?? '?'}` };\n }\n const out = `${res.stdout ?? ''}\\n${res.stderr ?? ''}`;\n // `npm notice total files: 42` — the canonical summary line.\n const totalMatch = out.match(/total files:\\s*(\\d+)/i);\n const fileCount = totalMatch?.[1] ? Number.parseInt(totalMatch[1], 10) : null;\n // `dist/` appears in the tarball contents (`npm notice <size> dist/<file>`).\n const distIncluded = /\\bdist\\//.test(out);\n return { fileCount, distIncluded };\n}\n\n/**\n * S11 publish-readiness check. For every workspace `package.json` under\n * `packagesDir`, validate publishability:\n * - `name` starts with `@noir-ai/`\n * - `version` matches {@link SEMVER_ISH}\n * - `files` is a non-empty array\n * - the cli package has a `bin` field\n *\n * Optionally runs `npm pack --dry-run` on the cli package (best-effort, gated\n * on npm being available) to report the file count + confirm `dist/` ships.\n *\n * Severity is ALWAYS `ok` or `warn` — NEVER `fail`: a missing/odd package.json\n * field does not break the local install (this is an advisory nudge to repo\n * developers, not a project-facing health check). The check runs ALWAYS (it\n * produces a row in every doctor report) but returns `null` from\n * `data.publish` when not running from a monorepo (`packagesDir === null`).\n */\nexport function checkPublish(\n checks: CheckResult[],\n packagesDir: string | null,\n opts: { skipNpmPack?: boolean } = {},\n): { checked: number; issues: string[] } | null {\n if (packagesDir === null) {\n checks.push({\n name: 'publish',\n status: 'ok',\n detail: 'skipped — not a monorepo checkout (no packages/* workspace)',\n });\n return null;\n }\n // Discover workspace package.json files (depth-1 dirs only — no glob dep).\n let entries: string[] = [];\n try {\n entries = readdirSync(packagesDir, { withFileTypes: true })\n .filter((d) => d.isDirectory())\n .map((d) => d.name);\n } catch (e) {\n checks.push({\n name: 'publish',\n status: 'warn',\n detail: `could not read ${packagesDir}: ${msg(e)}`,\n });\n return { checked: 0, issues: [`unreadable packages dir: ${msg(e)}`] };\n }\n\n const issues: string[] = [];\n let checked = 0;\n let cliDir: string | null = null;\n for (const name of entries) {\n const pkgPath = join(packagesDir, name, 'package.json');\n if (!existsSync(pkgPath)) continue;\n let pkg: Record<string, unknown>;\n try {\n pkg = JSON.parse(readFileSync(pkgPath, 'utf8')) as Record<string, unknown>;\n } catch (e) {\n issues.push(`${name}/package.json: unparseable (${msg(e)})`);\n checked++;\n continue;\n }\n checked++;\n const pkgName = typeof pkg.name === 'string' ? pkg.name : '';\n if (!pkgName.startsWith('@noir-ai/')) {\n issues.push(`${name}/package.json: name '${pkgName}' is not @noir-ai/*`);\n }\n const version = typeof pkg.version === 'string' ? pkg.version : '';\n if (!SEMVER_ISH.test(version)) {\n issues.push(`${name}/package.json: version '${version}' is not semver`);\n }\n if (!Array.isArray(pkg.files) || pkg.files.length === 0) {\n issues.push(`${name}/package.json: files missing or empty`);\n }\n if (pkgName === '@noir-ai/cli') {\n if (pkg.bin == null || (typeof pkg.bin === 'object' && Object.keys(pkg.bin).length === 0)) {\n issues.push(`${name}/package.json: bin missing (cli package must declare a bin)`);\n }\n cliDir = join(packagesDir, name);\n }\n }\n\n // Best-effort npm pack --dry-run on the cli package. Gated on npm being\n // available; a failure here is surfaced in the detail but does NOT add an\n // issue (it is environmental, not a package.json defect). `skipNpmPack` is a\n // testability seam — synthetic test fixtures have no real `dist/`, so the\n // dist-absent signal would otherwise pollute the package.json-validation\n // assertions. Production (`doctor()`) leaves it unset.\n let packNote = '';\n if (cliDir && opts.skipNpmPack !== true) {\n const pack = npmPackDryRun(cliDir);\n if ('error' in pack) {\n packNote = ` · npm pack skipped (${pack.error})`;\n } else {\n const count = pack.fileCount == null ? '?' : String(pack.fileCount);\n const dist = pack.distIncluded ? 'dist/ included' : 'dist/ NOT in tarball';\n packNote = ` · npm pack: ${count} files, ${dist}`;\n if (pack.distIncluded === false) {\n issues.push('cli npm pack --dry-run: dist/ absent from the tarball');\n }\n }\n }\n\n const status: Severity = issues.length > 0 ? 'warn' : 'ok';\n const detail =\n issues.length === 0\n ? `${checked}/${entries.length} packages publish-ready${packNote}`\n : `${issues.length} issue${issues.length === 1 ? '' : 's'} across ${checked} package${checked === 1 ? '' : 's'}${packNote}`;\n checks.push({ name: 'publish', status, detail });\n return { checked, issues };\n}\n\n/** Repo-relative POSIX form of `abs` under `root`. Defensive (N2): rejects\n * paths that escape `root` — mirrors `hostRel` in @noir-ai/create/manifest.ts.\n * A future adapter that returns a stray path fails loudly here instead of\n * producing a misleading \"missing\" row for a path doctor would never probe.\n * Relative literals (e.g. `'AGENTS.md'`, `'.mcp.json'`) pass through unchanged\n * AFTER the `..`-escape check so a buggy literal could not exfiltrate either. */\nfunction relOr(abs: string, root: string): string {\n const posix = abs.replace(/\\\\/g, '/');\n if (posix.startsWith('/')) {\n const rel = relative(root, abs).replace(/\\\\/g, '/');\n if (rel.length === 0 || rel.startsWith('..') || rel.startsWith('/')) {\n throw new Error(`doctor: host path '${abs}' is not under root '${root}'`);\n }\n return rel;\n }\n // Already-relative literal: still reject `..` segments (a `../etc/passwd`\n // literal from a buggy adapter must not silently pass through).\n if (posix.split('/').some((seg) => seg === '..')) {\n throw new Error(`doctor: host path '${abs}' escapes root '${root}'`);\n }\n return posix;\n}\n\n/** Join `root` with a repo-relative POSIX path for an existsSync probe. */\nfunction joinRoot(root: string, relPath: string): string {\n return `${root}/${relPath}`;\n}\n\nfunction severityBadge(s: Severity): string {\n // Doctor's vocabulary is ok/warn/fail; the badge palette is ok/warn/error/info.\n // `fail` is the CRITICAL state → red (`error`), so RED stays reserved for the\n // broken-host states. The TEXT label keeps doctor's own uppercase word so the\n // JSON envelope (`status: 'fail'`) and the human row agree on vocabulary.\n const state: BadgeState = s === 'fail' ? 'error' : s;\n return badge(state, s.toUpperCase());\n}\n\nfunction renderHuman(payload: DoctorPayload, opts: CliOptions): void {\n log(\n `noir doctor — ${payload.checks.length} check${payload.checks.length === 1 ? '' : 's'}`,\n opts,\n );\n table(\n payload.checks.map((c) => ({\n Check: c.name,\n Status: severityBadge(c.status),\n Detail: c.detail,\n })),\n ['Check', 'Status', 'Detail'],\n opts,\n );\n const { ok, warn: warnN, fail } = payload.summary;\n if (fail > 0) {\n err(\n `${fail} critical check${fail === 1 ? '' : 's'} failed (${warnN} warning${warnN === 1 ? '' : 's'}, ${ok} ok)`,\n opts,\n );\n } else if (warnN > 0) {\n warn(`all critical checks passed (${warnN} warning${warnN === 1 ? '' : 's'}, ${ok} ok)`, opts);\n } else {\n success(`all ${ok} check${ok === 1 ? '' : 's'} passed`, opts);\n }\n}\n\n/**\n * `noir doctor`: run all checks, render, and exit.\n *\n * Under `--json` writes `{ok:true, data: DoctorPayload}` to stdout (always —\n * the command produced a diagnosis). The exit code carries health: 0 when no\n * check failed, 1 when any CRITICAL (`fail`) check is unhealthy.\n */\nexport async function doctor(opts: DoctorOptions = {}): Promise<void> {\n const root = process.cwd();\n const checks: CheckResult[] = [];\n\n await checkRuntime(checks);\n const { project, result: configResult } = checkConfig(root);\n checks.push(configResult);\n await checkDaemon(checks, project);\n const { vecOk } = await checkNativeDeps(checks);\n await checkStore(checks, project, root);\n checkEmbedder(checks, project, vecOk);\n // `.noir/.env` is read ONCE and shared by the provider + noir-env rows — both\n // need \"which side won for this key\". Names only: the loader never opens a\n // value into anything doctor prints.\n const noirEnv = loadNoirEnv(root);\n checkProvider(checks, project, noirEnv.sources);\n checkNoirEnv(checks, root, noirEnv);\n const scaffold = checkScaffoldVersion(checks, root);\n const rules = checkRulesMdBudget(checks, root, project);\n const host = checkHostArtifacts(checks, root, project);\n checkNestedNoir(checks, root);\n if (opts.dedup === true) {\n await checkSemanticDupDoctor(checks, root, project);\n }\n const publish = checkPublish(checks, resolveWorkspacePackagesDir());\n\n // C1 — install-method check (advisory, cache-only, never fail).\n const installCheck = buildInstallCheck({\n method: detectActiveMethod(),\n version: readInstallRecord()?.version ?? null,\n latestKnown: latestVersionFromCache(readUpdateCache(), 'latest'),\n });\n checks.push(installCheck);\n\n const summary = summarize(checks);\n const payload: DoctorPayload = {\n noir: NOIR_VERSION,\n checks,\n summary,\n scaffold,\n rules,\n host,\n publish,\n install: {\n method: installCheck.method,\n installedVersion: installCheck.installedVersion,\n latestKnown: installCheck.latestKnown,\n },\n };\n\n if (opts.json === true) {\n process.stdout.write(`${JSON.stringify({ ok: true, data: payload })}\\n`);\n } else {\n renderHuman(payload, opts);\n }\n\n if (summary.fail > 0) {\n // Under --json the data envelope is already on stdout; throw with an empty\n // message so handleError sets exitCode=1 without a redundant stderr line.\n // Under human mode the summary line above already named the failures.\n throw new NoirCliError(\n EXIT.ERROR,\n opts.json === true ? '' : `noir doctor: ${summary.fail} critical check(s) failed`,\n );\n }\n}\n","// `noir env [--json]` — which configuration is in effect, and where each value\n// comes from.\n//\n// The command exists to answer the one question the maintainer hit live: \"I\n// edited `.noir/.env` and nothing changed — so which value is actually in\n// effect, and who supplied it?\". The resolution rule itself (spec 12.1) is that\n// a key `.noir/.env` DEFINES wins and the real environment is the fallback for\n// the keys the file omits; this command renders that decision per key instead of\n// leaving the user to infer it.\n//\n// HARD RULE (spec 12.4): NAMES AND SHAPES ONLY, NEVER A VALUE. Each row carries\n// the key, the side that won, and a REDACTED shape (`pk_…(42)` = the first three\n// characters + the length) so two tokens can be told apart without a secret ever\n// being printed. `--json` carries even less — `valueLength` only; the shape\n// belongs to the human table and never reaches stdout (see `env`, whose payload\n// is an EXPLICIT projection of the resolved rows).\n//\n// CURATION, NOT A DUMP (spec 12.3). `loadNoirEnv().sources` records every key\n// that resolves to something, including every ambient one as `'env'` — under the\n// default argument that is the whole of `process.env` (PATH, npm_config_*, …).\n// Rendering that inventory would bury the answer this command exists to give, so\n// the report is exactly:\n//\n// (a) every key `.noir/.env` defines — the user's own short list, and the\n// thing they just edited; plus\n// (b) ambient keys named by {@link CURATED_AMBIENT_KEYS} — the Noir-relevant\n// names a user may have exported from a shell rc; plus\n// (c) ambient keys named by the project's OWN config\n// (`model.providers.<name>.apiKeyEnv`), read through the shipped\n// `resolveModelConfig` mapper so the CLI never re-derives the schema.\n//\n// READ-ONLY: nothing here writes, spawns, or opens the store.\n\nimport { loadNoirEnv, loadProjectInfo } from '@noir-ai/core';\nimport { resolveModelConfig } from '@noir-ai/model';\nimport { type CliOptions, info, json, table } from '../output.js';\n\n/**\n * Ambient (environment-only) names worth reporting: the Noir-relevant keys a\n * user might reasonably have exported from a shell rc. Deliberately a SHORT\n * allowlist — see the curation note above. `CLICKUP_API_TOKEN` is the\n * integration token, the four `*_API_KEY` names are the remote embedder /\n * provider keys the docs name, `OLLAMA_BASE_URL` backs a local Ollama embedder,\n * and `NOIR_PROFILE` selects a `run.profiles` entry.\n *\n * An ambient key NOT in this list is still resolved (and still feeds the\n * precedence decision) — it is simply not reported, because \"every variable in\n * your shell\" is not an answer to \"which value is in effect\".\n */\nexport const CURATED_AMBIENT_KEYS: readonly string[] = [\n 'CLICKUP_API_TOKEN',\n 'OPENAI_API_KEY',\n 'VOYAGE_API_KEY',\n 'COHERE_API_KEY',\n 'OLLAMA_BASE_URL',\n 'ANTHROPIC_API_KEY',\n 'NOIR_PROFILE',\n];\n\n/**\n * The ambient environment as it was BEFORE `.noir/.env` was applied, captured by\n * the bin's `preAction` (see {@link captureAmbientEnv}).\n *\n * The loader APPLIES its overlay to `process.env` in place, and after that the\n * file's own values are indistinguishable from an inherited export for exactly\n * the keys where the question matters — so \"is my shell value being overridden?\"\n * (the `shadowed` column) can only be answered from a pre-overlay snapshot.\n *\n * A SHALLOW COPY of the environment, values included: the shadow comparison\n * needs the ambient VALUE to tell an override apart from an agreeing export.\n * The copy is in-memory and process-local for the lifetime of one invocation —\n * it is never persisted, never written back to `process.env`, and a value from\n * it reaches the user only as a redacted shape or a length (see\n * {@link redactShape} / {@link EnvVarRow.valueLength}).\n */\nlet ambientBaseline: Record<string, string | undefined> | undefined;\n\n/**\n * Snapshot the ambient environment before the bin applies `.noir/.env`. Called\n * from `bin.ts`'s `preAction` for `noir env` only — every other command just\n * applies the overlay and never needs the baseline.\n */\nexport function captureAmbientEnv(env: Record<string, string | undefined> = process.env): void {\n ambientBaseline = { ...env };\n}\n\n/** One resolved key: the name, the side that won, and a length — never a value. */\nexport interface EnvVarRow {\n /** The env-var NAME (safe to print; this is what the user types). */\n key: string;\n /** The side that won: `.noir/.env` (`'file'`) or the ambient environment. */\n source: 'file' | 'env';\n /** Present (true) only when `.noir/.env` defines the key AND the ambient\n * environment defined it with a DIFFERENT value — i.e. the file is\n * overriding something. Omitted otherwise (the JSON shape is additive). */\n shadowed?: boolean;\n /** Character count of the value in effect. A length is not a value. */\n valueLength: number;\n}\n\n/** The `data` of `noir env --json`. No value, and no fragment of one. */\nexport interface EnvPayload {\n vars: EnvVarRow[];\n /** Loader diagnostics (malformed lines, shadowed keys, a tracked-file\n * refusal). Names only — the loader never puts a value in a warning. */\n warnings: string[];\n}\n\n/** Resolved rows + the REDACTED display shapes for the human table. */\ninterface ResolvedEnv {\n vars: EnvVarRow[];\n warnings: string[];\n /** key → redacted shape (first three characters + length). Human-only: it is\n * never serialized (see the explicit projection in `env`). */\n shapes: Record<string, string>;\n}\n\n/**\n * A redacted DISPLAY shape for a value: the first three characters plus the\n * length (`pk_la…(42)`). Enough to tell two tokens apart in a table — the shape\n * a provider dashboard shows for a masked key — and never enough to use one.\n * The length is deliberate: it is what makes \"the file's value is in effect, not\n * the one I exported\" visible without printing either.\n *\n * SHORT VALUES ARE SHOWN AS LENGTH ONLY. For a value of `SHORT_VALUE_MAX` chars\n * or fewer the prefix would BE the whole value (`dev…(3)` for `NOIR_PROFILE=dev`\n * prints a complete value — and a short one is exactly the kind a user might\n * have picked, or a legacy token might be). The floor is 8 rather than the 3\n * the prefix needs, so a short-but-real value like a hostname or a base URL\n * cannot be reconstructed by guessing the last few characters.\n */\nconst SHORT_VALUE_MAX = 8;\n\nfunction redactShape(value: string): string {\n if (value.length <= SHORT_VALUE_MAX) return `…(${value.length})`;\n return `${value.slice(0, 3)}…(${value.length})`;\n}\n\n/**\n * The env-var NAMES the project's own model config requests\n * (`model.providers.<name>.apiKeyEnv`), read through the shipped\n * `resolveModelConfig` mapper rather than by reaching into the config shape —\n * so the CLI never re-derives the schema, and a config that names a key the\n * built-in allowlist would never guess still shows up.\n *\n * An uninitialized (or unparseable) project yields `[]`: `noir env` reports what\n * it can from the file + the environment instead of refusing to run — the file\n * is exactly what the user came here to inspect.\n */\nfunction configApiKeyEnvNames(root: string): string[] {\n try {\n const project = loadProjectInfo(root);\n const names = new Set<string>();\n for (const provider of Object.values(resolveModelConfig(project.config.model).providers)) {\n if (provider.apiKeyEnv !== undefined && provider.apiKeyEnv.length > 0) {\n names.add(provider.apiKeyEnv);\n }\n }\n return [...names];\n } catch {\n return [];\n }\n}\n\n/**\n * Resolve the reported keys: provenance from `loadNoirEnv` (spec 12.1's single\n * decision point — this command never re-implements the precedence), filtered\n * down to the curated report described at the top of this file.\n *\n * The resolved VALUE is used only for its length and its redacted shape, inside\n * the loop body below — it is never stored on a row, so it cannot leak into the\n * `--json` envelope.\n */\nfunction resolveEnv(root: string, ambientEnv: Record<string, string | undefined>): ResolvedEnv {\n const { overlay, warnings, sources } = loadNoirEnv(root, ambientEnv);\n const curated = new Set<string>(CURATED_AMBIENT_KEYS);\n for (const name of configApiKeyEnvNames(root)) curated.add(name);\n\n // Candidate keys: everything `sources` records (the loader's authority), plus\n // the curated names that are SET in the ambient environment. The second half\n // exists because `sources` is empty whenever the loader takes one of its two\n // no-op paths — no `.noir/.env` at all, or a git-tracked file refused outright\n // (spec 12.2) — and neither means \"nothing is in effect\": with no file\n // contributing, an exported `CLICKUP_API_TOKEN` IS the value in effect, and\n // reporting \"nothing to report\" while it sits in the user's shell would be a\n // lie. It cannot contradict the loader: those are exactly the keys the loader\n // would have recorded as `'env'` had it run its ambient pass.\n const candidates = new Set<string>(Object.keys(sources));\n for (const key of curated) {\n if (ambientEnv[key] !== undefined) candidates.add(key);\n }\n\n const vars: EnvVarRow[] = [];\n const shapes: Record<string, string> = {};\n // Sorted for a stable table (and a stable `--json` array) across runs.\n for (const key of [...candidates].sort()) {\n const source = sources[key] ?? 'env';\n // (b)/(c): an ambient key is reported ONLY when it is curated. `sources`\n // holds every ambient name, so this filter is what keeps the command from\n // enumerating the environment.\n if (source === 'env' && !curated.has(key)) continue;\n // The value in effect: the file's overlay when the file defined the key\n // (spec 12.1 — the file WINS), else the fallback the file fell through to.\n const value = source === 'file' ? (overlay[key] ?? '') : (ambientEnv[key] ?? '');\n // Shadowing is the same condition the loader warns on: the file defines a\n // key the ambient environment ALSO defines, with a different value. Equal\n // values are not a shadow — nothing the user exported is being overridden.\n const shadowed =\n source === 'file' && ambientEnv[key] !== undefined && ambientEnv[key] !== value;\n\n vars.push({\n key,\n source,\n ...(shadowed ? { shadowed: true } : {}),\n valueLength: value.length,\n });\n shapes[key] = redactShape(value);\n }\n return { vars, warnings, shapes };\n}\n\n/** Human label for the SOURCE column. */\nfunction describeSource(row: EnvVarRow): string {\n if (row.source !== 'file') return 'environment';\n return row.shadowed === true ? '.noir/.env (shadows environment)' : '.noir/.env';\n}\n\n/**\n * `noir env [--json]`: report every key that is in effect, its winning source,\n * and a redacted shape of its value.\n *\n * `--json` writes `{ok:true, data:{vars, warnings}}` to STDOUT — the explicit\n * projection below is the redaction boundary (`shapes` is deliberately dropped).\n * The human path renders a KEY/SOURCE/VALUE table to STDERR and writes nothing\n * to stdout.\n *\n * Loader warnings are NOT re-printed here: `bin.ts`'s `preAction` already\n * applies `.noir/.env` through `applyNoirEnv`, which writes every warning\n * (including the tracked-file refusal) to stderr before this action runs — so\n * they are visible in every real invocation, and printing them again would only\n * duplicate them. They are carried in the `--json` payload for consumers.\n *\n * Always exits 0: this is a report, and \"your file is not being loaded\" is\n * information, not a failure.\n */\nexport async function env(opts: CliOptions = {}): Promise<void> {\n const report = resolveEnv(process.cwd(), ambientBaseline ?? process.env);\n\n if (opts.json === true) {\n json({ ok: true, data: { vars: report.vars, warnings: report.warnings } });\n return;\n }\n\n if (report.vars.length === 0) {\n // \"no keys IN EFFECT\", not \"no keys\": a file can define keys that resolve to\n // nothing — a git-tracked file is refused outright (spec 12.2), and a\n // process-injection key (NODE_OPTIONS, npm_*) is skipped by the loader. Both\n // are reported by the loader's own stderr warnings above this line.\n info(\n 'nothing to report — .noir/.env defines no keys in effect and no Noir-relevant environment variable is set',\n opts,\n );\n return;\n }\n\n table(\n report.vars.map((row) => ({\n KEY: row.key,\n SOURCE: describeSource(row),\n VALUE: report.shapes[row.key] ?? '',\n })),\n ['KEY', 'SOURCE', 'VALUE'],\n opts,\n );\n}\n","// `noir handoff` (alias `noir wrap`).\n//\n// The on-demand, pasteable HOST HANDOFF artifact that closes Noir's internal\n// loop and points the user at the right host CLI. Reuses the SAME aggregation\n// path as `noir status` (`gatherStatusPayload`) and the SAME phase→skill map as\n// `noir task` (`PHASE_SKILL` / `skillFor`), then does a BOUNDED in-process\n// `context_search` + `memory_recall` for the active task's domain to seed the\n// host prompt, and renders a structured MARKDOWN block to STDOUT for pasteability.\n//\n// DOCTRINE (hard constraint): Noir NEVER launches the host and NEVER writes the\n// artifact into CLAUDE.md/AGENTS.md (claude byte-parity risk + the double-`@`-\n// import hazard the manifest already fixed). The host-launch directive is TEXT\n// ONLY — `hostLaunchDirective(host)` / `HostAdapter.emitHandoff` produce the\n// \"Open `<host>` …\" wording; `noir handoff` never spawns anything.\n//\n// Graceful degradation (mirrors `status.ts`): a down daemon is reported with an\n// honest note (\"start `noir daemon start` for live task/memory\") and the\n// artifact still renders from in-process `.noir/` reads (project info + a\n// workflow snapshot if locally available) — exit 0. A missing embedder during\n// the bounded extraction folds to `null` (via `tryTool`); the seed section\n// renders a \"degraded\" note instead of failing.\n//\n// Stream discipline: the markdown artifact → STDOUT ONLY (the single\n// stdout write under the default path); `--json` emits the structured payload\n// via the versioned `{ok,data}` envelope instead; ALL diagnostics (the\n// \"wrote <path>\" confirmation, the daemon-down note) → STDERR via `info()`.\n// `--write` persists to `.noir/handoff/HO-<NNNN>-<id>.md` (gitignored — see\n// `@noir-ai/core` `syncIgnores`); the path is reported on stderr, never stdout.\n\nimport { mkdirSync, writeFileSync } from 'node:fs';\nimport { join } from 'node:path';\nimport {\n defaultHandoffBlock,\n type EmitContext,\n type HandoffPayload,\n type HostId,\n hostLaunchDirective,\n resolveAdapter,\n} from '@noir-ai/adapters';\nimport { loadProjectInfo, NOIR_DIR, type ProjectInfo, resolveArtifactPath } from '@noir-ai/core';\nimport {\n type DaemonClientOptions,\n type DaemonProbe,\n probeDaemon,\n withRunningDaemon,\n} from '../daemon-client.js';\nimport { type CliOptions, EXIT, fail, info } from '../output.js';\nimport { gatherStatusPayload, tryTool } from './status.js';\nimport { PHASE_SKILL, skillFor } from './task.js';\n\n/** Options accepted by `noir handoff` (globals + daemon-client knobs). */\nexport interface HandoffOptions extends CliOptions, DaemonClientOptions {\n /** `--write`: persist the artifact to `.noir/handoff/HO-<NNNN>-<id>.md` (gitignored). */\n write?: boolean;\n}\n\n/** Bounded extraction limits — small enough to seed a prompt, never a dump. */\nconst SEED_LIMIT = 5;\n\n// ---------------------------------------------------------------------------\n// Wire result shapes (slices of the daemon payloads; local types — the CLI\n// depends only on the MCP wire contract, mirrors status.ts / context.ts).\n// ---------------------------------------------------------------------------\ninterface ContextSearchHit {\n path?: string;\n score?: number;\n snippet?: string;\n source?: string;\n}\ninterface ContextSearchResult {\n ok?: boolean;\n results?: unknown;\n consumedTokens?: number;\n truncated?: boolean;\n degraded?: boolean;\n mode?: string;\n}\ninterface MemoryRecallHit {\n id?: string;\n observation?: Record<string, unknown>;\n score?: number;\n}\ninterface MemoryRecallResult {\n ok?: boolean;\n results?: unknown;\n degraded?: boolean;\n}\n\n/** A normalized context_search seed entry rendered in the artifact. */\nexport interface HandoffContextHit {\n path: string;\n score: number;\n snippet: string;\n}\n/** A normalized memory_recall seed entry rendered in the artifact. */\nexport interface HandoffMemoryHit {\n id: string;\n summary: string;\n}\n\n/** The structured payload emitted by `--json` (and the source for the markdown\n * render). Every nullable field degrades cleanly (daemon-down / no active task\n * / missing embedder → null + a note), so the artifact NEVER hard-fails. */\nexport interface HandoffPayloadFull {\n project: { id: string; name: string };\n host: HostId;\n /** Host-launch directive text (single source: `hostLaunchDirective` or the\n * adapter's `emitHandoff` override). TEXT ONLY — never a spawn. */\n directive: string;\n task: {\n taskId: string;\n phase: string;\n nextGate: string | null;\n nextSkill: string | null;\n } | null;\n /** Bounded context_search seed (top hits for the task domain). Null when the\n * daemon is down OR the embedder is missing (degraded note rendered). */\n contextSeed: HandoffContextHit[] | null;\n /** Bounded memory_recall seed. Null when the daemon is down. */\n memorySeed: HandoffMemoryHit[] | null;\n /** Honest degradation flags so a `--json` consumer can branch. */\n degraded: {\n daemonDown: boolean;\n embedderMissing: boolean;\n };\n}\n\n// ---------------------------------------------------------------------------\n// Rendering — the markdown artifact (STDOUT) + the structured payload (--json).\n// ---------------------------------------------------------------------------\n\n/** Heading line: `# Noir handoff — <name> (<id>)`. */\nfunction heading(name: string, id: string): string {\n return `# Noir handoff — ${name} (${id})`;\n}\n\n/** Render the markdown artifact from the structured payload. STDOUT-safe (no\n * ANSI — the artifact is pasteable text; `--no-color` honored by virtue of\n * never coloring). */\nfunction renderMarkdown(p: HandoffPayloadFull): string {\n const lines: string[] = [];\n lines.push(heading(p.project.name, p.project.id));\n lines.push('');\n\n // Phase / gate line.\n if (p.task) {\n const gate = p.task.nextGate ?? '—';\n lines.push(`**Phase:** ${p.task.phase} — next gate: ${gate}`);\n } else {\n lines.push('**Phase:** no active task');\n }\n\n // Host directive (the pasteable \"open your host\" line).\n lines.push('');\n lines.push('## Open host');\n lines.push(p.directive);\n\n // Next step.\n lines.push('');\n lines.push('## Next step');\n if (p.task?.nextSkill) {\n lines.push(`Run \\`${p.task.nextSkill}\\` — the host's next gate skill.`);\n } else {\n lines.push('No further gate ahead (past verify, or no active task).');\n }\n\n // Extracted context seed.\n lines.push('');\n lines.push('## Extracted context (seed)');\n if (p.contextSeed && p.contextSeed.length > 0) {\n for (const h of p.contextSeed) {\n lines.push(`- \\`${h.path}\\` (score ${h.score.toFixed(4)})`);\n const snip = h.snippet.trim();\n if (snip.length > 0) lines.push(` > ${snip.replace(/\\n/g, '\\n > ')}`);\n }\n } else if (p.degraded.embedderMissing) {\n lines.push(\n '_Embedder unavailable — degraded to BM25-only or no hits. Start `noir daemon start` for live context._',\n );\n } else {\n lines.push('_No context hits (or daemon down). Start `noir daemon start` for live context._');\n }\n\n // Extracted memory seed.\n lines.push('');\n lines.push('## Extracted memory (seed)');\n if (p.memorySeed && p.memorySeed.length > 0) {\n for (const m of p.memorySeed) {\n lines.push(`- \\`${m.id}\\` — ${m.summary}`);\n }\n } else {\n lines.push(\n '_No memory observations (or daemon down). Start `noir daemon start` for live memory._',\n );\n }\n\n // Live data pointer.\n lines.push('');\n lines.push('## Live data — call these from the host (already wired via the host MCP config)');\n lines.push('- `noir.workflow_status` · `noir.context_search` · `noir.memory_recall`');\n\n // Daemon-down note (honest degradation, mirrors status.ts).\n if (p.degraded.daemonDown) {\n lines.push('');\n lines.push('> **Note:** daemon not running — start `noir daemon start` for live task/memory.');\n }\n\n lines.push('');\n return lines.join('\\n');\n}\n\n/** Normalize a raw context_search hit into the render shape. */\nfunction toContextHit(raw: unknown): HandoffContextHit {\n const h = (raw ?? {}) as ContextSearchHit;\n return {\n path: typeof h.path === 'string' ? h.path : '<unknown>',\n score: typeof h.score === 'number' ? h.score : 0,\n snippet: typeof h.snippet === 'string' ? h.snippet : '',\n };\n}\n\n/** Coerce a memory_recall observation's display summary from a raw hit. */\nfunction observationSummary(raw: MemoryRecallHit): string {\n const obs = raw.observation;\n if (obs && typeof obs === 'object') {\n const content = obs.content;\n if (typeof content === 'string' && content.length > 0) {\n return content.length > 160 ? `${content.slice(0, 157)}…` : content;\n }\n const type = obs.type;\n if (typeof type === 'string') return `(${type})`;\n }\n return '';\n}\n\n/** Normalize a raw memory_recall hit into the render shape. */\nfunction toMemoryHit(raw: unknown): HandoffMemoryHit {\n const h = (raw ?? {}) as MemoryRecallHit;\n return {\n id: typeof h.id === 'string' ? h.id : '<unknown>',\n summary: observationSummary(h),\n };\n}\n\n/** Build the host-facing {@link HandoffPayload} (the adapter hook's input) from\n * the full snapshot. Narrowed so the adapter never sees CLI-internal fields. */\nfunction toHostPayload(p: HandoffPayloadFull): HandoffPayload {\n return {\n project: p.project,\n host: p.host,\n task: p.task,\n };\n}\n\n/** Resolve the directive text: the adapter's `emitHandoff` override if present,\n * else the shared `defaultHandoffBlock` (which composes `hostLaunchDirective`).\n * Routes via `resolveAdapter` (no CLI branching — adding a host needs no CLI\n * edit, mirroring the host-adapter seam). */\nfunction resolveDirective(root: string, p: HandoffPayloadFull): string {\n const ctx: EmitContext = { root };\n const adapter = resolveAdapter(p.host);\n const hostPayload = toHostPayload(p);\n if (typeof adapter.emitHandoff === 'function') {\n return adapter.emitHandoff(ctx, hostPayload);\n }\n return defaultHandoffBlock(ctx, hostPayload);\n}\n\n/** Derive the on-disk filename for `--write`: `.noir/handoff/HO-<NNNN>-<id>.md`.\n * The id is the active task id when available, else the project id (stable +\n * unique per project). Reuses the existing artifact on rewrite. The path is\n * gitignored via `syncIgnores`. */\nfunction handoffFilePath(root: string, taskId: string | undefined, projectId: string): string {\n const id = typeof taskId === 'string' && taskId.length > 0 ? taskId : projectId;\n return resolveArtifactPath(root, 'handoff', { taskId: id });\n}\n\n// ---------------------------------------------------------------------------\n// Bounded extraction — `context_search` + `memory_recall` for the active task's\n// domain. Uses `withRunningDaemon` (probe-only — NEVER starts a daemon) so a\n// down daemon degrades to `null` (exit 0) instead of exit 4. A missing embedder\n// throws inside the tool call → `tryTool` folds to `null` → \"degraded\" note.\n// ---------------------------------------------------------------------------\n\n/** Run the bounded extraction over one daemon connection (if the daemon is up).\n * Returns `{context, memory}` where each is `null` on any failure path. The\n * `query` is the active task id (the task's domain); when no task is active,\n * the project name is used as a stable fallback. */\nasync function extractSeeds(\n opts: HandoffOptions,\n probe: DaemonProbe,\n query: string,\n): Promise<{ context: HandoffContextHit[] | null; memory: HandoffMemoryHit[] | null }> {\n // Guard: if the probe already said down, skip the connection entirely (the\n // artifact renders with a \"start daemon\" note — exit 0).\n if (!probe.running) return { context: null, memory: null };\n\n let context: HandoffContextHit[] | null = null;\n let memory: HandoffMemoryHit[] | null = null;\n\n await withRunningDaemon(\n opts,\n async (caller): Promise<void> => {\n // BOUNDED: small `limit` + a bounded `query` (the task id / project name)\n // on both tools — a seed, never a dump. tryTool folds ANY failure (missing\n // engine, embedder throw, transport hiccup) to null so the artifact never\n // hard-fails on extraction.\n const ctxRes = await tryTool<ContextSearchResult>(caller, 'context_search', {\n query,\n limit: SEED_LIMIT,\n });\n if (ctxRes && ctxRes.ok !== false && Array.isArray(ctxRes.results)) {\n context = (ctxRes.results as unknown[])\n .slice(0, SEED_LIMIT)\n .map(toContextHit)\n .filter((h) => h.path !== '<unknown>' || h.snippet.length > 0);\n }\n const memRes = await tryTool<MemoryRecallResult>(caller, 'memory_recall', {\n query,\n limit: SEED_LIMIT,\n });\n if (memRes && memRes.ok !== false && Array.isArray(memRes.results)) {\n memory = (memRes.results as unknown[])\n .slice(0, SEED_LIMIT)\n .map(toMemoryHit)\n .filter((h) => h.summary.length > 0);\n }\n },\n probe,\n );\n\n return { context, memory };\n}\n\n/** Probe helper — re-probe (gatherStatusPayload already probed once, but we need\n * the probe object here for the bounded extraction). Mirrors status.ts: never\n * starts a daemon, returns `{running:false}` on any miss. Static import matches\n * status.ts — vi.mock hoisting makes the mock apply to static imports too, so a\n * dynamic import is unnecessary (and it would trigger tsup code-splitting, which\n * re-chunks the CLI bin entry and breaks its `isMainModule` guard). */\nasync function probeOnly(opts: HandoffOptions): Promise<DaemonProbe> {\n return probeDaemon(opts);\n}\n\n// ---------------------------------------------------------------------------\n// The command.\n// ---------------------------------------------------------------------------\n\n/**\n * `noir handoff` (alias `noir wrap`): gather the live snapshot + a bounded\n * context/memory seed and render a pasteable host-handoff artifact.\n *\n * - Default: markdown → STDOUT (the single stdout write).\n * - `--write`: persist to `.noir/handoff/HO-<NNNN>-<id>.md` (gitignored); confirm on stderr.\n * - `--json`: emit the structured `{ok:true, data: HandoffPayloadFull}` envelope.\n *\n * Never hard-fails on a down daemon or a missing embedder — degrades to a note\n * (mirrors `status.ts`). Uninitialized project → exit 1 from `loadProjectInfo`.\n */\nexport async function handoff(opts: HandoffOptions): Promise<void> {\n // In-process project info — no daemon round-trip. Uninitialized → exit 1\n // (same as status / every other command). Route through fail() so --json\n // emits the canonical {ok:false,error} envelope (not empty stdout).\n let project: ProjectInfo;\n try {\n project = loadProjectInfo(process.cwd());\n } catch {\n fail(EXIT.ERROR, 'Noir is not initialized in this directory. Run `noir init` first.', opts);\n }\n const host = project.config.host;\n\n // Snapshot — the SAME path `noir status` uses (single source). gatherStatusPayload\n // probes + folds every optional engine to null. We re-probe here for the extraction\n // step (the probe is cheap — one GET /health).\n const snapshot = await gatherStatusPayload(opts);\n const probe = await probeOnly(opts);\n\n // Active task + next-skill (reuse task.ts's PHASE_SKILL — single source).\n const task = snapshot.workflow\n ? {\n taskId: snapshot.workflow.taskId,\n phase: snapshot.workflow.phase,\n nextGate: snapshot.workflow.nextGate,\n nextSkill: skillFor(snapshot.workflow.nextGate) ?? skillFor(snapshot.workflow.phase),\n }\n : null;\n\n // Bounded extraction — the query is the task id (the task's domain), else the\n // project name as a stable fallback.\n const query = task?.taskId ?? project.name;\n const { context, memory } = await extractSeeds(opts, probe, query);\n\n const full: HandoffPayloadFull = {\n project: { id: project.id, name: project.name },\n host,\n directive: '', // filled after the host payload is assembled (below)\n task,\n contextSeed: context,\n memorySeed: memory,\n degraded: {\n daemonDown: !probe.running,\n embedderMissing: context === null && probe.running,\n },\n };\n full.directive = resolveDirective(project.root, full);\n\n // --write persists the markdown artifact BEFORE the --json early-return so\n // `--write --json` writes the file too (previously --json silently skipped it).\n if (opts.write === true) {\n const md = renderMarkdown(full);\n const path = handoffFilePath(project.root, task?.taskId, project.id);\n mkdirSync(join(project.root, NOIR_DIR, 'handoff'), { recursive: true });\n writeFileSync(path, md, 'utf8');\n // Diagnostic → STDERR (stream discipline: stdout is reserved for the\n // artifact/envelope; --write reports its path here, never on stdout).\n info(`handoff written to ${path}`, opts);\n }\n\n if (opts.json === true) {\n process.stdout.write(`${JSON.stringify({ ok: true, data: full })}\\n`);\n return;\n }\n\n // Default: markdown → STDOUT ONLY (pasteability — the user pipes this into a\n // file or straight into the host). No trailing diagnostics on stdout. When\n // --write was set (and not --json), the file is already persisted and its\n // path reported to stderr — do not ALSO dump the artifact to stdout.\n if (opts.write !== true) process.stdout.write(renderMarkdown(full));\n}\n\n// Re-export so bin.ts can wire `noir wrap` as a sibling alias dispatching the\n// same handler, and so PHASE_SKILL stays usable from the test surface.\nexport { hostLaunchDirective, PHASE_SKILL };\n","// S9 — `noir task {new,status,advance,next}`.\n//\n// Thin MCP-client commands over the daemon's workflow surface. The daemon\n// registers four workflow tools (packages/daemon/src/server.ts): `workflow_status`\n// (read the active or named task), `checkpoint` (save/restore in-flight state),\n// `workflow_start` (start a task), and `workflow_advance` (advance/jump a task).\n// All four CLI sub-commands are wired: `status`/`next` → `workflow_status`;\n// `new` → `workflow_start`; `advance` → `workflow_advance`.\n//\n// `new`/`advance` are writes. A read-only (daemon-down) store refuses them with\n// a `{ok:false,degraded:true}` envelope (surfaced as exit 1 here); any other\n// logical failure (unknown task, no active task, illegal transition) is likewise\n// exit 1 for these writes. Daemon-unreachable ⇒ exit 4 (DAEMON_DOWN) from\n// `callDaemonTool`, so transport vs logical failures stay distinguishable.\n//\n// `status` / `next` (reads) map the daemon's logical-failure envelopes\n// (`{ok:false,error:'no active task'}` / `{ok:false,error:'unknown task'}`)\n// onto exit 3 (NOT_FOUND) — a focused task read reporting absence is a\n// not-found condition, not an error (the broader `noir status` folds the same\n// envelope to `null` and stays exit 0).\n\nimport { spawnSync } from 'node:child_process';\nimport { writeFileSync } from 'node:fs';\nimport { loadProjectInfo, nextArtifactSequence, type ProjectInfo, sha256Hex } from '@noir-ai/core';\nimport {\n PHASES,\n type Phase,\n TASK_CLASSES,\n type TaskClass,\n writeChangelogStub,\n writeDecisionStub,\n} from '@noir-ai/workflow';\nimport {\n callDaemonTool,\n type DaemonClientOptions,\n type DaemonProbe,\n probeDaemon,\n withInProcessRead,\n} from '../daemon-client.js';\nimport {\n type CliOptions,\n definitionList,\n EXIT,\n fail,\n info,\n isInteractive,\n log,\n success,\n tip,\n warn,\n} from '../output.js';\nimport { badge } from '../theme.js';\n\n/** Options accepted by every `task` sub-command (globals + daemon knobs). */\nexport interface TaskOptions extends CliOptions, DaemonClientOptions {}\n\n// ---------------------------------------------------------------------------\n// Tool result shapes (slices of the daemon wire payloads; local types).\n// ---------------------------------------------------------------------------\n\n/** `workflow_status` success payload (WorkflowStatus). */\ninterface WorkflowStatusResult {\n ok: true;\n taskId: string;\n phase: string;\n state: string;\n mode: string;\n nextGate: string | null;\n history?: unknown;\n updatedAt?: number;\n degraded?: boolean;\n /** Task class (drives the soft PRD gate); absent on legacy tasks. */\n taskClass?: string;\n /** Block reason captured by `setBlocked` (absent unless blocked). */\n blockReason?: string;\n}\n\n/** `workflow_status` logical-failure envelopes (no active / unknown task). */\ninterface WorkflowNotFound {\n ok: false;\n error?: string;\n taskId?: string;\n}\n\n/** `workflow_resume` payload — a WorkflowStatus + a resumable flag. */\ninterface WorkflowResumeResult {\n ok: boolean;\n resumable?: boolean;\n taskId?: string;\n phase?: string;\n state?: string;\n mode?: string;\n nextGate?: string | null;\n history?: unknown;\n updatedAt?: number;\n degraded?: boolean;\n taskClass?: string;\n blockReason?: string;\n error?: string;\n}\n\n// ---------------------------------------------------------------------------\n// Phase → skill suggestion (grounded in the real @noir-ai/skills builtin pack;\n// each phase maps to a shipped noir-* skill the host can invoke next).\n// Exported so `noir handoff` reuses the SAME phase→skill map when naming\n// the next gate's skill in the handoff artifact — single source.\n// ---------------------------------------------------------------------------\nexport const PHASE_SKILL: Readonly<Record<string, string>> = {\n // C3 curation (2026-08-10): intake+clarify merged into brainstorming;\n // execute → executing-plans; verify → verifying; document → wrap.\n intake: 'noir-brainstorming',\n clarify: 'noir-brainstorming',\n spec: 'noir-spec',\n plan: 'noir-planning',\n execute: 'noir-executing-plans',\n verify: 'noir-verifying',\n document: 'noir-wrap',\n};\n\n/** Map a phase string to its shipped skill id (`null` if unknown / absent).\n * Exported for `noir handoff`. */\nexport function skillFor(phase: string | null | undefined): string | null {\n if (typeof phase !== 'string') return null;\n return PHASE_SKILL[phase] ?? null;\n}\n\n/**\n * c4-verify-gate-recovery S8 — write the document-phase artifacts when a task\n * lands at `done`: a changelog entry + a pending decision-record stub. Uses the\n * artifact conflict seam with `preserve` policy (never clobber a user's edit).\n * The decision-record number is the next after the highest existing ADR.\n */\nfunction writeDoneArtifacts(opts: CliOptions, taskId: string): void {\n try {\n const project = loadProjectInfo(process.cwd());\n const conflict = { conflictPolicy: 'preserve' as const, interactive: false };\n writeChangelogStub(project.root, `- ${taskId}: completed (verify gate passed)`, conflict);\n // Decision-record numbering: the canonical per-type sequence over\n // `.noir/decisions/` (`ADR-<NNNN>-<slug>.md`), max+1. The CLI collapses\n // taskId == slug (`task new --slug`), so the task id doubles as the ADR slug.\n const nextN = nextArtifactSequence(project.root, 'adr');\n writeDecisionStub(project.root, nextN, taskId, undefined, conflict);\n } catch {\n // Artifact writes are best-effort — a failure must never mask the advance\n // result. Surface a tip so the user knows the artifacts didn't land.\n tip('document-phase artifacts could not be written (use --no-artifacts to skip)', opts);\n }\n}\n\n// ---------------------------------------------------------------------------\n// Shared fetch + render\n// ---------------------------------------------------------------------------\n\n/**\n * Call `workflow_status` (active task when `taskId` is absent). Returns the\n * success payload or throws exit 3 (NOT_FOUND) for a logical-failure envelope\n * (no active task / unknown task) — a focused task read's \"absent\" is a\n * not-found condition.\n */\nasync function fetchStatus(opts: TaskOptions, taskId?: string): Promise<WorkflowStatusResult> {\n const args: Record<string, unknown> =\n typeof taskId === 'string' && taskId.length > 0 ? { taskId } : {};\n const res = await callDaemonTool<WorkflowStatusResult | WorkflowNotFound>(\n opts,\n 'workflow_status',\n args,\n );\n if (res.ok === true) return res;\n const detail = res.error ?? 'task not found';\n // exit 3 (NOT_FOUND): the daemon was reachable; there's just no such task.\n fail(EXIT.NOT_FOUND, `task: ${detail}`, opts);\n}\n\n/** Format a `WorkflowStatus.updatedAt` epoch-ms stamp as a readable UTC string. */\nfunction formatStamp(ms?: number): string {\n if (typeof ms !== 'number' || ms <= 0) return '-';\n return new Date(ms).toISOString().replace('T', ' ').replace(/\\..*$/, 'Z');\n}\n\nfunction renderStatusRow(s: WorkflowStatusResult, opts: CliOptions): void {\n const flag = s.degraded === true ? ` ${badge('warn', 'degraded')}` : '';\n log(`task status — ${s.taskId}${flag}`, opts);\n const rows: { label: string; value: string }[] = [\n { label: 'Task', value: s.taskId },\n { label: 'Phase', value: s.phase },\n { label: 'State', value: s.state },\n { label: 'Mode', value: s.mode },\n ];\n if (typeof s.taskClass === 'string' && s.taskClass.length > 0) {\n rows.push({ label: 'Class', value: s.taskClass });\n }\n if (typeof s.blockReason === 'string' && s.blockReason.length > 0) {\n rows.push({ label: 'Block reason', value: s.blockReason });\n }\n rows.push(\n { label: 'Next gate', value: s.nextGate ?? '—' },\n { label: 'Updated', value: formatStamp(s.updatedAt) },\n );\n definitionList(rows, opts);\n}\n\n// ---------------------------------------------------------------------------\n// `noir task status [<id>]`\n// ---------------------------------------------------------------------------\nexport interface TaskStatusOptions extends TaskOptions {\n /** Positional task id; omitted ⇒ the active task. */\n id?: string;\n}\n\n/** The gate phases in lifecycle order (mirrors the daemon's `nextGateAfter`). */\nconst GATE_PHASES = ['spec', 'plan', 'verify'] as const satisfies readonly Phase[];\n\n/** The next gate-phase strictly ahead of `phase`, or `null` (past verify). */\nfunction nextGateAfter(phase: string): Phase | null {\n // The verify gate is ASYMMETRIC: it fires on entering DONE, so a task AT the\n // verify phase still has it ahead (mirrors the daemon's nextGateAfter).\n if (phase === 'verify') return 'verify';\n const cur = PHASES.indexOf(phase as Phase);\n for (const p of GATE_PHASES) {\n if (PHASES.indexOf(p) > cur) return p;\n }\n return null;\n}\n\n/**\n * Run `task status` against the daemon when it is up, or fall back to the\n * IN-PROCESS read-only workflow engine when the daemon probe reports it down\n * (S9 DS-5). A status read on a read-only store is a pure KV read, so instead\n * of exit 4 it resolves against the in-process engine (still exit 3 NOT_FOUND\n * for an unknown / absent task). Writes (`task new` / `advance`) keep the\n * daemon-required exit-4 path.\n */\nexport async function taskStatus(opts: TaskStatusOptions): Promise<void> {\n // Conservative probe (mirrors contextSearch/memoryRecall): only a CONFIRMED\n // `{running:false}` engages the in-process fallback; an unavailable probe\n // defaults to the daemon path.\n let probe: DaemonProbe;\n try {\n probe = await probeDaemon(opts);\n } catch {\n probe = { running: true };\n }\n if (!probe.running) {\n const s = await withInProcessRead(opts, async (engines) => {\n const id = typeof opts.id === 'string' && opts.id.length > 0 ? opts.id : null;\n const taskId = id ?? engines.workflow.activeTaskId();\n if (!taskId) fail(EXIT.NOT_FOUND, 'task: no active task', opts);\n const task = engines.workflow.status(taskId);\n if (!task) fail(EXIT.NOT_FOUND, `task: unknown task '${taskId}'`, opts);\n const stopped = task.state === 'blocked' || task.state === 'abandoned';\n return {\n ok: true as const,\n taskId: task.taskId,\n phase: task.phase,\n state: task.state,\n mode: task.mode,\n nextGate: stopped ? null : nextGateAfter(task.phase),\n history: task.history,\n updatedAt: task.updatedAt,\n degraded: true as const,\n };\n });\n if (opts.json === true) {\n process.stdout.write(`${JSON.stringify({ ok: true, data: s })}\\n`);\n return;\n }\n renderStatusRow(s, opts);\n return;\n }\n const s = await fetchStatus(opts, opts.id);\n if (opts.json === true) {\n process.stdout.write(`${JSON.stringify({ ok: true, data: s })}\\n`);\n return;\n }\n renderStatusRow(s, opts);\n}\n\n// ---------------------------------------------------------------------------\n// `noir task next`\n// ---------------------------------------------------------------------------\nexport async function taskNext(opts: TaskOptions): Promise<void> {\n const s = await fetchStatus(opts);\n const suggestion = skillFor(s.phase);\n const nextSkill = skillFor(s.nextGate);\n const data = {\n taskId: s.taskId,\n phase: s.phase,\n state: s.state,\n mode: s.mode,\n nextGate: s.nextGate,\n suggestion,\n nextSkill,\n degraded: s.degraded === true,\n };\n\n if (opts.json === true) {\n process.stdout.write(`${JSON.stringify({ ok: true, data })}\\n`);\n return;\n }\n const flag = data.degraded ? ` ${badge('warn', 'degraded')}` : '';\n log(`task next — ${s.taskId} · phase ${s.phase} (${s.state}, ${s.mode})${flag}`, opts);\n if (s.nextGate) {\n info(`next gate: ${s.nextGate}`, opts);\n } else {\n info('no further gate ahead (past verify, or stopped).', opts);\n }\n if (suggestion) info(`skill for current phase (${s.phase}): ${suggestion}`, opts);\n if (nextSkill) info(`skill for next gate (${s.nextGate}): ${nextSkill}`, opts);\n if (!suggestion && !nextSkill) {\n info('run `noir skills list` to see applicable skills.', opts);\n }\n}\n\n// ---------------------------------------------------------------------------\n// `noir task new --slug <slug> [--mode full|quick]` → workflow_start\n// ---------------------------------------------------------------------------\nexport interface TaskNewOptions extends TaskOptions {\n slug: string;\n mode?: string;\n /** Task class — drives the soft PRD gate (prd.mandatoryFor). */\n taskClass?: string;\n}\n\nexport async function taskNew(opts: TaskNewOptions): Promise<void> {\n // Validate mode client-side so a typo is a clean usage error (exit 2) rather\n // than a server-side zod rejection that would mis-map onto exit 4.\n let mode: 'full' | 'quick' | undefined;\n if (opts.mode !== undefined) {\n if (opts.mode !== 'full' && opts.mode !== 'quick') {\n fail(EXIT.USAGE, `task new: invalid mode '${opts.mode}' (expected 'full' or 'quick')`, opts);\n }\n mode = opts.mode;\n }\n // Validate taskClass client-side (exit 2 on a typo) — c4-surface-wiring S1.\n let taskClass: TaskClass | undefined;\n if (opts.taskClass !== undefined) {\n if (!TASK_CLASSES.includes(opts.taskClass as TaskClass)) {\n fail(\n EXIT.USAGE,\n `task new: invalid class '${opts.taskClass}' (expected one of: ${TASK_CLASSES.join(', ')})`,\n opts,\n );\n }\n taskClass = opts.taskClass as TaskClass;\n }\n // The CLI surface only takes a slug, so it doubles as the stable taskId — the\n // engine's taskId/slug distinction collapses to the slug here. Re-starting the\n // same slug overwrites (the KV is the source of truth, not a journal).\n const res = await callDaemonTool<WorkflowStatusResult | WorkflowNotFound>(\n opts,\n 'workflow_start',\n {\n taskId: opts.slug,\n slug: opts.slug,\n ...(mode === undefined ? {} : { mode }),\n ...(taskClass === undefined ? {} : { taskClass }),\n },\n );\n if (res.ok !== true) {\n const detail =\n typeof res.error === 'string' && res.error.length > 0 ? res.error : 'start failed';\n fail(EXIT.ERROR, `task new --slug ${opts.slug}: ${detail}`, opts);\n }\n if (opts.json === true) {\n process.stdout.write(`${JSON.stringify({ ok: true, data: res })}\\n`);\n return;\n }\n renderStatusRow(res, opts);\n}\n\n// ---------------------------------------------------------------------------\n// `noir task advance [--to <phase>] [--force <reason>]` → workflow_advance\n// ---------------------------------------------------------------------------\nexport interface TaskAdvanceOptions extends TaskOptions {\n to?: string;\n force?: string;\n /** Record the landing gate as `skipped` (advance continues). */\n skip?: boolean;\n /** Skip the document-phase artifact writes (changelog + decision stubs). */\n noArtifacts?: boolean;\n}\n\nexport async function taskAdvance(opts: TaskAdvanceOptions): Promise<void> {\n const args: Record<string, unknown> = {};\n if (typeof opts.to === 'string' && opts.to.length > 0) {\n // Validate the target phase client-side (exit 2 on a typo) — PHASE_SKILL's\n // keys ARE the valid phases, so reuse them rather than a second literal.\n if (!Object.keys(PHASE_SKILL).includes(opts.to)) {\n fail(EXIT.USAGE, `task advance: invalid phase '${opts.to}'`, opts);\n }\n args.to = opts.to;\n }\n if (typeof opts.force === 'string' && opts.force.length > 0) {\n args.force = { reason: opts.force };\n }\n if (opts.skip === true) {\n args.skip = true;\n }\n // Omit taskId → the daemon targets the active task (workflow:active).\n const res = await callDaemonTool<WorkflowStatusResult | WorkflowNotFound>(\n opts,\n 'workflow_advance',\n args,\n );\n if (res.ok !== true) {\n const detail =\n typeof res.error === 'string' && res.error.length > 0 ? res.error : 'advance failed';\n fail(EXIT.ERROR, `task advance: ${detail}`, opts);\n }\n // c4-verify-gate-recovery S8 — document-phase artifact wiring: when the task\n // lands at `done`, write a changelog entry + a pending decision-record stub\n // via the artifact conflict seam (preserve on conflict). `--no-artifacts`\n // skips; the memory consolidation hook is provider-gated and fires via the\n // daemon's existing memory engine when configured (not re-implemented here).\n if (res.state === 'done' && opts.noArtifacts !== true) {\n writeDoneArtifacts(opts, res.taskId);\n }\n // Surface (never auto-emit) the handoff command at the verify gate, the\n // natural handoff point (work moves from Noir's planning into the host's\n // execution). One-line stderr hint via `tip()` so `--no-tips` / `--json`\n // silence it in CI / pipes. Never blocks; never writes to stdout.\n if (typeof opts.to === 'string' && opts.to === 'verify') {\n tip('run `noir handoff` for a ready-to-paste host prompt', opts);\n }\n if (opts.json === true) {\n process.stdout.write(`${JSON.stringify({ ok: true, data: res })}\\n`);\n return;\n }\n renderStatusRow(res, opts);\n}\n\n// ---------------------------------------------------------------------------\n// `noir task resume [<id>] [--prompt '<continue instruction>']`\n// → workflow_resume (c4-surface-wiring S2)\n// ---------------------------------------------------------------------------\nexport interface TaskResumeOptions extends TaskOptions {\n id?: string;\n prompt?: string;\n}\n\n/** Render a resume briefing: state, phase, next action + skill hint + artifacts. */\nfunction renderResumeBriefing(r: WorkflowResumeResult, opts: CliOptions): void {\n const flag = r.degraded === true ? ` ${badge('warn', 'degraded')}` : '';\n log(`resume — ${r.taskId} (${r.state}, ${r.mode})${flag}`, opts);\n const rows: { label: string; value: string }[] = [\n { label: 'Task', value: String(r.taskId) },\n { label: 'Phase', value: String(r.phase) },\n { label: 'State', value: String(r.state) },\n { label: 'Mode', value: String(r.mode) },\n ];\n if (typeof r.taskClass === 'string' && r.taskClass.length > 0) {\n rows.push({ label: 'Class', value: r.taskClass });\n }\n if (typeof r.blockReason === 'string' && r.blockReason.length > 0) {\n rows.push({ label: 'Block reason', value: r.blockReason });\n }\n rows.push({ label: 'Next gate', value: r.nextGate ?? '—' });\n definitionList(rows, opts);\n const suggestion = skillFor(r.phase ?? null);\n if (suggestion) info(`skill for current phase (${r.phase}): ${suggestion}`, opts);\n // A blocked task resumes via jump-to-phase (FSM edges from blocked → any in-flight).\n if (r.state === 'blocked') {\n info('resume a blocked task with: noir task advance --to <phase>', opts);\n }\n}\n\nexport async function taskResume(opts: TaskResumeOptions): Promise<void> {\n const args: Record<string, unknown> = {};\n // A positional id targets a specific task; omit it → the active task.\n if (typeof opts.id === 'string' && opts.id.length > 0) {\n args.taskId = opts.id;\n }\n const res = await callDaemonTool<WorkflowResumeResult>(opts, 'workflow_resume', args);\n // resume is a read; the \"nothing to resume\" envelope is exit 1 (not a crash).\n // Route through fail() in BOTH branches so --json also exits 1 (fail emits the\n // canonical {ok:false,error} envelope on stdout) — previously --json wrote a\n // non-canonical shape and exited 0.\n if (res.resumable !== true) {\n const detail =\n typeof res.error === 'string' && res.error.length > 0 ? res.error : 'nothing to resume';\n fail(EXIT.ERROR, `task resume: ${detail}`, opts);\n }\n // `--prompt` records a resume intent (additive KV, observable — not an FSM\n // state change). Surface it in the briefing so the host sees the continue note.\n if (typeof opts.prompt === 'string' && opts.prompt.length > 0) {\n info(`resume prompt: ${opts.prompt}`, opts);\n }\n if (opts.json === true) {\n process.stdout.write(`${JSON.stringify({ ok: true, data: res })}\\n`);\n return;\n }\n renderResumeBriefing(res, opts);\n}\n\n// ---------------------------------------------------------------------------\n// `noir task block <reason> [--task <id>]` → workflow_block (S4)\n// ---------------------------------------------------------------------------\nexport interface TaskBlockOptions extends TaskOptions {\n reason: string;\n task?: string;\n}\n\nexport async function taskBlock(opts: TaskBlockOptions): Promise<void> {\n if (typeof opts.reason !== 'string' || opts.reason.trim().length === 0) {\n fail(EXIT.USAGE, 'task block: a non-empty <reason> is required', opts);\n }\n const args: Record<string, unknown> = { reason: opts.reason };\n if (typeof opts.task === 'string' && opts.task.length > 0) args.taskId = opts.task;\n const res = await callDaemonTool<WorkflowStatusResult | WorkflowNotFound>(\n opts,\n 'workflow_block',\n args,\n );\n if (res.ok !== true) {\n const detail =\n typeof res.error === 'string' && res.error.length > 0 ? res.error : 'block failed';\n fail(EXIT.ERROR, `task block: ${detail}`, opts);\n }\n if (opts.json === true) {\n process.stdout.write(`${JSON.stringify({ ok: true, data: res })}\\n`);\n return;\n }\n renderStatusRow(res, opts);\n}\n\n// ---------------------------------------------------------------------------\n// `noir task abandon [--task <id>]` → workflow_abandon (S4, destructive confirm)\n// ---------------------------------------------------------------------------\nexport interface TaskAbandonOptions extends TaskOptions {\n task?: string;\n}\n\nexport async function taskAbandon(opts: TaskAbandonOptions): Promise<void> {\n // Abandonment is terminal — confirm in interactive mode (mirrors the in-TUI\n // destructive-confirm pattern). --no-input / --json / CI skip the prompt.\n if (isInteractive(opts)) {\n const clack = await import('@clack/prompts');\n const confirm = await clack.confirm({\n message: 'Abandon this task? This is terminal and cannot be undone.',\n initialValue: false,\n });\n if (clack.isCancel(confirm)) {\n clack.cancel('Cancelled.');\n fail(EXIT.CANCELLED, 'cancelled', opts);\n }\n if (confirm !== true) {\n fail(EXIT.CANCELLED, 'abandon cancelled', opts);\n }\n }\n const args: Record<string, unknown> = {};\n if (typeof opts.task === 'string' && opts.task.length > 0) args.taskId = opts.task;\n const res = await callDaemonTool<WorkflowStatusResult | WorkflowNotFound>(\n opts,\n 'workflow_abandon',\n args,\n );\n if (res.ok !== true) {\n const detail =\n typeof res.error === 'string' && res.error.length > 0 ? res.error : 'abandon failed';\n fail(EXIT.ERROR, `task abandon: ${detail}`, opts);\n }\n if (opts.json === true) {\n process.stdout.write(`${JSON.stringify({ ok: true, data: res })}\\n`);\n return;\n }\n renderStatusRow(res, opts);\n}\n\n// ---------------------------------------------------------------------------\n// `noir task verify [--check <name> ...]` → runs checks + submits evidence\n// to workflow_advance (c4-verify-gate-recovery S3).\n// ---------------------------------------------------------------------------\nexport interface TaskVerifyOptions extends TaskOptions {\n /** Restrict to a named subset of checks; defaults to all configured checks. */\n check?: string[];\n}\n\n/** A check definition resolved from the project config. */\ninterface VerifyCheck {\n name: string;\n command: string;\n tier: 'hard' | 'soft';\n}\n\n/** `workflow_advance` result with optional verify-gate pending/recovery. */\ninterface WorkflowAdvanceResult {\n ok: boolean;\n taskId?: string;\n phase?: string;\n state?: string;\n mode?: string;\n nextGate?: string | null;\n history?: unknown;\n updatedAt?: number;\n degraded?: boolean;\n error?: string;\n /** c4-verify-gate-recovery: present when the verify gate did not admit `done`. */\n pendingGate?: { gate: string; reason: string };\n recovery?: string[];\n}\n\n/** Run one shell command and capture {exitCode, outputDigest}. */\nfunction runCheck(cmd: string): { exitCode: number; digest: string } {\n // The CLI (user-invoked) owns shell access — the engine never shells out.\n // Synchronous spawn keeps `noir task verify` a single atomic step; failures\n // surface as non-zero exit codes (the evidence), never a thrown crash.\n try {\n const buf = spawnSync('sh', ['-c', cmd], {\n stdio: ['ignore', 'pipe', 'pipe'],\n encoding: 'utf8',\n });\n let out = '';\n if (buf.stdout) out += buf.stdout.toString();\n if (buf.stderr) out += buf.stderr.toString();\n const status = buf.status;\n return {\n exitCode: typeof status === 'number' ? status : 1,\n digest: sha256Hex(out),\n };\n } catch {\n return { exitCode: 1, digest: sha256Hex('') };\n }\n}\n\nexport async function taskVerify(opts: TaskVerifyOptions): Promise<void> {\n // Resolve the check set from the project config (workflow.gate.verify.checks).\n // No checks resolvable → exit 2 (USAGE) rather than inventing commands.\n // A throw from loadProjectInfo on an uninitialized project must route through\n // fail() — otherwise under --json stdout stays EMPTY (the raw error only\n // reaches stderr), violating the S9 `{ok:false}` envelope contract.\n let project: ProjectInfo;\n try {\n project = loadProjectInfo(process.cwd());\n } catch {\n fail(EXIT.ERROR, 'Noir is not initialized in this directory. Run `noir init` first.', opts);\n }\n const cfgChecks = project.config.workflow?.gate?.verify?.checks ?? [];\n const all: VerifyCheck[] = cfgChecks.map((c) => ({\n name: c.name,\n command: c.command,\n tier: (c.tier ?? 'hard') as 'hard' | 'soft',\n }));\n let checks = all;\n if (opts.check && opts.check.length > 0) {\n const want = new Set(opts.check);\n checks = all.filter((c) => want.has(c.name));\n if (checks.length === 0) {\n fail(\n EXIT.USAGE,\n `task verify: no configured checks match --check ${[...want].join(',')}`,\n opts,\n );\n }\n }\n if (checks.length === 0) {\n fail(\n EXIT.USAGE,\n 'task verify: no verify checks configured (set workflow.gate.verify.checks in .noir/config.yml)',\n opts,\n );\n }\n\n // Run each check, capture evidence.\n const ranAt = Date.now();\n const evidence = {\n ranAt,\n checks: checks.map((c) => {\n const r = runCheck(c.command);\n return {\n name: c.name,\n exitCode: r.exitCode,\n outputDigest: r.digest,\n command: c.command,\n tier: c.tier,\n };\n }),\n summary: '',\n };\n const passed = evidence.checks.filter((c) => c.exitCode === 0).length;\n const failed = evidence.checks.length - passed;\n evidence.summary = `${passed} passed, ${failed} failed`;\n\n // Submit evidence to workflow_advance (targets the active task → verify gate).\n const res = await callDaemonTool<WorkflowAdvanceResult>(opts, 'workflow_advance', { evidence });\n if (res.ok === true) {\n if (opts.json === true) {\n // S9 `{ok:true, data}` — evidence nests INSIDE the payload (no ad-hoc\n // top-level sibling keys), matching every other command's envelope shape.\n process.stdout.write(`${JSON.stringify({ ok: true, data: { ...res, evidence } })}\\n`);\n return;\n }\n // Only a landing at `done` means the verify gate FIRED. If the advance\n // landed elsewhere (e.g. from `executing` → `verifying` before the engine's\n // evidence guard was added), be honest about it rather than claiming success.\n const landed = (res as WorkflowStatusResult).state;\n if (landed === 'done') {\n success(`verify — ${evidence.summary} → gate approved`, opts);\n } else {\n info(\n `verify — ${evidence.summary} → advanced to ${landed} (the verify gate fires at \\`done\\`; run \\`noir task verify\\` again when there)`,\n opts,\n );\n }\n renderStatusRow(res as WorkflowStatusResult, opts);\n return;\n }\n // Pending / failed: a failing verify gate is a FAILURE (exit non-zero), never\n // a silent exit-0 \"success\". Under --json emit the canonical {ok:false,error}\n // envelope (not a flattened `{evidence, ...res}`), preserving pendingGate +\n // recovery + evidence for consumers.\n const detail = res.error ?? res.pendingGate?.reason ?? 'verify failed';\n if (opts.json === true) {\n process.stdout.write(\n `${JSON.stringify({\n ok: false,\n error: { code: EXIT.ERROR, message: `task verify: ${detail}` },\n // S9 `{ok:false, error}` + a payload — recovery context + evidence nest\n // under `data`, not as top-level siblings (same envelope shape as the\n // success path; consumers read `data` for the full picture).\n data: {\n ...(res.pendingGate !== undefined ? { pendingGate: res.pendingGate } : {}),\n ...(res.recovery !== undefined ? { recovery: res.recovery } : {}),\n evidence,\n },\n })}\\n`,\n );\n process.exitCode = EXIT.ERROR;\n return;\n }\n if (res.pendingGate) {\n warn(`verify gate: ${res.pendingGate.reason} (${evidence.summary})`, opts);\n const recovery = res.recovery ?? ['retry', 'force', 'skip', 'block'];\n info(\n `recovery: ${recovery\n .map((r) =>\n r === 'retry'\n ? '`noir task verify`'\n : r === 'force'\n ? '`noir task advance --force <reason>`'\n : r === 'skip'\n ? '`noir task advance --skip`'\n : r === 'block'\n ? '`noir task block <reason>`'\n : `\\`${r}\\``,\n )\n .join(' | ')}`,\n opts,\n );\n }\n fail(EXIT.ERROR, `task verify: ${detail}`, opts);\n}\n\n// ---------------------------------------------------------------------------\n// `noir task research [<id>]` — list research findings (c4-research-grounding)\n// `noir task research record --type <t> --text \"...\" [--source <ref>] [--task <id>]`\n// → workflow_research_record\n// ---------------------------------------------------------------------------\nexport interface TaskResearchOptions extends TaskOptions {\n id?: string;\n}\n\nexport async function taskResearch(opts: TaskResearchOptions): Promise<void> {\n // List findings by reading the active task's status (which carries history\n // — the research records live in the engine's readResearch KV). For now,\n // surface through the daemon: call workflow_status and report the task's\n // Show status, then note that `noir task research record` writes findings.\n const s = await fetchStatus(opts, opts.id);\n if (opts.json === true) {\n process.stdout.write(`${JSON.stringify({ ok: true, data: s })}\\n`);\n return;\n }\n renderStatusRow(s, opts);\n info('research findings are recorded via `noir task research record` (list + record)', opts);\n}\n\nexport interface TaskResearchRecordOptions extends TaskOptions {\n type: string;\n text: string;\n source?: string;\n task?: string;\n}\n\nexport async function taskResearchRecord(opts: TaskResearchRecordOptions): Promise<void> {\n const TYPES = ['assumption', 'discovery', 'decision', 'grounding-fact'];\n if (!TYPES.includes(opts.type)) {\n fail(\n EXIT.USAGE,\n `task research record: invalid type '${opts.type}' (expected one of: ${TYPES.join(', ')})`,\n opts,\n );\n }\n const args: Record<string, unknown> = { type: opts.type, text: opts.text };\n if (typeof opts.source === 'string' && opts.source.length > 0) args.source = opts.source;\n if (typeof opts.task === 'string' && opts.task.length > 0) args.taskId = opts.task;\n const res = await callDaemonTool<{\n ok: boolean;\n taskId?: string;\n entry?: unknown;\n error?: string;\n }>(opts, 'workflow_research_record', args);\n if (res.ok !== true) {\n const detail =\n typeof res.error === 'string' && res.error.length > 0 ? res.error : 'record failed';\n fail(EXIT.ERROR, `task research record: ${detail}`, opts);\n }\n if (opts.json === true) {\n process.stdout.write(`${JSON.stringify({ ok: true, data: res })}\\n`);\n return;\n }\n success(\n `research recorded → ${opts.type}: ${opts.text.slice(0, 80)}${opts.text.length > 80 ? '…' : ''}`,\n opts,\n );\n}\n// ---------------------------------------------------------------------------\n// `noir task decompose <capability-id>` → draft a SlicePlan (c4-decomposition)\n// ---------------------------------------------------------------------------\nexport interface TaskDecomposeOptions extends TaskOptions {\n capability: string;\n out?: string;\n}\n\nexport async function taskDecompose(opts: TaskDecomposeOptions): Promise<void> {\n const cap = opts.capability.trim();\n if (cap.length === 0) fail(EXIT.USAGE, 'task decompose: <capability-id> is required', opts);\n\n // Template SlicePlan (offline — mirrors draftPrd P3: single-shot, no provider\n // needed for a template, null/empty on no-provider). A provider-backed drafting\n // pass would fill richer fields; the offline template gives a valid skeleton.\n const plan = {\n capabilityId: cap,\n intent: `Capability ${cap} — offline template (run with a provider for an LLM-drafted plan)`,\n slices: [\n {\n id: 's1-walking-skeleton',\n title: 'Walking skeleton — thinnest end-to-end',\n type: 'feature' as const,\n rationale: `The first slice for capability ${cap}.`,\n scopeIn: 'End-to-end path linking the main architecture.',\n scopeOut: 'Polish, edge cases, full coverage.',\n dependsOn: [] as { id: string; mode: 'sequential' | 'parallel' }[],\n files: { create: [], modify: [], preserve: [] },\n acceptance: [`verify acceptance criteria for capability ${cap}`],\n doD: ['pnpm test', 'pnpm typecheck'],\n rollbackPlan: { procedure: 'revert the slice commit', verifyCommand: 'pnpm test' },\n },\n ],\n status: { 's1-walking-skeleton': 'planned' as const },\n };\n\n // `--out <path>`: persist the plan JSON (a silent no-op before — the flag was\n // declared + forwarded but never acted on).\n if (typeof opts.out === 'string' && opts.out.length > 0) {\n try {\n writeFileSync(opts.out, `${JSON.stringify(plan, null, 2)}\\n`, 'utf8');\n } catch (err) {\n fail(\n EXIT.ERROR,\n `task decompose: could not write ${opts.out}: ${err instanceof Error ? err.message : String(err)}`,\n opts,\n );\n }\n if (opts.json !== true) info(`wrote plan to ${opts.out}`, opts);\n }\n\n if (opts.json === true) {\n process.stdout.write(`${JSON.stringify({ ok: true, data: plan })}\\n`);\n return;\n }\n log(`decompose — ${cap}`, opts);\n for (const s of plan.slices) {\n info(`${s.id}: ${s.title} (${s.type}) — rationale: ${s.rationale}`, opts);\n }\n tip('each piece enters the existing clarify→spec→plan→execute→verify→document workflow', opts);\n}\n","// S9 t4 + home-consolidation — `noir` (bare) home menu.\n//\n// The interactive entry point. Dispatch rules (spec F1 / AC1 / task t4):\n// • interactive (TTY && !CI && !NO_COLOR && !--json && !--no-input) → the\n// @clack/prompts grouped home menu (intro + sections + quick actions),\n// dispatching the chosen action through the SAME commander program the bin\n// uses, so the menu automatically inherits those implementations as they\n// land.\n// • non-interactive + --json → run `status --json` (machine snapshot).\n// • non-interactive + no --json → run `status` (human snapshot). Safe now that\n// `status` is probe-only: it NEVER auto-starts a daemon and exits 0\n// even when the daemon is down, so bare `noir` in CI / a pipe is a useful\n// no-op snapshot instead of a noisy failure or a help dump.\n//\n// Home-consolidation (S2): the interactive arm is a two-level grouped menu —\n// a section picker (select, arrow-navigable) then per-section action lists\n// (select with per-option hints). Navigation is smooth: Esc / backspace /\n// ← return to the section picker, → jumps to the next section, ← to the\n// previous, so the user can move across sections without re-entering level 1\n// each time. The section content comes from the SHARED React-free\n// {@link resolveSections} module (tui/commands/sections.ts), which references\n// palette-registry ids — so the menu cannot drift from the commander tree.\n// `deps.commands` is injected by bin.ts (the same list the TUI palette uses).\n//\n// Both levels use `clack.select` (NOT `selectKey`): `selectKey` is a\n// select-by-typed-letter prompt with no arrow/enter/esc handling, and its\n// `_track=false` value stays `undefined` until a letter is pressed — Enter\n// crashes with `Cannot read properties of undefined (reading 'label')` (the\n// 1.9.0 home-menu bug, fixed by `select` on @clack ≥1.7).\n//\n// `@clack/prompts` is imported lazily inside the interactive branch so the\n// non-interactive paths (the common CI/script case) never pay for it and never\n// touch stdin/stdout rendering (NF6). The menu never blocks when input is\n// disabled — `isInteractive` already gated that — and a Ctrl+C at any prompt\n// maps to exit 5 (CANCELLED) via `fail`.\n//\n// Decoupling: `home` takes its `dispatch` + `commands` as injected callbacks\n// (provided by bin.ts) so this module has NO import edge back to bin.ts (which\n// would be circular: bin imports home). That also makes the menu unit-testable\n// without commander — tests pass a fake callback + mock @clack.\n\nimport { type HostId, hostLaunchDirective } from '@noir-ai/adapters';\nimport {\n detectActiveMethod,\n type InstallRecord,\n latestVersionFromCache,\n loadProjectInfo,\n NOIR_VERSION,\n readInstallRecord,\n readUpdateCache,\n} from '@noir-ai/core';\nimport { NOIR_TAGLINE, renderBanner, shouldShowBanner } from '../banner.js';\nimport { type CliOptions, EXIT, fail, isInteractive } from '../output.js';\nimport { c } from '../theme.js';\nimport { isDestructive } from '../tui/commands/registry.js';\nimport { type HomeAction, type HomeSection, resolveSections } from '../tui/commands/sections.js';\nimport type { PaletteCommand } from '../tui/palette/types.js';\nimport { buildUpdateNotice, DEFAULT_UPDATE_CONFIG, runAsyncUpdateCheck } from './update.js';\n\n/** Callbacks home needs from the bin (injected → no circular import). */\nexport interface HomeDeps {\n /**\n * Run a sub-command by user-form argv (e.g. `['status','--json']`) on a fresh\n * commander program. Must NOT throw — it owns its own error → exit-code\n * mapping (bin's `handleError`) and leaves the outcome on `process.exitCode`\n * so it becomes the final exit code of the whole `noir` invocation.\n */\n dispatch: (argv: readonly string[]) => Promise<void>;\n /**\n * The live palette commands (derived from `createProgram()` by bin.ts) — the\n * same source the TUI palette uses. The grouped home menu resolves its\n * sections against this so it cannot drift. Optional for backward-compat\n * (older tests omit it); when absent, sections fall back to the internal\n * curated ids that resolve against a fresh registry.\n */\n readonly commands?: readonly PaletteCommand[];\n}\n\n/** Try to read the project for a friendlier intro banner; never throws. */\nfunction tryProject(): { id: string; name: string; host: HostId } | null {\n try {\n const info = loadProjectInfo(process.cwd());\n return { id: info.id, name: info.name, host: info.config.host };\n } catch {\n // Not initialized yet (no `.noir/project-id`) — the menu still works; it\n // just shows the generic intro. `Status` will surface the real error.\n return null;\n }\n}\n\n/**\n * One-time nudge: shows only for non-native installs, once per version. The\n * \"dismissed for this version\" flag is stored in install.json's record\n * (`dismissedVersions`); absence ⇒ show. Once the user dismisses (via\n * `noir install --dismiss`), the current CLI version is appended and the\n * banner stays silent until they next upgrade Noir.\n */\nexport function shouldShowMigrationBanner(rec: InstallRecord, currentVersion: string): boolean {\n if (rec.method === 'native') return false;\n if (rec.dismissedVersions?.includes(currentVersion)) return false;\n return true;\n}\n\n/** One-line summary of the CLI command surface (shown under the banner). */\nconst COMMANDS_HINT =\n 'Commands: status · context · memory · task · skills · daemon · doctor · install · update · tui · palette';\n\n/**\n * Bare-`noir` router. See module header for the three dispatch arms. Never\n * blocks when input is disabled (the interactive branch is unreachable then).\n *\n * TUI policy: `--no-tui` (`opts.tui === false`) forces the non-interactive\n * `status` path even when {@link isInteractive} would be true (a TTY). `--tui`\n * (`opts.tui === true`) is advisory only — it still requires a TTY, so the\n * `isInteractive(opts)` gate already encodes that. Auto (no flag) preserves the\n * prior behavior. Advisory only — `home` never hard-gates any subcommand.\n */\nexport async function home(opts: CliOptions, deps: HomeDeps): Promise<void> {\n if (isInteractive(opts) && opts.tui !== false) {\n await runMenu(opts, deps);\n return;\n }\n if (opts.json === true) {\n // Machine snapshot — same data `noir status --json` produces.\n await deps.dispatch(['status', '--json']);\n return;\n }\n // Non-interactive, human: run `status` (human snapshot). status is probe-only\n // — it never auto-starts a daemon and exits 0 even when down, so this is\n // a useful bare-`noir` snapshot in CI / pipes instead of a help dump.\n await deps.dispatch(['status']);\n}\n\n// ---------------------------------------------------------------------------\n// The grouped home menu (interactive arm).\n//\n// Two levels driven by a small state machine so navigation is smooth:\n// LEVEL 1 — section picker (clack.select): 1-6 sections + Exit.\n// LEVEL 2 — per-section action list (clack.select with hints).\n//\n// Navigation keys are handled by @clack itself at each level (Esc cancels that\n// prompt). We return a sentinel from each level and branch on it, so \"back\"\n// from level 2 loops back to level 1, and \"next\"/\"previous\" from level 2 jump\n// to the adjacent section's action list. Cancel anywhere → exit 5 (CANCELLED).\n// ---------------------------------------------------------------------------\n\n/** @clack's `select` result is a value | cancel-symbol. */\ntype ClackChoice = string | symbol;\n\n/** The @clack/prompts module (lazy). */\ntype Clack = typeof import('@clack/prompts');\n\n/**\n * Level 1 — the section picker. Returns which section to open, or a control\n * outcome. Uses `select` (NOT `selectKey`) so arrow navigation, Enter-to-submit,\n * and Esc/Ctrl+C cancel all work. `selectKey` is a select-by-typed-letter prompt\n * with no arrow/enter/esc handling and a `_track=false` value that stays\n * `undefined` until a matching letter is pressed — pressing Enter there crashes\n * with `Cannot read properties of undefined (reading 'label')` (the 1.9.0 home\n * menu bug, fixed by switching to `select` on @clack ≥1.7).\n */\nasync function pickSection(\n clack: Clack,\n sections: readonly HomeSection[],\n opts: CliOptions,\n): Promise<ClackChoice> {\n const result = await clack.select({\n message: 'What would you like to do?',\n options: [\n ...sections.map((s) => ({\n value: s.id,\n label: s.label,\n hint: s.hint,\n })),\n { value: 'exit', label: 'Exit', hint: 'leave the home menu' },\n ],\n });\n if (clack.isCancel(result)) {\n clack.cancel('Cancelled.');\n fail(EXIT.CANCELLED, 'cancelled', opts);\n }\n return result;\n}\n\n/**\n * Level 2 — the action list for `section`. Returns which action to run, or a\n * control outcome. `select` renders each action with a one-line `hint`; the\n * final \"Back\" option returns to the section picker. Cancel → back too.\n */\nasync function pickAction(\n clack: Clack,\n section: HomeSection,\n sections: readonly HomeSection[],\n opts: CliOptions,\n): Promise<ClackChoice> {\n const idx = sections.findIndex((s) => s.id === section.id);\n const hasPrev = idx > 0;\n const hasNext = idx !== -1 && idx < sections.length - 1;\n const result = await clack.select({\n message: section.label,\n initialValue: section.items[0]?.id,\n options: [\n ...section.items.map((a) => ({\n value: a.id,\n label: a.label,\n hint: a.hint,\n })),\n // Navigation options so the user can move across sections without\n // re-entering the section picker (the \"lancar\" navigation requirement).\n ...(hasPrev\n ? [{ value: 'prev' as const, label: '← Prev section', hint: sections[idx - 1]?.label }]\n : []),\n ...(hasNext\n ? [{ value: 'next' as const, label: '→ Next section', hint: sections[idx + 1]?.label }]\n : []),\n { value: 'back', label: '↑ Back to sections', hint: 'return to the section picker' },\n ],\n });\n if (clack.isCancel(result)) {\n // Esc / Ctrl+C at the action list → back to the section picker (not exit).\n clack.cancel('Back to the home menu.');\n return 'back';\n }\n if (opts.verbose) {\n process.stderr.write(`noir: home: section '${section.id}' selected\\n`);\n }\n return result;\n}\n\n/**\n * Collect an inline argument for an action that needs one (generalizes the\n * existing recall-query pattern). Cancel → exit 5.\n */\nasync function collectArg(\n clack: Clack,\n action: HomeAction,\n opts: CliOptions,\n): Promise<string | null> {\n if (!action.needsArg) return null;\n const value = await clack.text({\n message: action.needsArg.prompt,\n placeholder: action.needsArg.placeholder,\n validate: (v: string | undefined) =>\n !v || v.trim().length === 0 ? 'Please enter a value.' : undefined,\n });\n if (clack.isCancel(value)) {\n clack.cancel('Cancelled.');\n fail(EXIT.CANCELLED, 'cancelled', opts);\n }\n return String(value);\n}\n\n/**\n * Resolve the argv an action dispatches: the registry-derived `dispatch`,\n * plus the collected inline arg (when the action needs one). A `destructive`\n * action gates behind a clack.confirm first (reusing the palette registry's\n * destructive table). Returns null when the user declined a destructive action.\n */\nasync function argvForAction(\n clack: Clack,\n action: HomeAction,\n opts: CliOptions,\n): Promise<string[] | null> {\n const base = action.dispatch ?? [action.id];\n let argv = [...base];\n // Collect an inline arg ONLY when the action needs one; a non-arg action\n // skips the prompt entirely (this is what distinguishes \"no arg needed\"\n // from \"cancelled\" — both used to collide on `null` and infinite-loop).\n if (action.needsArg) {\n const arg = await collectArg(clack, action, opts);\n if (arg === null) return null; // cancelled → back to the section\n argv = [...base, arg];\n }\n\n // Gate destructive actions behind an explicit confirm (matches the TUI\n // palette's destructive-confirm overlay — same table, isDestructive()).\n if (action.destructive || isDestructive(argv)) {\n const confirmed = await clack.confirm({\n message: `Run \\`noir ${argv.join(' ')}\\`? This may modify project files / the store.`,\n initialValue: false,\n });\n if (clack.isCancel(confirmed) || !confirmed) return null;\n }\n return argv;\n}\n\n/**\n * The grouped home menu loop. Drives the two levels and the back/next/previous\n * navigation. Dispatch through the shared seam; a selected action returns so\n * `runMenu` can print the outro.\n */\nasync function runGroupedMenu(\n clack: Clack,\n opts: CliOptions,\n deps: HomeDeps,\n sections: readonly HomeSection[],\n): Promise<void> {\n // Start on the first section's action list if the user just wants to move\n // fast; otherwise start at the section picker. We begin at the picker so\n // first-run users see the grouping.\n let currentSection: number | null = null; // null = level 1 (section picker)\n\n // eslint-disable-next-line no-constant-condition\n while (true) {\n // LEVEL 1 — section picker\n if (currentSection === null) {\n const picked = await pickSection(clack, sections, opts);\n if (clack.isCancel(picked) || picked === 'exit') {\n clack.outro('bye');\n return;\n }\n const idx = sections.findIndex((s) => s.id === picked);\n if (idx === -1) {\n // Unknown section value — defensive: re-show the picker.\n continue;\n }\n currentSection = idx;\n continue;\n }\n\n // LEVEL 2 — the current section's action list\n const section = sections[currentSection];\n if (!section) {\n // Defensive: index out of range — back to the picker.\n currentSection = null;\n continue;\n }\n const chosen = await pickAction(clack, section, sections, opts);\n if (clack.isCancel(chosen)) {\n // Esc at the action list → back to the picker.\n currentSection = null;\n continue;\n }\n\n switch (chosen) {\n case 'back': {\n // ← Back → level 1.\n currentSection = null;\n continue;\n }\n case 'next': {\n // → Next section (progressive: no need to re-pick at level 1).\n currentSection = (currentSection + 1) % sections.length;\n continue;\n }\n case 'prev': {\n // ← Previous section.\n currentSection = (currentSection - 1 + sections.length) % sections.length;\n continue;\n }\n default: {\n const action = section.items.find((a) => a.id === chosen);\n if (!action) {\n // Defensive: unknown action id — back to the picker.\n currentSection = null;\n continue;\n }\n const argv = await argvForAction(clack, action, opts);\n if (argv === null) {\n // Destructive declined (or arg cancelled) → stay in the section.\n continue;\n }\n await deps.dispatch(argv);\n clack.outro('done');\n return; // one action per `noir` run, then the process exits\n }\n }\n }\n}\n\n/** The @clack select menu (interactive arm). */\nasync function runMenu(opts: CliOptions, deps: HomeDeps): Promise<void> {\n // Lazy import: the non-interactive paths never load @clack (NF6).\n const clack = await import('@clack/prompts');\n\n const project = tryProject();\n\n // fire-and-forget; never blocks, never prints under --json/--quiet/CI/non-TTY.\n void runAsyncUpdateCheck({\n env: process.env,\n configUpdate: (() => {\n // Try to read the project's update config block; fall back to defaults\n // if the project isn't initialized or the block is absent.\n try {\n const info = loadProjectInfo(process.cwd());\n return info.config.update ?? DEFAULT_UPDATE_CONFIG;\n } catch {\n return DEFAULT_UPDATE_CONFIG;\n }\n })(),\n quiet: opts.json === true || opts.quiet === true || !process.stdout.isTTY,\n });\n\n if (shouldShowBanner(opts)) {\n const host = project?.host ?? 'claude';\n process.stderr.write(\n `\\n${renderBanner()}\\n${NOIR_TAGLINE}\\n\\n${hostLaunchDirective(host)}\\n${COMMANDS_HINT}\\n\\n`,\n );\n }\n\n // One-time migration nudge for non-native installs.\n const rec = readInstallRecord();\n if (rec && shouldShowMigrationBanner(rec, NOIR_VERSION)) {\n process.stderr.write(\n `\\n ${c.warn(`noir installed via ${rec.method}`)} — consider \\`noir install\\` for the native path (auto-update, no npm prefix/PATH issues). Dismiss with: \\`noir install --dismiss\\` (persisted per version).\\n\\n`,\n );\n }\n\n // Update-available notice (version + install-type-specific advice). Reads the\n // CACHED latest version (the async check above refreshes it for next time) and\n // advertises it only when strictly newer (semver downgrade guard).\n const updateNotice = buildUpdateNotice({\n method: detectActiveMethod(),\n currentVersion: NOIR_VERSION,\n latestKnown: latestVersionFromCache(readUpdateCache(), 'latest'),\n });\n if (updateNotice) {\n process.stderr.write(\n `\\n ${c.warn(`noir ${updateNotice.latestVersion} is available`)} (you have ${updateNotice.currentVersion}) — ${updateNotice.advice}.\\n\\n`,\n );\n }\n\n clack.intro(project ? `noir — ${project.name}` : 'noir');\n\n // Resolve the curated sections against the LIVE palette registry. bin.ts\n // injects `deps.commands` (the same list the TUI palette uses). Tests that\n // omit it (backward-compat) pass an empty list → sections degrade to those\n // whose ids exist (none) — the menu would be empty, but those tests don't\n // drive the interactive arm's content. bin.ts always injects the real list.\n const sections = await resolveSections(deps.commands ?? []);\n\n await runGroupedMenu(clack, opts, deps, sections);\n}\n","// SP-B — Noir banner.\n//\n// Pre-rendered \"noir\" ASCII wordmark (figlet \"ANSI Shadow\", generated offline\n// and VERIFIED letter-by-letter to read N-O-I-R — an earlier hand-rolled\n// version had a malformed R that rendered as \"NOHA\") with a SMOOTH gradient via\n// gradient-string. (A per-row rainbow was garish; a smooth vertical gradient is\n// the modern look — cf. the GitHub Copilot CLI banner engineering post.)\n//\n// Guardrails: only the interactive home arm calls this (isInteractive already\n// gates TTY/CI/NO_COLOR/--json/--no-input); shouldShowBanner additionally\n// skips --quiet and NOIR_NO_BANNER. color:false → zero ANSI for snapshots/CI.\n// Responsive: ≥50 cols → block wordmark; <50 → compact `◆ noir` mark.\nimport gradient from 'gradient-string';\nimport type { CliOptions } from './output.js';\nimport { accessibleMode, c, useColor } from './theme.js';\n\n// figlet \"ANSI Shadow\" — regenerated 2026-07-26 from the standard per-letter\n// glyphs and verified (N, O, I, R) to read \"NOIR\". Do NOT hand-edit — regenerate\n// via `figlet -f \"ANSI Shadow\" NOIR` if a glyph changes.\nconst NOIR_BLOCK = [\n '███╗ ██╗ ██████╗ ██╗ ██████╗ ',\n '████╗ ██║ ██╔═══██╗ ██║ ██╔══██╗',\n '██╔██╗ ██║ ██║ ██║ ██║ ██████╔╝',\n '██║╚██╗██║ ██║ ██║ ██║ ██╔══██║',\n '██║ ╚████║ ╚██████╔╝ ██║ ██║ ██║',\n '╚═╝ ╚═══╝ ╚═════╝ ╚═╝ ╚═╝ ╚═╝',\n];\n\n// \"noir\" aesthetic — Midnight Cobalt: a smooth gradient-string gradient (dark\n// cobalt → bright blue → sky) applied per-character across the wordmark\n// (vertical, top → bottom). All stops are bright enough to read on a dark\n// terminal; the deep-blue start evokes \"midnight\" without disappearing.\nconst NOIR_GRADIENT = gradient('#2c5282', '#3b82f6', '#7dd3fc');\n\n/** One-line product tagline (shown under the wordmark). */\nexport const NOIR_TAGLINE = 'discipline, context, and memory layer for agentic CLIs';\n\ninterface BannerOptions {\n /** Terminal width in columns (defaults to process.stdout.columns, else 80). */\n width?: number;\n /** Apply the gradient. Default true. */\n color?: boolean;\n}\n\n/**\n * Render the Noir banner. Wide terminals (≥50 cols) get the full block\n * wordmark; narrow terminals get a compact `◆ noir` mark.\n *\n * Color gating: decoration is on only when the caller did not pass\n * `color:false` AND `useColor()` agrees (honoring NO_COLOR / CLICOLOR_FORCE /\n * TTY uniformly via the theme — the single color authority). Under\n * `NOIR_ACCESSIBLE` the gradient is replaced with a solid accent render\n * (maximum legibility); the wordmark stays recognizable either way.\n */\nexport function renderBanner(opts: BannerOptions = {}): string {\n const width = opts.width ?? process.stdout.columns ?? 80;\n const colorOn = opts.color !== false && useColor();\n if (width < 50) {\n return colorOn ? `${c.accent('◆')} noir` : '◆ noir';\n }\n const block = NOIR_BLOCK.join('\\n');\n if (!colorOn) return block;\n // Accessible mode: skip the multi-stop gradient in favor of a single solid\n // accent color (still the Midnight Cobalt blue role, just without the\n // per-character hue drift that can be harder to read).\n if (accessibleMode()) {\n return block\n .split('\\n')\n .map((line) => c.accent(line))\n .join('\\n');\n }\n return NOIR_GRADIENT.multiline(block);\n}\n\n/**\n * Gate: skip the banner under `--quiet` / `--json` or `NOIR_NO_BANNER`. The TTY\n * / CI / NO_COLOR guards are already handled by `isInteractive` (the only path\n * that calls the banner is the interactive home arm); this adds the\n * banner-specific opt-outs a user can set even inside an interactive session.\n */\nexport function shouldShowBanner(opts: CliOptions): boolean {\n if (opts.quiet === true || opts.json === true) return false;\n const v = process.env.NOIR_NO_BANNER;\n if (v !== undefined && v !== '') return false;\n return true;\n}\n","// A1 — derive {@link PaletteCommand} entries from a commander program.\n//\n// The TUI command palette needs a flat, searchable list of the `noir`\n// subcommands a user can dispatch. Rather than maintain a second hand-curated\n// command table (which would drift from the real tree in `bin.ts`), this module\n// walks the commander tree at palette-build time and projects each LEAF command\n// into a {@link PaletteCommand}.\n//\n// Leaf contract (mirrors the palette's intent — only dispatchable commands\n// surface, never bare groups):\n// - has an action handler (`.action()` was called), AND\n// - has no child commands.\n// Groups — which own children and carry a usage-throwing fallback action in the\n// real CLI — are excluded by the \"no children\" clause regardless of their action\n// state. The program root name ('noir' / '') is never part of the argv path.\n\nimport type { Command } from 'commander';\nimport type { PaletteCommand } from '../palette/types.js';\n\n/**\n * argv-prefix table for commands that mutate the store / workflow / host\n * artifacts. The palette uses this to require confirmation before dispatch.\n * A prefix matches when `commandArgv` starts with every token of the entry\n * (e.g. `['context', 'index']` matches the `context index` leaf).\n */\nconst DESTRUCTIVE_PREFIXES: readonly (readonly string[])[] = [\n ['context', 'index'],\n ['memory', 'save'],\n ['memory', 'forget'],\n ['memory', 'consolidate'],\n ['task', 'new'],\n ['task', 'advance'],\n ['skills', 'sync'],\n ['daemon', 'start'],\n ['daemon', 'stop'],\n ['daemon', 'restart'],\n ['init'],\n ['create'],\n ['sync'],\n ['install'],\n ['update'],\n ['run'],\n];\n\n/**\n * True when `argv` matches one of the {@link DESTRUCTIVE_PREFIXES}. A prefix\n * matches iff `argv` is at least as long as the prefix and every prefix token\n * equals the corresponding argv token — so `['context']` does NOT match the\n * `['context', 'index']` prefix (a bare group isn't destructive), but\n * `['context', 'index']` does.\n */\nexport function isDestructive(argv: readonly string[]): boolean {\n return DESTRUCTIVE_PREFIXES.some((prefix) => {\n if (argv.length < prefix.length) return false;\n return prefix.every((tok, i) => argv[i] === tok);\n });\n}\n\n/** Capitalize the first character of `s`, leaving the rest untouched. */\nfunction capitalizeFirst(s: string): string {\n if (s.length === 0) return s;\n return `${s[0]?.toUpperCase() ?? ''}${s.slice(1)}`;\n}\n\n/**\n * Commander keeps the registered action handler on a private `_actionHandler`\n * field (no public accessor exists). This narrow cast reads only that field so\n * we can tell \"a dispatchable command\" apart from \"a bare group container\".\n */\ntype CommandWithAction = Command & { _actionHandler: ((...args: unknown[]) => unknown) | null };\n\n/** True when commander has an `.action()` handler registered on `cmd`. */\nfunction hasAction(cmd: Command): boolean {\n return (cmd as CommandWithAction)._actionHandler != null;\n}\n\n/**\n * Walk `cmd`'s subtree depth-first, appending one {@link PaletteCommand} per\n * leaf (has an action handler AND no child commands). `path` accumulates the\n * argv tokens excluding the program root name; the caller seeds it as `[]` so\n * the root contributes nothing.\n */\nfunction collectLeaves(cmd: Command, path: string[], out: PaletteCommand[]): void {\n const children = cmd.commands;\n const isLeaf = hasAction(cmd) && children.length === 0;\n\n if (isLeaf) {\n const argv = path;\n const id = argv.join(' ');\n const description = cmd.description() || argv.join(' ');\n out.push({\n id,\n label: argv.map(capitalizeFirst).join(': '),\n argv,\n description,\n category: argv[0] ?? '',\n keywords: argv,\n destructive: isDestructive(argv),\n });\n return;\n }\n\n // Not a leaf — recurse into each child, extending the path with its name.\n // A child `name()` is always a non-empty token (commander rejects empty\n // command names), so `path` only grows with real argv segments.\n for (const child of children) {\n collectLeaves(child, [...path, child.name()], out);\n }\n}\n\n/**\n * Derive the palette entries for `program`: one {@link PaletteCommand} per leaf\n * subcommand, in commander's registration order. The program root name\n * ('noir' / '') is never part of any entry's argv.\n */\nexport function buildPaletteCommands(program: Command): PaletteCommand[] {\n const out: PaletteCommand[] = [];\n // Seed the path empty so the root's own name is excluded; its children become\n // the top-level argv segments (e.g. `context`, `doctor`, `init`).\n collectLeaves(program, [], out);\n return out;\n}\n","// Home-consolidation (S1) — the shared, React-free curated-section module.\n//\n// The bare `noir` home menu (packages/cli/src/commands/home.ts) and the Ink TUI\n// palette's `commands` corpus (App.tsx → palette/rows.ts) both render a curated\n// set of quick actions. This module is the SINGLE source of that curation so\n// the two renderers cannot drift — the same one-table-two-renderers idea that\n// keeps the TUI palette aligned with the commander tree.\n//\n// No-drift contract: every {@link HomeAction} references a palette-registry\n// `id` (e.g. 'context search'), NOT a hand-written argv. {@link resolveSections}\n// re-derives the live palette commands and drops any action whose id no longer\n// exists — so a future commander change degrades the menu to what exists\n// instead of crashing it.\n//\n// This module is deliberately React-free (no ink import) so `home.ts` (the lean\n// @clack path) can consume it without pulling React/Ink into the main CLI graph\n// (NF6 lazy-import constraint). Callers pass the live palette commands\n// explicitly (bin.ts injects them via HomeDeps / TuiDeps), so this module has\n// no import edge back to bin.ts (home.ts must stay circular-import-free).\n\nimport type { PaletteCommand } from '../palette/types.js';\n\n/** A single curated quick action: friendly copy + a palette-registry id. */\nexport interface HomeAction {\n /** The palette-registry id this action runs (e.g. `context search`). */\n readonly id: string;\n /** Friendly title-cased label for the menu (may differ from the leaf). */\n readonly label: string;\n /** One-line dim hint shown under/near the label (exact subcommand + purpose). */\n readonly hint: string;\n /**\n * True when this action mutates the store / workflow / host artifacts (the\n * same prefix table the TUI palette uses). The menu gates it behind a confirm\n * before dispatch.\n */\n readonly destructive?: boolean;\n /**\n * When set, the action collects this argument inline (via clack.text in the\n * menu, or a small text prompt in the TUI home) before dispatch. Mirrors the\n * existing recall-query pattern in home.ts.\n */\n readonly needsArg?: {\n readonly prompt: string;\n readonly placeholder: string;\n };\n /**\n * The exact argv to dispatch. Defaults to the palette entry's `argv`; a\n * `needsArg` action appends the collected value. Always resolves through the\n * registry so it cannot drift.\n */\n readonly dispatch?: readonly string[];\n}\n\n/** A named group of quick actions shown as one home-menu section. */\nexport interface HomeSection {\n /** Stable id (used as a section header + the select value). */\n readonly id: string;\n /** Section title, e.g. 'Status & context'. */\n readonly label: string;\n /** One-line dim hint for the section (its subcommands). */\n readonly hint: string;\n /** Ordered quick actions in this section. */\n readonly items: readonly HomeAction[];\n}\n\n/**\n * The curated home sections, in display order. Each action's `id` must exist in\n * the palette registry (verified by {@link resolveSections}); the friendly copy\n * is authored here once and rendered by both surfaces.\n */\nexport const HOME_SECTIONS: readonly HomeSection[] = [\n {\n id: 'status',\n label: 'Status & context',\n hint: 'snapshot · index · search · doctor',\n items: [\n {\n id: 'status',\n label: 'Status',\n hint: 'project + daemon + workflow + store snapshot (noir status)',\n },\n {\n id: 'context index',\n label: 'Index project',\n hint: '(re)index files into context · ⚠ destructive',\n destructive: true,\n },\n {\n id: 'context search',\n label: 'Search context',\n hint: 'hybrid search over indexed files',\n needsArg: { prompt: 'Context search query:', placeholder: 'e.g. auth flow, deploy steps' },\n },\n {\n id: 'doctor',\n label: 'Doctor',\n hint: 'environment + project health checks',\n },\n {\n id: 'context status',\n label: 'Context status',\n hint: 'index freshness + counts',\n },\n ],\n },\n {\n id: 'memory',\n label: 'Memory',\n hint: 'recall · save · sessions · forget · consolidate',\n items: [\n {\n id: 'memory recall',\n label: 'Recall memory',\n hint: 'search cross-session memory',\n needsArg: { prompt: 'Recall query:', placeholder: 'e.g. auth flow, deploy steps' },\n },\n {\n id: 'memory save',\n label: 'Save memory',\n hint: 'save an observation · ⚠ destructive',\n destructive: true,\n needsArg: { prompt: 'Memory content:', placeholder: 'what you want to remember' },\n },\n {\n id: 'memory sessions',\n label: 'Sessions',\n hint: 'list recent memory sessions',\n },\n {\n id: 'memory forget',\n label: 'Forget memory',\n hint: 'forget observations by id · ⚠ destructive',\n destructive: true,\n },\n {\n id: 'memory consolidate',\n label: 'Consolidate',\n hint: 'fold observations into lessons · ⚠ destructive',\n destructive: true,\n },\n ],\n },\n {\n id: 'workflow',\n label: 'Workflow',\n hint: 'next · status · advance · handoff · wrap',\n items: [\n {\n id: 'task next',\n label: 'Next task',\n hint: 'suggest next phase + applicable skill',\n },\n {\n id: 'task status',\n label: 'Task status',\n hint: 'active task status',\n },\n {\n id: 'task advance',\n label: 'Advance task',\n hint: 'advance to next phase · ⚠ destructive',\n destructive: true,\n },\n {\n id: 'handoff',\n label: 'Handoff',\n hint: 'ready-to-paste host prompt',\n },\n {\n id: 'wrap',\n label: 'Wrap (end session)',\n hint: 'session-end handoff',\n dispatch: ['wrap', '--write'],\n },\n ],\n },\n {\n id: 'setup',\n label: 'Setup & maintenance',\n hint: 'init · create · sync · skills · install · update',\n items: [\n {\n id: 'init',\n label: 'Init',\n hint: 'scaffold Noir in this project · ⚠ destructive',\n destructive: true,\n },\n {\n id: 'create',\n label: 'Create',\n hint: 'bootstrap in a new/empty dir · ⚠ destructive',\n destructive: true,\n },\n {\n id: 'sync',\n label: 'Sync',\n hint: 're-emit managed files + skills · ⚠ destructive',\n destructive: true,\n },\n {\n id: 'skills list',\n label: 'Skills list',\n hint: 'list installed skills',\n },\n {\n id: 'skills sync',\n label: 'Sync skills',\n hint: 're-emit builtin skills · ⚠ destructive',\n destructive: true,\n },\n {\n id: 'update',\n label: 'Update',\n hint: 'check for a new version · ⚠ destructive',\n destructive: true,\n },\n {\n id: 'install',\n label: 'Install / migrate',\n hint: 'native install / migrate · ⚠ destructive',\n destructive: true,\n },\n ],\n },\n {\n id: 'dashboard',\n label: 'Dashboard (full-screen)',\n hint: 'noir tui · noir palette · home',\n items: [\n {\n id: 'tui',\n label: 'Dashboard (full-screen)',\n hint: 'live status · /command · Ctrl+K palette (noir tui)',\n },\n {\n id: 'palette',\n label: 'All commands (fuzzy palette)',\n hint: 'fuzzy search over every command (noir palette)',\n },\n ],\n },\n];\n\n/**\n * Resolve the curated sections against a LIVE palette command list. Drops any\n * action whose `id` does not exist (graceful degradation) and any section left\n * empty. `dispatch` defaults to the palette entry's argv.\n *\n * @param commands The live palette commands (from\n * `buildPaletteCommands(createProgram())`). bin.ts supplies them to both\n * home.ts and the TUI — this module stays free of a bin.ts import edge (and\n * of the load-time cycle a dynamic `import('../../bin.js')` would create,\n * since bin.ts imports home.ts which imports this module).\n */\nexport async function resolveSections(commands: readonly PaletteCommand[]): Promise<HomeSection[]> {\n const byId = new Map(commands.map((c) => [c.id, c]));\n const out: HomeSection[] = [];\n for (const section of HOME_SECTIONS) {\n const items: HomeAction[] = [];\n for (const action of section.items) {\n const entry = byId.get(action.id);\n if (!entry) continue; // id removed from the tree — degrade, don't crash\n items.push({\n ...action,\n // Resolve the dispatch argv from the registry (never hand-written).\n dispatch: action.dispatch ?? [...entry.argv],\n });\n }\n if (items.length === 0) continue; // section went empty — drop it\n out.push({ ...section, items });\n }\n return out;\n}\n","// S9 — `noir memory {recall,save,sessions,forget,consolidate}`.\n//\n// Thin MCP-client commands over the running daemon's memory engine. Each is\n// a `callDaemonTool` round-trip (or `withDaemon` when capability discovery is\n// needed); the daemon owns the sole store handle, so the CLI never opens it\n// in-process. Daemon-unreachable ⇒ exit 4 (DAEMON_DOWN) from daemon-client.\n//\n// Scriptability (S9 hard rule): `memory save --content` may be supplied by\n// flag; only when it's missing AND the session is interactive do we prompt via\n// @clack (lazy-imported so non-interactive paths never load it). Missing\n// content under non-interactive / --no-input / --json / CI / NO_COLOR ⇒ exit 2\n// (USAGE) naming the missing flag — NO blocking prompt on a pipe. A cancel at\n// the prompt ⇒ exit 5 (CANCELLED).\n//\n// `memory consolidate` is opt-in + provider-explicit (blueprint D5/D6): the\n// daemon registers the `memory_consolidate` tool ONLY when the user set\n// `memory.consolidation.enabled: true` AND a provider+model resolved. Calling a\n// tool the daemon doesn't register would mis-map onto exit 4 (daemon-down), so\n// we discover the daemon's tool list first (caller.listTools) and, if the tool\n// is absent, emit a clear \"not exposed\" message + exit 1 (honest — the daemon IS\n// up, consolidation just isn't enabled). A provider refusal\n// (`{ok:false,reason:'no-provider'|'model-unavailable'|'no-candidates'}`) is\n// honored as exit 1 with the reason; it is NEVER a silent paid call.\n\nimport { readFileSync } from 'node:fs';\nimport { loadProjectInfo, type ProjectInfo } from '@noir-ai/core';\nimport {\n callDaemonTool,\n type DaemonClientOptions,\n type DaemonProbe,\n type DaemonToolCaller,\n probeDaemon,\n probeWorkspaceDaemon,\n type WorkspaceRouting,\n withDaemon,\n withInProcessRead,\n withWorkspaceDaemon,\n withWorkspaceMemoryRead,\n workspaceRoutingTarget,\n} from '../daemon-client.js';\nimport {\n type CliOptions,\n definitionList,\n EXIT,\n fail,\n info,\n isInteractive,\n log,\n table,\n} from '../output.js';\nimport { badge } from '../theme.js';\n\n/** Options accepted by every `memory` sub-command (globals + daemon knobs). */\nexport interface MemoryOptions extends CliOptions, DaemonClientOptions {}\n\n/**\n * Resolve this repo's workspace membership (marker → routing + project), or\n * `null` when it is not joined. Memory commands route to the WORKSPACE daemon\n * when joined (spec §6); context/workflow/task stay per-project.\n */\nfunction resolveWorkspace(): {\n routing: WorkspaceRouting;\n project: ProjectInfo;\n} | null {\n const routing = workspaceRoutingTarget(process.cwd());\n if (routing === null) return null;\n try {\n return { routing, project: loadProjectInfo(process.cwd()) };\n } catch {\n return null;\n }\n}\n\n/** Call a memory tool — workspace daemon when joined, else the project daemon. */\nasync function callMemory<T>(\n opts: MemoryOptions,\n name: string,\n args: Record<string, unknown> = {},\n): Promise<T> {\n const ws = resolveWorkspace();\n if (ws === null) return callDaemonTool<T>(opts, name, args);\n return withWorkspaceDaemon<T>(opts, ws.routing, (caller) => caller.callTool<T>(name, args));\n}\n\n/** Multi-call memory path (capability discovery): workspace daemon when joined. */\nasync function withMemoryDaemon<T>(\n opts: MemoryOptions,\n fn: (caller: DaemonToolCaller) => Promise<T>,\n): Promise<T> {\n const ws = resolveWorkspace();\n if (ws === null) return withDaemon(opts, fn);\n return withWorkspaceDaemon<T>(opts, ws.routing, fn);\n}\n\n// ---------------------------------------------------------------------------\n// Tool result shapes (slices of the daemon wire payloads; CLI depends only on\n// the MCP contract — local types, mirrors context.ts / status.ts).\n// ---------------------------------------------------------------------------\n\n/** A daemon logical-failure envelope, read generically. */\ninterface ToolFailure {\n ok: false;\n degraded?: boolean;\n error?: string;\n reason?: string;\n logged?: boolean;\n}\n\n/** Normalized memory hit (MemoryHit) rendered to humans + JSON. */\nexport interface MemoryHitData {\n id: string;\n type: string;\n score: number;\n content: string;\n concepts: string[];\n files: string[];\n ts: number;\n importance: number;\n source: string;\n}\n\n/** `memory_recall` success payload. */\ninterface MemoryRecallResult {\n ok: true;\n results?: unknown;\n degraded?: boolean;\n}\n\n/** `memory_save` success payload. */\ninterface MemorySaveResult {\n ok: true;\n id?: string;\n observation?: Record<string, unknown>;\n}\n\n/** One row of `memory_sessions`. */\nexport interface SessionRow {\n id: string;\n count: number;\n lastTs: number;\n}\n\n/** `memory_sessions` success payload. */\ninterface MemorySessionsResult {\n ok: true;\n sessions?: unknown;\n}\n\n/** `memory_forget` success payload (ForgetResult). */\ninterface MemoryForgetResult {\n ok: true;\n deleted?: number;\n ids?: unknown;\n}\n\n/** `memory_consolidate` success payload (ConsolidationResult success branch). */\ninterface MemoryConsolidateOk {\n ok: true;\n lessons?: unknown;\n from?: unknown;\n}\n\n/** `memory_consolidate` refusal (ConsolidationResult failure branch — data). */\ninterface MemoryConsolidateRefusal {\n ok: false;\n reason: 'no-provider' | 'model-unavailable' | 'no-candidates';\n logged?: boolean;\n}\n\n// ---------------------------------------------------------------------------\n// Small shared helpers\n// ---------------------------------------------------------------------------\n\n/** Coerce `--limit` (commander string) to a positive int, else exit 2. */\nfunction parseLimit(raw: string | undefined, label: string, opts: CliOptions): number | undefined {\n if (raw === undefined) return undefined;\n const n = Number(raw);\n if (!Number.isInteger(n) || n <= 0) {\n fail(EXIT.USAGE, `${label}: --limit must be a positive integer (got '${raw}')`, opts);\n }\n return n;\n}\n\n/** Split a comma-separated flag value (`--files a,b,c`) into a trimmed list. */\nfunction splitCsv(raw: string | undefined): string[] | undefined {\n if (raw === undefined) return undefined;\n const out = raw\n .split(',')\n .map((s) => s.trim())\n .filter((s) => s.length > 0);\n return out.length > 0 ? out : undefined;\n}\n\n/** Narrow a raw memory hit (MemoryHit) into the rendered {@link MemoryHitData}. */\nfunction toHit(raw: unknown): MemoryHitData {\n const h = (raw ?? {}) as Record<string, unknown>;\n const arr = (v: unknown): string[] =>\n Array.isArray(v) ? (v.filter((x) => typeof x === 'string') as string[]) : [];\n return {\n id: typeof h.id === 'string' ? h.id : '',\n type: typeof h.type === 'string' ? h.type : '',\n score: typeof h.score === 'number' ? h.score : 0,\n content: typeof h.content === 'string' ? h.content : '',\n concepts: arr(h.concepts),\n files: arr(h.files),\n ts: typeof h.ts === 'number' ? h.ts : 0,\n importance: typeof h.importance === 'number' ? h.importance : 0,\n source: typeof h.source === 'string' ? h.source : '',\n };\n}\n\n/** Surface a daemon logical-failure envelope as exit 1 (daemon was reachable). */\nfunction failTool(label: string, envelope: ToolFailure, opts: CliOptions): never {\n const detail = envelope.error ?? envelope.reason ?? 'unknown failure';\n fail(EXIT.ERROR, `${label}: ${detail}`, opts);\n}\n\n/** Render an epoch-ms as a short ISO-ish stamp for human tables. */\nfunction stamp(ts: number): string {\n if (typeof ts !== 'number' || ts <= 0) return '-';\n // UTC ISO (no tz surprises); clipped for table density.\n return new Date(ts).toISOString().replace('T', ' ').replace(/\\..*$/, 'Z');\n}\n\n// ---------------------------------------------------------------------------\n// `noir memory recall <query> [--limit N]`\n// ---------------------------------------------------------------------------\nexport interface MemoryRecallOptions extends MemoryOptions {\n query: string;\n limit?: string;\n}\n\n/**\n * Run `memory_recall` against the daemon when it is up, or fall back to the\n * IN-PROCESS read-only memory engine when the daemon probe reports it down\n * (S9 DS-5). Reads degrade to the read-only store (never exit 4); writes\n * (`memory save` / `forget` / `consolidate`) keep the daemon-required path.\n * The probe is conservative (mirrors contextSearch): only a CONFIRMED\n * `{running:false}` engages the fallback; an unavailable probe defaults to the\n * daemon path.\n */\nexport async function memoryRecall(opts: MemoryRecallOptions): Promise<void> {\n const limit = parseLimit(opts.limit, 'memory recall', opts);\n // Workspace mode: route to the workspace daemon / workspace read-only store.\n const ws = resolveWorkspace();\n if (ws !== null) {\n const probe = await probeWorkspaceDaemon(ws.routing);\n if (!probe.running) {\n await withWorkspaceMemoryRead(opts, ws.routing, ws.project, async (memory) => {\n const { hits, degraded, mode } = await memory.recallWithMeta(opts.query, {\n ...(limit === undefined ? {} : { limit }),\n });\n const data = { query: opts.query, hits, degraded, mode };\n if (opts.json === true) {\n process.stdout.write(`${JSON.stringify({ ok: true, data })}\\n`);\n return;\n }\n renderRecall(data.query, data.hits, data.degraded, opts);\n });\n return;\n }\n const res = await callMemory<MemoryRecallResult | ToolFailure>(opts, 'memory_recall', {\n query: opts.query,\n ...(limit === undefined ? {} : { limit }),\n });\n if (res.ok !== true) failTool('memory recall', res, opts);\n const hits = Array.isArray(res.results) ? (res.results as unknown[]).map(toHit) : [];\n const data = { query: opts.query, hits, degraded: res.degraded === true };\n if (opts.json === true) {\n process.stdout.write(`${JSON.stringify({ ok: true, data })}\\n`);\n return;\n }\n renderRecall(data.query, hits, data.degraded, opts);\n return;\n }\n let probe: DaemonProbe;\n try {\n probe = await probeDaemon(opts);\n } catch {\n probe = { running: true };\n }\n if (!probe.running) {\n await withInProcessRead(opts, async (engines) => {\n const { hits, degraded, mode } = await engines.memory.recallWithMeta(opts.query, {\n ...(limit === undefined ? {} : { limit }),\n });\n // Honest per-call outcome: this branch runs because the daemon is DOWN\n // (read-only fallback), AND the recall itself reports its own degraded\n // (BM25-only) state — both feed the rendered flag.\n const data = { query: opts.query, hits, degraded, mode };\n if (opts.json === true) {\n process.stdout.write(`${JSON.stringify({ ok: true, data })}\\n`);\n return;\n }\n renderRecall(data.query, data.hits, data.degraded, opts);\n });\n return;\n }\n const res = await callDaemonTool<MemoryRecallResult | ToolFailure>(opts, 'memory_recall', {\n query: opts.query,\n ...(limit === undefined ? {} : { limit }),\n });\n if (res.ok !== true) failTool('memory recall', res, opts);\n\n const hits = Array.isArray(res.results) ? (res.results as unknown[]).map(toHit) : [];\n const data = { query: opts.query, hits, degraded: res.degraded === true };\n\n if (opts.json === true) {\n process.stdout.write(`${JSON.stringify({ ok: true, data })}\\n`);\n return;\n }\n renderRecall(data.query, hits, data.degraded, opts);\n}\n\nfunction renderRecall(\n query: string,\n hits: MemoryHitData[],\n degraded: boolean,\n opts: CliOptions,\n): void {\n const flag = degraded ? ` ${badge('warn', 'degraded: BM25-only')}` : '';\n log(\n `memory recall — ${hits.length} hit${hits.length === 1 ? '' : 's'} for '${query}'${flag}`,\n opts,\n );\n if (hits.length === 0) {\n info('(no memories matched)', opts);\n return;\n }\n // Full content per hit (never truncate the DATA; display shows it whole\n // in a readable block rather than a cramped table cell). The block-list shape\n // is load-bearing — do NOT sweep this into the responsive table().\n for (let i = 0; i < hits.length; i++) {\n const h = hits[i];\n if (h === undefined) continue;\n const head = `[${i + 1}] ${h.type} · score ${h.score.toFixed(4)} · importance ${h.importance.toFixed(2)} · ${h.id}`;\n log(head, opts);\n if (h.files.length > 0) log(` files: ${h.files.join(', ')}`, opts);\n if (h.concepts.length > 0) log(` tags: ${h.concepts.join(', ')}`, opts);\n log(` ${h.content}`, opts);\n }\n}\n\n// ---------------------------------------------------------------------------\n// `noir memory save [--content] [--type] [--files]`\n// ---------------------------------------------------------------------------\nexport interface MemorySaveOptions extends MemoryOptions {\n content?: string;\n type?: string;\n files?: string;\n}\n\nexport async function memorySave(opts: MemorySaveOptions): Promise<void> {\n const content = await resolveContent(opts);\n const files = splitCsv(opts.files);\n const args: Record<string, unknown> = { content };\n if (typeof opts.type === 'string' && opts.type.length > 0) args.type = opts.type;\n if (files !== undefined) args.files = files;\n\n const res = await callMemory<MemorySaveResult | ToolFailure>(opts, 'memory_save', args);\n if (res.ok !== true) failTool('memory save', res, opts);\n\n const id = typeof res.id === 'string' ? res.id : '';\n const observation = res.observation ?? {};\n const data = { id, observation };\n\n if (opts.json === true) {\n process.stdout.write(`${JSON.stringify({ ok: true, data })}\\n`);\n return;\n }\n log(`Saved memory ${id}.`, opts);\n renderObservation(observation, opts);\n}\n\n/**\n * Resolve `--content`: from the flag when given; otherwise prompt interactively\n * (only when the session is interactive); otherwise exit 2 naming the flag. The\n * @clack import is lazy so a scripted / CI / --json run never loads it, and a\n * cancel at the prompt maps to exit 5.\n */\nasync function resolveContent(opts: MemorySaveOptions): Promise<string> {\n if (typeof opts.content === 'string' && opts.content.length > 0) return opts.content;\n if (!isInteractive(opts)) {\n fail(\n EXIT.USAGE,\n 'memory save requires --content <text> (or re-run in an interactive terminal to be prompted)',\n opts,\n );\n }\n const clack = await import('@clack/prompts');\n const value = await clack.text({\n message: 'Memory to save:',\n placeholder: 'the insight / decision / pattern to remember',\n validate: (v: string | undefined) =>\n !v || v.trim().length === 0 ? 'content cannot be empty' : undefined,\n });\n if (clack.isCancel(value)) {\n clack.cancel('Cancelled.');\n fail(EXIT.CANCELLED, 'cancelled', opts);\n }\n return String(value);\n}\n\nfunction renderObservation(obs: Record<string, unknown>, opts: CliOptions): void {\n const rows: Array<{ label: string; value: unknown }> = [];\n for (const key of ['id', 'type', 'importance', 'ts', 'source', 'project', 'sessionId']) {\n if (obs[key] !== undefined) rows.push({ label: key, value: obs[key] });\n }\n if (rows.length > 0) definitionList(rows, opts);\n const content = obs.content;\n if (typeof content === 'string') log(`\\n${content}`, opts);\n}\n\n// ---------------------------------------------------------------------------\n// `noir memory capture [file]` — manual transcript/notes distill (S9)\n// ---------------------------------------------------------------------------\nexport interface MemoryCaptureOptions extends MemoryOptions {\n /** A transcript/notes file to distill (or pipe stdin). */\n file?: string;\n /** Inline distilled content (overrides file/stdin). */\n content?: string;\n /** Capture hook label for provenance (defaults to 'Stop'). */\n eventType?: string;\n}\n\nexport async function memoryCapture(opts: MemoryCaptureOptions): Promise<void> {\n const content = await resolveCaptureContent(opts);\n const args: Record<string, unknown> = { content };\n if (typeof opts.eventType === 'string' && opts.eventType.length > 0)\n args.eventType = opts.eventType;\n\n const res = await callMemory<MemorySaveResult | ToolFailure>(opts, 'memory_capture', args);\n if (res.ok !== true) failTool('memory capture', res, opts);\n\n const id = typeof res.id === 'string' ? res.id : '';\n const observation = res.observation ?? {};\n if (opts.json === true) {\n process.stdout.write(`${JSON.stringify({ ok: true, data: { id, observation } })}\\n`);\n return;\n }\n log(`Captured memory ${id}.`, opts);\n renderObservation(observation, opts);\n}\n\n/**\n * Resolve capture content: `--content` > `--file` (read the file) > piped stdin\n * > interactive prompt. Missing all sources under non-interactive ⇒ exit 2.\n */\nasync function resolveCaptureContent(opts: MemoryCaptureOptions): Promise<string> {\n if (typeof opts.content === 'string' && opts.content.length > 0) return opts.content;\n if (typeof opts.file === 'string' && opts.file.length > 0) {\n try {\n return readFileSync(opts.file, 'utf8');\n } catch {\n fail(EXIT.USAGE, `memory capture could not read --file ${opts.file}`, opts);\n }\n }\n if (!process.stdin.isTTY) {\n // A non-TTY stdin can still be unreadable (closed fd 0, EAGAIN under CI).\n // Route that through fail() so `--json` gets its {ok:false} envelope instead\n // of a raw readFileSync error on stderr.\n try {\n return readFileSync(0, 'utf8');\n } catch {\n fail(\n EXIT.USAGE,\n 'memory capture could not read piped stdin — pass --content <text> or --file <path>.',\n opts,\n );\n }\n }\n if (!isInteractive(opts)) {\n fail(\n EXIT.USAGE,\n 'memory capture requires --content <text> or --file <path> (or piped stdin).',\n opts,\n );\n }\n const clack = await import('@clack/prompts');\n const value = await clack.text({ message: 'Captured memory content:' });\n if (clack.isCancel(value)) {\n clack.cancel('Cancelled.');\n fail(EXIT.CANCELLED, 'cancelled', opts);\n }\n return String(value);\n}\n\n// ---------------------------------------------------------------------------\n// `noir memory sessions`\n// ---------------------------------------------------------------------------\nexport async function memorySessions(opts: MemoryOptions): Promise<void> {\n const ws = resolveWorkspace();\n if (ws !== null) {\n const probe = await probeWorkspaceDaemon(ws.routing);\n if (!probe.running) {\n await withWorkspaceMemoryRead(opts, ws.routing, ws.project, async (memory) => {\n const sessions: SessionRow[] = memory.sessions().map((s) => ({\n id: s.id,\n count: s.count,\n lastTs: s.lastTs,\n }));\n const data = { sessions };\n if (opts.json === true) {\n process.stdout.write(`${JSON.stringify({ ok: true, data })}\\n`);\n return;\n }\n renderSessions(sessions, opts);\n });\n return;\n }\n const res = await callMemory<MemorySessionsResult | ToolFailure>(opts, 'memory_sessions');\n if (res.ok !== true) failTool('memory sessions', res, opts);\n const sessions: SessionRow[] = Array.isArray(res.sessions)\n ? (res.sessions as unknown[]).map((raw) => {\n const s = (raw ?? {}) as Record<string, unknown>;\n return {\n id: typeof s.id === 'string' ? s.id : '',\n count: typeof s.count === 'number' ? s.count : 0,\n lastTs: typeof s.lastTs === 'number' ? s.lastTs : 0,\n };\n })\n : [];\n const data = { sessions };\n if (opts.json === true) {\n process.stdout.write(`${JSON.stringify({ ok: true, data })}\\n`);\n return;\n }\n renderSessions(sessions, opts);\n return;\n }\n let probe: DaemonProbe;\n try {\n probe = await probeDaemon(opts);\n } catch {\n probe = { running: true };\n }\n if (!probe.running) {\n await withInProcessRead(opts, async (engines) => {\n const raw = engines.memory.sessions();\n const sessions: SessionRow[] = raw.map((s) => ({\n id: s.id,\n count: s.count,\n lastTs: s.lastTs,\n }));\n const data = { sessions };\n if (opts.json === true) {\n process.stdout.write(`${JSON.stringify({ ok: true, data })}\\n`);\n return;\n }\n renderSessions(sessions, opts);\n });\n return;\n }\n const res = await callDaemonTool<MemorySessionsResult | ToolFailure>(opts, 'memory_sessions');\n if (res.ok !== true) failTool('memory sessions', res, opts);\n\n const sessions: SessionRow[] = Array.isArray(res.sessions)\n ? (res.sessions as unknown[]).map((raw) => {\n const s = (raw ?? {}) as Record<string, unknown>;\n return {\n id: typeof s.id === 'string' ? s.id : '',\n count: typeof s.count === 'number' ? s.count : 0,\n lastTs: typeof s.lastTs === 'number' ? s.lastTs : 0,\n };\n })\n : [];\n const data = { sessions };\n if (opts.json === true) {\n process.stdout.write(`${JSON.stringify({ ok: true, data })}\\n`);\n return;\n }\n renderSessions(sessions, opts);\n}\n\n/** Render the sessions list (human table to stderr; --json handled by caller). */\nfunction renderSessions(sessions: SessionRow[], opts: CliOptions): void {\n log(`memory sessions — ${sessions.length} session${sessions.length === 1 ? '' : 's'}`, opts);\n table(\n sessions.map((s) => ({ Session: s.id, Observations: s.count, 'Last seen': stamp(s.lastTs) })),\n ['Session', 'Observations', 'Last seen'],\n opts,\n );\n}\n\n// ---------------------------------------------------------------------------\n// `noir memory forget <id> [<id> ...]`\n// ---------------------------------------------------------------------------\nexport interface MemoryForgetOptions extends MemoryOptions {\n /** Positional observation ids. */\n ids: string[];\n}\n\nexport async function memoryForget(opts: MemoryForgetOptions): Promise<void> {\n if (opts.ids.length === 0) {\n fail(EXIT.USAGE, 'memory forget requires at least one <id>', opts);\n }\n const res = await callMemory<MemoryForgetResult | ToolFailure>(opts, 'memory_forget', {\n ids: opts.ids,\n });\n if (res.ok !== true) failTool('memory forget', res, opts);\n\n const deleted = typeof res.deleted === 'number' ? res.deleted : 0;\n const data = { deleted, ids: opts.ids };\n\n if (opts.json === true) {\n process.stdout.write(`${JSON.stringify({ ok: true, data })}\\n`);\n return;\n }\n log(`Forgot ${deleted} observation${deleted === 1 ? '' : 's'}.`, opts);\n}\n\n// ---------------------------------------------------------------------------\n// `noir memory consolidate [--types <csv>] [--limit N]`\n// ---------------------------------------------------------------------------\nexport interface MemoryConsolidateOptions extends MemoryOptions {\n /** Comma-separated type filter (mapped to the daemon's `types[]`). */\n types?: string;\n limit?: string;\n}\n\nexport async function memoryConsolidate(opts: MemoryConsolidateOptions): Promise<void> {\n // Capability discovery (spec: \"only if the daemon exposes it — else a clear\n // message\"): a daemon that didn't opt into consolidation registers no\n // `memory_consolidate` tool. Detecting that via listTools lets us say so\n // honestly instead of calling a missing tool (which would mis-map to exit 4).\n const exposed = await withMemoryDaemon(opts, async (caller) => caller.listTools());\n if (!exposed.includes('memory_consolidate')) {\n fail(\n EXIT.ERROR,\n resolveWorkspace() !== null\n ? 'memory consolidate is not supported on shared workspaces (the workspace memory store has no consolidation model).'\n : 'memory consolidate: the daemon does not expose the memory_consolidate tool. Enable it in .noir/config under memory.consolidation (enabled: true + a provider + model), then restart the daemon.',\n opts,\n );\n }\n\n const types = splitCsv(opts.types);\n const limit = parseLimit(opts.limit, 'memory consolidate', opts);\n const args: Record<string, unknown> = {};\n if (types !== undefined) args.types = types;\n if (limit !== undefined) args.limit = limit;\n\n const res = await callMemory<MemoryConsolidateOk | MemoryConsolidateRefusal | ToolFailure>(\n opts,\n 'memory_consolidate',\n args,\n );\n if (res.ok === true) {\n const lessons = Array.isArray(res.lessons) ? (res.lessons as unknown[]) : [];\n const from = Array.isArray(res.from) ? (res.from as unknown[]) : [];\n const data = { lessons, from };\n if (opts.json === true) {\n process.stdout.write(`${JSON.stringify({ ok: true, data })}\\n`);\n return;\n }\n log(\n `Consolidated ${lessons.length} lesson${lessons.length === 1 ? '' : 's'} from ${from.length} observation${from.length === 1 ? '' : 's'}.`,\n opts,\n );\n for (let i = 0; i < lessons.length; i++) {\n const l = lessons[i];\n if (l === undefined) continue;\n const obs = (l ?? {}) as Record<string, unknown>;\n const id = typeof obs.id === 'string' ? obs.id : `<lesson ${i + 1}>`;\n const content = typeof obs.content === 'string' ? obs.content : '';\n log(`- ${id}: ${content}`, opts);\n }\n return;\n }\n\n // Refusal (no-provider / model-unavailable / no-candidates) or a degraded\n // envelope. Both are honest exit-1 outcomes — consolidation did NOT run. Read\n // via a record cast so the picks are valid across the refusal + ToolFailure\n // union members (they don't all carry `error` / `degraded`).\n const env = res as unknown as Record<string, unknown>;\n const reason =\n (typeof env.reason === 'string' ? env.reason : undefined) ??\n (typeof env.error === 'string' ? env.error : undefined) ??\n 'unknown';\n const logged = env.logged === true || env.degraded === true;\n const suffix = logged ? ' (logged)' : '';\n fail(EXIT.ERROR, `memory consolidate did not run: ${reason}${suffix}`, opts);\n}\n","// c4-release-phase — `noir release [<version>] [--channel beta|stable]`.\n// A guided orchestrator over the existing patch-release flow (CLAUDE.md).\n// Walks the checklist; hands off at human-approval gates. The FSM release\n// phase (optional, done→released) is documented in the design spec but not\n// yet wired — this CLI is the release tool the roadmap delta called for.\n// Build-once / idempotent: bump-version.mjs is idempotent; release:tag\n// refuses dirty/unpushed; tags are immutable (never reuse — deprecate+patch).\n\nimport { execSync, spawnSync } from 'node:child_process';\nimport { type CliOptions, EXIT, fail, info, log, success, tip, warn } from '../output.js';\n\nexport interface ReleaseOptions extends CliOptions {\n version?: string;\n channel?: string;\n dryRun?: boolean;\n}\n\ntype Step =\n | 'preflight'\n | 'bump'\n | 'gate'\n | 'commit'\n | 'ci-develop'\n | 'beta-tag'\n | 'human-approve-beta'\n | 'merge-main'\n | 'ci-main'\n | 'stable-tag'\n | 'human-approve-stable'\n | 'dist-bump'\n | 'sync';\n\n/** Report what step does and who runs it. */\nfunction describe(step: Step, who: 'noir' | 'human'): string {\n const m: Record<Step, string> = {\n preflight: 'check clean tree, on develop, HEAD pushed, gate green, no version collision',\n bump: 'run bump-version.mjs + update CHANGELOG + roadmap docs',\n gate: 're-run the full gate (lint/build/typecheck/test/docs:validate)',\n commit: 'commit chore(release) + push develop',\n 'ci-develop': 'wait for CI on develop → green',\n 'beta-tag': 'pnpm release:tag → beta tag + push',\n 'human-approve-beta': 'approve the release workflow publish job in GitHub Actions',\n 'merge-main': 'merge develop → main (fast-forward) + push',\n 'ci-main': 'wait for CI on main → green',\n 'stable-tag': 'pnpm release:tag → stable tag + push',\n 'human-approve-stable': 'approve the release workflow publish job in GitHub Actions (again)',\n 'dist-bump':\n 'update Homebrew (packaging/homebrew/noir.rb) + Scoop (packaging/scoop/noir.json) from npm',\n sync: 'merge main → develop + verify both branches at same SHA',\n };\n return `${m[step]} [${who}]`;\n}\n\nconst ALL: Step[] = [\n 'preflight',\n 'bump',\n 'gate',\n 'commit',\n 'ci-develop',\n 'beta-tag',\n 'human-approve-beta',\n 'merge-main',\n 'ci-main',\n 'stable-tag',\n 'human-approve-stable',\n 'dist-bump',\n 'sync',\n];\n\nexport async function release(opts: ReleaseOptions): Promise<void> {\n if (opts.dryRun) {\n log('noir release --dry-run (no changes will be made)', opts);\n for (const s of ALL) {\n const who: 'noir' | 'human' = s.startsWith('human-approve') ? 'human' : 'noir';\n info(`${s}: ${describe(s, who)}`, opts);\n }\n tip('full release flow documented in CLAUDE.md \"Patch release flow (beta → stable)\"', opts);\n return;\n }\n\n const version = opts.version?.trim();\n if (!version) {\n fail(EXIT.USAGE, 'release: <version> is required (e.g. noir release 1.10.0)', opts);\n }\n const channel = opts.channel === 'stable' ? 'stable' : 'beta';\n\n log(`noir release ${version} (${channel} channel)`, opts);\n\n // Run each step; hand off at human gates. Failures surface clearly.\n try {\n // 1. Preflight\n info(`[1/13] preflight: ${describe('preflight', 'noir')}`, opts);\n execSync('git diff --quiet', { encoding: 'utf8' });\n const branch = execSync('git branch --show-current', { encoding: 'utf8' }).trim();\n if (branch !== 'develop') fail(EXIT.ERROR, 'release: must be on develop', opts);\n const status = execSync('git status --porcelain', { encoding: 'utf8' }).trim();\n if (status) fail(EXIT.ERROR, 'release: tree must be clean', opts);\n success('preflight: ✓ clean, on develop', opts);\n\n // 2. Bump\n info(`[2/13] bump: ${describe('bump', 'noir')}`, opts);\n spawnSync('node', ['scripts/bump-version.mjs', version], {\n encoding: 'utf8',\n stdio: 'inherit',\n });\n success(`bump: ✓ version ${version}`, opts);\n\n // 3. Gate\n info(`[3/13] gate: ${describe('gate', 'noir')}`, opts);\n execSync('pnpm lint && pnpm build && pnpm typecheck && pnpm test && pnpm docs:validate', {\n encoding: 'utf8',\n stdio: 'inherit',\n });\n success('gate: ✓ full gate green', opts);\n\n // 4. Commit (spawnSync — no shell, no injection).\n info(`[4/13] commit/push: ${describe('commit', 'noir')}`, opts);\n spawnSync('git', ['add', '-A'], { encoding: 'utf8', stdio: 'inherit' });\n spawnSync('git', ['commit', '-m', `chore(release): v${version} + docs sync`], {\n encoding: 'utf8',\n stdio: 'inherit',\n });\n execSync('git push origin develop', { encoding: 'utf8' });\n success('commit: ✓ pushed to develop', opts);\n\n // 5-6. CI wait + beta tag\n info(`[5/13] ci-develop: waiting for CI on develop…`, opts);\n info(`[6/13] beta-tag: ${describe('beta-tag', 'noir')}`, opts);\n tip('after CI green: run `pnpm release:tag` and push the beta tag', opts);\n\n // 7. Human handoff\n warn(`[7/13] ${describe('human-approve-beta', 'human')}`, opts);\n tip('open GitHub Actions → approve the publish job, then continue', opts);\n tip('after approval: verify `npm view @noir-ai/cli dist-tags beta` = beta version', opts);\n\n // 8-13 (remaining steps — documented for human continuation)\n info('remaining steps (merge→stable→dist→sync): see CLAUDE.md', opts);\n for (const s of ALL.slice(7)) {\n const who: 'noir' | 'human' = s.startsWith('human-approve') ? 'human' : 'noir';\n info(` ${s}: ${describe(s, who)}`, opts);\n }\n\n success(`release ${version}: preflight→bump→gate→commit done. Resume after approval.`, opts);\n } catch (err) {\n fail(EXIT.ERROR, `release failed: ${err instanceof Error ? err.message : String(err)}`, opts);\n }\n}\n","// v2 — `noir run <prompt>`: drive the host agentic CLI headless and render its\n// stream-json. This is the programmatic host-driving line (roadmap v2.0) and the\n// v2 orchestrator surface: Noir spawns the host as a subprocess (Archetype B),\n// streams its output, and reports the token/cost from the `result` event — it\n// never runs its own model + tool loop (D5).\n//\n// Custom command (D2a): `--command <binary>` lets users with multiple host\n// profiles (e.g. two Claude Code installs, `claude` vs `claude-work`) point the\n// orchestrator at their own binary without restarting the terminal. The host\n// default is used when `--command` is absent.\n//\n// Contract: `--json` emits one `{ok,data}` envelope to stdout (scriptable);\n// otherwise the host's assistant text streams to stdout and the token/cost\n// summary + transcript path go to stderr. A transcript of the raw stream-json is\n// always persisted to `.noir/transcripts/`.\n\nimport { existsSync, mkdirSync, writeFileSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { type HostId, SUPPORTED_HOSTS } from '@noir-ai/adapters';\nimport { loadNoirEnv, NOIR_DIR, parseConfig } from '@noir-ai/core';\nimport {\n type NoirEvent,\n type RunHostResult,\n runHost,\n type UsageSnapshot,\n} from '../orchestrator.js';\nimport { type CliOptions, EXIT, fail, json, log, success } from '../output.js';\nimport { loadRunConfig, resolveRunProfile } from '../run-profiles.js';\n\n/**\n * Anthropic credential / gateway variables that change how a headless (`-p`)\n * host run authenticates. A custom gateway sets `ANTHROPIC_AUTH_TOKEN` +\n * `ANTHROPIC_BASE_URL` and fails exactly like a stale API key, so the auth\n * advice must cover every recognised shape — not just `ANTHROPIC_API_KEY`.\n */\nconst CREDENTIAL_ENV_VARS = [\n 'ANTHROPIC_API_KEY',\n 'ANTHROPIC_AUTH_TOKEN',\n 'ANTHROPIC_BASE_URL',\n] as const;\n\n/**\n * The auth addendum that names each credential variable in effect AND the\n * source that won for it (`.noir/.env` vs the environment), so the \"unset it\"\n * advice stays actionable: after consolidation `applyNoirEnv` re-injects a\n * file-scoped key on every invocation, so shell-level unsetting does nothing —\n * the message must point at the file (spec 13.2).\n *\n * NAMES AND SOURCES ONLY (spec G4): the message is loggable and shareable, so\n * no branch here may ever print a variable's value. Returns `''` when no\n * recognised credential variable is set.\n */\nfunction credentialNote(\n env: Record<string, string | undefined>,\n sources: Record<string, 'file' | 'env'>,\n): string {\n const named = CREDENTIAL_ENV_VARS.filter((name) => {\n const value = env[name];\n return value !== undefined && value.length > 0;\n }).map(\n (name) => `${name} (from ${sources[name] === 'file' ? `${NOIR_DIR}/.env` : 'the environment'})`,\n );\n if (named.length === 0) return '';\n const one = named.length === 1;\n const subject = one ? `${named[0]} is set` : `${named.join(', ')} are set`;\n const pronoun = one ? 'it' : 'them';\n const verb = one ? 'overrides' : 'override';\n return (\n ` Note: ${subject} — ${pronoun} ${verb} the logged-in account in \\`-p\\` mode; ` +\n `unset ${pronoun} in the named source (or fix the value) if you meant to use your subscription.`\n );\n}\n\n/** Options accepted by `noir run` (globals + host/command/profile knobs). */\nexport interface RunOptions extends CliOptions {\n /** Host to drive (default `claude`). */\n readonly host?: string;\n /** Custom host binary overriding the per-host default (D2a). */\n readonly command?: string;\n /** Named run profile from .noir/config.yml `run.profiles` (D). */\n readonly profile?: string;\n}\n\n/** A single-row token/cost summary (human-readable). */\nfunction formatUsage(u: UsageSnapshot): string {\n const cost = u.totalCostUsd > 0 ? ` $${u.totalCostUsd.toFixed(2)}` : '';\n const turns = u.numTurns > 0 ? ` · ${u.numTurns} turns` : '';\n return `${u.inputTokens.toLocaleString()} in / ${u.outputTokens.toLocaleString()} out${cost}${turns}`;\n}\n\n/**\n * Stream an assistant text delta to stdout (non-json mode only). The host's\n * answer is data, so it goes to stdout; diagnostics go to stderr.\n */\nfunction streamEvent(event: NoirEvent, opts: RunOptions): void {\n if (opts.json === true) return; // json mode buffers; no streaming writes\n // API-error assistant text (e.g. \"Not logged in · Please run /login\") is a\n // diagnostic, not the answer — never stream it to the data channel.\n if (event.kind === 'assistant' && event.text && event.text.length > 0 && event.isError !== true) {\n process.stdout.write(event.text);\n }\n}\n\n/**\n * Run the host headless and report. Rejects are translated to a clean CLI\n * failure (exit 1) rather than an unhandled rejection.\n */\nexport async function run(prompt: string, opts: RunOptions): Promise<void> {\n const host = (opts.host ?? 'claude') as HostId;\n if (!(SUPPORTED_HOSTS as readonly string[]).includes(host)) {\n fail(EXIT.USAGE, `unknown host '${host}' (supported: ${SUPPORTED_HOSTS.join(', ')})`, opts);\n }\n if (prompt.length === 0) {\n const selectors: string[] = [];\n if (opts.command) selectors.push(`--command ${opts.command}`);\n if (opts.profile) selectors.push(`--profile ${opts.profile}`);\n const usage =\n selectors.length > 0 ? `noir run ${selectors.join(' ')} <prompt>` : 'noir run <prompt>';\n fail(EXIT.USAGE, `a prompt is required: \\`${usage}\\``, opts);\n }\n\n const root = process.cwd();\n // Credential provenance for the failure advice: `sources` records, per key,\n // whether `.noir/.env` or the ambient environment won (spec 12.4). Names\n // only — never a value. Read from `process.env`, which the bin's preAction\n // has already overlaid with `.noir/.env` (spec 12.1: the file wins).\n const envSources = loadNoirEnv(root).sources;\n\n // Run-profile resolution: --profile > NOIR_PROFILE > run.defaultProfile >\n // built-in default. Config load is best-effort — `noir run` keeps working\n // outside an initialized project (no profiles, built-in host behavior).\n const config = loadRunConfig(root) ?? parseConfig({});\n const resolved = resolveRunProfile(opts.profile, config, process.env);\n if (!resolved.ok) fail(EXIT.USAGE, resolved.message, opts);\n const profile = resolved.profile;\n // An explicit `--command` (per-invocation override) wins over a profile's\n // binary; the profile's binary is the fallback when --command is absent.\n const customBinary = opts.command ?? profile.binary;\n const extraArgs = profile.args;\n const env = profile.env ? mergeEnv(process.env, profile.env) : undefined;\n\n // Spec 13.3: running outside an initialized project stays supported, but the\n // gap deserves a word — with no `.noir/.env` there are no project\n // credentials, so an auth failure would read as \"noir is broken\" instead of\n // \"this project has none\". One informational stderr line, BEFORE the spawn:\n // never a failure, never a prompt, and silenced by `log()` under\n // --json/--quiet so a machine consumer's output stays pristine.\n if (!existsSync(join(root, NOIR_DIR, '.env'))) {\n log(\n `This project has no ${NOIR_DIR}/.env — that is where Noir reads project credentials and ` +\n `run config from. Run \\`noir init\\` to scaffold one (\\`noir run\\` works without it).`,\n opts,\n );\n }\n\n const transcriptLines: string[] = [];\n\n let result: RunHostResult;\n try {\n result = await runHost({\n host,\n prompt,\n customBinary,\n extraArgs,\n env,\n onLine: (line) => transcriptLines.push(line),\n onEvent: (event) => streamEvent(event, opts),\n });\n } catch (err) {\n const binary = customBinary && customBinary.length > 0 ? customBinary : host;\n const detail = err instanceof Error ? err.message : String(err);\n const enoent = (err as NodeJS.ErrnoException)?.code === 'ENOENT';\n const guidance = enoent\n ? ` No executable '${binary}' was found. Shell aliases and functions (e.g. from .zshrc) are invisible to noir — use an executable on PATH, an absolute path, or a launcher script such as ~/.local/bin/${binary}.`\n : '';\n const subject =\n customBinary && customBinary.length > 0\n ? `custom command '${customBinary}'`\n : `host '${host}'`;\n fail(EXIT.ERROR, `failed to run ${subject}: ${detail}.${guidance}`, opts);\n }\n\n const transcript = writeTranscript(host, transcriptLines);\n const failed = result.exitCode !== 0 || result.isError;\n\n if (failed) {\n // A failed host run is an error, not a success: exit 1, {ok:false} under\n // --json, and no misleading \"usage\" line. The raw stream-json transcript is\n // still persisted (it is the audit record) and referenced in the message.\n const binary = customBinary && customBinary.length > 0 ? customBinary : host;\n const reason =\n result.errorText && result.errorText.trim().length > 0\n ? result.errorText.trim()\n : result.stderr.trim() || `exit code ${result.exitCode}`;\n // Auth guidance is keyed off the stream's error CATEGORY (authoritative),\n // falling back to a text heuristic only when the category is absent. The\n // login hint names the RESOLVED binary, not a literal 'claude'.\n const isAuth =\n result.errorCategory === 'authentication_failed' ||\n result.errorCategory === 'oauth_org_not_allowed' ||\n /not logged|login|authenticate|invalid api key/i.test(reason);\n let message = `host '${binary}' failed (exit ${result.exitCode}): ${reason}`;\n if (isAuth) {\n message += ` Open a terminal and run \\`${binary} /login\\` (interactive-only — it cannot run inside \\`noir run\\`), then retry.`;\n message += credentialNote(env ?? process.env, envSources);\n }\n message += ` If you use another profile, pass \\`--command <binary>\\` or define a run profile under run.profiles. transcript: ${transcript}`;\n fail(EXIT.ERROR, message, opts);\n }\n\n if (opts.json === true) {\n json({\n ok: true,\n data: {\n host,\n prompt,\n exitCode: result.exitCode,\n usage: result.usage,\n numTurns: result.usage.numTurns,\n events: result.eventCount,\n transcript,\n },\n });\n return;\n }\n\n // Separator so the streamed answer and the summary don't run together.\n process.stdout.write('\\n');\n success(`usage: ${formatUsage(result.usage)} (API-equivalent estimate, not billed)`, opts);\n log(`transcript: ${transcript}`, opts);\n}\n\n/** Merge a profile's env overlay over the base env; `undefined` values delete the key. */\nexport function mergeEnv(\n base: Record<string, string | undefined>,\n overlay: Record<string, string | undefined>,\n): Record<string, string | undefined> {\n const merged = { ...base, ...overlay };\n return Object.fromEntries(Object.entries(merged).filter(([, v]) => v !== undefined));\n}\n\n/** Persist the raw stream-json lines to `.noir/transcripts/<host>-<ts>.jsonl`. */\nfunction writeTranscript(host: string, lines: readonly string[]): string {\n const ts = new Date().toISOString().replace(/[:.]/g, '-');\n const dir = join(process.cwd(), '.noir', 'transcripts');\n const file = join(dir, `${host}-${ts}.jsonl`);\n try {\n // Transcripts contain raw host prompts/output (may include secrets) — create\n // the dir 0700 and the file 0600 so they are not group/world-readable.\n mkdirSync(dir, { recursive: true, mode: 0o700 });\n writeFileSync(file, `${lines.join('\\n')}${lines.length > 0 ? '\\n' : ''}`, { mode: 0o600 });\n } catch {\n // Transcript persistence is best-effort — a read-only .noir/ must not fail\n // the run.\n return '(not persisted)';\n }\n return file;\n}\n","// v2 — the host orchestrator (Archetype B). Drives the host agentic CLI as a\n// headless subprocess and consumes its `stream-json` event stream, rather than\n// Noir running its own model + tool loop (which D5 forbids).\n//\n// This module is the PURE, testable core:\n// - `resolveHostRun` — the spawn command for a host (custom binary wins over\n// the host default, so users with multiple profiles — e.g. `claude` vs\n// `claude-work` — can point Noir at their own binary without a restart).\n// - `parseStreamLine` / `normalizeStreamEvent` — map a raw `stream-json` line\n// to a small `NoirEvent` union (the `init`/`assistant`/`result` payloads are\n// the stable, shared contract across hosts).\n// - `UsageReducer` — accumulates token/cost with the `max usage per\n// message.id` rule (Claude emits one JSONL line PER content block of an\n// assistant message, each line's `usage` a CUMULATIVE snapshot of that\n// message — summing lines over-counts ~2.5-3x).\n// - `runHost` — the spawn + readline integration over that core.\n\nimport { spawn } from 'node:child_process';\nimport { constants } from 'node:os';\nimport { createInterface } from 'node:readline';\nimport type { HostId } from '@noir-ai/adapters';\nimport { buildBridgeArgs, resolveCommandViaShell } from './shell-bridge.js';\n\n/** A resolved spawn command: binary + the headless flags appended before prompt. */\nexport interface HostRunSpec {\n readonly binary: string;\n readonly flags: readonly string[];\n}\n\n/** Default headless binary per host. `null` = not a spawnable CLI. */\nconst HOST_BINARY: Record<HostId, string | null> = {\n claude: 'claude',\n gemini: 'gemini',\n opencode: 'opencode',\n cursor: 'cursor-agent',\n 'agents-md': null, // emits AGENTS.md — a file host, not a spawnable CLI\n};\n\n/**\n * Headless flags per host. `claude` is the regression anchor (fully specified);\n * the others use the same `-p --output-format stream-json` contract where the\n * host supports it, and remain overridable via the custom-binary path (D2a).\n */\nconst HOST_FLAGS: Record<HostId, readonly string[]> = {\n claude: ['-p', '--output-format', 'stream-json', '--verbose'],\n gemini: ['-p', '--output-format', 'stream-json'],\n opencode: ['run'],\n cursor: ['-p'],\n 'agents-md': [],\n};\n\n/**\n * Resolve the spawn command for `host`. `customBinary` (the user's own profile\n * command, e.g. `claude-work`) wins over the host default. Returns `null` when\n * the host has no spawnable CLI (agents-md).\n */\nexport function resolveHostRun(host: HostId, customBinary?: string): HostRunSpec | null {\n const binary = customBinary && customBinary.length > 0 ? customBinary : HOST_BINARY[host];\n if (!binary) return null;\n return { binary, flags: HOST_FLAGS[host] };\n}\n\n// ---------------------------------------------------------------------------\n// Event normalization\n// ---------------------------------------------------------------------------\n\n/** A token-usage snapshot (the fields of the stream-json `usage` object). */\nexport interface TokenUsage {\n readonly inputTokens?: number;\n readonly outputTokens?: number;\n readonly cacheReadTokens?: number;\n}\n\n/** The normalized event union — the shared, host-agnostic payload. */\nexport type NoirEvent =\n | { readonly kind: 'init'; readonly sessionId?: string; readonly model?: string }\n | {\n readonly kind: 'assistant';\n readonly messageId?: string;\n readonly text?: string;\n readonly usage?: TokenUsage;\n /** Set when the host flags the assistant message as an API error\n * (`is_api_error_message:true` or an `error` category string) — its text\n * is a diagnostic, never the answer. */\n readonly isError?: boolean;\n /** The host's error category string (e.g. \"authentication_failed\") when\n * the assistant event carries one — used for actionable auth guidance. */\n readonly errorCategory?: string;\n }\n | {\n readonly kind: 'result';\n readonly isError: boolean;\n readonly durationMs?: number;\n readonly numTurns?: number;\n readonly totalCostUsd?: number;\n readonly usage?: TokenUsage;\n }\n | { readonly kind: 'other' };\n\nfunction asObj(v: unknown): Record<string, unknown> | null {\n return typeof v === 'object' && v !== null ? (v as Record<string, unknown>) : null;\n}\n\nfunction str(v: unknown): string | undefined {\n return typeof v === 'string' ? v : undefined;\n}\n\nfunction num(v: unknown): number | undefined {\n return typeof v === 'number' && Number.isFinite(v) ? v : undefined;\n}\n\n/** Map a POSIX signal name (e.g. \"SIGKILL\") to its numeric value, else undefined. */\nfunction signalNumber(signal: NodeJS.Signals): number | undefined {\n const n = (constants.signals as Record<string, number>)[signal];\n return typeof n === 'number' ? n : undefined;\n}\n\nfunction usageFrom(v: unknown): TokenUsage | undefined {\n const o = asObj(v);\n if (!o) return undefined;\n const input = num(o.input_tokens);\n const output = num(o.output_tokens);\n const cache = num(o.cache_read_input_tokens) ?? num(o.cache_creation_input_tokens);\n if (input === undefined && output === undefined && cache === undefined) return undefined;\n return { inputTokens: input, outputTokens: output, cacheReadTokens: cache };\n}\n\n/** Extract the text delta from an assistant message's content (best-effort). */\nfunction messageText(message: Record<string, unknown> | null): string | undefined {\n if (!message) return undefined;\n const content = message.content;\n if (typeof content === 'string') return content;\n if (Array.isArray(content)) {\n const parts = content\n .map((block) => {\n const b = asObj(block);\n return b && typeof b.text === 'string' ? (b.text as string) : null;\n })\n .filter((t): t is string => t !== null);\n if (parts.length > 0) return parts.join('');\n }\n return undefined;\n}\n\n/** Parse a raw stream-json line to a JSON value, or `null` for blank/invalid. */\nexport function parseStreamLine(line: string): unknown | null {\n const trimmed = line.trim();\n if (trimmed.length === 0) return null;\n try {\n return JSON.parse(trimmed);\n } catch {\n return null;\n }\n}\n\n/** Normalize a raw stream-json event to a {@link NoirEvent}, or `null`. */\nexport function normalizeStreamEvent(raw: unknown): NoirEvent | null {\n const r = asObj(raw);\n if (!r) return null;\n const type = r.type;\n if (type === 'system') {\n if (r.subtype === 'init') {\n return { kind: 'init', sessionId: str(r.session_id), model: str(r.model) };\n }\n return { kind: 'other' };\n }\n if (type === 'assistant') {\n const message = asObj(r.message);\n return {\n kind: 'assistant',\n messageId: message ? str(message.id) : undefined,\n text: messageText(message),\n usage: message ? usageFrom(message.usage) : undefined,\n // An API error message is a diagnostic, not the answer — flag it so the\n // caller never streams it as assistant text (optional-when-true keeps\n // exact-shape consumers of the existing union intact).\n ...(r.is_api_error_message === true || typeof r.error === 'string'\n ? {\n isError: true as const,\n ...(typeof r.error === 'string' ? { errorCategory: r.error } : {}),\n }\n : {}),\n };\n }\n if (type === 'result') {\n return {\n kind: 'result',\n isError: r.is_error === true,\n durationMs: num(r.duration_ms),\n numTurns: num(r.num_turns),\n totalCostUsd: num(r.total_cost_usd),\n usage: usageFrom(r.usage),\n };\n }\n return { kind: 'other' };\n}\n\n// ---------------------------------------------------------------------------\n// Usage reduction\n// ---------------------------------------------------------------------------\n\n/** A monotonic token/cost accumulator snapshot. */\nexport interface UsageSnapshot {\n readonly inputTokens: number;\n readonly outputTokens: number;\n readonly totalCostUsd: number;\n readonly numTurns: number;\n}\n\n/**\n * Accumulates token/cost from a `stream-json` feed with the dedup rule: take\n * the `max` usage per `message.id`, never sum lines. Claude emits one line per\n * content block of an assistant message, each carrying that message's\n * CUMULATIVE usage — so the correct per-message total is the max, and the\n * session total is the sum of per-message maxes.\n */\nexport class UsageReducer {\n private readonly maxByMessage = new Map<string, { input: number; output: number }>();\n private input = 0;\n private output = 0;\n private costUsd = 0;\n private turns = 0;\n\n /** Feed one normalized event into the reducer. */\n add(event: NoirEvent): void {\n if (event.kind === 'assistant' && event.messageId && event.usage) {\n const key = event.messageId;\n const input = event.usage.inputTokens ?? 0;\n const output = event.usage.outputTokens ?? 0;\n const prev = this.maxByMessage.get(key);\n if (!prev) {\n this.maxByMessage.set(key, { input, output });\n this.input += input;\n this.output += output;\n } else {\n // Cumulative snapshot — only the growth over the last-seen max counts.\n this.input += Math.max(0, input - prev.input);\n this.output += Math.max(0, output - prev.output);\n this.maxByMessage.set(key, {\n input: Math.max(prev.input, input),\n output: Math.max(prev.output, output),\n });\n }\n } else if (event.kind === 'result') {\n if (event.totalCostUsd !== undefined) this.costUsd = event.totalCostUsd;\n if (event.numTurns !== undefined) this.turns = event.numTurns;\n }\n }\n\n /** The current accumulator snapshot. */\n snapshot(): UsageSnapshot {\n return {\n inputTokens: this.input,\n outputTokens: this.output,\n totalCostUsd: this.costUsd,\n numTurns: this.turns,\n };\n }\n}\n\n// ---------------------------------------------------------------------------\n// Spawn integration\n// ---------------------------------------------------------------------------\n\nexport interface RunHostOptions {\n readonly host: HostId;\n readonly prompt: string;\n readonly customBinary?: string;\n /** Extra args appended after the host's headless flags (run-profile `args`). */\n readonly extraArgs?: readonly string[];\n /** Environment for the host spawn + shell fallback (defaults to process.env). */\n readonly env?: Record<string, string | undefined>;\n /** Raw stream-json line (for transcript persistence). */\n onLine?: (line: string) => void;\n /** Normalized event (for streaming render). */\n onEvent?: (event: NoirEvent) => void;\n}\n\nexport interface RunHostResult {\n readonly exitCode: number;\n readonly usage: UsageSnapshot;\n readonly eventCount: number;\n /** Host stderr (surfaced on a non-zero exit so errors are not swallowed). */\n readonly stderr: string;\n /** Whether the host signalled an error (non-zero exit OR a stream-json\n * `is_error:true` result / API-error assistant event). Exit code alone is\n * not reliable — claude can exit 0 with `is_error:true` (#79500). */\n readonly isError: boolean;\n /** The first API-error assistant text (e.g. \"Not logged in · Please run\n * /login\"), quoted into the CLI's failure message. */\n readonly errorText?: string;\n /** The first API-error category (e.g. \"authentication_failed\"), for\n * actionable auth guidance in the CLI. */\n readonly errorCategory?: string;\n}\n\n/**\n * Spawn the host headless and consume its `stream-json` over a stdio pipe.\n * Rejects when the host has no spawnable CLI or the binary fails to spawn;\n * otherwise resolves with the exit code + the reduced usage snapshot.\n */\nexport function runHost(opts: RunHostOptions): Promise<RunHostResult> {\n const spec = resolveHostRun(opts.host, opts.customBinary);\n if (!spec) {\n return Promise.reject(\n new Error(`host '${opts.host}' is not a spawnable CLI (no default command)`),\n );\n }\n return spawnAndConsume(\n spec.binary,\n [...spec.flags, ...(opts.extraArgs ?? []), opts.prompt],\n opts,\n false,\n );\n}\n\n/**\n * Spawn `binary` with `args` and consume its stream-json. On an ENOENT spawn\n * error (and not already a shell-bridge run) it attempts the shell fallback:\n * the name may be an alias/function or a PATH entry only visible inside the\n * user's interactive shell — see `shell-bridge.ts` for the safety model.\n */\nfunction spawnAndConsume(\n binary: string,\n args: readonly string[],\n opts: RunHostOptions,\n shellRun: boolean,\n): Promise<RunHostResult> {\n return new Promise((resolve, reject) => {\n const child = spawn(binary, [...args], {\n stdio: ['ignore', 'pipe', 'pipe'],\n ...(opts.env ? { env: opts.env as NodeJS.ProcessEnv } : {}),\n });\n const reducer = new UsageReducer();\n let eventCount = 0;\n let stderrBuf = '';\n let errored = false;\n let errorText: string | undefined;\n let errorCategory: string | undefined;\n // A failed spawn fires BOTH 'error' and 'close' (close with a synthetic\n // code like -2). The 'close' handler must defer to the 'error' path so the\n // shell fallback (or the rejection) owns the resolution, never a -2 result.\n let spawnError: unknown = null;\n\n child.on('error', (err) => {\n spawnError = err;\n if (!shellRun && (err as NodeJS.ErrnoException).code === 'ENOENT') {\n void shellFallback(binary, args, opts, resolve, reject, err);\n return;\n }\n reject(err);\n });\n\n const rl = createInterface({ input: child.stdout });\n rl.on('line', (line) => {\n opts.onLine?.(line);\n const raw = parseStreamLine(line);\n if (raw === null) return;\n const event = normalizeStreamEvent(raw);\n if (event === null) return;\n eventCount += 1;\n if (event.kind === 'assistant' && event.isError === true) {\n errored = true;\n if (errorText === undefined && event.text && event.text.length > 0) errorText = event.text;\n if (errorCategory === undefined && event.errorCategory) errorCategory = event.errorCategory;\n } else if (event.kind === 'result' && event.isError === true) {\n errored = true;\n }\n reducer.add(event);\n opts.onEvent?.(event);\n });\n\n child.stderr.setEncoding('utf8');\n child.stderr.on('data', (chunk: string) => {\n stderrBuf += chunk;\n });\n\n child.on('close', (code, signal) => {\n if (spawnError !== null) return; // the error/fallback path owns this spawn\n // A host terminated by a signal (crash/SIGKILL/OOM) yields code === null\n // with no result event — without this it would be reported as exit 0\n // success. Fold the kill into a non-zero exit + isError (128+n is the\n // shell convention for signal termination).\n const killed = code === null && signal != null;\n resolve({\n exitCode: killed ? 128 + (signalNumber(signal) ?? 0) : (code ?? 0),\n usage: reducer.snapshot(),\n eventCount,\n stderr: stderrBuf,\n isError: errored || killed,\n errorText: killed && errorText === undefined ? `terminated by signal ${signal}` : errorText,\n errorCategory,\n });\n });\n });\n}\n\n/**\n * ENOENT shell-bridge attempt: probe the user's shell for `binary`; respawn the\n * resolved absolute path directly, or bridge an alias/function via the shell\n * (prompt + flags travel only as argv). On any failure re-reject the original\n * ENOENT so run.ts builds the friendly \"no executable found\" message.\n */\nasync function shellFallback(\n binary: string,\n args: readonly string[],\n opts: RunHostOptions,\n resolve: (r: RunHostResult) => void,\n reject: (e: unknown) => void,\n originalErr: unknown,\n): Promise<void> {\n try {\n const res = await resolveCommandViaShell(binary, { env: opts.env ?? process.env });\n if (res.kind === 'path') {\n resolve(await spawnAndConsume(res.path, args, opts, true));\n return;\n }\n if (res.kind === 'alias' || res.kind === 'function') {\n const bridge = buildBridgeArgs(binary, args, res.shell);\n resolve(await spawnAndConsume(bridge.binary, bridge.args, opts, true));\n return;\n }\n } catch {\n // fall through to the original ENOENT below\n }\n reject(originalErr);\n}\n","// ENOENT fallback for `noir run --command <name>`: resolves a command name\n// through the user's interactive shell. `child_process.spawn()` cannot see shell\n// aliases or functions (they only exist inside an interactive shell that has\n// sourced .zshrc/.bashrc/config.fish), and PATH entries exported only in rc\n// files are invisible to non-interactive children — both surface as ENOENT.\n//\n// Safety model (the whole point of this module):\n// - the NAME is validated against a strict charset and passed ONLY via argv\n// ($1), never interpolated into the -c string;\n// - the host's flags + prompt travel only as \"$@\" / $argv positional\n// parameters, so no user-controlled text ever reaches the shell parser;\n// - the probe is a one-shot lookup with a Node-side timeout killed via the\n// process group (rc files can hang, exit, or spawn orphaned children).\n// On Windows the fallback is disabled entirely (cmd/PowerShell aliases are\n// session-scoped and unspawnable).\n\nimport { spawn } from 'node:child_process';\nimport { basename } from 'node:path';\n\nconst PROBE_TIMEOUT_MS = 3000;\n/** Strict command-name charset — anything else is never handed to a shell. */\nconst NAME_RE = /^[A-Za-z0-9][A-Za-z0-9._+-]*$/;\nconst SUPPORTED_SHELLS = new Set(['zsh', 'bash', 'fish']);\n\nexport interface ShellBridgeEnv {\n SHELL?: string;\n PATH?: string;\n HOME?: string;\n [key: string]: string | undefined;\n}\n\n/** What the probe found for a name, or why it bailed. */\nexport type ShellResolution =\n | { readonly kind: 'path'; readonly path: string; readonly shell: string }\n | { readonly kind: 'alias'; readonly shell: string }\n | { readonly kind: 'function'; readonly shell: string }\n | { readonly kind: 'none'; readonly shell: string }\n | { readonly kind: 'error'; readonly message: string }\n | { readonly kind: 'unsupported' };\n\nexport interface ResolveOptions {\n readonly env?: ShellBridgeEnv;\n readonly platform?: NodeJS.Platform;\n readonly timeoutMs?: number;\n}\n\n/**\n * Guard: only plain command names on a POSIX platform with a supported\n * interactive shell (zsh/bash/fish) are eligible for the shell fallback.\n */\nexport function isEligibleForShellFallback(name: string, opts: ResolveOptions = {}): boolean {\n const { env = process.env, platform = process.platform } = opts;\n if (platform === 'win32') return false;\n if (name.length === 0 || name.includes('/') || !NAME_RE.test(name)) return false;\n const shell = env.SHELL;\n if (!shell || shell.length === 0) return false;\n return SUPPORTED_SHELLS.has(basename(shell).toLowerCase());\n}\n\n/** Extract the LAST `N:` (resolved path) and `K:` (kind) sentinel lines. */\nexport function parseProbeOutput(stdout: string): { path: string; kind: string } {\n let path = '';\n let kind = '';\n for (const line of stdout.split('\\n')) {\n if (line.startsWith('N:')) path = line.slice(2).trim();\n else if (line.startsWith('K:')) kind = line.slice(2).trim();\n }\n return { path, kind };\n}\n\n/** Map probe output onto a spawnable outcome (PATH wins over kind). */\nexport function classifyResolution(\n path: string,\n kind: string,\n): 'path' | 'alias' | 'function' | 'none' {\n if (path.trim().startsWith('/')) return 'path';\n const k = kind.trim().toLowerCase();\n if (k.includes('alias')) return 'alias';\n if (k.includes('function')) return 'function';\n return 'none';\n}\n\nfunction shellKind(shell: string): 'zsh' | 'bash' | 'fish' | null {\n const kind = basename(shell).toLowerCase();\n return (SUPPORTED_SHELLS.has(kind) ? kind : null) as 'zsh' | 'bash' | 'fish' | null;\n}\n\n/** Login+interactive flags per shell. fish has no separate login mode — `-i -c`\n * sources config.fish; zsh/bash use `-lic` (login+interactive) so rc files that\n * only load in login shells (PATH via .zprofile / /etc/zprofile) are visible. */\nconst PROBE_FLAGS: Record<'zsh' | 'bash' | 'fish', string> = {\n zsh: '-lic',\n bash: '-lic',\n fish: '-ic',\n};\n\n/**\n * One-shot probe scripts. The NAME is always read from `$1`/`$argv[1]` (argv),\n * never written into the script. bash login shells skip .bashrc, so it is\n * sourced explicitly (double-source is harmless). stdout noise (rc banners,\n * \"no job control\") is ignored by sentinel parsing.\n */\nconst PROBE_SCRIPTS: Record<'zsh' | 'bash' | 'fish', string> = {\n zsh: 'printf \"\\\\nN:%s\" \"$(whence -p \"$1\")\"; printf \"\\\\nK:%s\" \"$(whence -w \"$1\")\"',\n bash: 'shopt -s expand_aliases; [ -r \"$HOME/.bashrc\" ] && . \"$HOME/.bashrc\" 2>/dev/null; printf \"\\\\nN:%s\" \"$(type -P \"$1\")\"; printf \"\\\\nK:%s\" \"$(type -t \"$1\")\"',\n fish: 'printf \"\\\\nN:%s\" (type -P \"$argv[1]\"); printf \"\\\\nK:%s\" (type -t \"$argv[1]\")',\n};\n\n/** Run the probe; always resolves (never rejects), reporting a timeout. */\nfunction probeCommand(\n name: string,\n shell: string,\n opts: ResolveOptions,\n): Promise<{ stdout: string; timedOut: boolean }> {\n const kind = shellKind(shell);\n const timeoutMs = opts.timeoutMs ?? PROBE_TIMEOUT_MS;\n return new Promise((resolve) => {\n const script = kind ? PROBE_SCRIPTS[kind] : '';\n const flags = kind ? PROBE_FLAGS[kind] : '-lic';\n // bash/zsh consume a positional `$0` (the `noirbridge` dummy) and read the\n // command name from `$1`; fish has NO `$0` — its positional args ARE `$argv`\n // starting at $argv[1] — so the dummy must be omitted there or $argv[1] would\n // resolve the literal \"noirbridge\" and the probe would always come back empty.\n const probeArgs = kind === 'fish' ? [name] : ['noirbridge', name];\n const child = spawn(shell, [flags, script, ...probeArgs], {\n stdio: ['ignore', 'pipe', 'pipe'],\n detached: true, // new process group so the timeout can kill rc-spawned children\n ...(opts.env ? { env: opts.env as NodeJS.ProcessEnv } : {}),\n });\n let stdout = '';\n child.stdout.setEncoding('utf8');\n child.stdout.on('data', (c: string) => {\n stdout += c;\n });\n child.stderr.resume(); // rc noise (e.g. \"no job control\") — ignored\n const timer = setTimeout(() => {\n if (child.pid) {\n try {\n process.kill(-child.pid, 'SIGKILL'); // orphan guard: group, not just shell\n } catch {\n /* already gone */\n }\n }\n resolve({ stdout, timedOut: true });\n }, timeoutMs);\n child.on('error', () => {\n clearTimeout(timer);\n resolve({ stdout, timedOut: false });\n });\n child.on('close', () => {\n clearTimeout(timer);\n resolve({ stdout, timedOut: false });\n });\n });\n}\n\n/** Cache resolved absolute paths per (shell, name) so repeated runs skip the probe. */\nconst pathCache = new Map<string, string>();\n\n/**\n * Resolve `name` through the user's interactive shell. Returns `path` for a\n * PATH executable (respawn directly, clean stream-json pipe), `alias`/`function`\n * for shell entities (bridge execution needed), `none` for a genuine miss,\n * `error` for a probe timeout, or `unsupported` when the guards reject.\n */\nexport async function resolveCommandViaShell(\n name: string,\n opts: ResolveOptions = {},\n): Promise<ShellResolution> {\n const { env = process.env } = opts;\n if (!isEligibleForShellFallback(name, opts)) return { kind: 'unsupported' };\n const shell = env.SHELL as string;\n const cached = pathCache.get(`${shell}:${name}`);\n if (cached) return { kind: 'path', path: cached, shell };\n const probe = await probeCommand(name, shell, opts);\n if (probe.timedOut) {\n return {\n kind: 'error',\n message: `shell resolution timed out after ${opts.timeoutMs ?? PROBE_TIMEOUT_MS}ms`,\n };\n }\n const { path, kind } = parseProbeOutput(probe.stdout);\n const cls = classifyResolution(path, kind);\n if (cls === 'path') {\n pathCache.set(`${shell}:${name}`, path);\n return { kind: 'path', path, shell };\n }\n if (cls === 'alias' || cls === 'function') return { kind: cls, shell };\n return { kind: 'none', shell };\n}\n\nexport interface BridgeSpec {\n readonly binary: string;\n readonly args: readonly string[];\n}\n\n/**\n * Build the bridge spawn for an alias/function: run the user's interactive\n * shell and execute `NAME \"$@\"` (fish: `NAME $argv`). The host's flags + prompt\n * are appended as positional args after the dummy `$0` (`noirbridge`) — they are\n * forwarded verbatim by the shell and never parsed. bash re-sources .bashrc\n * (login shells skip it) so the alias/function defined there is available.\n */\nexport function buildBridgeArgs(\n name: string,\n hostArgs: readonly string[],\n shell: string,\n): BridgeSpec {\n const kind = shellKind(shell) ?? 'zsh';\n if (kind === 'fish') {\n // fish has no `$0`; positional args ARE `$argv` from $argv[1], so no dummy.\n return { binary: shell, args: ['-ic', `${name} $argv`, ...hostArgs] };\n }\n if (kind === 'bash') {\n return {\n binary: shell,\n args: [\n '-lic',\n `shopt -s expand_aliases; [ -r \"$HOME/.bashrc\" ] && . \"$HOME/.bashrc\" 2>/dev/null; ${name} \"$@\"`,\n 'noirbridge',\n ...hostArgs,\n ],\n };\n }\n return { binary: shell, args: ['-lic', `${name} \"$@\"`, 'noirbridge', ...hostArgs] };\n}\n","// Run profiles (D2c → `run.profiles` in .noir/config.yml): named host-binary\n// bundles selected by `--profile` / NOIR_PROFILE / run.defaultProfile, modeled\n// on the ssh_config / VS-Code-terminal-profiles precedent. Selection precedence\n// is the universal ladder: explicit flag > env var > persisted config default >\n// built-in default. An explicitly named profile that does not exist is a hard\n// error that lists the available names (botocore semantics + inline listing).\n//\n// Security doctrine: `env` values may reference `${VAR}` from Noir's process\n// environment and `null` deletes a variable from the child env — .noir/config.yml\n// is committable project state, so literal secrets must never be stored there.\n\nimport type { NoirConfig } from '@noir-ai/core';\nimport { loadProjectInfo } from '@noir-ai/core';\n\nexport interface ProfileResolution {\n readonly binary?: string;\n readonly env?: Record<string, string | undefined>;\n readonly args?: readonly string[];\n readonly profileName?: string;\n}\n\nexport type ProfileResolutionResult =\n | { readonly ok: true; readonly profile: ProfileResolution }\n | { readonly ok: false; readonly message: string };\n\n/** Best-effort project config load — `noir run` keeps working outside a project. */\nexport function loadRunConfig(root: string): NoirConfig | null {\n try {\n return loadProjectInfo(root).config;\n } catch {\n return null;\n }\n}\n\n/** Expand `${NAME}` references from `env`; unresolved references stay literal. */\nexport function expandEnvVars(value: string, env: Record<string, string | undefined>): string {\n return value.replace(/\\$\\{([A-Za-z_][A-Za-z0-9_]*)\\}/g, (match, name: string) =>\n env[name] !== undefined ? (env[name] as string) : match,\n );\n}\n\n/**\n * Resolve the effective profile. `requested` is the `--profile` flag value.\n * Precedence: requested > NOIR_PROFILE env > run.defaultProfile > none.\n */\nexport function resolveRunProfile(\n requested: string | undefined,\n config: NoirConfig,\n env: Record<string, string | undefined>,\n): ProfileResolutionResult {\n const profiles = config.run?.profiles ?? {};\n const names = Object.keys(profiles);\n const name = requested ?? env.NOIR_PROFILE ?? config.run?.defaultProfile;\n if (name === undefined || name.length === 0) {\n return { ok: true, profile: {} }; // built-in host default, unchanged\n }\n const profile = profiles[name];\n if (!profile) {\n const available =\n names.length > 0\n ? names.join(', ')\n : '(none defined — add a run.profiles block to .noir/config.yml)';\n return {\n ok: false,\n message: `unknown run profile \"${name}\" — no profile named \"${name}\" is defined under run.profiles in .noir/config.yml. Available: ${available}`,\n };\n }\n const envExpanded: Record<string, string | undefined> = {};\n if (profile.env) {\n for (const [k, v] of Object.entries(profile.env)) {\n envExpanded[k] = v === null ? undefined : expandEnvVars(v, env);\n }\n }\n return {\n ok: true,\n profile: { binary: profile.binary, env: envExpanded, args: profile.args, profileName: name },\n };\n}\n\n/** Rows for `noir run --list-profiles`. Keys match the table() column labels. */\nexport function listProfiles(\n config: NoirConfig,\n): Array<{ NAME: string; DEFAULT: string; BINARY: string }> {\n const profiles = config.run?.profiles ?? {};\n const def = config.run?.defaultProfile;\n return Object.keys(profiles).map((name) => ({\n NAME: name,\n DEFAULT: name === def ? '*' : '',\n BINARY: profiles[name]?.binary ?? '',\n }));\n}\n","// S9 — `noir skills {list,sync}`.\n//\n// Both sub-commands are IN-PROCESS (no daemon, no store): the builtin skill\n// pack is a filesystem artifact shipped with `@noir-ai/skills`, so `list` reads\n// it directly via `discoverBuiltin()` and `sync` re-emits it into the host\n// adapter's skills dir via `emitSkillsToDir` (the same primitive `noir init` /\n// `noir sync` use). Skill state is host-local files, never the daemon store, so\n// these never hit exit 4 (DAEMON_DOWN).\n//\n// Scriptability (S9 hard rule): `--json` emits the versioned `{ok,data}`\n// envelope to stdout (the only stdout write); the human table + banner go to\n// stderr via the centralized `table()` / `log()` helpers, which auto-strip\n// under NO_COLOR / non-TTY / --json. No interactive input is ever required, so\n// these commands are safe on a pipe / CI unconditionally.\n\nimport { resolveAdapter } from '@noir-ai/adapters';\nimport { loadProjectInfo, type ProjectInfo } from '@noir-ai/core';\nimport {\n type BuiltinSkill,\n buildRegistry,\n type CompileTarget,\n discoverAll,\n emitSkillsToDir,\n type IntegrationSkill,\n lintSkill,\n} from '@noir-ai/skills';\nimport { type CliOptions, EXIT, fail, info, log, table, warn } from '../output.js';\n\n/** Options accepted by `skills` sub-commands (the global flags only). */\nexport interface SkillsOptions extends CliOptions {}\n\n// ---------------------------------------------------------------------------\n// Category derivation.\n//\n// Skills ship no `category` frontmatter field (S5 contract is `{name,\n// description, references?}`), so the column is a PRESENTATION-layer grouping\n// derived from the skill name. The map covers the 26 builtins; an unknown name\n// falls back to its `noir-`-stripped segment so a newly authored skill still\n// gets a sensible cell instead of an empty one. This is display-only — the\n// `--json` payload carries `category` too (same derivation) for consistency.\n// ---------------------------------------------------------------------------\nconst CATEGORY: Record<string, string> = {\n 'noir-brainstorming': 'discovery',\n 'noir-sync': 'discovery',\n 'noir-checkpoint': 'discovery',\n 'noir-exploring': 'discovery',\n 'noir-spec': 'spec',\n 'noir-planning': 'plan',\n 'noir-prd': 'plan',\n 'noir-executing-plans': 'execute',\n 'noir-test-driven-development': 'execute',\n 'noir-systematic-debugging': 'execute',\n 'noir-subagent': 'execute',\n 'noir-parallel': 'execute',\n 'noir-verifying': 'verify',\n 'noir-security': 'verify',\n 'noir-wrap': 'document',\n 'noir-readme': 'document',\n 'noir-shipping': 'git',\n 'noir-worktree': 'git',\n 'noir-recall': 'memory',\n 'noir-remember': 'memory',\n 'noir-context': 'context',\n 'noir-frontend': 'domain',\n 'noir-backend': 'domain',\n 'noir-doctor': 'meta',\n 'noir-writing-skills': 'meta',\n 'noir-rules': 'meta',\n};\n\nfunction categoryOf(name: string): string {\n const mapped = CATEGORY[name];\n if (mapped !== undefined) return mapped;\n // Unknown skill: its own topic (the `noir-`-stripped name) is a reasonable\n // default cell so the table never shows an empty category.\n return name.replace(/^noir-/, '') || 'general';\n}\n\n/** Normalized skill row (the `data.skills[]` element + the table source). */\nexport interface SkillRow {\n name: string;\n category: string;\n description: string;\n /** Slice X — distinguishes the shipped builtins from the integration skills\n * (e.g. `noir-clickup`) so `noir skills list` shows the full pack and which\n * entries are integrations. Defaults to `'builtin'` for back-compat. */\n kind: 'builtin' | 'integration';\n /** C3 — `full` (playbook) vs `stub` (marker). Derived from the body; the\n * registry enriches this from the same source so list + registry agree. */\n status: 'full' | 'stub';\n}\n\nfunction toRow(s: BuiltinSkill, kind: 'builtin' | 'integration' = 'builtin'): SkillRow {\n const description =\n typeof s.frontmatter.description === 'string' ? s.frontmatter.description : '';\n const status: 'full' | 'stub' = s.skillMd.includes('> **Stub:**') ? 'stub' : 'full';\n // Category: frontmatter `metadata.category` is the C3 single source of truth\n // (\"data, not code\"); the curated CATEGORY map is only the fallback for a\n // legacy skill that lacks metadata. Keeps `skills list`, the registry, and\n // the docs table agreeing on one category per skill.\n const category = s.frontmatter.metadata?.category?.trim() || categoryOf(s.name);\n return { name: s.name, category, description, kind, status };\n}\n\n/**\n * Truncate `text` to `max` chars on a word boundary for dense table cells. This\n * is DISPLAY-ONLY for the human table; the full description is always carried\n * verbatim in the `--json` payload. (Distinct from the S6 \"never truncate the\n * retrieval DATA\" rule — that governs search snippets, not table formatting.)\n */\nfunction truncate(text: string, max: number): string {\n if (text.length <= max) return text;\n const slice = text.slice(0, Math.max(0, max - 1));\n // Cut at the last whitespace inside the slice so we don't split a word.\n const boundary = slice.lastIndexOf(' ');\n const head = boundary > 0 ? slice.slice(0, boundary) : slice;\n return `${head.trimEnd()}…`;\n}\n\n// ---------------------------------------------------------------------------\n// `noir skills list`\n// ---------------------------------------------------------------------------\n/**\n * `noir skills list`: discover the full shipped pack (builtins + integrations)\n * and render it. Consistent with `emitSkillsToDir` (which emits BOTH) — the\n * `noir-clickup` integration shows up here alongside the 26 builtins.\n *\n * `--json` emits `{ok:true, data:{count, skills: SkillRow[]}}` to stdout. A\n * discovery failure (the pack dir is unreadable) maps to exit 1 (ERROR) —\n * not exit 4, since this command never touches the daemon.\n */\nexport async function skillsList(opts: SkillsOptions): Promise<void> {\n let builtins: BuiltinSkill[];\n let integrations: IntegrationSkill[];\n try {\n const all = discoverAll();\n builtins = all.builtins;\n integrations = all.integrations;\n } catch (err) {\n fail(\n EXIT.ERROR,\n `skills list: could not discover skills (${err instanceof Error ? err.message : String(err)})`,\n opts,\n );\n }\n const rows = [\n ...builtins.map((b) => toRow(b, 'builtin')),\n ...integrations.map((i) => toRow(i, 'integration')),\n ];\n // Status is derived from the body (stub marker); category uses the CLI's\n // CATEGORY map (name-derived) until skills carry `metadata.category` — after\n // the C3 content rewrite every skill does, and `skills registry` reads it.\n // `skills list` keeps the curated CATEGORY map as its single source so the\n // human table is stable; the registry is the queryable form.\n const data = { count: rows.length, skills: rows };\n\n if (opts.json === true) {\n process.stdout.write(`${JSON.stringify({ ok: true, data })}\\n`);\n return;\n }\n\n const intCount = integrations.length;\n const banner =\n intCount > 0\n ? `noir skills — ${rows.length} skill${rows.length === 1 ? '' : 's'} (${builtins.length} builtin, ${intCount} integration${intCount === 1 ? '' : 's'})`\n : `noir skills — ${rows.length} builtin skill${rows.length === 1 ? '' : 's'}`;\n log(banner, opts);\n table(\n rows.map((r) => ({\n Skill: r.name,\n Kind: r.kind,\n Category: r.category,\n Status: r.status,\n Description: truncate(r.description, 80),\n })),\n ['Skill', 'Kind', 'Category', 'Status', 'Description'],\n opts,\n );\n}\n\n// ---------------------------------------------------------------------------\n// `noir skills sync`\n// ---------------------------------------------------------------------------\n/**\n * `noir skills sync`: re-emit the builtin pack into the host adapter's skills\n * dir. Reuses the same `emitSkillsToDir` primitive as `noir init` / `noir sync`\n * (the host-local file write; no daemon involved).\n *\n * Requires the project to be initialized (`loadProjectInfo` throws otherwise →\n * exit 1 with the \"Run `noir init` first\" hint). When the host adapter exposes\n * no `skillsDir` (no skill emitter for this host), the command reports nothing\n * to sync and exits 0 — behavior-preserving with the existing `noir sync`.\n *\n * `--json` emits `{ok:true, data:{emitted, references, dir}}` to stdout.\n */\nexport async function skillsSync(opts: SkillsOptions): Promise<void> {\n const root = process.cwd();\n // loadProjectInfo asserts Noir is initialized; route it through fail() so an\n // uninitialized project emits the canonical S9 {ok:false,error} envelope under\n // --json (a plain Error would leave stdout empty) — same as every other command.\n let project: ProjectInfo;\n try {\n project = loadProjectInfo(root);\n } catch {\n fail(EXIT.ERROR, 'Noir is not initialized in this directory. Run `noir init` first.', opts);\n }\n\n // Resolve the PROJECT's host adapter (not a hardcoded claude) — mirroring\n // sync.ts. A non-claude host (cursor/agents-md/opencode) has its own skillsDir\n // (e.g. .cursor/rules), and a host with NO skillsDir must report no-emitter\n // instead of silently writing a spurious .claude/skills/ tree.\n const adapter = resolveAdapter(project.config.host);\n if (!adapter.skillsDir) {\n const data = {\n emitted: [],\n references: 0,\n host: project.config.host,\n reason: 'no-skill-emitter',\n };\n if (opts.json === true) {\n process.stdout.write(`${JSON.stringify({ ok: true, data })}\\n`);\n return;\n }\n info('This host has no skill emitter; nothing to sync.', opts);\n return;\n }\n\n const dir = adapter.skillsDir({ root });\n const target: CompileTarget = project.config.host;\n const summary = await emitSkillsToDir(dir, { target });\n const pruned = summary.pruned ?? [];\n const data = {\n emitted: summary.emitted,\n references: summary.references,\n dir,\n pruned,\n };\n\n if (opts.json === true) {\n process.stdout.write(`${JSON.stringify({ ok: true, data })}\\n`);\n return;\n }\n\n log(\n `Synced ${summary.emitted.length} Noir skill${summary.emitted.length === 1 ? '' : 's'} to ${dir}.`,\n opts,\n );\n // Surface stale-dir pruning in both human + JSON modes for parity with\n // `noir sync` (the structured `pruned` field above covers --json).\n if (pruned.length > 0) {\n warn(\n `Pruned ${pruned.length} stale noir-* skill dir${pruned.length === 1 ? '' : 's'}: ${pruned.join(', ')}`,\n opts,\n );\n }\n}\n\n// ---------------------------------------------------------------------------\n// `noir skills lint`\n// ---------------------------------------------------------------------------\n/**\n * `noir skills lint`: the C3 structural quality gate over the full shipped pack.\n * Runs `lintSkill` (validateSkill errors + soft warnings) over `discoverAll()`.\n * In-process (no daemon) — the pack is a filesystem artifact.\n *\n * Exit contract: 0 when every skill validates clean (errors empty); 1 when any\n * skill has errors (the gate fails). Warnings alone do NOT fail the lint — they\n * are advisory and listed for the author. This mirrors how a real linter treats\n * hard errors vs style warnings.\n *\n * `--json` emits `{ok, data:{skills:[{name, errors, warnings}]}}` to stdout\n * (the only stdout write); the human report goes to stderr.\n */\nexport async function skillsLint(opts: SkillsOptions): Promise<void> {\n let skills: Array<{ name: string; errors: string[]; warnings: string[] }>;\n try {\n const all = discoverAll();\n skills = [...all.builtins, ...all.integrations].map(lintSkill);\n } catch (err) {\n fail(\n EXIT.ERROR,\n `skills lint: could not lint skills (${err instanceof Error ? err.message : String(err)})`,\n opts,\n );\n }\n const errored = skills.filter((s) => s.errors.length > 0);\n const warned = skills.filter((s) => s.warnings.length > 0 && s.errors.length === 0);\n\n const data = { count: skills.length, errored: errored.length, skills };\n\n // Exit-1 contract (the gate must FAIL, not silently pass): a lint error\n // produces a non-zero exit + the canonical S9 failure envelope under --json\n // (`{ok:false,error:{code,message}}` — no ad-hoc `{ok:false,data}` shape).\n if (errored.length > 0) {\n const message = `skills lint: ${errored.length} skill${errored.length === 1 ? '' : 's'} failed validation`;\n if (opts.json === true) {\n process.stdout.write(\n `${JSON.stringify({ ok: false, error: { code: EXIT.ERROR, message }, data })}\\n`,\n );\n process.exitCode = EXIT.ERROR;\n return;\n }\n warn(\n `noir skills lint — ${errored.length} skill${errored.length === 1 ? '' : 's'} FAIL validation:`,\n opts,\n );\n for (const s of errored) {\n for (const e of s.errors) warn(` ${s.name}: ${e}`, opts);\n }\n if (warned.length > 0) {\n info(` ${warned.length} skill${warned.length === 1 ? '' : 's'} carry lint warnings:`, opts);\n for (const s of warned) {\n for (const w of s.warnings) info(` ${s.name}: ${w}`, opts);\n }\n }\n fail(EXIT.ERROR, message, opts);\n }\n\n // Clean: exit 0.\n if (opts.json === true) {\n process.stdout.write(`${JSON.stringify({ ok: true, data })}\\n`);\n return;\n }\n log(`noir skills lint — ${skills.length} skills, all validate clean.`, opts);\n if (warned.length > 0) {\n info(` ${warned.length} skill${warned.length === 1 ? '' : 's'} carry lint warnings:`, opts);\n for (const s of warned) {\n for (const w of s.warnings) info(` ${s.name}: ${w}`, opts);\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// `noir skills registry`\n// ---------------------------------------------------------------------------\n/**\n * `noir skills registry`: emit the C3 runtime-derived skill registry (id, kind,\n * category, version, status, refs, lines). In-process (no daemon) — reads the\n * shipped pack via `buildRegistry()`. The registry is NOT a committed file;\n * frontmatter is the single source of truth and this command derives it on\n * demand (C3 decision D3).\n *\n * `--json` emits `{ok:true, data:{count, skills: SkillRegistryEntry[]}}` to\n * stdout; the human view is a table to stderr.\n */\nexport async function skillsRegistry(opts: SkillsOptions): Promise<void> {\n let reg: ReturnType<typeof buildRegistry>;\n try {\n reg = buildRegistry();\n } catch (err) {\n fail(\n EXIT.ERROR,\n `skills registry: could not build registry (${err instanceof Error ? err.message : String(err)})`,\n opts,\n );\n }\n const data = { count: reg.length, skills: reg };\n if (opts.json === true) {\n process.stdout.write(`${JSON.stringify({ ok: true, data })}\\n`);\n return;\n }\n log(`noir skills registry — ${reg.length} skills.`, opts);\n table(\n reg.map((r) => ({\n Skill: r.name,\n Kind: r.kind,\n Category: r.category,\n Version: r.version,\n Status: r.status,\n Refs: String(r.referenceCount),\n Lines: String(r.lines),\n })),\n ['Skill', 'Kind', 'Category', 'Version', 'Status', 'Refs', 'Lines'],\n opts,\n );\n}\n","// `noir init` — first-run + `--upgrade`.\n//\n// Slice S-T2 refactor: the ad-hoc writers (syncIgnores, writeManagedRegion,\n// writeFileSync for .mcp.json/project.id/config.yml/NOIR.md/RULES.md) are\n// replaced by a single call into `@noir-ai/create`'s `scaffold({mode:'init'})`.\n// The manifest + three-mode writer are the source of truth for what init\n// emits; this module is now a thin caller that owns ONLY:\n// - the transport/url precondition (the localhost security gate, whose\n// error strings are locked by url-validation.test.ts), and\n// - skills emission (out-of-manifest by design — composed after scaffold()).\n//\n// S10 multi-host: the 8 direct `claudeAdapter` imports across init/sync/create\n// collapsed to `resolveAdapter(host)` where `host` comes from `--host <id>`\n// (default `'claude'`). The adapter drives (a) the manifest via\n// `scaffold({host})` and (b) skills emission — claude/cursor have a skill dir;\n// gemini/agents-md/opencode have no skill concept and the call is skipped.\n//\n// Deliberate behavior changes vs the predecessor (spec-aligned latent-bug\n// fixes; see S-T1 contract notes + CHANGELOG):\n// - `.noir/project.id` → skipIfExists (predecessor overwrote on every init,\n// orphaning the store DB named after the id). Re-init now preserves it.\n// - `.noir/config.yml` → skipIfExists (predecessor overwrote).\n// - `.noir/NOIR.md` → managedBlock with BRIEF_BLOCK markers (predecessor\n// wrote the whole file with no markers). First-run output GAINS markers;\n// user notes outside the markers survive re-runs.\n// - `.noir/scaffold-version` is now stamped on init/create (engine-owned).\n\nimport { type HostId, resolveAdapter } from '@noir-ai/adapters';\nimport { loadProjectInfo, type ProjectInfo } from '@noir-ai/core';\nimport { type ScaffoldResult, scaffold } from '@noir-ai/create';\nimport { type CompileTarget, emitSkillsToDir } from '@noir-ai/skills';\nimport { buildConflictOpts, type ScaffoldConflictOpts } from './conflict.js';\nimport { checkWritePathDedup } from './dedup-write.js';\nimport { log, resolveInteractive } from './output.js';\n\nexport interface InitOptions {\n transport: 'stdio' | 'streamable-http';\n url?: string;\n /** `noir init --upgrade`: run scaffold migrations from the on-disk\n * scaffold-version to current, then re-emit every manifest mode except\n * `mergeJson` — including `skipIfExists`, which creates only when the file is\n * absent. That backfills seeds added to the manifest after this project was\n * initialized without ever touching a user-owned file. */\n upgrade?: boolean;\n /** S10 target host. Defaults to `'claude'` (the regression anchor). Drives\n * both scaffold emission (the manifest's host-specific half) and skills\n * emission (skipped for hosts with no `skillsDir`). */\n host?: HostId;\n /** SP-A: re-scaffold even if already initialized (bypasses the\n * already-initialized no-op guard in scaffold()). */\n force?: boolean;\n /** F1: `--dry-run`/`--preview` — report the planned writes to stderr\n * (via {@link reportPlannedWrites}) without touching disk. The scaffold\n * engine already supports this; the CLI just surfaces it. */\n dryRun?: boolean;\n /** F1: alias for `--dry-run`. Kept on the options bag so direct callers can\n * pass either spelling; the bin collapses both flags before dispatch. */\n preview?: boolean;\n}\n\n/**\n * Initialize Noir in `root`. Returns the {@link ScaffoldResult} (with\n * structured `conflicts[]` + any dedup records appended) so `--json`\n * callers can surface conflict detail. `undefined` when the already-initialized\n * guard short-circuited (a no-op).\n */\nexport async function init(root: string, opts: InitOptions): Promise<ScaffoldResult | undefined> {\n assertTransportUrl(opts);\n\n const host: HostId = opts.host ?? 'claude';\n // The engine reads ScaffoldOptions.interactive (hermetic — never\n // process.env). The CLI derives it once from the bridge + TTY/CI/NO_COLOR gate.\n const interactive = resolveInteractive();\n const conflictOpts = buildConflictOpts({ force: opts.force, interactive });\n // F1: --dry-run/--preview collapse to a single dryRun boolean. The engine\n // skips every write and returns the PLANNED lists; skills emission + dedup are\n // skipped too (they would touch disk / load the embedder).\n const dryRun = opts.dryRun === true || opts.preview === true;\n\n const res = await scaffold({\n root,\n mode: 'init',\n host,\n transport: opts.transport,\n interactive,\n ...(opts.url !== undefined ? { url: opts.url } : {}),\n ...(opts.upgrade === true ? { upgrade: true } : {}),\n ...(opts.force === true ? { force: true } : {}),\n ...(dryRun ? { dryRun: true } : {}),\n ...conflictOpts,\n });\n // F1: dry-run reports the planned writes (result's written/skipped/identical)\n // and stops BEFORE skills emission + the \"initialized\" message — nothing was\n // written, so the host skill dir must stay untouched and we must not claim\n // init. Under --json the bin emits the planned list as the `{ok, data}`\n // envelope on stdout (the data channel) instead.\n if (dryRun) {\n reportPlannedWrites(res);\n return res;\n }\n // SP-A: if the already-initialized guard no-op'd scaffold, stop — don't re-emit\n // skills or print \"initialized\" (scaffold already printed the no-op message).\n if (res.noop) return res;\n\n // Thread the SAME conflictOpts into skills emission so the\n // skills-emit conflict flow is LIVE in interactive mode (the producer\n // accepts conflict opts; this closes the wiring gap). The safe-default\n // `assertNotUserOwned` runs unconditionally inside the producer.\n await emitHostSkills(root, host, conflictOpts, interactive);\n\n // Write-path semantic dedup. Non-blocking; degrades to a\n // stderr warn-skip when the embedder is unavailable. Records near-dups on\n // `res.conflicts` so `--json` consumers see them without a prompt.\n // Best-effort project read: first-run init has no .noir/config.yml yet →\n // undefined → resolveEmbedder warn-skips. `init --force` on an existing\n // project reads the config and runs the dedup against existing host files.\n let projectInfo: ProjectInfo | undefined;\n try {\n projectInfo = loadProjectInfo(root);\n } catch {\n projectInfo = undefined;\n }\n const dedup = await checkWritePathDedup(root, res, { interactive, project: projectInfo });\n if (dedup.conflicts.length > 0) res.conflicts.push(...dedup.conflicts);\n\n process.stderr.write(\n `Noir initialized in ${root} (host: ${host}, transport: ${opts.transport}).\\n`,\n );\n process.stderr.write(\n 'Next: run `noir` to open the home menu (or `noir status` for a snapshot).\\n',\n );\n return res;\n}\n\n/**\n * F1 — report a dry-run (--dry-run/--preview) scaffold result. After\n * `scaffold({dryRun:true})` the result's `written`/`skipped`/`identical` carry\n * the PLANNED paths (nothing touched disk): `written` = files that WOULD be\n * written, `skipped` = skipIfExists files already present (left alone),\n * `identical` = files whose bytes would match the template (no rewrite).\n * `conflicts` is always empty under dryRun (no writes → no conflicts).\n * `fileModes` carries the planned permission for entries that would CREATE at a\n * non-default mode — annotated onto the planned line (`… (mode 600)`).\n *\n * Emitted via the `log()` stderr helper — a HUMAN diagnostic, so under `--json`\n * the bin emits the planned list as the structured `{ok, data}` envelope on\n * stdout (the data channel) instead, matching the S9 stream discipline used by\n * the other init/create/sync diagnostics. Shared by init/create/sync (the same\n * dryRun surface on all three scaffold modes).\n */\nexport function reportPlannedWrites(res: ScaffoldResult): void {\n log('Dry run — no files were written.');\n if (res.written.length > 0) {\n log('Planned writes:');\n for (const p of res.written) {\n // Slice E (§8.1): a planned creation at a non-default mode is reported\n // here so `noir init --dry-run` shows the 0600 `.noir/.env` seed without\n // writing it. `fileModes` is absent/empty for every other entry.\n const mode = res.fileModes?.[p];\n log(mode === undefined ? ` ${p}` : ` ${p} (mode ${mode.toString(8).padStart(3, '0')})`);\n }\n }\n if (res.skipped.length > 0) {\n log('Would leave as-is (already present):');\n for (const p of res.skipped) log(` ${p}`);\n }\n if (res.identical.length > 0) {\n log('Would rewrite (byte-identical, no-op):');\n for (const p of res.identical) log(` ${p}`);\n }\n}\n\n/**\n * Compose skill emission onto the resolved adapter's `skillsDir` (claude →\n * `.claude/skills/`; cursor → `.cursor/rules/` compiled as `.mdc`; the other\n * three hosts have no skill concept and are skipped with a stderr note).\n *\n * The `CompileTarget` matches the host id (S10 foundation widened the enum to\n * the same union) so cursor skills compile to the `.mdc` rule shape via\n * `compileSkill(_, 'cursor')`; the others keep the verbatim SKILL.md format.\n */\nasync function emitHostSkills(\n root: string,\n host: HostId,\n conflictOpts: ScaffoldConflictOpts,\n interactive: boolean,\n): Promise<void> {\n const adapter = resolveAdapter(host);\n const skillsDir = adapter.skillsDir?.({ root });\n if (skillsDir === undefined) {\n // N1: standardized wording — same phrase across init/sync/create so logs\n // grep uniformly. (Pre-N1 each command phrased this differently.)\n process.stderr.write(`host '${host}' has no skill emitter; skipping skills\\n`);\n return;\n }\n const target: CompileTarget = host;\n // Forward conflictPolicy + onConflict + interactive so an\n // interactive `noir init` with a conflicting skill emit consults the\n // resolver (clack menu + diff preview + apply-to-all); --json/--no-input\n // stays prompt-free via the `interactive: false` guard. The resolver shape\n // is structurally compatible with the skill emit seam (see skills/types.ts);\n // the cast isolates the literal-narrowing mismatch on the return type.\n type SkillEmitOpts = NonNullable<Parameters<typeof emitSkillsToDir>[1]>;\n const skillOpts: SkillEmitOpts = {\n includeIntegrations: true,\n target,\n conflictPolicy: conflictOpts.conflictPolicy,\n interactive,\n };\n if (conflictOpts.onConflict !== undefined) {\n skillOpts.onConflict = conflictOpts.onConflict as SkillEmitOpts['onConflict'];\n }\n const summary = await emitSkillsToDir(skillsDir, skillOpts);\n const relDir = skillsDir.replace(`${root}/`, '');\n process.stderr.write(\n `Emitted ${summary.emitted.length} Noir skills to ${relDir}/ (target: ${target}).\\n`,\n );\n}\n\n/**\n * Transport + URL precondition. The error strings here are the SECURITY GATE\n * locked by `url-validation.test.ts` — do not rephrase. Thrown errors are\n * plain `Error`s (bin.ts's `main().catch` maps them to stderr + exitCode 1).\n *\n * Exported so `noir create` (commands/create.ts) reuses the SAME gate instead\n * of duplicating the localhost allowlist.\n */\nexport function assertTransportUrl(opts: {\n transport: 'stdio' | 'streamable-http';\n url?: string;\n}): void {\n if (opts.transport === 'streamable-http' && opts.url === undefined) {\n throw new Error('--transport streamable-http requires --url');\n }\n if (opts.url !== undefined) {\n assertLocalhostUrl(opts.url);\n }\n}\n\n// Validate a streamable-http --url is http(s) and localhost-only. Gate 2's\n// daemon binds 127.0.0.1, so persisting a non-localhost URL is a footgun.\n// Not exported: the single external surface is assertTransportUrl(); thrown\n// errors propagate to bin.ts's main().catch (stderr + exitCode 1).\nfunction assertLocalhostUrl(raw: string): void {\n let url: URL;\n try {\n url = new URL(raw);\n } catch {\n throw new Error(`Invalid URL: ${raw}`);\n }\n if (!['http:', 'https:'].includes(url.protocol)) {\n throw new Error('Only http/https URLs are supported');\n }\n if (!['localhost', '127.0.0.1', '::1'].includes(url.hostname)) {\n throw new Error(`Only localhost URLs are supported (got ${url.hostname})`);\n }\n}\n","// SP-C — conflict-resolution UX seam. The engine (@noir-ai/create) is UI-free;\n// this module builds the scaffold conflict options (policy + a lazy @clack\n// resolver) per the S9 interactivity contract:\n// - TTY + interactive → @clack select menu (Replace/Rename/Duplicate/Keep/Cancel,\n// plus a 6th \"merge (with conflict markers)\" when `mergedWithMarkers` is set)\n// - non-TTY / CI / NO_COLOR → preserve (never silently clobber in a pipe)\n// - --force → overwrite (explicit re-scaffold; no prompt)\n//\n// Universal contract: this seam now drives EVERY file-producing path. The\n// engine's regenerate path consults `onConflict` (apply-to-all keyed by artifact\n// CLASS so an N-pointer `noir init --upgrade` → 1 prompt); managedBlock conflicts\n// stay PER-FILE. A unified line-diff preview (LCS-based, from\n// @noir-ai/create's `lineDiff`) renders to STDERR before the prompt (via the\n// A2 theme — `+` green / `-` red / context dim), so `--json`/piped stdout stays\n// pristine. The 6th \"merge\" option writes the engine-provided zdiff3-marked\n// bytes when a 3-way merge hit an overlap.\nimport {\n type ConflictContext,\n type ConflictResolution,\n type ConflictResolverReturn,\n lineDiff,\n} from '@noir-ai/create';\nimport { isInteractive } from './output.js';\nimport { c } from './theme.js';\n\nexport interface ConflictOptsInput {\n /** `--force`: explicit re-scaffold — overwrite differing files, no prompt. */\n force?: boolean;\n /** B1: explicit interactivity signal. When set, wins over the env/TTY\n * heuristic. `false` ⇒ preserve (never prompt); `true` ⇒ allow the @clack\n * resolver. The CLI derives this from the `NOIR_NON_INTERACTIVE` bridge\n * bin.ts owns + the `isInteractive()` TTY/CI/NO_COLOR gate. */\n interactive?: boolean;\n}\n\nexport type ScaffoldConflictOpts = {\n conflictPolicy: 'overwrite' | 'preserve';\n onConflict?: (ctx: ConflictContext) => Promise<ConflictResolverReturn> | ConflictResolverReturn;\n};\n\n/**\n * Build the scaffold conflict options for the current invocation. The engine\n * calls `onConflict` only when a `regenerate` file exists AND differs from the\n * template, so passing this on every init/create/sync is harmless on a first\n * run (no existing files → no conflict).\n *\n * B1 + SP-G: the `interactive` flag (explicit > env bridge > TTY/CI/NO_COLOR\n * gate) drives the prompt decision so the engine never reads `process.env` for\n * interactivity. The `NOIR_NON_INTERACTIVE` bridge (--json/--no-input) and the\n * `isInteractive()` gate both reduce to `preserve` (never prompt).\n *\n * B2 apply-to-all: when the resolver returns `{resolution, applyToAll: true}`\n * the engine stores the choice in its per-run memory keyed by artifact CLASS\n * (regenerate shares one decision; managedBlock/managedBlocks stay per-file).\n */\n/** True when the bin's preAction hook flagged this invocation non-interactive\n * (`--json` / `--no-input`) so the conflict resolver never prompts under those. */\nfunction flaggedNonInteractive(): boolean {\n const v = process.env.NOIR_NON_INTERACTIVE;\n return v !== undefined && v !== '';\n}\n\nexport function buildConflictOpts(input: ConflictOptsInput = {}): ScaffoldConflictOpts {\n if (input.force === true) {\n return { conflictPolicy: 'overwrite' };\n }\n // Explicit interactive flag wins over the env/TTY heuristic.\n if (input.interactive === false) {\n return { conflictPolicy: 'preserve' };\n }\n if (input.interactive === true) {\n return { conflictPolicy: 'preserve', onConflict: clackConflictResolver };\n }\n // Fallback: NOIR_NON_INTERACTIVE bridge (--json/--no-input) OR the\n // isInteractive() TTY/CI/NO_COLOR gate — either ⇒ preserve, never prompt.\n if (flaggedNonInteractive() || !isInteractive()) {\n return { conflictPolicy: 'preserve' };\n }\n return { conflictPolicy: 'preserve', onConflict: clackConflictResolver };\n}\n\n/**\n * B2 — render a colored unified line-diff of `{existing, proposed}` to STDERR\n * before the @clack prompt. Stderr (not stdout) so `--json` / piped stdout\n * stays pristine. The A2 theme colors `+` lines green (`c.ok`), `-` lines red\n * (`c.error`), and dims context lines (`c.dim`); all color is gated through\n * `useColor()` so NO_COLOR / non-TTY / CLICOLOR_FORCE behave consistently.\n * Honored by `theme.test.ts`'s NO_COLOR gate.\n */\nfunction renderDiffPreview(ctx: ConflictContext): void {\n // `lineDiff` is imported statically at the top of this module. It used to be\n // a lazy `require('@noir-ai/create')`, but tsup bundles every @noir-ai/*\n // internal into dist/bin.js — a dynamic `require` survives bundling as an\n // ESM-incompatible `__require` shim that throws \"Dynamic require of\n // @noir-ai/create is not supported\" at runtime (broke `init --upgrade`\n // whenever a file conflict triggered this preview). The static import is\n // bundled correctly and runs in pure ESM with no side effects here.\n const lines = lineDiff(ctx.existing, ctx.proposed);\n if (lines.length === 0) return;\n const out: string[] = [`noir: conflict in ${ctx.relPath}`];\n for (const dl of lines) {\n if (dl.type === 'add') out.push(c.ok(`+ ${dl.line}`));\n else if (dl.type === 'del') out.push(c.error(`- ${dl.line}`));\n else out.push(c.dim(` ${dl.line}`));\n }\n process.stderr.write(`${out.join('\\n')}\\n`);\n}\n\n/**\n * SP-C + B2 — @clack-based conflict resolver. Renders a unified diff to stderr\n * (via {@link renderDiffPreview}) BEFORE the select prompt, then offers the\n * usual Replace/Rename/Duplicate/Keep/Cancel set PLUS a 6th \"merge (with\n * conflict markers)\" option when `ctx.mergedWithMarkers` is set (a 3-way merge\n * hit an overlap and the engine has the marked bytes ready).\n *\n * Apply-to-all: when the user picks an option, @clack asks whether to reuse the\n * choice for the rest of the run; if yes, the resolver returns the rich\n * `{resolution, applyToAll: true}` shape and the engine stores it in per-class\n * memory. `managedBlock`/`managedBlocks` modes bypass apply-to-all (per-file).\n */\nasync function clackConflictResolver(ctx: ConflictContext): Promise<ConflictResolverReturn> {\n renderDiffPreview(ctx);\n const clack = await import('@clack/prompts');\n const options: Array<{ value: ConflictResolution; label: string; hint: string }> = [\n {\n value: 'replace',\n label: 'Replace',\n hint: 'overwrite with the template (discard your edits)',\n },\n { value: 'rename', label: 'Rename', hint: 'keep yours as <file>.local; write the template' },\n {\n value: 'duplicate',\n label: 'Create duplicate',\n hint: 'write template to <file>.noir; keep yours',\n },\n { value: 'preserve', label: 'Keep mine', hint: 'skip; leave your file unchanged' },\n { value: 'cancel', label: 'Cancel', hint: 'abort the scaffold' },\n ];\n // 6th \"merge\" option only when the engine has marked bytes ready.\n if (ctx.mergedWithMarkers !== undefined) {\n options.splice(4, 0, {\n value: 'merge',\n label: 'Merge (with conflict markers)',\n hint: 'write the 3-way merge with <<<<<<< / ||||||| / ======= / >>>>>>> markers',\n });\n }\n const choice = await clack.select({\n message: `${ctx.relPath} was edited and differs from the Noir template.`,\n initialValue: 'preserve',\n options,\n });\n if (clack.isCancel(choice)) return 'cancel';\n const resolution = choice as ConflictResolution;\n // Apply-to-all. The `regenerate` scaffold path AND the `skill` emit path both\n // key their per-run memory by a single class, so one \"Yes\" reuses the choice\n // across the whole run. The `managedBlock`/`managedBlocks` paths are per-file\n // (the engine keys memory by path::block, not by class), so they must NOT\n // offer \"apply to all\" — reusing a per-file decision there would silently\n // clobber unrelated blocks.\n const mode = (ctx.mode ?? 'regenerate') as string;\n const supportsApplyToAll = mode !== 'managedBlock' && mode !== 'managedBlocks';\n if (supportsApplyToAll) {\n const remember = await clack.select({\n message: `Apply \"${labelFor(resolution)}\" to all remaining conflicts this run?`,\n initialValue: 'no',\n options: [\n { value: 'yes', label: 'Yes', hint: 'reuse this choice for the rest of this run' },\n { value: 'no', label: 'No', hint: 'prompt again for each conflict' },\n ],\n });\n if (!clack.isCancel(remember) && remember === 'yes') {\n return { resolution, applyToAll: true };\n }\n }\n return resolution;\n}\n\nfunction labelFor(resolution: ConflictResolution): string {\n switch (resolution) {\n case 'replace':\n return 'Replace';\n case 'rename':\n return 'Rename';\n case 'duplicate':\n return 'Create duplicate';\n case 'preserve':\n return 'Keep mine';\n case 'merge':\n return 'Merge (with conflict markers)';\n case 'cancel':\n return 'Cancel';\n }\n}\n","// Write-path semantic dedup. After `scaffold()` writes host-context\n// files (CLAUDE.md / AGENTS.md / GEMINI.md / .noir/rules/RULES.md), embed the\n// just-written file and compare it against the OTHER existing host-context\n// files. Surface a near-duplicate as a NON-BLOCKING recommendation:\n//\n// - cosine ≥ 0.95 → ACTION prompt (interactive): Replace the existing /\n// Mirror into it / Skip (delete the new file) / Create\n// anyway. Under --json/--no-input the action tier records\n// the near-dup in ScaffoldResult.conflicts[] (mode=\n// 'artifact', similarity set) and proceeds with the\n// default (Create anyway); NEVER prompts.\n// - 0.85–0.95 → INFO-only hint to stderr, write proceeds.\n// - < 0.85 → silent.\n//\n// GRACEFUL DEGRADATION (the make-orreak constraint): the embedder (ONNX\n// Runtime + the ~22 MB all-MiniLM-L6-v2 model) is lazy-loaded with a 5s ping\n// timeout; if it is unavailable, slow, OR throws, the hook prints a one-line\n// stderr warn-skip and returns an empty result. `noir init`/`sync`/`create`\n// NEVER block on a model download or fail because the embedder is missing —\n// dedup is an ENHANCEMENT, not a gate. A fresh project with no existing\n// host-context candidates short-circuits BEFORE any embedding (fast path).\n//\n// CONTENT-HASH GATE: candidate embeddings are cached under\n// `.noir/dedup-cache.json` keyed by SHA-256(content); only changed candidates\n// re-embed. The proposed file's embedding is cached the same way, so a repeat\n// `noir sync` that re-emits byte-identical content does NOT re-embed. Cache\n// entries are scoped to the resolved model id (a model change invalidates them).\n//\n// When a near-dup is found, the conflict record (mode 'artifact'\n// — the closest generic in ConflictContext['mode']) is appended to the\n// ScaffoldResult.conflicts[] the caller returns, so `--json` consumers see the\n// near-dup with its cosine `similarity` without a prompt.\n//\n// Stream discipline: every hint / warn-skip → STDERR; the CLI's `json()` is the\n// sole stdout writer. Colors via the A2 theme (`c.warn`/`c.dim`) so NO_COLOR /\n// non-TTY strip cleanly.\n\nimport { mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { type ConflictResolution, type ProjectInfo, sha256Hex, sha256Hex12 } from '@noir-ai/core';\nimport type { ConflictRecord, ScaffoldResult } from '@noir-ai/create';\nimport { collectDedupCandidates } from './commands/doctor.js';\nimport { c } from './theme.js';\n\n/** Local embedder shape (@noir-ai/context's `EmbedFn`). */\nexport type EmbedLike = (text: string) => Promise<Float32Array>;\n\n/** Host-context files dedup scans (mirrors `collectDedupCandidates`). */\nconst HOST_CONTEXT_RELS = new Set(['CLAUDE.md', 'AGENTS.md', 'GEMINI.md', '.noir/rules/RULES.md']);\n\n/** Cosine ≥ this → ACTION prompt (interactive) or conflict record (--json). */\nconst ACTION_THRESHOLD = 0.95;\n/** Cosine ≥ this (and < ACTION) → INFO-only hint. Below → silent. */\nconst INFO_THRESHOLD = 0.85;\n/** The first embed() call triggers ONNX load + possibly a model download; bound\n * it so init/sync/create never block indefinitely on a cold cache. */\nconst EMBEDDER_PING_TIMEOUT_MS = 5000;\n/** Bump on disk-format changes; an older file is discarded (no migration). */\nconst DEDUP_CACHE_VERSION = 1;\n\nexport interface DedupWriteOpts {\n /** Explicit interactivity flag (the engine + skills emit read the same). */\n interactive: boolean;\n /** Project info — read from `.noir/config.yml` by the caller. When undefined\n * OR when the resolved embedder is `kind:'none'`, the hook warn-skips. */\n project?: ProjectInfo;\n /** Testability seam (mirrors `checkSemanticDupDoctor`'s `opts.embed`): when\n * set, the hook uses this embedder directly and skips the lazy ONNX load +\n * ping-timeout. Production omits it. */\n embed?: EmbedLike;\n}\n\nexport interface DedupWriteResult {\n /** Near-duplicates found, one entry per (proposed, matched) pair. */\n found: Array<{ proposedRel: string; matchedRel: string; similarity: number }>;\n /** Conflict records to append to {@link ScaffoldResult.conflicts}. */\n conflicts: ConflictRecord[];\n}\n\n/**\n * Run the write-path semantic dedup over the host-context files in\n * `res.written`. Does NOT mutate `res`; the caller decides whether to splice\n * `result.conflicts` into `res.conflicts`. Non-blocking: any embedder failure\n * degrades to a stderr warn-skip and an empty result.\n */\nexport async function checkWritePathDedup(\n root: string,\n res: ScaffoldResult,\n opts: DedupWriteOpts,\n): Promise<DedupWriteResult> {\n const result: DedupWriteResult = { found: [], conflicts: [] };\n // Fast path: only host-context files we JUST wrote are eligible. Fresh\n // projects (first init/create) typically write ONE host pointer + RULES.md;\n // if no other host-context file exists, candidates is empty → no embedding.\n const writtenHostFiles = res.written.filter((p) => HOST_CONTEXT_RELS.has(p));\n if (writtenHostFiles.length === 0) return result;\n\n const cache = loadCache(root);\n const embed = await resolveEmbedder(opts, cache);\n if (embed === undefined) return result; // warn-skip already emitted\n\n // Wrap the embedder with the content-hash cache so unchanged candidates (and\n // a repeat-emit of byte-identical proposed bytes) skip the underlying call.\n const cachedEmbed = makeCachedEmbed(cache, embed);\n\n for (const proposedRel of writtenHostFiles) {\n const proposedAbs = join(root, proposedRel);\n let proposedText: string;\n try {\n proposedText = readFileSync(proposedAbs, 'utf8');\n } catch {\n continue;\n }\n if (proposedText.trim().length === 0) continue;\n\n // Candidates = existing host-context files MINUS this proposed path. A\n // first-run init writing CLAUDE.md while AGENTS.md already exists compares\n // the new CLAUDE.md against AGENTS.md + RULES.md (not against itself).\n const candidates = collectDedupCandidates(root).filter((c) => c.path !== proposedRel);\n if (candidates.length === 0) continue; // fresh project, nothing to compare\n\n const ctx = await import('@noir-ai/context');\n const proposed = { path: proposedRel, text: proposedText };\n // Graceful degradation INSIDE the loop too: an embedder that loads (passes\n // the ping) but throws mid-batch (transient remote failure, OOM, …) must\n // never break the write. Catch, warn-skip this proposal, keep going.\n let best: Awaited<ReturnType<typeof ctx.findNearestDuplicate>>;\n try {\n best = await ctx.findNearestDuplicate(\n proposed,\n candidates,\n async (t) => cachedEmbed(t),\n INFO_THRESHOLD,\n );\n } catch (e) {\n process.stderr.write(\n `${c.dim(`noir: semantic-dedup skipped for ${proposedRel} (${errMsg(e)}).`)}\\n`,\n );\n continue;\n }\n if (best === null) continue;\n\n const matchedRel = best.a === proposedRel ? best.b : best.a;\n const sim = best.similarity;\n result.found.push({ proposedRel, matchedRel, similarity: sim });\n\n // The conflict record's resolution reflects what actually happened — not a\n // hardcoded 'preserve'. Non-interactive + cancel default to 'preserve'\n // (Create anyway); the prompt's replace/mirror choices map onto the\n // ConflictResolution union.\n let resolution: ConflictResolution = 'preserve';\n if (sim >= ACTION_THRESHOLD) {\n if (opts.interactive) {\n resolution = await promptDedupAction(root, proposedRel, matchedRel, proposedText, sim);\n } else {\n // --json / --no-input: record + proceed with the default (Create\n // anyway). Never prompt under non-interactive.\n process.stderr.write(\n `${c.warn('noir: near-duplicate')} ${proposedRel} ≈ ${matchedRel} (cosine ${sim.toFixed(2)}); creating anyway.\\n`,\n );\n }\n } else {\n // 0.85 – 0.95: INFO-only hint. Write already succeeded; just surface.\n process.stderr.write(\n `${c.dim(`noir: hint ${proposedRel} looks similar to existing ${matchedRel} (cosine ${sim.toFixed(2)}).`)}\\n`,\n );\n }\n\n // Append a structured record so --json consumers see the\n // near-dup with its cosine similarity without a prompt. The path is the\n // file we just wrote (consistent with the \"path = the file being\n // written\" convention); existingSha is the MATCHED file's hash, proposedSha the new\n // bytes'. Resolution 'preserve' = we kept both as-is under Create-anyway.\n const matchedText = safeRead(join(root, matchedRel));\n result.conflicts.push({\n path: proposedRel,\n mode: 'artifact',\n similarity: sim,\n existingSha: sha256Hex12(matchedText ?? ''),\n proposedSha: sha256Hex12(proposedText),\n resolution,\n });\n }\n\n saveCache(root, cache);\n return result;\n}\n\n/**\n * Resolve the embedder: injected (test seam) > local-embedder from the user's\n * `context.embedder` config. Returns undefined (after a stderr warn-skip) when\n * kind='none', the factory throws, OR the first ping exceeds the timeout.\n *\n * Model-id tracking runs in BOTH paths so a config change invalidates the\n * on-disk cache even when the caller injected an embedder (the test seam\n * still flows through the same cache discipline as production).\n */\nasync function resolveEmbedder(\n opts: DedupWriteOpts,\n cache: DedupCache,\n): Promise<EmbedLike | undefined> {\n const ctx = await import('@noir-ai/context');\n // Resolve the model id from config when available; an injected embedder\n // without project info skips invalidation (cache stays model-scoped to '' —\n // a fresh cache, which is fine for tests that always inject).\n let modelId: string | undefined;\n if (opts.project !== undefined) {\n const cfg = ctx.resolveEmbedderConfig(opts.project.config.context);\n if (cfg.kind === 'none') {\n process.stderr.write(`${c.dim('noir: semantic-dedup skipped (embedder kind=none).')}\\n`);\n return undefined;\n }\n modelId =\n cfg.kind === 'local' ? (cfg.model ?? ctx.DEFAULT_LOCAL_MODEL) : (cfg.model ?? cfg.kind);\n // Invalidate cache on a model change BEFORE deciding the embedder source.\n if (modelId !== undefined && cache.model !== modelId) {\n cache.model = modelId;\n cache.entries = {};\n }\n }\n // Test seam: an injected embedder bypasses the lazy ONNX load + ping.\n if (opts.embed !== undefined) return opts.embed;\n if (modelId === undefined) return undefined; // no project + no inject → skip\n\n let embed: EmbedLike;\n try {\n const project = opts.project;\n if (project === undefined) return undefined;\n const cfg = ctx.resolveEmbedderConfig(project.config.context);\n embed = ctx.createEmbedFn(cfg).embed as EmbedLike;\n } catch (e) {\n process.stderr.write(\n `${c.dim(`noir: semantic-dedup skipped (embedder unavailable: ${errMsg(e)}).`)}\\n`,\n );\n return undefined;\n }\n // Pre-warm with a ping under a timeout. The first call triggers the ONNX\n // load + (on a cold ~/.noir/models/) a ~22 MB model download; bound it so\n // init/sync never block on the network. A throw OR a timeout → warn-skip.\n const ping = await withTimeout(\n embed('ping').then(() => true),\n EMBEDDER_PING_TIMEOUT_MS,\n );\n if (ping !== true) {\n process.stderr.write(\n `${c.dim('noir: semantic-dedup skipped (embedder load too slow or unavailable).')}\\n`,\n );\n return undefined;\n }\n return embed;\n}\n\n/** ACTION prompt for the ≥0.95 tier (interactive only). */\nasync function promptDedupAction(\n root: string,\n proposedRel: string,\n matchedRel: string,\n proposedText: string,\n sim: number,\n): Promise<ConflictResolution> {\n const clack = await import('@clack/prompts');\n type Choice = 'create' | 'skip' | 'replace' | 'mirror';\n const choice = await clack.select({\n message: `${proposedRel} is near-duplicate of existing ${matchedRel} (cosine ${sim.toFixed(2)}). Create anyway?`,\n initialValue: 'create' as Choice,\n options: [\n {\n value: 'create' as Choice,\n label: 'Create anyway',\n hint: 'keep the new file as-is (default)',\n },\n { value: 'skip' as Choice, label: 'Skip', hint: `delete ${proposedRel}; keep ${matchedRel}` },\n {\n value: 'replace' as Choice,\n label: 'Replace existing',\n hint: `overwrite ${matchedRel} with this content`,\n },\n {\n value: 'mirror' as Choice,\n label: 'Mirror into existing',\n hint: `append this content to ${matchedRel}`,\n },\n ],\n });\n if (clack.isCancel(choice)) return 'preserve'; // cancel = keep the default (Create anyway)\n if (choice === 'skip') {\n try {\n rmSync(join(root, proposedRel), { force: true });\n } catch {\n /* best-effort; the write already happened */\n }\n return 'preserve'; // the matched file is kept\n } else if (choice === 'replace') {\n try {\n writeFileSync(join(root, matchedRel), proposedText, 'utf8');\n } catch {\n /* best-effort */\n }\n return 'replace';\n } else if (choice === 'mirror') {\n try {\n const existing = readFileSync(join(root, matchedRel), 'utf8');\n writeFileSync(\n join(root, matchedRel),\n `${existing}\\n\\n<!-- mirrored from ${proposedRel} -->\\n${proposedText}\\n`,\n 'utf8',\n );\n } catch {\n /* best-effort */\n }\n return 'duplicate'; // the proposed content was folded into the existing file\n }\n // 'create' → no-op (the just-written file stands).\n return 'preserve';\n}\n\n// ---------------------------------------------------------------------------\n// Content-hash cache (.noir/dedup-cache.json).\n// ---------------------------------------------------------------------------\n\ninterface DedupCache {\n version: number;\n model: string;\n entries: Record<string, { v: number[] }>;\n}\n\nfunction emptyCache(): DedupCache {\n return { version: DEDUP_CACHE_VERSION, model: '', entries: {} };\n}\n\nfunction cachePath(root: string): string {\n return join(root, '.noir', 'dedup-cache.json');\n}\n\nfunction loadCache(root: string): DedupCache {\n try {\n const raw = readFileSync(cachePath(root), 'utf8');\n const parsed = JSON.parse(raw) as Partial<DedupCache>;\n if (parsed.version !== DEDUP_CACHE_VERSION) return emptyCache();\n if (typeof parsed.entries !== 'object' || parsed.entries === null) return emptyCache();\n return {\n version: DEDUP_CACHE_VERSION,\n model: typeof parsed.model === 'string' ? parsed.model : '',\n entries: parsed.entries,\n };\n } catch {\n return emptyCache();\n }\n}\n\nfunction saveCache(root: string, cache: DedupCache): void {\n try {\n mkdirSync(join(root, '.noir'), { recursive: true });\n writeFileSync(cachePath(root), JSON.stringify(cache), 'utf8');\n } catch {\n // Best-effort; cache persistence is an enhancement, never a gate.\n }\n}\n\n/** Wrap `embed` with a SHA-256 content-hash cache. Cache hits return the\n * stored vector WITHOUT calling `embed`; misses call `embed` and store. */\nfunction makeCachedEmbed(cache: DedupCache, embed: EmbedLike): EmbedLike {\n return async (text: string): Promise<Float32Array> => {\n const key = sha256Hex(text);\n const cached = cache.entries[key];\n if (cached !== undefined) return Float32Array.from(cached.v);\n const v = await embed(text);\n cache.entries[key] = { v: Array.from(v) };\n return v;\n };\n}\n\n// ---------------------------------------------------------------------------\n// Small helpers.\n// ---------------------------------------------------------------------------\n\nfunction safeRead(abs: string): string | undefined {\n try {\n return readFileSync(abs, 'utf8');\n } catch {\n return undefined;\n }\n}\n\n/** Resolve `p` OR undefined on timeout/throw (never rejects). The underlying\n * promise keeps running in the background; we just stop awaiting it. */\nfunction withTimeout<T>(p: Promise<T>, ms: number): Promise<T | undefined> {\n return new Promise((resolve) => {\n const t = setTimeout(() => resolve(undefined), ms);\n p.then(\n (v) => {\n clearTimeout(t);\n resolve(v);\n },\n () => {\n clearTimeout(t);\n resolve(undefined);\n },\n );\n });\n}\n\nfunction errMsg(e: unknown): string {\n return e instanceof Error ? e.message : String(e);\n}\n","import { applyNoirEnv, loadProjectInfo } from '@noir-ai/core';\nimport { ensureDaemonRunning, startStdioServer } from '@noir-ai/daemon';\n\nexport async function serve(opts: { stdio: boolean }): Promise<void> {\n // Load .noir/.env before constructing the MCP server so integration tokens\n // (e.g. CLICKUP_API_TOKEN) are resolvable at call time even when the daemon\n // was launched from a context that did not inherit the shell rc.\n applyNoirEnv(process.cwd());\n const project = loadProjectInfo(process.cwd());\n if (opts.stdio) {\n await startStdioServer({ project, transport: 'stdio', daemon: false });\n return; // stdio server runs until stdin closes\n }\n // Prefer the shared daemon; on failure fall back to in-process stdio so Noir\n // keeps working even when the daemon cannot start (FS-degradation path).\n try {\n const { url } = await ensureDaemonRunning({\n project,\n idleTimeoutSec: project.config.daemon.idleTimeoutSec,\n ...(project.config.daemon.port !== undefined ? { port: project.config.daemon.port } : {}),\n });\n process.stderr.write(\n `Noir daemon available at ${url}. (For HTTP clients, use this URL in .mcp.json.) ` +\n `Add the daemon's bearer token via the host MCP headersHelper (run \\`noir daemon token\\`).\\n`,\n );\n } catch (err) {\n process.stderr.write(\n `Noir daemon unavailable (${err instanceof Error ? err.message : String(err)}); falling back to stdio.\\n`,\n );\n await startStdioServer({ project, transport: 'stdio', daemon: false });\n }\n}\n"],"mappings":"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","names":["loadProjectInfo","NOIR_VERSION","loadProjectInfo","NOIR_VERSION","readWorkspaceMarker","ensureDaemonRunning","pidAlive","readDaemonToken","readProjectDaemonRecord","readWorkspaceDaemonRecord","SUPPORTED_HOSTS","applyNoirEnv","NOIR_VERSION","data","paths","loadProjectInfo","pidAlive","ensured","loadProjectInfo","pidAlive","errMsg","existsSync","readdirSync","readFileSync","join","resolveAdapter","loadProjectInfo","pidAlive","readProjectDaemonRecord","existsSync","loadProjectInfo","readProjectDaemonRecord","pidAlive","status","openStore","join","readFileSync","fail","c","resolveAdapter","readdirSync","scaffold","loadNoirEnv","loadProjectInfo","resolveModelConfig","env","loadProjectInfo","resolveModelConfig","loadNoirEnv","writeFileSync","join","resolveAdapter","loadProjectInfo","spawnSync","loadProjectInfo","loadProjectInfo","s","spawnSync","status","c","resolveAdapter","loadProjectInfo","join","writeFileSync","hostLaunchDirective","detectActiveMethod","latestVersionFromCache","loadProjectInfo","NOIR_VERSION","readInstallRecord","readUpdateCache","program","c","info","loadProjectInfo","hostLaunchDirective","readInstallRecord","NOIR_VERSION","detectActiveMethod","latestVersionFromCache","readUpdateCache","readFileSync","loadProjectInfo","loadProjectInfo","parseLimit","toHit","failTool","probe","hits","data","res","readFileSync","sessions","env","spawnSync","status","spawnSync","existsSync","mkdirSync","writeFileSync","join","loadNoirEnv","NOIR_DIR","spawn","PROBE_TIMEOUT_MS","env","c","spawn","loadProjectInfo","env","env","NOIR_DIR","loadNoirEnv","existsSync","join","mkdirSync","writeFileSync","resolveAdapter","loadProjectInfo","status","loadProjectInfo","resolveAdapter","data","resolveAdapter","loadProjectInfo","emitSkillsToDir","mkdirSync","readFileSync","writeFileSync","join","sha256Hex","join","readFileSync","c","writeFileSync","mkdirSync","sha256Hex","loadProjectInfo","resolveAdapter","emitSkillsToDir","loadProjectInfo","ensureDaemonRunning","c","program","NOIR_VERSION","str","applyNoirEnv","SUPPORTED_HOSTS","run","loadProjectInfo","readProjectDaemonRecord","pidAlive","ensureDaemonRunning","readDaemonToken","NOIR_VERSION","readWorkspaceMarker","readWorkspaceDaemonRecord","describeEmbedder","c","NOIR_VERSION","renderHuman","loadProjectInfo","info"]}
|