@noir-ai/cli 1.11.2-beta.1 → 1.12.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.
Files changed (45) hide show
  1. package/dist/bin.js +3295 -575
  2. package/dist/bin.js.map +1 -1
  3. package/dist/index.js +6136 -6
  4. package/dist/index.js.map +1 -1
  5. package/dist/{chunk-QIVHIKYD.js → tui/chunk-2RK6AFZQ.js} +37 -16
  6. package/dist/tui/chunk-2RK6AFZQ.js.map +1 -0
  7. package/dist/tui/{chunk-R5YX44UL.js → chunk-ESZTOQEC.js} +211 -2
  8. package/dist/tui/chunk-ESZTOQEC.js.map +1 -0
  9. package/dist/tui/chunk-J77RHAWG.js +5010 -0
  10. package/dist/tui/chunk-J77RHAWG.js.map +1 -0
  11. package/dist/{create-VK2QMXYS.js → tui/create-BTYLBVV6.js} +4 -4
  12. package/dist/tui/{create-WKFVM237.js.map → create-BTYLBVV6.js.map} +1 -1
  13. package/dist/tui/index.js +45 -3454
  14. package/dist/tui/index.js.map +1 -1
  15. package/dist/tui/{install-JR6ZXNYA.js → install-YGTUSLRO.js} +2 -3
  16. package/dist/{sync-VXZKODQA.js → tui/sync-LRHPJ5VV.js} +4 -4
  17. package/dist/tui/{sync-DUWJAF7Z.js.map → sync-LRHPJ5VV.js.map} +1 -1
  18. package/dist/tui/{update-PGAM6OVL.js → update-LET5BWOU.js} +3 -4
  19. package/package.json +12 -12
  20. package/dist/chunk-A5W2E3X2.js +0 -33
  21. package/dist/chunk-A5W2E3X2.js.map +0 -1
  22. package/dist/chunk-CT6TYLHN.js +0 -1105
  23. package/dist/chunk-CT6TYLHN.js.map +0 -1
  24. package/dist/chunk-I2R55ACD.js +0 -369
  25. package/dist/chunk-I2R55ACD.js.map +0 -1
  26. package/dist/chunk-QIVHIKYD.js.map +0 -1
  27. package/dist/chunk-RON2XESF.js +0 -210
  28. package/dist/chunk-RON2XESF.js.map +0 -1
  29. package/dist/create-VK2QMXYS.js.map +0 -1
  30. package/dist/install-4U4UDDNE.js +0 -13
  31. package/dist/sync-VXZKODQA.js.map +0 -1
  32. package/dist/tui/chunk-F6XRS72N.js +0 -1106
  33. package/dist/tui/chunk-F6XRS72N.js.map +0 -1
  34. package/dist/tui/chunk-NLK6UNIA.js +0 -223
  35. package/dist/tui/chunk-NLK6UNIA.js.map +0 -1
  36. package/dist/tui/chunk-QF6777NJ.js +0 -209
  37. package/dist/tui/chunk-QF6777NJ.js.map +0 -1
  38. package/dist/tui/chunk-R5YX44UL.js.map +0 -1
  39. package/dist/tui/create-WKFVM237.js +0 -79
  40. package/dist/tui/sync-DUWJAF7Z.js +0 -90
  41. package/dist/tui/update-PGAM6OVL.js.map +0 -1
  42. package/dist/update-ZDAVLOXB.js +0 -20
  43. package/dist/update-ZDAVLOXB.js.map +0 -1
  44. /package/dist/{install-4U4UDDNE.js.map → tui/install-YGTUSLRO.js.map} +0 -0
  45. /package/dist/tui/{install-JR6ZXNYA.js.map → update-LET5BWOU.js.map} +0 -0
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/tui/index.tsx","../../src/bin.ts","../../src/daemon-client.ts","../../src/commands/context.ts","../../src/commands/daemon.ts","../../src/commands/handoff.ts","../../src/commands/status.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/commands/skills.ts","../../src/serve.ts","../../src/tui/App.tsx","../../src/tui/CommandInput.tsx","../../src/tui/capture.ts","../../src/tui/Footer.tsx","../../src/tui/hints.ts","../../src/tui/format.ts","../../src/tui/Header.tsx","../../src/tui/hooks/useInputBuffer.ts","../../src/tui/OutputPane.tsx","../../src/tui/overlays/ConfirmOverlay.tsx","../../src/tui/Panel.tsx","../../src/tui/palette/fuzzyMatch.ts","../../src/tui/palette/matcher.ts","../../src/tui/palette/Palette.tsx","../../src/tui/palette/output.ts","../../src/tui/palette/rows.ts","../../src/tui/StatusBar.tsx","../../src/tui/palette/history.ts"],"sourcesContent":["// `noir tui` entry — mounts the Ink dashboard. LAZY-loaded: bin.ts does\n// `await import('./tui/index.js')` inside the `tui` action only, so React +\n// Ink never enter the main CLI startup path (`noir status`, `noir doctor`, a\n// bare `noir` all stay React-free). The entry wires the default\n// {@link TuiDeps.fetchStatus} (a wrapper around `gatherStatusPayload` that\n// folds any failure to `null`) and the SAME dispatch seam `home(opts, deps)`\n// uses, then renders the App and resolves on exit.\n//\n// Stream discipline: while the dashboard runs, Ink owns the terminal (raw-mode\n// stdin + ANSI render to stdout). On `q` / Esc / Ctrl+C, Ink restores the\n// terminal before unmounting. Dispatched commands write through the captured\n// stream shim, so the host terminal only ever sees Ink's frames.\n\nimport { loadProjectInfo } from '@noir-ai/core';\nimport { render } from 'ink';\nimport { buildPaletteCommandsForTui } from '../bin.js';\nimport { gatherStatusPayload, type StatusOptions, type StatusPayload } from '../commands/status.js';\nimport type { CliOptions } from '../output.js';\nimport { App, type TuiDeps } from './App.js';\nimport { loadRecent, recordRecent } from './palette/history.js';\n\nexport type { TuiDeps } from './App.js';\n\n/**\n * Default status fetcher: wraps {@link gatherStatusPayload} so any failure (an\n * uninitialized project, a probe hiccup, a daemon-down that threw) folds to\n * `null` and the dashboard degrades cleanly. `gatherStatusPayload` itself is\n * probe-only and never auto-starts a daemon, so this is safe to poll.\n */\nfunction defaultFetchStatus(opts: CliOptions): () => Promise<StatusPayload | null> {\n return async () => {\n try {\n return await gatherStatusPayload(opts as StatusOptions);\n } catch {\n return null;\n }\n };\n}\n\n/**\n * Mount the dashboard and resolve when the user exits. The caller (bin.ts)\n * supplies the dispatch seam — the same shape `home(opts, deps).dispatch`\n * uses — so command routing is owned by the bin, not reimplemented here.\n */\nexport async function runTui(opts: CliOptions, dispatch: TuiDeps['dispatch']): Promise<void> {\n process.stdout.write('\\x1b[2J\\x1b[H');\n const deps = await buildTuiDeps(opts, dispatch);\n const instance = render(<App deps={deps} />);\n await instance.waitUntilExit();\n}\n\n/**\n * `noir palette` — mount the App palette-first (S3). Reuses the SAME\n * `runTui` deps (dispatch seam, commands, recents) so the fuzzy command\n * palette is identical to the dashboard's Ctrl+K palette, just opened\n * directly. `dispatch` is the same shape `runTui` receives from bin.ts.\n */\nexport async function runPalette(opts: CliOptions, dispatch: TuiDeps['dispatch']): Promise<void> {\n process.stdout.write('\\x1b[2J\\x1b[H');\n // Reuse runTui's deps wiring wholesale, then render palette-first.\n // Factor the shared deps build out of runTui into a helper to avoid\n // duplicating the projectId/commands/recents logic.\n const deps = await buildTuiDeps(opts, dispatch);\n const instance = render(\n <App deps={deps} initialMode={{ kind: 'palette', corpus: 'commands' }} />,\n );\n await instance.waitUntilExit();\n}\n\n/**\n * Build the shared {@link TuiDeps} for both `runTui` and `runPalette`.\n * Extracted so the two entry points cannot drift (projectId-keyed recents,\n * the palette source, and the dispatch seam are identical).\n */\nasync function buildTuiDeps(opts: CliOptions, dispatch: TuiDeps['dispatch']): Promise<TuiDeps> {\n // ProjectId-keyed recent-commands persistence (C3): resolve the canonical id\n // once at launch so recents are isolated per project (respects the .noir/\n // single-source-of-truth invariant). An uninitialized project (loadProjectInfo\n // throws) degrades to empty recents — the palette still works with the full\n // command list.\n let projectId: string | null = null;\n try {\n projectId = loadProjectInfo(process.cwd()).id;\n } catch {\n projectId = null;\n }\n const deps: TuiDeps = {\n dispatch,\n fetchStatus: defaultFetchStatus(opts),\n // The palette source, derived from a fresh commander program at launch (B3).\n commands: buildPaletteCommandsForTui(),\n // C3 — persistent recent commands (projectId-keyed). recordRecent is async\n // only to match the TuiDeps seam; it never rejects.\n record: (argv) => {\n if (projectId) recordRecent(projectId, argv);\n return Promise.resolve();\n },\n loadRecent: async () => {\n if (!projectId) return [];\n // Hydrate the bare {argv,id} entries against the live palette commands so\n // the palette renders real labels/descriptions; drop stale entries whose\n // argv no longer exists in the current build.\n const byId = new Map(deps.commands?.map((c) => [c.id, c]) ?? []);\n return loadRecent(projectId)\n .map((e) => byId.get(e.id))\n .filter((c): c is NonNullable<typeof c> => c !== undefined);\n },\n };\n return deps;\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 { NOIR_VERSION } from '@noir-ai/core';\nimport { Command, Option } from 'commander';\nimport { contextIndex, contextSearch, contextStatus } from './commands/context.js';\nimport { daemonRestart, daemonStart, daemonStatus, daemonStop } from './commands/daemon.js';\nimport { doctor } from './commands/doctor.js';\nimport { type HandoffOptions, handoff } from './commands/handoff.js';\nimport { type HomeDeps, home } from './commands/home.js';\nimport {\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 { init } from './init.js';\nimport {\n type CliOptions,\n EXIT,\n fail,\n handleError,\n inferExitCode,\n json,\n NoirCliError,\n requireInteractive,\n tip,\n} from './output.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 };\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 // 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 .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 await daemonStart({\n ...toCliOptions(g),\n ...(detach ? { detach } : {}),\n ...(detachChild ? { detachChild } : {}),\n });\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('restart')\n .description('stop then start the daemon')\n .action(async (...args: unknown[]) => {\n await daemonRestart(toCliOptions(trailingCmd(args).optsWithGlobals()));\n });\n daemonGrp.action(() => {\n throw new NoirCliError(EXIT.USAGE, 'Usage: noir daemon start|stop|status|restart');\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 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.action(() => {\n throw new NoirCliError(\n EXIT.USAGE,\n 'Usage: noir memory recall|save|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('--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.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('--last', 'target the active task explicitly (scripting)')\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 last = g.last === true;\n const prompt = typeof g.prompt === 'string' ? (g.prompt as string) : undefined;\n await taskResume({\n ...toCliOptions(g),\n ...(id === undefined ? {} : { id }),\n ...(last ? { last } : {}),\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 .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 };\n await runHostCommand(prompt, 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 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 the daemon\n// record at `~/.noir/daemon.json` (NOIR_DAEMON_JSON override for tests) and\n// STARTS a foreground daemon if no healthy one is present, returning its URL +\n// a `stop()` tear-down. We connect a @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\nimport { Client, StreamableHTTPClientTransport } from '@modelcontextprotocol/client';\nimport { ContextEngine, createEmbedFn, resolveEmbedderConfig } from '@noir-ai/context';\nimport { loadProjectInfo, NOIR_VERSION, type ProjectInfo } from '@noir-ai/core';\nimport {\n ensureDaemonRunning,\n pidAlive,\n readDaemonRecord,\n resolveGateConfig,\n} from '@noir-ai/daemon';\nimport { createMemoryEngine, type MemoryEngine } from '@noir-ai/memory';\nimport { openStore } 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 * Reads the daemon record (`~/.noir/daemon.json` via {@link readDaemonRecord}),\n * checks {@link pidAlive}, and GETs `http://127.0.0.1:<port>/health`. Any miss\n * (no record, stale pid, non-200, unreachable, malformed body) → `{running:false}`\n * — this function NEVER throws and NEVER starts a daemon. Under `--verbose` the\n * reason for a miss is logged to stderr (NF5: honest degradation).\n */\nexport async function probeDaemon(opts: DaemonClientOptions = {}): Promise<DaemonProbe> {\n const rec = readDaemonRecord();\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 if (body?.ok !== true) {\n if (opts.verbose) process.stderr.write('noir: daemon probe: /health body not ok\\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 * Ensure a healthy daemon is running and return its MCP URL + a tear-down\n * callback. Maps any start / record error onto exit 4.\n */\nasync function resolveDaemon(\n opts: DaemonClientOptions,\n): Promise<{ url: string; 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 // Deliberately OUTSIDE the try below: an uninitialized project (`loadProjectInfo`\n // throws \"Run `noir init` first\") is a usage error, not a daemon-down — letting\n // it propagate as a plain Error surfaces exit 1 with that hint instead of exit 4.\n const project = opts.project ?? loadProjectInfo(process.cwd());\n const idleTimeoutSec = opts.idleTimeoutSec ?? project.config.daemon.idleTimeoutSec;\n try {\n const ensured = await ensureDaemonRunning({ project, idleTimeoutSec });\n return { url: ensured.url, stop: ensured.stop };\n } catch (err) {\n failDaemonDown(opts, err);\n }\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): Promise<void> {\n try {\n await client.connect(new StreamableHTTPClientTransport(new URL(url)));\n } catch (err) {\n failDaemonDown(opts, err);\n }\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 * Connect to the daemon and run `fn` against a {@link DaemonToolCaller} that\n * shares one MCP connection across any number of tool calls. The client is\n * closed and any daemon this call started is torn down in `finally`, even when\n * `fn` throws — so a one-shot CLI command never strands a server or leaks a\n * connection, while a reused (already-running) daemon is left untouched\n * (`ensureDaemonRunning`'s `stop` is a no-op in that case).\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 */\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\nexport async function withDaemon<T>(\n opts: DaemonClientOptions,\n fn: (caller: DaemonToolCaller) => Promise<T>,\n): Promise<T> {\n const { url, stop } = await resolveDaemon(opts);\n let client: Client | undefined;\n try {\n client = new Client(\n { name: 'noir-cli', version: NOIR_VERSION },\n { versionNegotiation: { mode: 'auto' } },\n );\n // Capture the now-definitely-assigned client BEFORE any `await` so buildCaller\n // sees `Client` (not `Client | undefined`) without relying on how TS narrows a\n // `let` across an await.\n const connected: Client = client;\n await connectClient(connected, url, opts);\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 / swallowed result */\n });\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 = new Client(\n { name: 'noir-cli', version: NOIR_VERSION },\n { versionNegotiation: { mode: 'auto' } },\n );\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).\n await connected.connect(new StreamableHTTPClientTransport(new URL(url)));\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 const project = opts.project ?? loadProjectInfo(process.cwd());\n const store = await openStore({ projectId: project.id, root: project.root, readonly: true });\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","// 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}`.\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 } from '@noir-ai/core';\nimport {\n clearDaemonRecord,\n ensureDaemonRunning,\n pidAlive,\n readDaemonRecord,\n spawnDetachedDaemon,\n} from '@noir-ai/daemon';\nimport { type CliOptions, EXIT, fail, info, log, spinner } from '../output.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}\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 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/** Best-effort `/health` probe for the detach double-spawn guard (never throws). */\nasync function isHealthy(port: number): Promise<boolean> {\n try {\n const res = await fetch(`http://127.0.0.1:${port}/health`);\n return res.status === 200;\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 const project = loadProjectInfo(process.cwd());\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 });\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 const existing = readDaemonRecord();\n if (existing && pidAlive(existing.pid) && (await isHealthy(existing.port))) {\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 const spawned = await spawnDetachedDaemon({ project });\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 const ensured = await ensureDaemonRunning({\n project,\n idleTimeoutSec: project.config.daemon.idleTimeoutSec,\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 const rec = readDaemonRecord();\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 try {\n process.kill(rec.pid, 'SIGTERM');\n signalled = true;\n } catch (err) {\n // Process may have already exited; report but still clear the record below.\n errMsg = err instanceof Error ? err.message : String(err);\n } finally {\n clearDaemonRecord();\n }\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 ds.warn(`Daemon (pid ${rec.pid}) could not be signalled: ${errMsg}`);\n info(`Noir daemon (pid ${rec.pid}) could not be signalled: ${errMsg}`, 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 const rec = readDaemonRecord();\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 DaemonRecord below.\n\n if (!pidAlive(rec.pid)) {\n clearDaemonRecord();\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 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 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 if (health?.ok !== true) {\n hs.fail('Daemon not responding');\n clearDaemonRecord();\n fail(\n EXIT.DAEMON_DOWN,\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 (legacy record, foreground start) 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 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): 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 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, resolveArtifactPath } from '@noir-ai/core';\nimport {\n type DaemonClientOptions,\n type DaemonProbe,\n probeDaemon,\n withRunningDaemon,\n} from '../daemon-client.js';\nimport { type CliOptions, 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).\n const project = loadProjectInfo(process.cwd());\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 if (opts.json === true) {\n process.stdout.write(`${JSON.stringify({ ok: true, data: full })}\\n`);\n return;\n }\n\n const md = renderMarkdown(full);\n\n if (opts.write === true) {\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 under the default path; --write is a convenience that reports\n // its path here, never on stdout).\n info(`handoff written to ${path}`, opts);\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.\n process.stdout.write(md);\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 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, 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// ---------------------------------------------------------------------------\nexport function 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 // (propagated; both `status` and `handoff` treat an uninitialized project as a\n // hard error — there is no project to snapshot).\n const project = loadProjectInfo(process.cwd());\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 — `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 { createHash } from 'node:crypto';\nimport { loadProjectInfo, nextArtifactSequence } 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 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 /** 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 // 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>] [--last] [--prompt '<continue instruction>']`\n// → workflow_resume (c4-surface-wiring S2)\n// ---------------------------------------------------------------------------\nexport interface TaskResumeOptions extends TaskOptions {\n id?: string;\n last?: boolean;\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 // `--last` / a positional id both target a specific task; omit both → active.\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 if (res.resumable !== true) {\n const detail =\n typeof res.error === 'string' && res.error.length > 0 ? res.error : 'nothing to resume';\n if (opts.json === true) {\n process.stdout.write(`${JSON.stringify({ ok: false, resumable: false, error: detail })}\\n`);\n return;\n }\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: createHash('sha256').update(out).digest('hex'),\n };\n } catch {\n return { exitCode: 1, digest: createHash('sha256').update('').digest('hex') };\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 const project = loadProjectInfo(process.cwd());\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)',\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 process.stdout.write(`${JSON.stringify({ ok: true, data: res, evidence })}\\n`);\n return;\n }\n success(`verify — ${evidence.summary} → gate approved`, opts);\n renderStatusRow(res as WorkflowStatusResult, opts);\n return;\n }\n // Pending / failed: render recovery options.\n if (opts.json === true) {\n process.stdout.write(`${JSON.stringify({ evidence, ...res })}\\n`);\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 } else {\n fail(EXIT.ERROR, `task verify: ${res.error ?? 'verify failed'}`, opts);\n }\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} — details TBD (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 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\nexport interface 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 {\n callDaemonTool,\n type DaemonClientOptions,\n type DaemonProbe,\n probeDaemon,\n withDaemon,\n withInProcessRead,\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// 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 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 result = await engines.memory.recall(opts.query, {\n ...(limit === undefined ? {} : { limit }),\n });\n const data = { query: opts.query, hits: result, degraded: false };\n if (opts.json === true) {\n process.stdout.write(`${JSON.stringify({ ok: true, data })}\\n`);\n return;\n }\n renderRecall(data.query, result, 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 callDaemonTool<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 sessions`\n// ---------------------------------------------------------------------------\nexport async function memorySessions(opts: MemoryOptions): Promise<void> {\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 callDaemonTool<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 withDaemon(opts, async (caller) => caller.listTools());\n if (!exposed.includes('memory_consolidate')) {\n fail(\n EXIT.ERROR,\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 callDaemonTool<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 { mkdirSync, writeFileSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { type HostId, SUPPORTED_HOSTS } from '@noir-ai/adapters';\nimport { type NoirEvent, runHost, type UsageSnapshot } from '../orchestrator.js';\nimport { type CliOptions, EXIT, fail, json, log, success } from '../output.js';\n\n/** Options accepted by `noir run` (globals + host/command 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}\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 if (event.kind === 'assistant' && event.text && event.text.length > 0) {\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 fail(EXIT.USAGE, 'a prompt is required: `noir run <prompt>`', opts);\n }\n\n const transcriptLines: string[] = [];\n\n try {\n const result = await runHost({\n host,\n prompt,\n customBinary: opts.command,\n onLine: (line) => transcriptLines.push(line),\n onEvent: (event) => streamEvent(event, opts),\n });\n\n if (opts.json !== true) {\n // Separator so the streamed answer and the summary don't run together.\n process.stdout.write('\\n');\n }\n\n const transcript = writeTranscript(host, transcriptLines);\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 if (result.exitCode !== 0) {\n log(`host exited ${result.exitCode}`, opts);\n if (result.stderr.length > 0) log(result.stderr.trim(), opts);\n }\n success(`usage: ${formatUsage(result.usage)} (API-equivalent estimate, not billed)`, opts);\n log(`transcript: ${transcript}`, opts);\n } catch (err) {\n fail(\n EXIT.ERROR,\n `failed to run host '${host}': ${err instanceof Error ? err.message : String(err)}`,\n opts,\n );\n }\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 mkdirSync(dir, { recursive: true });\n writeFileSync(file, `${lines.join('\\n')}${lines.length > 0 ? '\\n' : ''}`);\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 { createInterface } from 'node:readline';\nimport type { HostId } from '@noir-ai/adapters';\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 }\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\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 };\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 /** 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}\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 return new Promise((resolve, reject) => {\n if (!spec) {\n reject(new Error(`host '${opts.host}' is not a spawnable CLI (no default command)`));\n return;\n }\n const child = spawn(spec.binary, [...spec.flags, opts.prompt], {\n stdio: ['ignore', 'pipe', 'pipe'],\n });\n const reducer = new UsageReducer();\n let eventCount = 0;\n let stderrBuf = '';\n\n child.on('error', (err) => reject(err));\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 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) => {\n resolve({ exitCode: code ?? 0, usage: reducer.snapshot(), eventCount, stderr: stderrBuf });\n });\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 { claudeAdapter } from '@noir-ai/adapters';\nimport { loadProjectInfo } from '@noir-ai/core';\nimport {\n type BuiltinSkill,\n buildRegistry,\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; its throw propagates as a\n // plain Error → exit 1 with the actionable hint (not a daemon-down).\n const project = loadProjectInfo(root);\n\n if (!claudeAdapter.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 = claudeAdapter.skillsDir({ root });\n const summary = await emitSkillsToDir(dir);\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 if (opts.json === true) {\n process.stdout.write(`${JSON.stringify({ ok: errored.length === 0, data })}\\n`);\n return;\n }\n\n if (errored.length === 0) {\n log(`noir skills lint — ${skills.length} skills, all validate clean.`, opts);\n } else {\n warn(\n `noir skills lint — ${errored.length} skill${errored.length === 1 ? '' : 's'} FAIL validation:`,\n opts,\n );\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}\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","import { loadProjectInfo } from '@noir-ai/core';\nimport { ensureDaemonRunning, startStdioServer } from '@noir-ai/daemon';\n\nexport async function serve(opts: { stdio: boolean }): Promise<void> {\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 });\n process.stderr.write(\n `Noir daemon available at ${url}. (For HTTP clients, use this URL in .mcp.json.)\\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","// Dashboard root component. Owns the interactive state (input buffer, scroll\n// offset, dispatched output, snapshot, palette query/active, the active screen)\n// and the SINGLE keybinding dispatcher (v2 — the palette, home, help, and search\n// surfaces all collapsed into one corpus-aware palette, so keyboard routing\n// lives here alone). The snapshot is fetched via {@link TuiDeps.fetchStatus} on\n// a short interval (paused while a `/<command>` is dispatching, so a StatusBar\n// refresh can never race the stream capture). Dispatch goes through the EXISTING\n// {@link TuiDeps.dispatch} seam — the same `home(opts, deps).dispatch` shape —\n// so command routing is NOT reimplemented here.\n//\n// Screens (the {@link Mode} union): `dashboard` (default), `palette` (the single\n// command surface — corpus `commands` | `output` | `help`, opened by Ctrl+K /\n// Ctrl+F / h / ? and cycled with Tab), and `confirm` (the `y/N` gate before a\n// destructive dispatch — now covering EVERY dispatch path, typed /command\n// included). Every selection funnels through {@link handleRun}, so destructive\n// commands always pause at the confirm overlay.\n\nimport { Box, type Key, Text, useApp, useInput } from 'ink';\nimport { type ReactElement, useEffect, useMemo, useState } from 'react';\nimport type { StatusPayload } from '../commands/status.js';\nimport { c, divider } from '../theme.js';\nimport { CommandInput } from './CommandInput.js';\nimport { captureProcessOutput } from './capture.js';\nimport { isDestructive } from './commands/registry.js';\nimport { type HomeSection, resolveSections } from './commands/sections.js';\nimport { Footer } from './Footer.js';\nimport { formatStatusPayload } from './format.js';\nimport { Header } from './Header.js';\nimport { useInputBuffer } from './hooks/useInputBuffer.js';\nimport { OutputPane } from './OutputPane.js';\nimport { ConfirmOverlay } from './overlays/ConfirmOverlay.js';\nimport { Panel } from './Panel.js';\nimport { type FuzzyMatcher, handRolledMatcher } from './palette/matcher.js';\nimport { Palette } from './palette/Palette.js';\nimport { buildPaletteRows, CORPORA, type Corpus } from './palette/rows.js';\nimport type { PaletteCommand } from './palette/types.js';\nimport { StatusBar } from './StatusBar.js';\n\n/** Injected dependencies (mirrors the `home(opts, deps)` seam). */\nexport interface TuiDeps {\n /**\n * Run a Noir sub-command by user-form argv on a fresh commander program.\n * Same contract as {@link HomeDeps.dispatch}: must not throw — it owns its\n * own error → exit-code mapping and leaves the outcome on `process.exitCode`.\n */\n dispatch: (argv: readonly string[]) => Promise<void>;\n /**\n * Fetch the live status snapshot. Defaults to a wrapper around\n * `gatherStatusPayload` that folds ANY failure to `null` so the dashboard\n * degrades cleanly (uninitialized project, daemon down, probe hiccup).\n */\n fetchStatus: () => Promise<StatusPayload | null>;\n /**\n * The palette source — one {@link PaletteCommand} per leaf `noir` subcommand,\n * derived from the commander tree at `noir tui` launch (NOT re-walked per\n * keystroke). Optional for backward-compat (B1 tests omit it); when absent the\n * palette falls back to an empty command list.\n */\n readonly commands?: readonly PaletteCommand[];\n /** The fuzzy matcher. Optional — defaults to {@link handRolledMatcher}. */\n readonly matcher?: FuzzyMatcher;\n /**\n * Record a dispatched command into the persisted recent-commands list\n * (C3). Optional for backward-compat — when absent, recents are not recorded.\n */\n record?: (argv: readonly string[]) => Promise<void>;\n /**\n * Load the persisted recent commands (newest first) for the palette's recent\n * section. Optional — when absent, defaults to the on-disk history loader.\n */\n loadRecent?: () => Promise<readonly PaletteCommand[]>;\n}\n\n/** Optional initial state for tests (the live entry leaves these at defaults). */\nexport interface AppProps {\n deps: TuiDeps;\n /** Initial snapshot — skips the first fetch when provided (tests). */\n initialPayload?: StatusPayload | null;\n /** Refresh interval in ms (default 5000). Set large in tests. */\n refreshMs?: number;\n /**\n * The mode the App starts in. Defaults to the dashboard. `noir palette`\n * mounts the app palette-first via `{ kind: 'palette', corpus: 'commands' }`.\n */\n initialMode?: Mode;\n}\n\n/**\n * The dashboard's discriminated screen union. Exactly one screen is active at a\n * time; the App keys its render + keybinding handler off `mode.kind`.\n * - `dashboard` — the default screen: live snapshot, command input, output pane.\n * - `palette` — the single command surface, with a `corpus` selecting what the\n * query filters (commands / output / help).\n * - `confirm` — an in-TUI confirmation prompt for a destructive dispatch.\n */\nexport type Mode =\n | { kind: 'dashboard' }\n | { kind: 'palette'; corpus: Corpus }\n | { kind: 'confirm'; argv: string[] };\n\ninterface DispatchedOutput {\n title: string;\n lines: string[];\n}\n\nexport function App({\n deps,\n initialPayload = null,\n refreshMs = 5000,\n initialMode = { kind: 'dashboard' },\n}: AppProps): ReactElement {\n const { exit } = useApp();\n const { buffer, setBuffer, pushHistory, recall, clear, seed } = useInputBuffer();\n const [mode, setMode] = useState<Mode>(initialMode);\n const [payload, setPayload] = useState<StatusPayload | null>(initialPayload);\n const [loading, setLoading] = useState(initialPayload === null);\n const [output, setOutput] = useState<DispatchedOutput | null>(null);\n // The output lines the `output` corpus searches. Captured from the CURRENT\n // dispatched output when the corpus opens, so a new dispatch landing mid-search\n // cannot change the corpus mid-filter.\n const [searchLines, setSearchLines] = useState<readonly string[]>([]);\n const [scrollOffset, setScrollOffset] = useState(0);\n const [running, setRunning] = useState(false);\n const [notice, setNotice] = useState<string | null>(null);\n // The argv of a dispatch the user just submitted. An effect watches this so\n // the dispatch runs AFTER React flushes the \"running…\" frame.\n const [pending, setPending] = useState<string[] | null>(null);\n // The persisted recent-commands list for the palette, loaded once on mount.\n const [recent, setRecent] = useState<readonly PaletteCommand[]>([]);\n // The curated home sections, resolved against the live registry once.\n const [homeSections, setHomeSections] = useState<readonly HomeSection[]>([]);\n // v2 — the single palette's query + active row (owned here so the App's one\n // `useInput` routes palette keys and can resolve the active row on Enter).\n const [paletteQuery, setPaletteQuery] = useState('');\n const [paletteActive, setPaletteActive] = useState(0);\n\n // ----- load the palette's recent commands once on mount ------------------\n useEffect(() => {\n if (!deps.loadRecent) return;\n const loader = deps.loadRecent;\n let cancelled = false;\n void loader()\n .then((entries) => {\n if (!cancelled) {\n setRecent(entries);\n // Seed the shell-recall overlay from the SAME persisted recents the\n // palette shows, so ↑/↓ recall and the palette recents never diverge.\n seed(entries.map((c) => `/${c.argv.join(' ')}`));\n }\n })\n .catch(() => {\n // Recents are a nice-to-have — a read failure leaves the full list.\n });\n return () => {\n cancelled = true;\n };\n }, [deps.loadRecent, seed]);\n\n // ----- resolve the curated home sections once ---------------------------\n useEffect(() => {\n let cancelled = false;\n void resolveSections(deps.commands ?? []).then((sections) => {\n if (!cancelled) setHomeSections(sections);\n });\n return () => {\n cancelled = true;\n };\n }, [deps.commands]);\n\n // ----- snapshot refresh: paused while a dispatch is in flight ----------\n useEffect(() => {\n // Pause polling while a dispatch runs OR the palette/confirm overlay is\n // open (the dashboard snapshot is off-screen then, so polling only wastes\n // a fetch + a re-render).\n if (running || mode.kind !== 'dashboard') return;\n let cancelled = false;\n let inFlight = false;\n const fetched = (p: StatusPayload | null): void => {\n inFlight = false;\n if (cancelled) return;\n setPayload(p);\n setLoading(false);\n };\n setLoading(true);\n inFlight = true;\n void deps\n .fetchStatus()\n .then(fetched)\n .catch(() => fetched(null));\n const id = setInterval(() => {\n // Skip the tick while a fetch is still pending — a slow/restarting daemon\n // (gatherStatusPayload does a probe + MCP round-trips) must not stack\n // concurrent fetches.\n if (inFlight) return;\n inFlight = true;\n void deps\n .fetchStatus()\n .then(fetched)\n .catch(() => {\n // Keep the last-good payload on a transient probe/daemon failure — a\n // poll-time hiccup must not wipe the dashboard to \"down\".\n inFlight = false;\n });\n }, refreshMs);\n return () => {\n cancelled = true;\n clearInterval(id);\n };\n }, [running, mode.kind, refreshMs, deps.fetchStatus]);\n\n // ----- dispatch runner: fires after the \"running\" frame has flushed ------\n useEffect(() => {\n if (pending === null) return;\n const argv = pending;\n let active = true;\n const run = async (): Promise<void> => {\n const captured = await captureProcessOutput(() => deps.dispatch(argv));\n if (!active) return;\n const combined = `${captured.stdout}${captured.stderr}`;\n const lines = combined.split('\\n');\n while (lines.length > 0 && lines[lines.length - 1] === '') lines.pop();\n const title = `/${argv.join(' ')} → exit ${captured.exitCode}`;\n setOutput({ title, lines });\n setNotice(`ran /${argv.join(' ')} → exit ${captured.exitCode}`);\n setRunning(false);\n setPending(null);\n setScrollOffset(0);\n };\n void run();\n return () => {\n active = false;\n };\n }, [pending, deps.dispatch]);\n\n // ----- shared dispatch helper --------------------------------------------\n function dispatchCmd(argv: readonly string[]): void {\n setOutput(null);\n setRunning(true);\n setPending([...argv]);\n }\n\n // ----- unified run seam: every selection (palette / home / confirm) ------\n function handleRun(argv: readonly string[], destructive: boolean): void {\n if (destructive) {\n setMode({ kind: 'confirm', argv: [...argv] });\n return;\n }\n dispatchCmd([...argv]);\n void recordRuns([...argv]);\n pushHistory(`/${argv.join(' ')}`);\n setMode({ kind: 'dashboard' });\n }\n\n function recordRuns(argv: readonly string[]): void {\n const recorder = deps.record;\n if (recorder) void recorder(argv);\n }\n\n // ----- palette open / cycle helpers --------------------------------------\n function openPalette(corpus: Corpus): void {\n setPaletteQuery('');\n setPaletteActive(0);\n setMode({ kind: 'palette', corpus });\n setNotice(null);\n }\n\n function openOutputSearch(): void {\n if (output === null) return;\n setSearchLines(output.lines);\n openPalette('output');\n }\n\n function nextCorpus(current: Corpus): Corpus {\n const idx = CORPORA.indexOf(current);\n const candidates = [...CORPORA.slice(idx + 1), ...CORPORA.slice(0, idx + 1)];\n for (const corpus of candidates) {\n if (corpus === 'output' && output === null) continue; // no output to search\n return corpus;\n }\n return 'commands';\n }\n\n // ----- dashboard-mode keybinding handler -------------------------------\n function handleDashboardInput(input: string, key: Key): void {\n if (running) return;\n setNotice(null);\n\n if (key.return) {\n submit();\n return;\n }\n if (key.escape) {\n if (buffer.length > 0) clear();\n else if (output !== null) setOutput(null);\n else exit();\n return;\n }\n if (key.backspace || key.delete) {\n setBuffer((b) => b.slice(0, -1));\n return;\n }\n if (key.upArrow) {\n if (buffer === '/') {\n const entry = recall('up');\n if (entry !== null) {\n setBuffer(() => entry);\n return;\n }\n }\n setScrollOffset((o) => Math.max(0, o - 1));\n return;\n }\n if (key.downArrow) {\n if (buffer === '/') {\n const entry = recall('down');\n if (entry !== null) {\n setBuffer(() => entry);\n return;\n }\n }\n setScrollOffset((o) => o + 1);\n return;\n }\n if (key.ctrl) {\n if (input === 'k') {\n openPalette('commands');\n return;\n }\n if (input === 'f' && output !== null) {\n openOutputSearch();\n return;\n }\n return;\n }\n if (input.length === 1) {\n if (buffer.length === 0) {\n if (input === 'q') {\n exit();\n return;\n }\n if (input === '?') {\n openPalette('help');\n return;\n }\n if (input === 'h') {\n openPalette('commands');\n return;\n }\n }\n setBuffer((b) => b + input);\n return;\n }\n if (input.length > 1) {\n setBuffer((b) => b + input);\n }\n }\n\n // ----- palette-mode keybinding handler (single router) -------------------\n // Clamp the active cursor to the FULL row list. The renderer slides a\n // VISIBLE_ROWS window over the list, so the cursor (and Enter) can reach\n // every row, not just the first ten.\n function moveActive(delta: number): void {\n const max = Math.max(0, paletteRows.length - 1);\n setPaletteActive((a) => Math.min(max, Math.max(0, a + delta)));\n }\n\n function handlePaletteInput(input: string, key: Key): void {\n if (mode.kind !== 'palette') return;\n if (key.escape) {\n setPaletteQuery('');\n setPaletteActive(0);\n setMode({ kind: 'dashboard' });\n return;\n }\n if (key.tab) {\n setMode({ kind: 'palette', corpus: nextCorpus(mode.corpus) });\n setPaletteQuery('');\n setPaletteActive(0);\n return;\n }\n if (mode.corpus === 'help') {\n if (key.upArrow) moveActive(-1);\n else if (key.downArrow) moveActive(1);\n return; // help corpus takes no typing\n }\n if (key.return) {\n if (mode.corpus === 'commands') {\n const row = paletteRows[paletteActive];\n if (row?.argv) handleRun(row.argv, row.destructive);\n } else {\n moveActive(1); // output corpus: next match\n }\n return;\n }\n if (key.upArrow) {\n moveActive(-1);\n return;\n }\n if (key.downArrow) {\n moveActive(1);\n return;\n }\n if (key.backspace || key.delete) {\n setPaletteQuery((q) => q.slice(0, -1));\n setPaletteActive(0);\n return;\n }\n if (key.ctrl) return;\n if (input.length > 0) {\n setPaletteQuery((q) => q + input);\n setPaletteActive(0);\n }\n }\n\n // ----- confirm-mode keybinding handler ----------------------------------\n function handleConfirmInput(input: string, key: Key): void {\n if (key.escape || input === 'n' || input === 'N') {\n // Back to the palette with a clean query so the full list is visible.\n setPaletteQuery('');\n setPaletteActive(0);\n setMode({ kind: 'palette', corpus: 'commands' });\n return;\n }\n if (input === 'y' || input === 'Y') {\n if (mode.kind !== 'confirm') return;\n dispatchCmd([...mode.argv]);\n void recordRuns([...mode.argv]);\n pushHistory(`/${mode.argv.join(' ')}`);\n setMode({ kind: 'dashboard' });\n }\n }\n\n // ----- keybinding dispatcher (single `useInput` for the whole App) ------\n useInput((input, key) => {\n switch (mode.kind) {\n case 'dashboard':\n handleDashboardInput(input, key);\n return;\n case 'palette':\n handlePaletteInput(input, key);\n return;\n case 'confirm':\n handleConfirmInput(input, key);\n return;\n }\n });\n\n function submit(): void {\n const text = buffer;\n if (text.length === 0) return;\n clear();\n if (!text.startsWith('/')) {\n setNotice('type a /command to run it (bare text is just a hint)');\n return;\n }\n const argv = text\n .slice(1)\n .split(/\\s+/)\n .map((s) => s.trim())\n .filter((s) => s.length > 0);\n if (argv.length === 0) {\n setNotice('empty /command');\n return;\n }\n if (isDestructive(argv)) {\n // Destructive typed /commands go through the SAME confirm gate the\n // palette uses (v2 — closes the old typed-path bypass).\n setMode({ kind: 'confirm', argv });\n return;\n }\n pushHistory(text);\n dispatchCmd(argv);\n void recordRuns(argv);\n }\n\n // The rows for the active palette corpus, memoized so the dashboard hot path\n // (every keystroke + snapshot poll) does NOT rebuild ~60 row objects. Only\n // recompute when a palette input actually changes.\n const paletteRows = useMemo(\n () =>\n buildPaletteRows({\n corpus: mode.kind === 'palette' ? mode.corpus : 'commands',\n query: paletteQuery,\n commands: deps.commands ?? [],\n matcher: deps.matcher ?? handRolledMatcher,\n recent,\n homeSections,\n outputLines: searchLines,\n }),\n [mode, paletteQuery, deps.commands, deps.matcher, recent, homeSections, searchLines],\n );\n\n // ----- render -----------------------------------------------------------\n if (mode.kind === 'palette') {\n return (\n <Box flexDirection=\"column\">\n <Header tagline={`palette · ${mode.corpus}`} />\n <Palette\n corpus={mode.corpus}\n query={paletteQuery}\n active={paletteActive}\n rows={paletteRows}\n />\n <Footer running={false} />\n </Box>\n );\n }\n\n if (mode.kind === 'confirm') {\n return (\n <Box flexDirection=\"column\">\n <Header tagline=\"confirm\" />\n <ConfirmOverlay argv={mode.argv} />\n <Footer running={false} />\n </Box>\n );\n }\n\n const snapshotLines = formatStatusPayload(payload);\n const paneLines = output?.lines ?? snapshotLines ?? [];\n const paneTitle = output?.title ?? 'snapshot';\n\n return (\n <Box flexDirection=\"column\">\n <Header tagline=\"dashboard\" />\n <Panel>\n <Box paddingX={1}>\n <StatusBar payload={payload} loading={loading} />\n </Box>\n <Box paddingX={1}>\n <Text>{divider()}</Text>\n </Box>\n <Box flexDirection=\"column\" paddingX={1}>\n <OutputPane lines={paneLines} scrollOffset={scrollOffset} title={paneTitle} />\n </Box>\n </Panel>\n <CommandInput buffer={buffer} running={running} />\n {notice !== null ? <Text>{c.dim(notice)}</Text> : null}\n <Footer running={running} />\n </Box>\n );\n}\n","// Command input display. The input buffer + cursor live in the App (so is the\n// keybinding dispatch); this component is purely presentational — it renders\n// the prefix convention (`/` invokes a native Noir subcommand, bare text is a\n// hint) and shows a block cursor at the end of the buffer.\n//\n// The hint rule: when the buffer is empty, show a dim placeholder describing\n// the convention; once the user types, render the buffer verbatim with an\n// accent prefix when the first char is `/` (a recognized dispatch) or a dim\n// prefix otherwise (a hint that this input would NOT dispatch on Enter).\n//\n// The input is drawn inside a rounded border so the interactive field is\n// visually distinct from the static output above it (TUI redesign: rounded\n// outlines on every interactive surface).\n\nimport { Box, Text } from 'ink';\nimport type { ReactElement } from 'react';\nimport { c, contentWidth } from '../theme.js';\n\ninterface CommandInputProps {\n buffer: string;\n running?: boolean;\n}\n\nexport function CommandInput({ buffer, running }: CommandInputProps): ReactElement {\n if (running) {\n return (\n <Box borderStyle=\"round\" borderColor=\"gray\" paddingX={1} width={contentWidth() + 4}>\n <Text>{c.dim('…')}</Text>\n </Box>\n );\n }\n let body: ReactElement;\n if (buffer.length === 0) {\n body = (\n <Text>\n <Text>{c.dim('▌')}</Text>{' '}\n <Text>{c.dim('type a /command (e.g. /status, /sync, /task next), or q to quit')}</Text>\n </Text>\n );\n } else {\n const isCommand = buffer.startsWith('/');\n body = (\n <Text>\n <Text>{isCommand ? c.accent('▸') : c.dim('▸')}</Text> {buffer}\n <Text>{c.dim('▌')}</Text>\n </Text>\n );\n }\n return (\n <Box borderStyle=\"round\" borderColor=\"gray\" paddingX={1} width={contentWidth() + 4}>\n {body}\n </Box>\n );\n}\n","// Stream capture for the dashboard's command dispatch.\n//\n// While the dashboard runs, Ink owns the terminal (raw-mode stdin + ANSI render\n// writes to stdout). When the user submits a `/<command>`, the EXISTING command\n// dispatch seam is reused verbatim — the dispatched command writes to\n// `process.stdout` / `process.stderr` via the same centralized output helpers\n// (`log`, `json`, `table`, `definitionList`, …) every other invocation uses.\n// To keep that contract AND render the result inside the dashboard's output\n// pane (instead of corrupting Ink's render), the dispatched command's writes\n// are captured for the duration of the dispatch and restored after.\n//\n// Invariant: Ink does not rerender mid-dispatch, because the App does not\n// `setState` between the stream swap and its restore (the only state change is\n// the single `setOutput` AFTER the await resolves). So the captured text is\n// exactly the dispatched command's bytes — no Ink frames leak in.\n\n/** Capture everything written to stdout/stderr during `fn`, plus the exit code. */\nexport interface CapturedOutput {\n stdout: string;\n stderr: string;\n exitCode: number;\n}\n\n/**\n * Run `fn` with `process.stdout.write` / `process.stderr.write` temporarily\n * replaced by string collectors. Restores the original writers in a `finally`\n * (so an unexpected throw still restores them). `process.exitCode` set by the\n * dispatched command is captured and then RESET to its pre-call value, so a\n * failing sub-command does not poison the dashboard's own process exit.\n */\nexport async function captureProcessOutput(fn: () => Promise<void>): Promise<CapturedOutput> {\n const outChunks: string[] = [];\n const errChunks: string[] = [];\n const origOut = process.stdout.write.bind(process.stdout);\n const origErr = process.stderr.write.bind(process.stderr);\n const prevExitCode = process.exitCode;\n\n // Type narrower: Node's Write result is `boolean`. The captured writers\n // always succeed (they just buffer), so return `true`.\n process.stdout.write = ((chunk: unknown) => {\n outChunks.push(typeof chunk === 'string' ? chunk : String(chunk));\n return true;\n }) as typeof process.stdout.write;\n process.stderr.write = ((chunk: unknown) => {\n errChunks.push(typeof chunk === 'string' ? chunk : String(chunk));\n return true;\n }) as typeof process.stderr.write;\n\n try {\n await fn();\n } finally {\n process.stdout.write = origOut;\n process.stderr.write = origErr;\n }\n\n const exitCode = typeof process.exitCode === 'number' ? process.exitCode : 0;\n // Reset so the dashboard's own process exit is not affected by a sub-command.\n process.exitCode = prevExitCode;\n return { stdout: outChunks.join(''), stderr: errChunks.join(''), exitCode };\n}\n","// Footer with the shortcut hints. Kept as a pure function of the running state\n// so the App can swap it without re-wiring keybindings. The hint copy lives in\n// `hints.ts` (single source of truth) — the bindings themselves live in App.tsx.\n\nimport { Text } from 'ink';\nimport type { ReactElement } from 'react';\nimport { c } from '../theme.js';\nimport { FOOTER_HINT, RUNNING_HINT } from './hints.js';\n\ninterface FooterProps {\n /** When true, a dispatched command is in flight — show the running hint. */\n running?: boolean;\n}\n\nexport function Footer({ running }: FooterProps): ReactElement {\n return <Text>{c.dim(running ? RUNNING_HINT : FOOTER_HINT)}</Text>;\n}\n","// Shared hint strings + the keybinding manifest (single source of truth).\n//\n// Before v2, the same \"navigate / run / close\" hint was copy-pasted into the\n// (now-retired) home menu and palette, and the `?` help screen re-listed every\n// binding as a second encoding. This module owns the hint copy once so the\n// footer, the palette footer line, and the `help` corpus all render the same\n// text and cannot drift from the actual bindings (which live in App.tsx).\n\n/** The dashboard's idle footer hint (the App's keybinding manifest as text). */\nexport const FOOTER_HINT =\n '?/h/Ctrl+K palette · Ctrl+F find · ↑/↓ scroll · Enter run · q/Esc quit · Ctrl+C exit';\n\n/** The hint shown while a dispatched command is in flight. */\nexport const RUNNING_HINT = 'running… (Ctrl+C to force exit)';\n\n/** The palette/home list footer hint (navigate · run · close). */\nexport const LIST_NAV_HINT = '↑/↓ navigate · Enter run · Esc close · Tab view';\n\n/** A single keybinding row for the `help` corpus. */\nexport interface HelpEntry {\n readonly keys: string;\n readonly desc: string;\n}\n\n/**\n * The keybinding manifest, rendered by the palette's `help` corpus. Keep this in\n * sync with the App's single `useInput` dispatcher (the same file that owns the\n * bindings) — a drift here is a doc bug, not a behavior bug.\n */\nexport const HELP_ENTRIES: readonly HelpEntry[] = [\n { keys: '/command', desc: 'run a Noir sub-command (e.g. /status, /sync, /task next)' },\n { keys: 'Enter', desc: 'run the typed /command' },\n { keys: 'Esc', desc: 'back: clear input → dismiss output → quit' },\n { keys: 'q', desc: 'quit (when the input is empty)' },\n { keys: '↑ / ↓', desc: 'scroll the output pane (dashboard) · navigate the list (palette)' },\n { keys: '?', desc: 'palette — help & keybindings (this list)' },\n { keys: 'h', desc: 'palette — commands (quick actions + all commands)' },\n { keys: 'Ctrl+K', desc: 'palette — all commands (fuzzy search)' },\n { keys: 'Ctrl+F', desc: 'palette — find in the dispatched output' },\n { keys: 'Tab', desc: 'switch between commands, output, and help' },\n { keys: 'y / n', desc: 'approve / decline a destructive command prompt' },\n { keys: 'Ctrl+C', desc: 'force exit' },\n];\n","// Format the live {@link StatusPayload} as plain text lines for the dashboard's\n// output pane. Reuses the SAME describe helpers `noir status` renders with, so\n// the dashboard's snapshot and `noir status`'s human table never drift apart.\n\nimport {\n describeContext,\n describeDaemon,\n describeMemory,\n describeStore,\n describeWorkflow,\n type StatusPayload,\n} from '../commands/status.js';\n\n/**\n * Render a status snapshot as `Label: value` lines. Returns `null` when the\n * payload is absent (the dashboard shows a placeholder in that case).\n */\nexport function formatStatusPayload(p: StatusPayload | null): string[] | null {\n if (p === null) return null;\n return [\n `Project: ${p.project.name} (${p.project.id})`,\n `Host: ${p.host}`,\n `Noir: ${p.noir}`,\n `Daemon: ${describeDaemon(p.daemon)}`,\n `Store: ${describeStore(p.store)}`,\n `Context: ${describeContext(p.context)}`,\n `Workflow: ${describeWorkflow(p.workflow)}`,\n `Memory: ${describeMemory(p.memory)}`,\n ];\n}\n","// Branded header. The diamond mark uses the Midnight Cobalt brand role\n// (`c.accent`, solid blue), which is the single-line form of the banner's\n// gradient — it strips under NO_COLOR and stays solid under NOIR_ACCESSIBLE.\n// The full block wordmark lives in the banner module; a dashboard header is a\n// one-line surface, so the compact mark is the right altitude.\n\nimport { Text } from 'ink';\nimport type { ReactElement } from 'react';\nimport { c } from '../theme.js';\n\nexport function Header({ tagline }: { tagline?: string }): ReactElement {\n return (\n <Text>\n {c.accent('◆')} {c.bold('noir')} <Text>{c.dim(tagline ?? 'dashboard')}</Text>\n </Text>\n );\n}\n","// B1 — the dashboard input-buffer hook. Extracted from `App.tsx` so the\n// command-history + recall-cursor state can live with the keybindings that use\n// it instead of dangling inside the App's single `useInput` closure. Owns:\n// - `buffer` — the current text being composed at the prompt.\n// - `history` — in-memory command history (newest first), with move-to-front\n// dedup (matches the persisted recents store).\n// - `recall` — Up/Down history walk via an index cursor (`-1` = not\n// recalling).\n// - `seed` — replace the session history with the persisted recents.\n//\n// Deliberately tiny + framework-shaped like the rest of the TUI state: `buffer`\n// is a React state string so keystrokes rerender the CommandInput, while\n// `history` + the cursor are refs (they are recalled on demand, never painted).\n//\n// IMPORTANT: every returned function is wrapped in `useCallback` so its identity\n// is STABLE across renders. The App passes `seed` into a `useEffect` dependency\n// array (`[deps.loadRecent, seed]`); a plain function re-created each render\n// would make that effect re-run every render — an infinite setState loop that\n// leaks memory and OOMs the TUI after ~a minute of idle. All these functions\n// only touch refs (+ the stable `setBuffer`), so `useCallback(…, [])` is safe.\n\nimport { useCallback, useRef, useState } from 'react';\n\n/** Cap on the in-memory session history (mirrors the persisted recents cap). */\nconst MAX_HISTORY = 50;\n\n/** The input-buffer + command-history surface the App's keybindings consume. */\nexport interface InputBuffer {\n /** The text currently being composed (never `undefined`). */\n readonly buffer: string;\n /** Apply an updater to the current buffer (React `useState` setter shape). */\n setBuffer: (updater: (prev: string) => string) => void;\n /** Record a submitted command into history (newest first, move-to-front dedup). */\n pushHistory: (text: string) => void;\n /**\n * Walk the command history from the recall cursor. `up` returns the next\n * older entry (or the newest when not recalling); `down` returns the next\n * newer entry. Either direction clamps at its boundary — past the newest it\n * returns `null` (back on the edit line).\n */\n recall: (dir: 'up' | 'down') => string | null;\n /** Empty the buffer and reset the recall cursor to \"not recalling\". */\n clear: () => void;\n /**\n * Replace the session history with the persisted recents (the source of\n * truth). Called once after `loadRecent` resolves so shell recall and the\n * palette recents read the same list instead of diverging.\n */\n seed: (entries: readonly string[]) => void;\n}\n\n/**\n * Mount the dashboard's input buffer + in-memory history. `clear` is what a\n * successful submit / an Escape-back invokes: it empties the buffer AND parks\n * the recall cursor so the next Up starts over from the newest entry, while\n * leaving `history` intact for the session.\n */\nexport function useInputBuffer(): InputBuffer {\n const [buffer, setBuffer] = useState('');\n // Newest command first. Refs, never state: history is only read on demand\n // by `recall`, so storing it in state would rerender the App for no benefit.\n const historyRef = useRef<string[]>([]);\n // Index into `historyRef.current`; -1 = not recalling (editing fresh text).\n const cursorRef = useRef(-1);\n\n const pushHistory = useCallback((text: string): void => {\n if (text.length === 0) return;\n // Move-to-front dedup (matches `recordRecent` in palette/history.ts): an\n // exact re-run moves the entry to the head instead of duplicating, so the\n // shell-recall overlay and the persisted recents apply one dedup rule.\n const history = historyRef.current.filter((e) => e !== text);\n // Cap at MAX_HISTORY so a long session running many distinct commands does\n // not grow the in-memory overlay without bound (the persisted store is\n // already capped at 50).\n historyRef.current = [text, ...history].slice(0, MAX_HISTORY);\n }, []);\n\n const recall = useCallback((dir: 'up' | 'down'): string | null => {\n const history = historyRef.current;\n if (history.length === 0) return null;\n let cursor = cursorRef.current;\n if (dir === 'up') {\n // -1 (edit line) steps to the newest; otherwise walk one older, clamped\n // at the oldest entry so Up can never walk off the front of the list.\n cursor = cursor === -1 ? 0 : Math.min(cursor + 1, history.length - 1);\n } else {\n // Walk newer; stepping past the newest returns to the edit line.\n cursor = cursor === -1 ? -1 : cursor - 1;\n }\n cursorRef.current = cursor;\n return cursor === -1 ? null : (history[cursor] ?? null);\n }, []);\n\n const clear = useCallback((): void => {\n setBuffer(() => '');\n cursorRef.current = -1;\n }, []);\n\n const seed = useCallback((entries: readonly string[]): void => {\n historyRef.current = [...entries];\n cursorRef.current = -1;\n }, []);\n\n return { buffer, setBuffer, pushHistory, recall, clear, seed };\n}\n","// Scrollable output pane. Renders a windowed slice of `lines` based on the\n// current scroll offset (controlled by ArrowUp/ArrowDown at the App level).\n// Two sources of text share this pane: (a) the live project snapshot (the same\n// payload `noir status` shows), and (b) the captured stdout/stderr of a\n// dispatched `/<command>`. When dispatched output is present it takes\n// precedence (the user just asked for it); the App returns to the snapshot view\n// when the output is dismissed.\n\nimport { Text } from 'ink';\nimport type { ReactElement } from 'react';\nimport { c, contentWidth } from '../theme.js';\n\ninterface OutputPaneProps {\n lines: readonly string[];\n /** Index of the FIRST line scrolled to the top of the viewport. */\n scrollOffset: number;\n /** Visible row height of the pane. Defaults to a comfortable 12 rows. */\n height?: number;\n /** Optional title for the pane (shown as a dim header line). */\n title?: string;\n}\n\ninterface Row {\n /** Stable, content-derived React key (deduplicated so duplicate lines don't collide). */\n key: string;\n /** The text to render for this row. */\n text: string;\n}\n\n/**\n * Build stable React keys from line content. Duplicate lines get a `#N` suffix\n * so each row's key is unique WITHOUT using the array index — the lint rule\n * flags index keys, and content keys are also correct here (the pane is read-\n * only, but content keys keep reconciliation honest across scroll refreshes).\n */\nfunction toRows(visible: readonly string[]): Row[] {\n const rows: Row[] = [];\n const seen = new Map<string, number>();\n for (let i = 0; i < visible.length; i++) {\n const text = visible[i] ?? '';\n const n = (seen.get(text) ?? 0) + 1;\n seen.set(text, n);\n rows.push({ key: n === 1 ? text || '_blank' : `${text || '_blank'}#${n}`, text });\n }\n return rows;\n}\n\nexport function OutputPane({\n lines,\n scrollOffset,\n height = 12,\n title,\n}: OutputPaneProps): ReactElement {\n // Content width already accounts for the parent panel's border + padding\n // (see contentWidth()). Truncating to this (not the full terminal width)\n // keeps long lines — like the `noir status` table — inside the rounded box.\n const width = contentWidth();\n\n if (lines.length === 0) {\n return <Text>{c.dim('(no output — type a /command, or ? for help)')}</Text>;\n }\n\n // Clamp the offset into range so a stale value (e.g. after the content\n // shrinks) never produces a blank pane.\n const maxOffset = Math.max(0, lines.length - height);\n const offset = Math.min(Math.max(0, scrollOffset), maxOffset);\n const rows = toRows(lines.slice(offset, offset + height));\n\n return (\n <>\n {title !== undefined ? <Text wrap=\"truncate-end\">{c.dim(`── ${title} ──`)}</Text> : null}\n {rows.map((row) => {\n const truncated =\n row.text.length > width ? `${row.text.slice(0, Math.max(1, width - 1))}…` : row.text;\n // wrap=\"truncate-end\" guarantees a long line never wraps inside the\n // bordered panel — the manual truncate above is the first line of\n // defense; this is the second (Ink will hard-truncate if the panel is\n // narrower than contentWidth() reported, e.g. under a tiny COLUMNS).\n return (\n <Text key={row.key} wrap=\"truncate-end\">\n {truncated}\n </Text>\n );\n })}\n </>\n );\n}\n","// C1 — in-TUI confirmation prompt for a destructive palette dispatch.\n//\n// Presentational only: it renders the `y/N` prompt for the argv the App wants\n// to approve. The App owns the input routing (its single `useInput` handles `y`\n// / `n` / Esc in confirm mode) and the dispatch seam, so this component has no\n// knowledge of what the command does or how to run it.\n//\n// Drawn inside a rounded, warn-colored border so a destructive gate is visually\n// unmistakable (TUI redesign: rounded outlines on every interactive surface).\n\nimport { Box, Text } from 'ink';\nimport type { ReactElement } from 'react';\nimport { c } from '../../theme.js';\nimport { Panel } from '../Panel.js';\n\n/** The confirm overlay's props — supplied by the App. */\nexport interface ConfirmOverlayProps {\n /** The argv being approved, e.g. `['context','index']`. */\n readonly argv: readonly string[];\n}\n\n/**\n * Render the `y/N` confirmation prompt. Capital `N` marks the default (decline),\n * matching the CLI's prompt convention.\n */\nexport function ConfirmOverlay({ argv }: ConfirmOverlayProps): ReactElement {\n return (\n <Panel>\n <Box paddingX={1}>\n <Text>\n {c.warn(`! run /${argv.join(' ')}? (y/N)`)}\n <Text>{c.dim(' [y approve · n/Esc back to palette]')}</Text>\n </Text>\n </Box>\n </Panel>\n );\n}\n","// Shared container — every TUI surface uses this one component for rounded\n// borders + width accounting so no caller duplicates `borderStyle round` /\n// `borderColor gray` / `width` math.\n//\n// When `maxWidth` is set the panel caps at that column ceiling — used by the\n// command palette for the fixed-width overlay look (like Raycast / VS Code).\n// Defaults to full terminal width via contentWidth().\n\nimport { Box } from 'ink';\nimport type { ReactElement, ReactNode } from 'react';\nimport { contentWidth } from '../theme.js';\n\nexport interface PanelProps {\n readonly children: ReactNode;\n /** Optional max-width ceiling in columns (e.g. 64 for the command palette). */\n readonly maxWidth?: number;\n}\n\nexport function Panel({ children, maxWidth }: PanelProps): ReactElement {\n const full = contentWidth() + 4; // border (2) + inner padding (2)\n const width = maxWidth != null ? Math.min(full, maxWidth) : full;\n return (\n <Box flexDirection=\"column\" borderStyle=\"round\" borderColor=\"gray\" paddingX={1} width={width}>\n {children}\n </Box>\n );\n}\n","// Hand-rolled fuzzy scorer for the command palette. This is the swap seam:\n// `fuzzyScore` + `matchCommand` are pure functions a future fzf/ItsFuzzy-style\n// matcher can replace without touching the TUI; `FuzzyMatch` is the shared\n// result shape both the matcher and the rendering layer speak.\n//\n// Design notes:\n// - Subsequence matcher (not substring): \"sts\" matches \"status\" (s, t, s).\n// - Case-insensitive — both sides lowercased before comparison.\n// - Gap penalty (-0.1 per skipped char) makes tight matches beat scattered ones.\n// - Consecutive bonus (+8) rewards runs like a real fuzzy finder.\n// - Prefix bonus (+4 while text-index < query.length) makes a leading match\n// dominate a trailing one, so \"sta\" ranks above a \"status\"-tail hit.\n\nimport type { PaletteCommand } from './types.js';\n\n/** A scored palette hit returned by the matcher. */\nexport interface FuzzyMatch {\n item: PaletteCommand;\n score: number;\n /** Text indices of the best-scoring field that matched (for highlight). */\n matchedIndices: number[];\n}\n\n/** Field weights — label dominates so titles win ties over help text. */\nconst WEIGHTS = {\n label: 1.0,\n keyword: 0.7,\n description: 0.5,\n} as const;\n\n/** Flat bonus added to the label field so it wins cross-field ties. */\nconst LABEL_TIE_BONUS = 50;\n\n/**\n * Score `query` against `text` as a (case-insensitive) subsequence. Returns\n * `{score, indices}` when every query char is matched in order, else `null`.\n * An empty query scores 0 with no indices.\n */\nexport function fuzzyScore(\n query: string,\n text: string,\n): { score: number; indices: number[] } | null {\n if (query.length === 0) return { score: 0, indices: [] };\n\n const q = query.toLowerCase();\n const t = text.toLowerCase();\n\n const indices: number[] = [];\n let score = 0;\n let prevMatchedIndex = -1;\n\n let qi = 0;\n for (let ti = 0; ti < t.length && qi < q.length; ti++) {\n if (t[ti] === q[qi]) {\n indices.push(ti);\n // consecutive-match bonus: only when this char directly follows the\n // previous matched char (a real fuzzy-finder \"run\" reward).\n const consecutive = prevMatchedIndex !== -1 && ti === prevMatchedIndex + 1;\n if (consecutive) score += 8;\n if (ti < q.length) score += 4; // prefix-region bonus\n // gap penalty for chars skipped between matches\n if (prevMatchedIndex !== -1) {\n const skipped = ti - prevMatchedIndex - 1;\n if (skipped > 0) score -= 0.1 * skipped;\n }\n prevMatchedIndex = ti;\n qi++;\n }\n }\n\n if (qi < q.length) return null; // query not a full subsequence\n return { score, indices };\n}\n\n/**\n * Score a single command across its label / keywords / description, returning\n * the best field's weighted result (plus the flat label tie-break bonus so a\n * label hit always wins a tie against a keyword or description hit). Returns\n * `null` when the query matches no field.\n */\nexport function matchCommand(query: string, item: PaletteCommand): FuzzyMatch | null {\n if (query.length === 0) {\n return { item, score: 0, matchedIndices: [] };\n }\n\n // Track the best field hit. Kept as a mutable holder (rather than a\n // `| null` union) so the `consider` closure can read the running high score\n // without TypeScript narrowing it to `never` across the conditional updates.\n const best: { score: number; indices: number[] } = {\n score: Number.NEGATIVE_INFINITY,\n indices: [],\n };\n let matched = false;\n\n // Replace the running best if `candidate` scores higher.\n const consider = (score: number, indices: number[]): void => {\n if (!matched || score > best.score) {\n best.score = score;\n best.indices = indices;\n matched = true;\n }\n };\n\n // Label — weighted highest, plus the flat tie-break bonus.\n const labelHit = fuzzyScore(query, item.label);\n if (labelHit) {\n consider(labelHit.score * WEIGHTS.label + LABEL_TIE_BONUS, labelHit.indices);\n }\n\n // Keywords — each scored independently, best keyword wins the field.\n if (item.keywords) {\n let bestKw: { score: number; indices: number[] } | null = null;\n for (const kw of item.keywords) {\n const kwHit = fuzzyScore(query, kw);\n if (kwHit && (bestKw === null || kwHit.score > bestKw.score)) bestKw = kwHit;\n }\n if (bestKw) {\n consider(bestKw.score * WEIGHTS.keyword, bestKw.indices);\n }\n }\n\n // Description — lowest weight, last resort.\n if (item.description) {\n const descHit = fuzzyScore(query, item.description);\n if (descHit) {\n consider(descHit.score * WEIGHTS.description, descHit.indices);\n }\n }\n\n if (!matched) return null;\n return { item, score: best.score, matchedIndices: best.indices };\n}\n","// The matcher swap seam. `FuzzyMatcher` is the interface the TUI depends on;\n// `handRolledMatcher` is the default, dependency-free implementation built on\n// `matchCommand`. Swapping in a native fzf/ItsFuzzy binding later means shipping\n// a second `FuzzyMatcher` — the palette code never changes.\n\nimport { type FuzzyMatch, matchCommand } from './fuzzyMatch.js';\nimport type { PaletteCommand } from './types.js';\n\n/**\n * What the palette asks for: \"rank these items against this query, capped at\n * `limit`\". Implementations must be deterministic and side-effect free.\n */\nexport interface FuzzyMatcher {\n search(query: string, items: readonly PaletteCommand[], limit: number): FuzzyMatch[];\n}\n\n/**\n * Default matcher. Empty query returns every item (score 0, empty indices) so\n * the palette can render the full list before the user types; otherwise each\n * item is scored, filtered to matches, sorted by descending score, and sliced\n * to `limit`. Sort is stable (ties keep input order) via a Array.prototype.sort\n * that only reorders on a strict score difference.\n */\nexport const handRolledMatcher: FuzzyMatcher = {\n search(query: string, items: readonly PaletteCommand[], limit: number): FuzzyMatch[] {\n if (query.length === 0) {\n return items.slice(0, Math.max(0, limit)).map((item) => ({\n item,\n score: 0,\n matchedIndices: [],\n }));\n }\n\n const matched: FuzzyMatch[] = [];\n for (const item of items) {\n const m = matchCommand(query, item);\n if (m) matched.push(m);\n }\n\n matched.sort((a, b) => b.score - a.score);\n return matched.slice(0, Math.max(0, limit));\n },\n};\n","// The single command surface (v2) — presentational renderer.\n//\n// The App owns the query + active row + the single `useInput` dispatcher; this\n// component only paints the rows {@link buildPaletteRows} produced for the\n// active corpus (commands / output / help). No `useInput`, no dispatch, no\n// history — the App is the sole decision-maker, so home, palette, and typed\n// /command all funnel through one seam.\n//\n// Layout (two-column, per the v2 design): a fixed label column (bold) on the\n// left, a dim hint column on the right. For command rows the hint is the\n// command's argv (short + unambiguous); the FULL description is shown as a\n// wrapped detail line on the ACTIVE row only, so it is never truncated. The\n// active row is highlighted with reverse video (SGR 7) — visible on any\n// terminal, not just color ones.\n\nimport { Box, Text } from 'ink';\nimport type { ReactElement } from 'react';\nimport { c } from '../../theme.js';\nimport { LIST_NAV_HINT } from '../hints.js';\nimport { Panel } from '../Panel.js';\nimport { type Corpus, type PaletteRow, VISIBLE_ROWS } from './rows.js';\n\nconst PALETTE_WIDTH = 64;\n/** Fixed label column: the `▸ `/` ` prefix (2) + the label. */\nconst LABEL_WIDTH = 26;\n/** Max hint column width (keeps the two-column row inside the panel). */\nconst HINT_WIDTH = 34;\n\n/** Word-boundary wrap so a long description never truncates or overflows. */\nfunction wrap(text: string, width: number): string[] {\n const words = text.split(/\\s+/).filter((w) => w.length > 0);\n const lines: string[] = [];\n let cur = '';\n for (const w of words) {\n if (cur.length === 0) cur = w;\n else if ((cur + ' ' + w).length <= width) cur = `${cur} ${w}`;\n else {\n lines.push(cur);\n cur = w;\n }\n }\n if (cur) lines.push(cur);\n return lines;\n}\n\n/** Truncate a label to fit the fixed label column. */\nfunction truncateLabel(label: string): string {\n const max = LABEL_WIDTH - 2;\n return label.length > max ? `${label.slice(0, max - 1)}…` : label;\n}\n\n/** Placeholder hint for the query row, per corpus. */\nfunction placeholder(corpus: Corpus): string {\n if (corpus === 'commands') return 'type to search commands';\n if (corpus === 'output') return 'type to filter output';\n return 'keybindings';\n}\n\n/** The palette's props — supplied by the App (which owns input + dispatch). */\nexport interface PaletteProps {\n readonly corpus: Corpus;\n readonly query: string;\n readonly active: number;\n readonly rows: readonly PaletteRow[];\n}\n\n/**\n * Render the palette overlay: an input row + the corpus list. Presentational —\n * the App owns query/active/input and passes the rows in.\n */\nexport function Palette({ corpus, query, active, rows }: PaletteProps): ReactElement {\n const total = rows.length;\n // Sliding window: the cursor spans the FULL row list; slide a VISIBLE_ROWS\n // window so the active row is always on screen (sticking to the bottom once\n // scrolled). Without this, only the first 10 rows of a ~60-row command list\n // would be reachable.\n const scroll = Math.max(0, Math.min(active - (VISIBLE_ROWS - 1), total - VISIBLE_ROWS));\n const visible = rows.slice(scroll, scroll + VISIBLE_ROWS);\n const activeIndex = Math.min(Math.max(active - scroll, 0), Math.max(0, visible.length - 1));\n\n const elements: ReactElement[] = [\n <Box key=\"header\" paddingX={1}>\n <Text>\n {c.bold('▸ palette ')}\n <Text>{c.dim(`· ${corpus}`)}</Text>\n </Text>\n </Box>,\n <Box key=\"query\" paddingX={1}>\n <Text>\n {c.dim('> ')}\n {query.length > 0 ? query : c.dim(placeholder(corpus))}\n <Text>{c.dim('▌')}</Text>\n </Text>\n </Box>,\n ];\n\n let lastGroup: string | null = null;\n for (let i = 0; i < visible.length; i++) {\n const row = visible[i];\n if (!row) continue;\n if (row.group !== null && row.group !== lastGroup) {\n // A blank spacer before every section (except the first) so the group\n // headers read as distinct, scannable blocks rather than a wall of rows.\n if (lastGroup !== null) {\n elements.push(\n <Box key={`gap:${row.group}`}>\n <Text> </Text>\n </Box>,\n );\n }\n elements.push(\n <Box key={`cat:${row.group}`} paddingX={1}>\n <Text>{c.bold(`── ${row.group} ──`)}</Text>\n </Box>,\n );\n lastGroup = row.group;\n }\n const isActive = i === activeIndex;\n const prefix = isActive ? '▸ ' : ' ';\n const label = truncateLabel(row.primary);\n const labelCol = (prefix + label).padEnd(LABEL_WIDTH);\n // Hint (right column): the argv for command rows, prefixed with `/` so it\n // reads as \"the command that runs on Enter\" (matching the dashboard's\n // `/command` convention). Non-command rows use the secondary line. Clipped\n // to the hint column so a long keybinding description (help corpus) never\n // overflows the panel.\n const hintRaw = row.argv ? `/${row.argv.join(' ')}` : row.secondary;\n const hint = hintRaw.length > HINT_WIDTH ? `${hintRaw.slice(0, HINT_WIDTH - 1)}…` : hintRaw;\n\n if (isActive) {\n // Reverse video highlights the whole row — no inner color needed.\n elements.push(\n <Box key={row.key} paddingX={1}>\n <Text>{c.inverse(`${labelCol}${hint}`)}</Text>\n </Box>,\n );\n } else {\n elements.push(\n <Box key={row.key} paddingX={1}>\n <Text>\n {c.bold(labelCol)}\n {hint.length > 0 ? c.dim(hint) : null}\n </Text>\n </Box>,\n );\n }\n\n // Detail line: the FULL description on the active command row, wrapped so\n // it is never truncated. A leading `↳` marks it as the detail of the row\n // above (not a new selectable item); continuation lines align under the\n // text so they read as one wrapped block.\n if (isActive && row.argv && row.secondary) {\n const detailLines = wrap(row.secondary, PALETTE_WIDTH - 12);\n for (let di = 0; di < detailLines.length; di++) {\n const line = detailLines[di] ?? '';\n const prefix = di === 0 ? ' ↳ ' : ' ';\n elements.push(\n <Box key={`${row.key}:d:${di}`} paddingX={1}>\n <Text>{c.dim(`${prefix}${line}`)}</Text>\n </Box>,\n );\n }\n }\n }\n\n return (\n <Box flexDirection=\"column\">\n <Panel maxWidth={PALETTE_WIDTH}>{elements}</Panel>\n <Text>{c.dim(LIST_NAV_HINT)}</Text>\n </Box>\n );\n}\n","// Output-search primitives (moved from the retired `overlays/SearchMode.ts`).\n//\n// Pure, framework-free functions the palette's `output` corpus consumes:\n// `computeMatches` turns a query into the line indices that contain it. The\n// `/` dispatch prefix makes '/' unusable as a search key, so Ctrl+F (or the\n// palette `Tab` switch) is the entry into this corpus.\n\n/**\n * Line indices whose (case-insensitive) text contains `query`, in line order.\n * An empty query matches nothing (`[]`) — the search only starts once the user\n * types, and an empty query must never be treated as \"matches every line\".\n */\nexport function computeMatches(lines: readonly string[], query: string): number[] {\n if (query.length === 0) return [];\n const needle = query.toLowerCase();\n const out: number[] = [];\n for (let i = 0; i < lines.length; i++) {\n if ((lines[i] ?? '').toLowerCase().includes(needle)) out.push(i);\n }\n return out;\n}\n","// Pure row-building for the single command surface (v2). The App owns the\n// query + active row + key routing; this module derives the visible rows for a\n// corpus so the App can resolve the active row into a dispatch (Enter) while\n// the presentational `Palette` renders the same rows — one source of truth for\n// what the palette shows and what a selection runs.\n\nimport type { HomeAction, HomeSection } from '../commands/sections.js';\nimport { HELP_ENTRIES } from '../hints.js';\nimport type { FuzzyMatcher } from './matcher.js';\nimport { computeMatches } from './output.js';\nimport type { PaletteCommand } from './types.js';\n\n/** The palette's active corpus. */\nexport type Corpus = 'commands' | 'output' | 'help';\n\n/** All corpora, in `Tab`-cycle order. */\nexport const CORPORA: readonly Corpus[] = ['commands', 'output', 'help'];\n\nconst MATCH_LIMIT = 20;\n\n/** How many rows the palette renders at once (the sliding window size). */\nexport const VISIBLE_ROWS = 10;\n\n/** A rendered palette row. `argv` is null for non-dispatchable rows. */\nexport interface PaletteRow {\n key: string;\n primary: string;\n secondary: string;\n argv: readonly string[] | null;\n destructive: boolean;\n group: string | null;\n}\n\n/** Inputs to {@link buildPaletteRows}. */\nexport interface BuildRowsInput {\n corpus: Corpus;\n query: string;\n commands: readonly PaletteCommand[];\n matcher: FuzzyMatcher;\n recent: readonly PaletteCommand[];\n homeSections: readonly HomeSection[];\n outputLines: readonly string[];\n}\n\n/** Flatten curated home sections into `{ group, action }` rows. */\nfunction flattenHome(sections: readonly HomeSection[]): { group: string; action: HomeAction }[] {\n const out: { group: string; action: HomeAction }[] = [];\n for (const section of sections) {\n for (const action of section.items) out.push({ group: section.label, action });\n }\n return out;\n}\n\n/** `recent` entries that still exist in `commands`, in recent order. */\nfunction recentDeduped(\n recent: readonly PaletteCommand[],\n commands: readonly PaletteCommand[],\n): PaletteCommand[] {\n const known = new Set(commands.map((cmd) => cmd.id));\n return recent.filter((cmd) => known.has(cmd.id));\n}\n\n/** Build the visible rows for the active corpus + query. */\nexport function buildPaletteRows(input: BuildRowsInput): PaletteRow[] {\n const { corpus, query, commands, matcher, recent, homeSections, outputLines } = input;\n\n if (corpus === 'help') {\n return HELP_ENTRIES.map((e) => ({\n key: `help:${e.keys}`,\n primary: e.keys,\n secondary: e.desc,\n argv: null,\n destructive: false,\n group: 'keybindings',\n }));\n }\n\n if (corpus === 'output') {\n const matches = computeMatches(outputLines, query);\n if (query.length > 0 && matches.length === 0) {\n // A typed filter with zero hits is an explicit empty state — never list\n // the full output under a misleading \"matches\" header.\n return [\n {\n key: 'empty',\n primary: '(no matches)',\n secondary: `nothing matches \"${query}\"`,\n argv: null,\n destructive: false,\n group: null,\n },\n ];\n }\n if (matches.length === 0) {\n if (outputLines.length === 0) {\n return [\n {\n key: 'empty',\n primary: '(no output)',\n secondary: 'run a /command first',\n argv: null,\n destructive: false,\n group: null,\n },\n ];\n }\n // Empty query: browse the full output.\n return outputLines.map((line, i) => ({\n key: `out:${i}`,\n primary: line,\n secondary: String(i + 1),\n argv: null,\n destructive: false,\n group: null,\n }));\n }\n return matches.map((i) => ({\n key: `out:${i}`,\n primary: outputLines[i] ?? '',\n secondary: String(i + 1),\n argv: null,\n destructive: false,\n group: 'matches',\n }));\n }\n\n // commands corpus.\n if (query.length === 0) {\n const rows: PaletteRow[] = [];\n const recents = recentDeduped(recent, commands);\n const recentIds = new Set(recents.map((r) => r.id));\n for (const cmd of recents) {\n rows.push({\n key: `recent:${cmd.id}`,\n primary: cmd.label,\n secondary: cmd.description,\n argv: cmd.argv,\n destructive: cmd.destructive,\n group: 'recent',\n });\n }\n const homeIds = new Set<string>();\n for (const { group, action } of flattenHome(homeSections)) {\n // Skip a curated action already shown in the recents section, so a command\n // run recently never appears twice (recents + its section) on one screen.\n if (recentIds.has(action.id)) continue;\n const argv = action.dispatch ?? [action.id];\n homeIds.add(action.id);\n rows.push({\n key: `home:${action.id}`,\n primary: action.label,\n secondary: action.hint,\n argv,\n destructive: action.destructive ?? false,\n group,\n });\n }\n for (const cmd of commands) {\n // Skip commands already shown as a recent or as a curated quick action —\n // the curated label wins over the raw leaf label (one row per command).\n if (recentIds.has(cmd.id) || homeIds.has(cmd.id)) continue;\n rows.push({\n key: `cmd:${cmd.id}`,\n primary: cmd.label,\n secondary: cmd.description,\n argv: cmd.argv,\n destructive: cmd.destructive,\n group: cmd.category,\n });\n }\n return rows;\n }\n\n // Non-empty query: fuzzy-rank the full command list.\n return matcher.search(query, commands, MATCH_LIMIT).map((m) => ({\n key: `cmd:${m.item.id}`,\n primary: m.item.label,\n secondary: m.item.description,\n argv: m.item.argv,\n destructive: m.item.destructive,\n group: null,\n }));\n}\n","// Top status bar. Renders a one-line summary of the live snapshot: host, mode\n// (from the active workflow task, if any), phase (or \"idle\"), and daemon\n// health. Degrades cleanly — when the payload is null (project uninitialized,\n// snapshot in flight, or the daemon fully down), every field shows a dash and\n// the daemon cell reads \"down\" so the user is never looking at empty space.\n\nimport { Text } from 'ink';\nimport type { ReactElement } from 'react';\nimport type { StatusPayload } from '../commands/status.js';\nimport { c } from '../theme.js';\n\ninterface StatusBarProps {\n payload: StatusPayload | null;\n /** When true, the snapshot is being (re)loaded — shown as a dim hint. */\n loading?: boolean;\n}\n\nfunction Cell({\n label,\n value,\n accent,\n}: {\n label: string;\n value: string;\n accent?: boolean;\n}): ReactElement {\n return (\n <Text>\n <Text>{c.dim(`${label}:`)}</Text> <Text>{accent ? c.accent(value) : value}</Text>\n </Text>\n );\n}\n\nexport function StatusBar({ payload, loading }: StatusBarProps): ReactElement {\n const host = payload?.host ?? '—';\n const mode = payload?.workflow?.mode ?? '—';\n const phase = payload?.workflow?.phase ?? (loading ? '…' : 'idle');\n const daemonRunning = payload?.daemon.running === true;\n const daemon = payload === null && loading ? '…' : daemonRunning ? 'up' : 'down';\n\n return (\n <Text>\n <Cell label=\"host\" value={host} accent />\n <Text>{c.dim(' · ')}</Text>\n <Cell label=\"mode\" value={mode} />\n <Text>{c.dim(' · ')}</Text>\n <Cell label=\"phase\" value={phase} />\n <Text>{c.dim(' · ')}</Text>\n <Text>\n {c.dim('daemon:')} {daemonRunning ? c.ok(daemon) : c.warn(daemon)}\n </Text>\n </Text>\n );\n}\n","// C3 — palette command-history persistence.\n//\n// The palette shows the user's recently-run commands above the full list on an\n// empty query. That recency data lives on disk so it survives sessions. The file\n// is keyed by canonical ProjectId — `~/.noir/<projectId>/tui-history.json` (NOT a\n// filesystem path) — so it respects the `.noir/` single-source-of-truth invariant\n// (CLAUDE.md): a project's recents are isolated from every other project. The\n// file is a simple newest-first JSON array of `{ argv, id }` (id is the\n// space-joined argv — the same stable dispatch key the registry uses).\n//\n// Opt-out: set `NOIR_DISABLE_TUI_HISTORY=1` to make persistence in-memory only\n// (loadRecent/recordRecent become no-ops). Useful for ephemeral/CI shells.\n//\n// Bounds: `MAX_ENTRIES` (50) caps the file so it never grows without bound, and\n// every write is atomic via the shared `atomicWriteFile` (@noir-ai/core — the\n// same helper daemon/lifecycle.ts and update-check.ts use) so a crash mid-write\n// never leaves a half-written JSON blob. A corrupt file (manual edit, truncated\n// write from an older build) degrades to `[]` rather than throwing — recency is\n// a nice-to-have, never a crash.\n//\n// Test seam: `__setNoirHome` overrides the home dir so the offline suite can\n// point at a tmpdir instead of the real `~/.noir` (mirrors `NOIR_DAEMON_JSON`).\n\nimport { existsSync, mkdirSync, readFileSync } from 'node:fs';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\nimport { atomicWriteFile } from '@noir-ai/core';\n\n/** A single entry in the persisted recent-commands list. */\nexport interface RecentEntry {\n /** The raw argv the user selected (e.g. `['context','search','foo']`). */\n readonly argv: readonly string[];\n /** Space-joined argv — the stable dispatch key (e.g. `context search foo`). */\n readonly id: string;\n}\n\n/** Bounded history size — the palette only needs a handful of recents. */\nconst MAX_ENTRIES = 50;\n\n/** The env var that disables palette-history persistence (in-memory only). */\nexport const TUI_HISTORY_DISABLE_ENV = 'NOIR_DISABLE_TUI_HISTORY';\n\nlet testHome: string | null = null;\n\n/**\n * Test override for the Noir home dir. Pass `null` to restore the real\n * `~/.noir` resolution. Never called from production code.\n */\nexport function __setNoirHome(home: string | null): void {\n testHome = home;\n}\n\n/** The user-global Noir home (test override wins when set). */\nfunction homeDir(): string {\n return testHome ?? join(homedir(), '.noir');\n}\n\n/**\n * Path of the palette history file for a project:\n * `<home>/<projectId>/tui-history.json`. ProjectId-keyed so recents are isolated\n * per project (respects the `.noir/` single-source-of-truth invariant).\n */\nfunction historyFile(projectId: string): string {\n return join(homeDir(), projectId, 'tui-history.json');\n}\n\n/**\n * Whether palette history persistence is enabled. Honors\n * `NOIR_DISABLE_TUI_HISTORY` (any non-empty value disables it → in-memory only).\n */\nexport function isHistoryEnabled(): boolean {\n const v = process.env[TUI_HISTORY_DISABLE_ENV];\n return v === undefined || v === '';\n}\n\n/**\n * Load the persisted recent commands for `projectId`, newest first. Returns `[]`\n * when persistence is disabled, the file is missing/empty/corrupt — recency is\n * best-effort and must never throw.\n */\nexport function loadRecent(projectId: string): RecentEntry[] {\n if (!isHistoryEnabled()) return [];\n const file = historyFile(projectId);\n try {\n if (!existsSync(file)) return [];\n const raw = readFileSync(file, 'utf8');\n const parsed: unknown = JSON.parse(raw);\n if (!Array.isArray(parsed)) return [];\n const entries: RecentEntry[] = [];\n for (const item of parsed) {\n if (typeof item !== 'object' || item === null) continue;\n const argv = (item as { argv?: unknown }).argv;\n const id = (item as { id?: unknown }).id;\n if (!Array.isArray(argv) || typeof id !== 'string') continue;\n if (!argv.every((tok): tok is string => typeof tok === 'string')) continue;\n entries.push({ argv, id });\n }\n return entries;\n } catch {\n return [];\n }\n}\n\n/**\n * Record a dispatched command as the newest recent entry for `projectId`.\n * Adjacent duplicates are dropped (re-running the same command once is one\n * entry); re-running a command from deeper in the list moves it to the front.\n * The persisted list is capped at {@link MAX_ENTRIES}. No-op when persistence is\n * disabled. Best-effort: a failed write is swallowed (recency is a nice-to-have\n * — a read-only home or a full disk must not break command dispatch).\n */\nexport function recordRecent(projectId: string, argv: readonly string[]): void {\n if (argv.length === 0) return;\n if (!isHistoryEnabled()) return;\n const entry: RecentEntry = { argv, id: argv.join(' ') };\n const current = loadRecent(projectId).filter((e) => e.id !== entry.id);\n const next = [entry, ...current].slice(0, MAX_ENTRIES);\n try {\n const dir = join(homeDir(), projectId);\n mkdirSync(dir, { recursive: true });\n atomicWriteFile(historyFile(projectId), `${JSON.stringify(next, null, 2)}\\n`);\n } catch {\n // Recency is a nice-to-have — a read-only home (or a full disk) must not\n // break command dispatch.\n }\n}\n"],"mappings":"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","names":["loadProjectInfo","SUPPORTED_HOSTS","NOIR_VERSION","data","loadProjectInfo","ensureDaemonRunning","pidAlive","readDaemonRecord","loadProjectInfo","ensureDaemonRunning","readDaemonRecord","pidAlive","loadProjectInfo","loadProjectInfo","NOIR_VERSION","describeEmbedder","c","NOIR_VERSION","loadProjectInfo","info","loadProjectInfo","loadProjectInfo","s","status","c","loadProjectInfo","hostLaunchDirective","loadProjectInfo","NOIR_VERSION","program","c","info","loadProjectInfo","hostLaunchDirective","NOIR_VERSION","parseLimit","toHit","failTool","data","sessions","spawnSync","status","spawnSync","mkdirSync","writeFileSync","join","join","mkdirSync","writeFileSync","loadProjectInfo","status","loadProjectInfo","data","loadProjectInfo","ensureDaemonRunning","c","program","NOIR_VERSION","str","SUPPORTED_HOSTS","runTui","runPalette","run","Box","Text","useState","Text","jsx","Text","Text","jsx","jsxs","Text","Text","jsx","jsxs","Text","Box","Text","Box","jsx","Box","jsx","jsxs","Box","Text","Box","Text","jsx","jsxs","Box","Text","prefix","Text","jsx","jsxs","Text","jsx","jsxs","useState","c","run","Box","Text","mkdirSync","join","join","mkdirSync","jsx","loadProjectInfo","c"]}
1
+ {"version":3,"sources":["../../src/tui/index.tsx","../../src/tui/App.tsx","../../src/tui/CommandInput.tsx","../../src/tui/capture.ts","../../src/tui/Footer.tsx","../../src/tui/hints.ts","../../src/tui/format.ts","../../src/tui/Header.tsx","../../src/tui/hooks/useInputBuffer.ts","../../src/tui/OutputPane.tsx","../../src/tui/overlays/ConfirmOverlay.tsx","../../src/tui/Panel.tsx","../../src/tui/palette/fuzzyMatch.ts","../../src/tui/palette/matcher.ts","../../src/tui/palette/Palette.tsx","../../src/tui/palette/output.ts","../../src/tui/palette/rows.ts","../../src/tui/StatusBar.tsx","../../src/tui/palette/history.ts"],"sourcesContent":["// `noir tui` entry — mounts the Ink dashboard. LAZY-loaded: bin.ts does\n// `await import('./tui/index.js')` inside the `tui` action only, so React +\n// Ink never enter the main CLI startup path (`noir status`, `noir doctor`, a\n// bare `noir` all stay React-free). The entry wires the default\n// {@link TuiDeps.fetchStatus} (a wrapper around `gatherStatusPayload` that\n// folds any failure to `null`) and the SAME dispatch seam `home(opts, deps)`\n// uses, then renders the App and resolves on exit.\n//\n// Stream discipline: while the dashboard runs, Ink owns the terminal (raw-mode\n// stdin + ANSI render to stdout). On `q` / Esc / Ctrl+C, Ink restores the\n// terminal before unmounting. Dispatched commands write through the captured\n// stream shim, so the host terminal only ever sees Ink's frames.\n\nimport { loadProjectInfo } from '@noir-ai/core';\nimport { render } from 'ink';\nimport { buildPaletteCommandsForTui } from '../bin.js';\nimport { gatherStatusPayload, type StatusOptions, type StatusPayload } from '../commands/status.js';\nimport type { CliOptions } from '../output.js';\nimport { App, type TuiDeps } from './App.js';\nimport { loadRecent, recordRecent } from './palette/history.js';\n\nexport type { TuiDeps } from './App.js';\n\n/**\n * Default status fetcher: wraps {@link gatherStatusPayload} so any failure (an\n * uninitialized project, a probe hiccup, a daemon-down that threw) folds to\n * `null` and the dashboard degrades cleanly. `gatherStatusPayload` itself is\n * probe-only and never auto-starts a daemon, so this is safe to poll.\n */\nfunction defaultFetchStatus(opts: CliOptions): () => Promise<StatusPayload | null> {\n return async () => {\n try {\n return await gatherStatusPayload(opts as StatusOptions);\n } catch {\n return null;\n }\n };\n}\n\n/**\n * Mount the dashboard and resolve when the user exits. The caller (bin.ts)\n * supplies the dispatch seam — the same shape `home(opts, deps).dispatch`\n * uses — so command routing is owned by the bin, not reimplemented here.\n */\nexport async function runTui(opts: CliOptions, dispatch: TuiDeps['dispatch']): Promise<void> {\n process.stdout.write('\\x1b[2J\\x1b[H');\n const deps = await buildTuiDeps(opts, dispatch);\n const instance = render(<App deps={deps} />);\n await instance.waitUntilExit();\n}\n\n/**\n * `noir palette` — mount the App palette-first (S3). Reuses the SAME\n * `runTui` deps (dispatch seam, commands, recents) so the fuzzy command\n * palette is identical to the dashboard's Ctrl+K palette, just opened\n * directly. `dispatch` is the same shape `runTui` receives from bin.ts.\n */\nexport async function runPalette(opts: CliOptions, dispatch: TuiDeps['dispatch']): Promise<void> {\n process.stdout.write('\\x1b[2J\\x1b[H');\n // Reuse runTui's deps wiring wholesale, then render palette-first.\n // Factor the shared deps build out of runTui into a helper to avoid\n // duplicating the projectId/commands/recents logic.\n const deps = await buildTuiDeps(opts, dispatch);\n const instance = render(\n <App deps={deps} initialMode={{ kind: 'palette', corpus: 'commands' }} />,\n );\n await instance.waitUntilExit();\n}\n\n/**\n * Build the shared {@link TuiDeps} for both `runTui` and `runPalette`.\n * Extracted so the two entry points cannot drift (projectId-keyed recents,\n * the palette source, and the dispatch seam are identical).\n */\nasync function buildTuiDeps(opts: CliOptions, dispatch: TuiDeps['dispatch']): Promise<TuiDeps> {\n // ProjectId-keyed recent-commands persistence (C3): resolve the canonical id\n // once at launch so recents are isolated per project (respects the .noir/\n // single-source-of-truth invariant). An uninitialized project (loadProjectInfo\n // throws) degrades to empty recents — the palette still works with the full\n // command list.\n let projectId: string | null = null;\n try {\n projectId = loadProjectInfo(process.cwd()).id;\n } catch {\n projectId = null;\n }\n const deps: TuiDeps = {\n dispatch,\n fetchStatus: defaultFetchStatus(opts),\n // The palette source, derived from a fresh commander program at launch (B3).\n commands: buildPaletteCommandsForTui(),\n // C3 — persistent recent commands (projectId-keyed). recordRecent is async\n // only to match the TuiDeps seam; it never rejects.\n record: (argv) => {\n if (projectId) recordRecent(projectId, argv);\n return Promise.resolve();\n },\n loadRecent: async () => {\n if (!projectId) return [];\n // Hydrate the bare {argv,id} entries against the live palette commands so\n // the palette renders real labels/descriptions; drop stale entries whose\n // argv no longer exists in the current build.\n const byId = new Map(deps.commands?.map((c) => [c.id, c]) ?? []);\n return loadRecent(projectId)\n .map((e) => byId.get(e.id))\n .filter((c): c is NonNullable<typeof c> => c !== undefined);\n },\n };\n return deps;\n}\n","// Dashboard root component. Owns the interactive state (input buffer, scroll\n// offset, dispatched output, snapshot, palette query/active, the active screen)\n// and the SINGLE keybinding dispatcher (v2 — the palette, home, help, and search\n// surfaces all collapsed into one corpus-aware palette, so keyboard routing\n// lives here alone). The snapshot is fetched via {@link TuiDeps.fetchStatus} on\n// a short interval (paused while a `/<command>` is dispatching, so a StatusBar\n// refresh can never race the stream capture). Dispatch goes through the EXISTING\n// {@link TuiDeps.dispatch} seam — the same `home(opts, deps).dispatch` shape —\n// so command routing is NOT reimplemented here.\n//\n// Screens (the {@link Mode} union): `dashboard` (default), `palette` (the single\n// command surface — corpus `commands` | `output` | `help`, opened by Ctrl+K /\n// Ctrl+F / h / ? and cycled with Tab), and `confirm` (the `y/N` gate before a\n// destructive dispatch — now covering EVERY dispatch path, typed /command\n// included). Every selection funnels through {@link handleRun}, so destructive\n// commands always pause at the confirm overlay.\n\nimport { Box, type Key, Text, useApp, useInput } from 'ink';\nimport { type ReactElement, useEffect, useMemo, useState } from 'react';\nimport type { StatusPayload } from '../commands/status.js';\nimport { c, divider } from '../theme.js';\nimport { CommandInput } from './CommandInput.js';\nimport { captureProcessOutput } from './capture.js';\nimport { isDestructive } from './commands/registry.js';\nimport { type HomeSection, resolveSections } from './commands/sections.js';\nimport { Footer } from './Footer.js';\nimport { formatStatusPayload } from './format.js';\nimport { Header } from './Header.js';\nimport { useInputBuffer } from './hooks/useInputBuffer.js';\nimport { OutputPane } from './OutputPane.js';\nimport { ConfirmOverlay } from './overlays/ConfirmOverlay.js';\nimport { Panel } from './Panel.js';\nimport { type FuzzyMatcher, handRolledMatcher } from './palette/matcher.js';\nimport { Palette } from './palette/Palette.js';\nimport { buildPaletteRows, CORPORA, type Corpus } from './palette/rows.js';\nimport type { PaletteCommand } from './palette/types.js';\nimport { StatusBar } from './StatusBar.js';\n\n/** Injected dependencies (mirrors the `home(opts, deps)` seam). */\nexport interface TuiDeps {\n /**\n * Run a Noir sub-command by user-form argv on a fresh commander program.\n * Same contract as {@link HomeDeps.dispatch}: must not throw — it owns its\n * own error → exit-code mapping and leaves the outcome on `process.exitCode`.\n */\n dispatch: (argv: readonly string[]) => Promise<void>;\n /**\n * Fetch the live status snapshot. Defaults to a wrapper around\n * `gatherStatusPayload` that folds ANY failure to `null` so the dashboard\n * degrades cleanly (uninitialized project, daemon down, probe hiccup).\n */\n fetchStatus: () => Promise<StatusPayload | null>;\n /**\n * The palette source — one {@link PaletteCommand} per leaf `noir` subcommand,\n * derived from the commander tree at `noir tui` launch (NOT re-walked per\n * keystroke). Optional for backward-compat (B1 tests omit it); when absent the\n * palette falls back to an empty command list.\n */\n readonly commands?: readonly PaletteCommand[];\n /** The fuzzy matcher. Optional — defaults to {@link handRolledMatcher}. */\n readonly matcher?: FuzzyMatcher;\n /**\n * Record a dispatched command into the persisted recent-commands list\n * (C3). Optional for backward-compat — when absent, recents are not recorded.\n */\n record?: (argv: readonly string[]) => Promise<void>;\n /**\n * Load the persisted recent commands (newest first) for the palette's recent\n * section. Optional — when absent, defaults to the on-disk history loader.\n */\n loadRecent?: () => Promise<readonly PaletteCommand[]>;\n}\n\n/** Optional initial state for tests (the live entry leaves these at defaults). */\nexport interface AppProps {\n deps: TuiDeps;\n /** Initial snapshot — skips the first fetch when provided (tests). */\n initialPayload?: StatusPayload | null;\n /** Refresh interval in ms (default 5000). Set large in tests. */\n refreshMs?: number;\n /**\n * The mode the App starts in. Defaults to the dashboard. `noir palette`\n * mounts the app palette-first via `{ kind: 'palette', corpus: 'commands' }`.\n */\n initialMode?: Mode;\n}\n\n/**\n * The dashboard's discriminated screen union. Exactly one screen is active at a\n * time; the App keys its render + keybinding handler off `mode.kind`.\n * - `dashboard` — the default screen: live snapshot, command input, output pane.\n * - `palette` — the single command surface, with a `corpus` selecting what the\n * query filters (commands / output / help).\n * - `confirm` — an in-TUI confirmation prompt for a destructive dispatch.\n */\nexport type Mode =\n | { kind: 'dashboard' }\n | { kind: 'palette'; corpus: Corpus }\n | { kind: 'confirm'; argv: string[] };\n\ninterface DispatchedOutput {\n title: string;\n lines: string[];\n}\n\nexport function App({\n deps,\n initialPayload = null,\n refreshMs = 5000,\n initialMode = { kind: 'dashboard' },\n}: AppProps): ReactElement {\n const { exit } = useApp();\n const { buffer, setBuffer, pushHistory, recall, clear, seed } = useInputBuffer();\n const [mode, setMode] = useState<Mode>(initialMode);\n const [payload, setPayload] = useState<StatusPayload | null>(initialPayload);\n const [loading, setLoading] = useState(initialPayload === null);\n const [output, setOutput] = useState<DispatchedOutput | null>(null);\n // The output lines the `output` corpus searches. Captured from the CURRENT\n // dispatched output when the corpus opens, so a new dispatch landing mid-search\n // cannot change the corpus mid-filter.\n const [searchLines, setSearchLines] = useState<readonly string[]>([]);\n const [scrollOffset, setScrollOffset] = useState(0);\n const [running, setRunning] = useState(false);\n const [notice, setNotice] = useState<string | null>(null);\n // The argv of a dispatch the user just submitted. An effect watches this so\n // the dispatch runs AFTER React flushes the \"running…\" frame.\n const [pending, setPending] = useState<string[] | null>(null);\n // The persisted recent-commands list for the palette, loaded once on mount.\n const [recent, setRecent] = useState<readonly PaletteCommand[]>([]);\n // The curated home sections, resolved against the live registry once.\n const [homeSections, setHomeSections] = useState<readonly HomeSection[]>([]);\n // v2 — the single palette's query + active row (owned here so the App's one\n // `useInput` routes palette keys and can resolve the active row on Enter).\n const [paletteQuery, setPaletteQuery] = useState('');\n const [paletteActive, setPaletteActive] = useState(0);\n\n // ----- load the palette's recent commands once on mount ------------------\n useEffect(() => {\n if (!deps.loadRecent) return;\n const loader = deps.loadRecent;\n let cancelled = false;\n void loader()\n .then((entries) => {\n if (!cancelled) {\n setRecent(entries);\n // Seed the shell-recall overlay from the SAME persisted recents the\n // palette shows, so ↑/↓ recall and the palette recents never diverge.\n seed(entries.map((c) => `/${c.argv.join(' ')}`));\n }\n })\n .catch(() => {\n // Recents are a nice-to-have — a read failure leaves the full list.\n });\n return () => {\n cancelled = true;\n };\n }, [deps.loadRecent, seed]);\n\n // ----- resolve the curated home sections once ---------------------------\n useEffect(() => {\n let cancelled = false;\n void resolveSections(deps.commands ?? []).then((sections) => {\n if (!cancelled) setHomeSections(sections);\n });\n return () => {\n cancelled = true;\n };\n }, [deps.commands]);\n\n // ----- snapshot refresh: paused while a dispatch is in flight ----------\n useEffect(() => {\n // Pause polling while a dispatch runs OR the palette/confirm overlay is\n // open (the dashboard snapshot is off-screen then, so polling only wastes\n // a fetch + a re-render).\n if (running || mode.kind !== 'dashboard') return;\n let cancelled = false;\n let inFlight = false;\n const fetched = (p: StatusPayload | null): void => {\n inFlight = false;\n if (cancelled) return;\n setPayload(p);\n setLoading(false);\n };\n setLoading(true);\n inFlight = true;\n void deps\n .fetchStatus()\n .then(fetched)\n .catch(() => fetched(null));\n const id = setInterval(() => {\n // Skip the tick while a fetch is still pending — a slow/restarting daemon\n // (gatherStatusPayload does a probe + MCP round-trips) must not stack\n // concurrent fetches.\n if (inFlight) return;\n inFlight = true;\n void deps\n .fetchStatus()\n .then(fetched)\n .catch(() => {\n // Keep the last-good payload on a transient probe/daemon failure — a\n // poll-time hiccup must not wipe the dashboard to \"down\".\n inFlight = false;\n });\n }, refreshMs);\n return () => {\n cancelled = true;\n clearInterval(id);\n };\n }, [running, mode.kind, refreshMs, deps.fetchStatus]);\n\n // ----- dispatch runner: fires after the \"running\" frame has flushed ------\n useEffect(() => {\n if (pending === null) return;\n const argv = pending;\n let active = true;\n const run = async (): Promise<void> => {\n const captured = await captureProcessOutput(() => deps.dispatch(argv));\n if (!active) return;\n const combined = `${captured.stdout}${captured.stderr}`;\n const lines = combined.split('\\n');\n while (lines.length > 0 && lines[lines.length - 1] === '') lines.pop();\n const title = `/${argv.join(' ')} → exit ${captured.exitCode}`;\n setOutput({ title, lines });\n setNotice(`ran /${argv.join(' ')} → exit ${captured.exitCode}`);\n setRunning(false);\n setPending(null);\n setScrollOffset(0);\n };\n void run();\n return () => {\n active = false;\n };\n }, [pending, deps.dispatch]);\n\n // ----- shared dispatch helper --------------------------------------------\n function dispatchCmd(argv: readonly string[]): void {\n setOutput(null);\n setRunning(true);\n setPending([...argv]);\n }\n\n // ----- unified run seam: every selection (palette / home / confirm) ------\n function handleRun(argv: readonly string[], destructive: boolean): void {\n if (destructive) {\n setMode({ kind: 'confirm', argv: [...argv] });\n return;\n }\n dispatchCmd([...argv]);\n void recordRuns([...argv]);\n pushHistory(`/${argv.join(' ')}`);\n setMode({ kind: 'dashboard' });\n }\n\n function recordRuns(argv: readonly string[]): void {\n const recorder = deps.record;\n if (recorder) void recorder(argv);\n }\n\n // ----- palette open / cycle helpers --------------------------------------\n function openPalette(corpus: Corpus): void {\n setPaletteQuery('');\n setPaletteActive(0);\n setMode({ kind: 'palette', corpus });\n setNotice(null);\n }\n\n function openOutputSearch(): void {\n if (output === null) return;\n setSearchLines(output.lines);\n openPalette('output');\n }\n\n function nextCorpus(current: Corpus): Corpus {\n const idx = CORPORA.indexOf(current);\n const candidates = [...CORPORA.slice(idx + 1), ...CORPORA.slice(0, idx + 1)];\n for (const corpus of candidates) {\n if (corpus === 'output' && output === null) continue; // no output to search\n return corpus;\n }\n return 'commands';\n }\n\n // ----- dashboard-mode keybinding handler -------------------------------\n function handleDashboardInput(input: string, key: Key): void {\n if (running) return;\n setNotice(null);\n\n if (key.return) {\n submit();\n return;\n }\n if (key.escape) {\n if (buffer.length > 0) clear();\n else if (output !== null) setOutput(null);\n else exit();\n return;\n }\n if (key.backspace || key.delete) {\n setBuffer((b) => b.slice(0, -1));\n return;\n }\n if (key.upArrow) {\n if (buffer === '/') {\n const entry = recall('up');\n if (entry !== null) {\n setBuffer(() => entry);\n return;\n }\n }\n setScrollOffset((o) => Math.max(0, o - 1));\n return;\n }\n if (key.downArrow) {\n if (buffer === '/') {\n const entry = recall('down');\n if (entry !== null) {\n setBuffer(() => entry);\n return;\n }\n }\n setScrollOffset((o) => o + 1);\n return;\n }\n if (key.ctrl) {\n if (input === 'k') {\n openPalette('commands');\n return;\n }\n if (input === 'f' && output !== null) {\n openOutputSearch();\n return;\n }\n return;\n }\n if (input.length === 1) {\n if (buffer.length === 0) {\n if (input === 'q') {\n exit();\n return;\n }\n if (input === '?') {\n openPalette('help');\n return;\n }\n if (input === 'h') {\n openPalette('commands');\n return;\n }\n }\n setBuffer((b) => b + input);\n return;\n }\n if (input.length > 1) {\n setBuffer((b) => b + input);\n }\n }\n\n // ----- palette-mode keybinding handler (single router) -------------------\n // Clamp the active cursor to the FULL row list. The renderer slides a\n // VISIBLE_ROWS window over the list, so the cursor (and Enter) can reach\n // every row, not just the first ten.\n function moveActive(delta: number): void {\n const max = Math.max(0, paletteRows.length - 1);\n setPaletteActive((a) => Math.min(max, Math.max(0, a + delta)));\n }\n\n function handlePaletteInput(input: string, key: Key): void {\n if (mode.kind !== 'palette') return;\n if (key.escape) {\n setPaletteQuery('');\n setPaletteActive(0);\n setMode({ kind: 'dashboard' });\n return;\n }\n if (key.tab) {\n setMode({ kind: 'palette', corpus: nextCorpus(mode.corpus) });\n setPaletteQuery('');\n setPaletteActive(0);\n return;\n }\n if (mode.corpus === 'help') {\n if (key.upArrow) moveActive(-1);\n else if (key.downArrow) moveActive(1);\n return; // help corpus takes no typing\n }\n if (key.return) {\n if (mode.corpus === 'commands') {\n const row = paletteRows[paletteActive];\n if (row?.argv) handleRun(row.argv, row.destructive);\n } else {\n moveActive(1); // output corpus: next match\n }\n return;\n }\n if (key.upArrow) {\n moveActive(-1);\n return;\n }\n if (key.downArrow) {\n moveActive(1);\n return;\n }\n if (key.backspace || key.delete) {\n setPaletteQuery((q) => q.slice(0, -1));\n setPaletteActive(0);\n return;\n }\n if (key.ctrl) return;\n if (input.length > 0) {\n setPaletteQuery((q) => q + input);\n setPaletteActive(0);\n }\n }\n\n // ----- confirm-mode keybinding handler ----------------------------------\n function handleConfirmInput(input: string, key: Key): void {\n if (key.escape || input === 'n' || input === 'N') {\n // Back to the palette with a clean query so the full list is visible.\n setPaletteQuery('');\n setPaletteActive(0);\n setMode({ kind: 'palette', corpus: 'commands' });\n return;\n }\n if (input === 'y' || input === 'Y') {\n if (mode.kind !== 'confirm') return;\n dispatchCmd([...mode.argv]);\n void recordRuns([...mode.argv]);\n pushHistory(`/${mode.argv.join(' ')}`);\n setMode({ kind: 'dashboard' });\n }\n }\n\n // ----- keybinding dispatcher (single `useInput` for the whole App) ------\n useInput((input, key) => {\n switch (mode.kind) {\n case 'dashboard':\n handleDashboardInput(input, key);\n return;\n case 'palette':\n handlePaletteInput(input, key);\n return;\n case 'confirm':\n handleConfirmInput(input, key);\n return;\n }\n });\n\n function submit(): void {\n const text = buffer;\n if (text.length === 0) return;\n clear();\n if (!text.startsWith('/')) {\n setNotice('type a /command to run it (bare text is just a hint)');\n return;\n }\n const argv = text\n .slice(1)\n .split(/\\s+/)\n .map((s) => s.trim())\n .filter((s) => s.length > 0);\n if (argv.length === 0) {\n setNotice('empty /command');\n return;\n }\n if (isDestructive(argv)) {\n // Destructive typed /commands go through the SAME confirm gate the\n // palette uses (v2 — closes the old typed-path bypass).\n setMode({ kind: 'confirm', argv });\n return;\n }\n pushHistory(text);\n dispatchCmd(argv);\n void recordRuns(argv);\n }\n\n // The rows for the active palette corpus, memoized so the dashboard hot path\n // (every keystroke + snapshot poll) does NOT rebuild ~60 row objects. Only\n // recompute when a palette input actually changes.\n const paletteRows = useMemo(\n () =>\n buildPaletteRows({\n corpus: mode.kind === 'palette' ? mode.corpus : 'commands',\n query: paletteQuery,\n commands: deps.commands ?? [],\n matcher: deps.matcher ?? handRolledMatcher,\n recent,\n homeSections,\n outputLines: searchLines,\n }),\n [mode, paletteQuery, deps.commands, deps.matcher, recent, homeSections, searchLines],\n );\n\n // ----- render -----------------------------------------------------------\n if (mode.kind === 'palette') {\n return (\n <Box flexDirection=\"column\">\n <Header tagline={`palette · ${mode.corpus}`} />\n <Palette\n corpus={mode.corpus}\n query={paletteQuery}\n active={paletteActive}\n rows={paletteRows}\n />\n <Footer running={false} />\n </Box>\n );\n }\n\n if (mode.kind === 'confirm') {\n return (\n <Box flexDirection=\"column\">\n <Header tagline=\"confirm\" />\n <ConfirmOverlay argv={mode.argv} />\n <Footer running={false} />\n </Box>\n );\n }\n\n const snapshotLines = formatStatusPayload(payload);\n const paneLines = output?.lines ?? snapshotLines ?? [];\n const paneTitle = output?.title ?? 'snapshot';\n\n return (\n <Box flexDirection=\"column\">\n <Header tagline=\"dashboard\" />\n <Panel>\n <Box paddingX={1}>\n <StatusBar payload={payload} loading={loading} />\n </Box>\n <Box paddingX={1}>\n <Text>{divider()}</Text>\n </Box>\n <Box flexDirection=\"column\" paddingX={1}>\n <OutputPane lines={paneLines} scrollOffset={scrollOffset} title={paneTitle} />\n </Box>\n </Panel>\n <CommandInput buffer={buffer} running={running} />\n {notice !== null ? <Text>{c.dim(notice)}</Text> : null}\n <Footer running={running} />\n </Box>\n );\n}\n","// Command input display. The input buffer + cursor live in the App (so is the\n// keybinding dispatch); this component is purely presentational — it renders\n// the prefix convention (`/` invokes a native Noir subcommand, bare text is a\n// hint) and shows a block cursor at the end of the buffer.\n//\n// The hint rule: when the buffer is empty, show a dim placeholder describing\n// the convention; once the user types, render the buffer verbatim with an\n// accent prefix when the first char is `/` (a recognized dispatch) or a dim\n// prefix otherwise (a hint that this input would NOT dispatch on Enter).\n//\n// The input is drawn inside a rounded border so the interactive field is\n// visually distinct from the static output above it (TUI redesign: rounded\n// outlines on every interactive surface).\n\nimport { Box, Text } from 'ink';\nimport type { ReactElement } from 'react';\nimport { c, contentWidth } from '../theme.js';\n\ninterface CommandInputProps {\n buffer: string;\n running?: boolean;\n}\n\nexport function CommandInput({ buffer, running }: CommandInputProps): ReactElement {\n if (running) {\n return (\n <Box borderStyle=\"round\" borderColor=\"gray\" paddingX={1} width={contentWidth() + 4}>\n <Text>{c.dim('…')}</Text>\n </Box>\n );\n }\n let body: ReactElement;\n if (buffer.length === 0) {\n body = (\n <Text>\n <Text>{c.dim('▌')}</Text>{' '}\n <Text>{c.dim('type a /command (e.g. /status, /sync, /task next), or q to quit')}</Text>\n </Text>\n );\n } else {\n const isCommand = buffer.startsWith('/');\n body = (\n <Text>\n <Text>{isCommand ? c.accent('▸') : c.dim('▸')}</Text> {buffer}\n <Text>{c.dim('▌')}</Text>\n </Text>\n );\n }\n return (\n <Box borderStyle=\"round\" borderColor=\"gray\" paddingX={1} width={contentWidth() + 4}>\n {body}\n </Box>\n );\n}\n","// Stream capture for the dashboard's command dispatch.\n//\n// While the dashboard runs, Ink owns the terminal (raw-mode stdin + ANSI render\n// writes to stdout). When the user submits a `/<command>`, the EXISTING command\n// dispatch seam is reused verbatim — the dispatched command writes to\n// `process.stdout` / `process.stderr` via the same centralized output helpers\n// (`log`, `json`, `table`, `definitionList`, …) every other invocation uses.\n// To keep that contract AND render the result inside the dashboard's output\n// pane (instead of corrupting Ink's render), the dispatched command's writes\n// are captured for the duration of the dispatch and restored after.\n//\n// Invariant: Ink does not rerender mid-dispatch, because the App does not\n// `setState` between the stream swap and its restore (the only state change is\n// the single `setOutput` AFTER the await resolves). So the captured text is\n// exactly the dispatched command's bytes — no Ink frames leak in.\n\n/** Capture everything written to stdout/stderr during `fn`, plus the exit code. */\nexport interface CapturedOutput {\n stdout: string;\n stderr: string;\n exitCode: number;\n}\n\n/**\n * Run `fn` with `process.stdout.write` / `process.stderr.write` temporarily\n * replaced by string collectors. Restores the original writers in a `finally`\n * (so an unexpected throw still restores them). `process.exitCode` set by the\n * dispatched command is captured and then RESET to its pre-call value, so a\n * failing sub-command does not poison the dashboard's own process exit.\n */\nexport async function captureProcessOutput(fn: () => Promise<void>): Promise<CapturedOutput> {\n const outChunks: string[] = [];\n const errChunks: string[] = [];\n const origOut = process.stdout.write.bind(process.stdout);\n const origErr = process.stderr.write.bind(process.stderr);\n const prevExitCode = process.exitCode;\n\n // Type narrower: Node's Write result is `boolean`. The captured writers\n // always succeed (they just buffer), so return `true`.\n process.stdout.write = ((chunk: unknown) => {\n outChunks.push(typeof chunk === 'string' ? chunk : String(chunk));\n return true;\n }) as typeof process.stdout.write;\n process.stderr.write = ((chunk: unknown) => {\n errChunks.push(typeof chunk === 'string' ? chunk : String(chunk));\n return true;\n }) as typeof process.stderr.write;\n\n try {\n await fn();\n } finally {\n process.stdout.write = origOut;\n process.stderr.write = origErr;\n }\n\n const exitCode = typeof process.exitCode === 'number' ? process.exitCode : 0;\n // Reset so the dashboard's own process exit is not affected by a sub-command.\n process.exitCode = prevExitCode;\n return { stdout: outChunks.join(''), stderr: errChunks.join(''), exitCode };\n}\n","// Footer with the shortcut hints. Kept as a pure function of the running state\n// so the App can swap it without re-wiring keybindings. The hint copy lives in\n// `hints.ts` (single source of truth) — the bindings themselves live in App.tsx.\n\nimport { Text } from 'ink';\nimport type { ReactElement } from 'react';\nimport { c } from '../theme.js';\nimport { FOOTER_HINT, RUNNING_HINT } from './hints.js';\n\ninterface FooterProps {\n /** When true, a dispatched command is in flight — show the running hint. */\n running?: boolean;\n}\n\nexport function Footer({ running }: FooterProps): ReactElement {\n return <Text>{c.dim(running ? RUNNING_HINT : FOOTER_HINT)}</Text>;\n}\n","// Shared hint strings + the keybinding manifest (single source of truth).\n//\n// Before v2, the same \"navigate / run / close\" hint was copy-pasted into the\n// (now-retired) home menu and palette, and the `?` help screen re-listed every\n// binding as a second encoding. This module owns the hint copy once so the\n// footer, the palette footer line, and the `help` corpus all render the same\n// text and cannot drift from the actual bindings (which live in App.tsx).\n\n/** The dashboard's idle footer hint (the App's keybinding manifest as text). */\nexport const FOOTER_HINT =\n '?/h/Ctrl+K palette · Ctrl+F find · ↑/↓ scroll · Enter run · q/Esc quit · Ctrl+C exit';\n\n/** The hint shown while a dispatched command is in flight. */\nexport const RUNNING_HINT = 'running… (Ctrl+C to force exit)';\n\n/** The palette/home list footer hint (navigate · run · close). */\nexport const LIST_NAV_HINT = '↑/↓ navigate · Enter run · Esc close · Tab view';\n\n/** A single keybinding row for the `help` corpus. */\nexport interface HelpEntry {\n readonly keys: string;\n readonly desc: string;\n}\n\n/**\n * The keybinding manifest, rendered by the palette's `help` corpus. Keep this in\n * sync with the App's single `useInput` dispatcher (the same file that owns the\n * bindings) — a drift here is a doc bug, not a behavior bug.\n */\nexport const HELP_ENTRIES: readonly HelpEntry[] = [\n { keys: '/command', desc: 'run a Noir sub-command (e.g. /status, /sync, /task next)' },\n { keys: 'Enter', desc: 'run the typed /command' },\n { keys: 'Esc', desc: 'back: clear input → dismiss output → quit' },\n { keys: 'q', desc: 'quit (when the input is empty)' },\n { keys: '↑ / ↓', desc: 'scroll the output pane (dashboard) · navigate the list (palette)' },\n { keys: '?', desc: 'palette — help & keybindings (this list)' },\n { keys: 'h', desc: 'palette — commands (quick actions + all commands)' },\n { keys: 'Ctrl+K', desc: 'palette — all commands (fuzzy search)' },\n { keys: 'Ctrl+F', desc: 'palette — find in the dispatched output' },\n { keys: 'Tab', desc: 'switch between commands, output, and help' },\n { keys: 'y / n', desc: 'approve / decline a destructive command prompt' },\n { keys: 'Ctrl+C', desc: 'force exit' },\n];\n","// Format the live {@link StatusPayload} as plain text lines for the dashboard's\n// output pane. Reuses the SAME describe helpers `noir status` renders with, so\n// the dashboard's snapshot and `noir status`'s human table never drift apart.\n\nimport {\n describeContext,\n describeDaemon,\n describeMemory,\n describeStore,\n describeWorkflow,\n type StatusPayload,\n} from '../commands/status.js';\n\n/**\n * Render a status snapshot as `Label: value` lines. Returns `null` when the\n * payload is absent (the dashboard shows a placeholder in that case).\n */\nexport function formatStatusPayload(p: StatusPayload | null): string[] | null {\n if (p === null) return null;\n return [\n `Project: ${p.project.name} (${p.project.id})`,\n `Host: ${p.host}`,\n `Noir: ${p.noir}`,\n `Daemon: ${describeDaemon(p.daemon)}`,\n `Store: ${describeStore(p.store)}`,\n `Context: ${describeContext(p.context)}`,\n `Workflow: ${describeWorkflow(p.workflow)}`,\n `Memory: ${describeMemory(p.memory)}`,\n ];\n}\n","// Branded header. The diamond mark uses the Midnight Cobalt brand role\n// (`c.accent`, solid blue), which is the single-line form of the banner's\n// gradient — it strips under NO_COLOR and stays solid under NOIR_ACCESSIBLE.\n// The full block wordmark lives in the banner module; a dashboard header is a\n// one-line surface, so the compact mark is the right altitude.\n\nimport { Text } from 'ink';\nimport type { ReactElement } from 'react';\nimport { c } from '../theme.js';\n\nexport function Header({ tagline }: { tagline?: string }): ReactElement {\n return (\n <Text>\n {c.accent('◆')} {c.bold('noir')} <Text>{c.dim(tagline ?? 'dashboard')}</Text>\n </Text>\n );\n}\n","// B1 — the dashboard input-buffer hook. Extracted from `App.tsx` so the\n// command-history + recall-cursor state can live with the keybindings that use\n// it instead of dangling inside the App's single `useInput` closure. Owns:\n// - `buffer` — the current text being composed at the prompt.\n// - `history` — in-memory command history (newest first), with move-to-front\n// dedup (matches the persisted recents store).\n// - `recall` — Up/Down history walk via an index cursor (`-1` = not\n// recalling).\n// - `seed` — replace the session history with the persisted recents.\n//\n// Deliberately tiny + framework-shaped like the rest of the TUI state: `buffer`\n// is a React state string so keystrokes rerender the CommandInput, while\n// `history` + the cursor are refs (they are recalled on demand, never painted).\n//\n// IMPORTANT: every returned function is wrapped in `useCallback` so its identity\n// is STABLE across renders. The App passes `seed` into a `useEffect` dependency\n// array (`[deps.loadRecent, seed]`); a plain function re-created each render\n// would make that effect re-run every render — an infinite setState loop that\n// leaks memory and OOMs the TUI after ~a minute of idle. All these functions\n// only touch refs (+ the stable `setBuffer`), so `useCallback(…, [])` is safe.\n\nimport { useCallback, useRef, useState } from 'react';\n\n/** Cap on the in-memory session history (mirrors the persisted recents cap). */\nconst MAX_HISTORY = 50;\n\n/** The input-buffer + command-history surface the App's keybindings consume. */\nexport interface InputBuffer {\n /** The text currently being composed (never `undefined`). */\n readonly buffer: string;\n /** Apply an updater to the current buffer (React `useState` setter shape). */\n setBuffer: (updater: (prev: string) => string) => void;\n /** Record a submitted command into history (newest first, move-to-front dedup). */\n pushHistory: (text: string) => void;\n /**\n * Walk the command history from the recall cursor. `up` returns the next\n * older entry (or the newest when not recalling); `down` returns the next\n * newer entry. Either direction clamps at its boundary — past the newest it\n * returns `null` (back on the edit line).\n */\n recall: (dir: 'up' | 'down') => string | null;\n /** Empty the buffer and reset the recall cursor to \"not recalling\". */\n clear: () => void;\n /**\n * Replace the session history with the persisted recents (the source of\n * truth). Called once after `loadRecent` resolves so shell recall and the\n * palette recents read the same list instead of diverging.\n */\n seed: (entries: readonly string[]) => void;\n}\n\n/**\n * Mount the dashboard's input buffer + in-memory history. `clear` is what a\n * successful submit / an Escape-back invokes: it empties the buffer AND parks\n * the recall cursor so the next Up starts over from the newest entry, while\n * leaving `history` intact for the session.\n */\nexport function useInputBuffer(): InputBuffer {\n const [buffer, setBuffer] = useState('');\n // Newest command first. Refs, never state: history is only read on demand\n // by `recall`, so storing it in state would rerender the App for no benefit.\n const historyRef = useRef<string[]>([]);\n // Index into `historyRef.current`; -1 = not recalling (editing fresh text).\n const cursorRef = useRef(-1);\n\n const pushHistory = useCallback((text: string): void => {\n if (text.length === 0) return;\n // Move-to-front dedup (matches `recordRecent` in palette/history.ts): an\n // exact re-run moves the entry to the head instead of duplicating, so the\n // shell-recall overlay and the persisted recents apply one dedup rule.\n const history = historyRef.current.filter((e) => e !== text);\n // Cap at MAX_HISTORY so a long session running many distinct commands does\n // not grow the in-memory overlay without bound (the persisted store is\n // already capped at 50).\n historyRef.current = [text, ...history].slice(0, MAX_HISTORY);\n }, []);\n\n const recall = useCallback((dir: 'up' | 'down'): string | null => {\n const history = historyRef.current;\n if (history.length === 0) return null;\n let cursor = cursorRef.current;\n if (dir === 'up') {\n // -1 (edit line) steps to the newest; otherwise walk one older, clamped\n // at the oldest entry so Up can never walk off the front of the list.\n cursor = cursor === -1 ? 0 : Math.min(cursor + 1, history.length - 1);\n } else {\n // Walk newer; stepping past the newest returns to the edit line.\n cursor = cursor === -1 ? -1 : cursor - 1;\n }\n cursorRef.current = cursor;\n return cursor === -1 ? null : (history[cursor] ?? null);\n }, []);\n\n const clear = useCallback((): void => {\n setBuffer(() => '');\n cursorRef.current = -1;\n }, []);\n\n const seed = useCallback((entries: readonly string[]): void => {\n historyRef.current = [...entries];\n cursorRef.current = -1;\n }, []);\n\n return { buffer, setBuffer, pushHistory, recall, clear, seed };\n}\n","// Scrollable output pane. Renders a windowed slice of `lines` based on the\n// current scroll offset (controlled by ArrowUp/ArrowDown at the App level).\n// Two sources of text share this pane: (a) the live project snapshot (the same\n// payload `noir status` shows), and (b) the captured stdout/stderr of a\n// dispatched `/<command>`. When dispatched output is present it takes\n// precedence (the user just asked for it); the App returns to the snapshot view\n// when the output is dismissed.\n\nimport { Text } from 'ink';\nimport type { ReactElement } from 'react';\nimport { c, contentWidth } from '../theme.js';\n\ninterface OutputPaneProps {\n lines: readonly string[];\n /** Index of the FIRST line scrolled to the top of the viewport. */\n scrollOffset: number;\n /** Visible row height of the pane. Defaults to a comfortable 12 rows. */\n height?: number;\n /** Optional title for the pane (shown as a dim header line). */\n title?: string;\n}\n\ninterface Row {\n /** Stable, content-derived React key (deduplicated so duplicate lines don't collide). */\n key: string;\n /** The text to render for this row. */\n text: string;\n}\n\n/**\n * Build stable React keys from line content. Duplicate lines get a `#N` suffix\n * so each row's key is unique WITHOUT using the array index — the lint rule\n * flags index keys, and content keys are also correct here (the pane is read-\n * only, but content keys keep reconciliation honest across scroll refreshes).\n */\nfunction toRows(visible: readonly string[]): Row[] {\n const rows: Row[] = [];\n const seen = new Map<string, number>();\n for (let i = 0; i < visible.length; i++) {\n const text = visible[i] ?? '';\n const n = (seen.get(text) ?? 0) + 1;\n seen.set(text, n);\n rows.push({ key: n === 1 ? text || '_blank' : `${text || '_blank'}#${n}`, text });\n }\n return rows;\n}\n\nexport function OutputPane({\n lines,\n scrollOffset,\n height = 12,\n title,\n}: OutputPaneProps): ReactElement {\n // Content width already accounts for the parent panel's border + padding\n // (see contentWidth()). Truncating to this (not the full terminal width)\n // keeps long lines — like the `noir status` table — inside the rounded box.\n const width = contentWidth();\n\n if (lines.length === 0) {\n return <Text>{c.dim('(no output — type a /command, or ? for help)')}</Text>;\n }\n\n // Clamp the offset into range so a stale value (e.g. after the content\n // shrinks) never produces a blank pane.\n const maxOffset = Math.max(0, lines.length - height);\n const offset = Math.min(Math.max(0, scrollOffset), maxOffset);\n const rows = toRows(lines.slice(offset, offset + height));\n\n return (\n <>\n {title !== undefined ? <Text wrap=\"truncate-end\">{c.dim(`── ${title} ──`)}</Text> : null}\n {rows.map((row) => {\n const truncated =\n row.text.length > width ? `${row.text.slice(0, Math.max(1, width - 1))}…` : row.text;\n // wrap=\"truncate-end\" guarantees a long line never wraps inside the\n // bordered panel — the manual truncate above is the first line of\n // defense; this is the second (Ink will hard-truncate if the panel is\n // narrower than contentWidth() reported, e.g. under a tiny COLUMNS).\n return (\n <Text key={row.key} wrap=\"truncate-end\">\n {truncated}\n </Text>\n );\n })}\n </>\n );\n}\n","// C1 — in-TUI confirmation prompt for a destructive palette dispatch.\n//\n// Presentational only: it renders the `y/N` prompt for the argv the App wants\n// to approve. The App owns the input routing (its single `useInput` handles `y`\n// / `n` / Esc in confirm mode) and the dispatch seam, so this component has no\n// knowledge of what the command does or how to run it.\n//\n// Drawn inside a rounded, warn-colored border so a destructive gate is visually\n// unmistakable (TUI redesign: rounded outlines on every interactive surface).\n\nimport { Box, Text } from 'ink';\nimport type { ReactElement } from 'react';\nimport { c } from '../../theme.js';\nimport { Panel } from '../Panel.js';\n\n/** The confirm overlay's props — supplied by the App. */\nexport interface ConfirmOverlayProps {\n /** The argv being approved, e.g. `['context','index']`. */\n readonly argv: readonly string[];\n}\n\n/**\n * Render the `y/N` confirmation prompt. Capital `N` marks the default (decline),\n * matching the CLI's prompt convention.\n */\nexport function ConfirmOverlay({ argv }: ConfirmOverlayProps): ReactElement {\n return (\n <Panel>\n <Box paddingX={1}>\n <Text>\n {c.warn(`! run /${argv.join(' ')}? (y/N)`)}\n <Text>{c.dim(' [y approve · n/Esc back to palette]')}</Text>\n </Text>\n </Box>\n </Panel>\n );\n}\n","// Shared container — every TUI surface uses this one component for rounded\n// borders + width accounting so no caller duplicates `borderStyle round` /\n// `borderColor gray` / `width` math.\n//\n// When `maxWidth` is set the panel caps at that column ceiling — used by the\n// command palette for the fixed-width overlay look (like Raycast / VS Code).\n// Defaults to full terminal width via contentWidth().\n\nimport { Box } from 'ink';\nimport type { ReactElement, ReactNode } from 'react';\nimport { contentWidth, useColor } from '../theme.js';\n\nexport interface PanelProps {\n readonly children: ReactNode;\n /** Optional max-width ceiling in columns (e.g. 64 for the command palette). */\n readonly maxWidth?: number;\n}\n\nexport function Panel({ children, maxWidth }: PanelProps): ReactElement {\n const full = contentWidth() + 4; // border (2) + inner padding (2)\n const width = maxWidth != null ? Math.min(full, maxWidth) : full;\n // The border color rides the SAME color authority as every other surface:\n // when colors are off (NO_COLOR / non-TTY), pass `undefined` so Ink renders\n // the border in the default terminal color with no ANSI — a hardcoded\n // borderColor=\"gray\" bypassed useColor() and left colored borders around\n // plain content (the documented NO_COLOR contract).\n const borderColor = useColor() ? ('gray' as const) : undefined;\n return (\n <Box\n flexDirection=\"column\"\n borderStyle=\"round\"\n borderColor={borderColor}\n paddingX={1}\n width={width}\n >\n {children}\n </Box>\n );\n}\n","// Hand-rolled fuzzy scorer for the command palette. This is the swap seam:\n// `fuzzyScore` + `matchCommand` are pure functions a future fzf/ItsFuzzy-style\n// matcher can replace without touching the TUI; `FuzzyMatch` is the shared\n// result shape both the matcher and the rendering layer speak.\n//\n// Design notes:\n// - Subsequence matcher (not substring): \"sts\" matches \"status\" (s, t, s).\n// - Case-insensitive — both sides lowercased before comparison.\n// - Gap penalty (-0.1 per skipped char) makes tight matches beat scattered ones.\n// - Consecutive bonus (+8) rewards runs like a real fuzzy finder.\n// - Prefix bonus (+4 while text-index < query.length) makes a leading match\n// dominate a trailing one, so \"sta\" ranks above a \"status\"-tail hit.\n\nimport type { PaletteCommand } from './types.js';\n\n/** A scored palette hit returned by the matcher. */\nexport interface FuzzyMatch {\n item: PaletteCommand;\n score: number;\n /** Text indices of the best-scoring field that matched (for highlight). */\n matchedIndices: number[];\n}\n\n/** Field weights — label dominates so titles win ties over help text. */\nconst WEIGHTS = {\n label: 1.0,\n keyword: 0.7,\n description: 0.5,\n} as const;\n\n/** Flat bonus added to the label field so it wins cross-field ties. */\nconst LABEL_TIE_BONUS = 50;\n\n/**\n * Score `query` against `text` as a (case-insensitive) subsequence. Returns\n * `{score, indices}` when every query char is matched in order, else `null`.\n * An empty query scores 0 with no indices.\n */\nexport function fuzzyScore(\n query: string,\n text: string,\n): { score: number; indices: number[] } | null {\n if (query.length === 0) return { score: 0, indices: [] };\n\n const q = query.toLowerCase();\n const t = text.toLowerCase();\n\n const indices: number[] = [];\n let score = 0;\n let prevMatchedIndex = -1;\n\n let qi = 0;\n for (let ti = 0; ti < t.length && qi < q.length; ti++) {\n if (t[ti] === q[qi]) {\n indices.push(ti);\n // consecutive-match bonus: only when this char directly follows the\n // previous matched char (a real fuzzy-finder \"run\" reward).\n const consecutive = prevMatchedIndex !== -1 && ti === prevMatchedIndex + 1;\n if (consecutive) score += 8;\n if (ti < q.length) score += 4; // prefix-region bonus\n // gap penalty for chars skipped between matches\n if (prevMatchedIndex !== -1) {\n const skipped = ti - prevMatchedIndex - 1;\n if (skipped > 0) score -= 0.1 * skipped;\n }\n prevMatchedIndex = ti;\n qi++;\n }\n }\n\n if (qi < q.length) return null; // query not a full subsequence\n return { score, indices };\n}\n\n/**\n * Score a single command across its label / keywords / description, returning\n * the best field's weighted result (plus the flat label tie-break bonus so a\n * label hit always wins a tie against a keyword or description hit). Returns\n * `null` when the query matches no field.\n */\nexport function matchCommand(query: string, item: PaletteCommand): FuzzyMatch | null {\n if (query.length === 0) {\n return { item, score: 0, matchedIndices: [] };\n }\n\n // Track the best field hit. Kept as a mutable holder (rather than a\n // `| null` union) so the `consider` closure can read the running high score\n // without TypeScript narrowing it to `never` across the conditional updates.\n const best: { score: number; indices: number[] } = {\n score: Number.NEGATIVE_INFINITY,\n indices: [],\n };\n let matched = false;\n\n // Replace the running best if `candidate` scores higher.\n const consider = (score: number, indices: number[]): void => {\n if (!matched || score > best.score) {\n best.score = score;\n best.indices = indices;\n matched = true;\n }\n };\n\n // Label — weighted highest, plus the flat tie-break bonus.\n const labelHit = fuzzyScore(query, item.label);\n if (labelHit) {\n consider(labelHit.score * WEIGHTS.label + LABEL_TIE_BONUS, labelHit.indices);\n }\n\n // Keywords — each scored independently, best keyword wins the field.\n if (item.keywords) {\n let bestKw: { score: number; indices: number[] } | null = null;\n for (const kw of item.keywords) {\n const kwHit = fuzzyScore(query, kw);\n if (kwHit && (bestKw === null || kwHit.score > bestKw.score)) bestKw = kwHit;\n }\n if (bestKw) {\n consider(bestKw.score * WEIGHTS.keyword, bestKw.indices);\n }\n }\n\n // Description — lowest weight, last resort.\n if (item.description) {\n const descHit = fuzzyScore(query, item.description);\n if (descHit) {\n consider(descHit.score * WEIGHTS.description, descHit.indices);\n }\n }\n\n if (!matched) return null;\n return { item, score: best.score, matchedIndices: best.indices };\n}\n","// The matcher swap seam. `FuzzyMatcher` is the interface the TUI depends on;\n// `handRolledMatcher` is the default, dependency-free implementation built on\n// `matchCommand`. Swapping in a native fzf/ItsFuzzy binding later means shipping\n// a second `FuzzyMatcher` — the palette code never changes.\n\nimport { type FuzzyMatch, matchCommand } from './fuzzyMatch.js';\nimport type { PaletteCommand } from './types.js';\n\n/**\n * What the palette asks for: \"rank these items against this query, capped at\n * `limit`\". Implementations must be deterministic and side-effect free.\n */\nexport interface FuzzyMatcher {\n search(query: string, items: readonly PaletteCommand[], limit: number): FuzzyMatch[];\n}\n\n/**\n * Default matcher. Empty query returns every item (score 0, empty indices) so\n * the palette can render the full list before the user types; otherwise each\n * item is scored, filtered to matches, sorted by descending score, and sliced\n * to `limit`. Sort is stable (ties keep input order) via a Array.prototype.sort\n * that only reorders on a strict score difference.\n */\nexport const handRolledMatcher: FuzzyMatcher = {\n search(query: string, items: readonly PaletteCommand[], limit: number): FuzzyMatch[] {\n if (query.length === 0) {\n return items.slice(0, Math.max(0, limit)).map((item) => ({\n item,\n score: 0,\n matchedIndices: [],\n }));\n }\n\n const matched: FuzzyMatch[] = [];\n for (const item of items) {\n const m = matchCommand(query, item);\n if (m) matched.push(m);\n }\n\n matched.sort((a, b) => b.score - a.score);\n return matched.slice(0, Math.max(0, limit));\n },\n};\n","// The single command surface (v2) — presentational renderer.\n//\n// The App owns the query + active row + the single `useInput` dispatcher; this\n// component only paints the rows {@link buildPaletteRows} produced for the\n// active corpus (commands / output / help). No `useInput`, no dispatch, no\n// history — the App is the sole decision-maker, so home, palette, and typed\n// /command all funnel through one seam.\n//\n// Layout (two-column, per the v2 design): a fixed label column (bold) on the\n// left, a dim hint column on the right. For command rows the hint is the\n// command's argv (short + unambiguous); the FULL description is shown as a\n// wrapped detail line on the ACTIVE row only, so it is never truncated. The\n// active row is highlighted with reverse video (SGR 7) — visible on any\n// terminal, not just color ones.\n\nimport { Box, Text } from 'ink';\nimport type { ReactElement } from 'react';\nimport { c } from '../../theme.js';\nimport { LIST_NAV_HINT } from '../hints.js';\nimport { Panel } from '../Panel.js';\nimport { type Corpus, type PaletteRow, VISIBLE_ROWS } from './rows.js';\n\nconst PALETTE_WIDTH = 64;\n/** Border + padding overhead between the panel width and a row's text budget:\n * round border (2) + Panel paddingX (2) + row paddingX (2) = 6. A row's\n * label(26) + hint must never exceed the remaining width or Ink wraps the\n * hint tail onto a flush-left second line (the v1.11.2 two-column bug). */\nconst ROW_TEXT_WIDTH = PALETTE_WIDTH - 6; // 58\n/** Fixed label column: the `▸ `/` ` prefix (2) + the label. */\nconst LABEL_WIDTH = 26;\n/** Max hint column width — derived from the row budget so the two-column row\n * can never overflow again (was a hardcoded 34, off by 2). */\nconst HINT_WIDTH = ROW_TEXT_WIDTH - LABEL_WIDTH; // 32\n\n/** Word-boundary wrap so a long description never truncates or overflows. */\nfunction wrap(text: string, width: number): string[] {\n const words = text.split(/\\s+/).filter((w) => w.length > 0);\n const lines: string[] = [];\n let cur = '';\n for (const w of words) {\n if (cur.length === 0) cur = w;\n else if (`${cur} ${w}`.length <= width) cur = `${cur} ${w}`;\n else {\n lines.push(cur);\n cur = w;\n }\n }\n if (cur) lines.push(cur);\n return lines;\n}\n\n/** Truncate a label to fit the fixed label column. */\nfunction truncateLabel(label: string): string {\n const max = LABEL_WIDTH - 2;\n return label.length > max ? `${label.slice(0, max - 1)}…` : label;\n}\n\n/** Placeholder hint for the query row, per corpus. */\nfunction placeholder(corpus: Corpus): string {\n if (corpus === 'commands') return 'type to search commands';\n if (corpus === 'output') return 'type to filter output';\n return 'keybindings';\n}\n\n/** The palette's props — supplied by the App (which owns input + dispatch). */\nexport interface PaletteProps {\n readonly corpus: Corpus;\n readonly query: string;\n readonly active: number;\n readonly rows: readonly PaletteRow[];\n}\n\n/**\n * Render the palette overlay: an input row + the corpus list. Presentational —\n * the App owns query/active/input and passes the rows in.\n */\nexport function Palette({ corpus, query, active, rows }: PaletteProps): ReactElement {\n const total = rows.length;\n // Sliding window: the cursor spans the FULL row list; slide a VISIBLE_ROWS\n // window so the active row is always on screen (sticking to the bottom once\n // scrolled). Without this, only the first 10 rows of a ~60-row command list\n // would be reachable.\n const scroll = Math.max(0, Math.min(active - (VISIBLE_ROWS - 1), total - VISIBLE_ROWS));\n const visible = rows.slice(scroll, scroll + VISIBLE_ROWS);\n const activeIndex = Math.min(Math.max(active - scroll, 0), Math.max(0, visible.length - 1));\n\n const elements: ReactElement[] = [\n <Box key=\"header\" paddingX={1}>\n <Text>\n {c.bold('▸ palette ')}\n <Text>{c.dim(`· ${corpus}`)}</Text>\n </Text>\n </Box>,\n <Box key=\"query\" paddingX={1}>\n <Text>\n {c.dim('> ')}\n {query.length > 0 ? query : c.dim(placeholder(corpus))}\n <Text>{c.dim('▌')}</Text>\n </Text>\n </Box>,\n ];\n\n let lastGroup: string | null = null;\n for (let i = 0; i < visible.length; i++) {\n const row = visible[i];\n if (!row) continue;\n if (row.group !== null && row.group !== lastGroup) {\n // A blank spacer before every section (except the first) so the group\n // headers read as distinct, scannable blocks rather than a wall of rows.\n if (lastGroup !== null) {\n elements.push(\n <Box key={`gap:${row.group}`}>\n <Text> </Text>\n </Box>,\n );\n }\n elements.push(\n <Box key={`cat:${row.group}`} paddingX={1}>\n <Text>{c.bold(`── ${row.group} ──`)}</Text>\n </Box>,\n );\n lastGroup = row.group;\n }\n const isActive = i === activeIndex;\n const prefix = isActive ? '▸ ' : ' ';\n const label = truncateLabel(row.primary);\n const labelCol = (prefix + label).padEnd(LABEL_WIDTH);\n // Hint (right column): the argv for command rows, prefixed with `/` so it\n // reads as \"the command that runs on Enter\" (matching the dashboard's\n // `/command` convention). Non-command rows use the secondary line. Clipped\n // to the hint column so a long keybinding description (help corpus) never\n // overflows the panel.\n const hintRaw = row.argv ? `/${row.argv.join(' ')}` : row.secondary;\n const hint = hintRaw.length > HINT_WIDTH ? `${hintRaw.slice(0, HINT_WIDTH - 1)}…` : hintRaw;\n\n if (isActive) {\n // Reverse video highlights the whole row — no inner color needed.\n elements.push(\n <Box key={row.key} paddingX={1}>\n <Text>{c.inverse(`${labelCol}${hint}`)}</Text>\n </Box>,\n );\n } else {\n elements.push(\n <Box key={row.key} paddingX={1}>\n <Text>\n {c.bold(labelCol)}\n {hint.length > 0 ? c.dim(hint) : null}\n </Text>\n </Box>,\n );\n }\n\n // Detail line: the FULL description on the active row, wrapped so it is\n // never truncated. Command rows always show it; help rows show it too\n // (matching command-row UX — the hint column only truncates). Output-corpus\n // rows are excluded: their secondary is a line number / empty-state text,\n // not a description. A leading `↳` marks the detail as belonging to the row\n // above (not a new selectable item); continuation lines align under the\n // text so they read as one wrapped block.\n if (isActive && row.secondary && (row.argv || corpus === 'help')) {\n const detailLines = wrap(row.secondary, ROW_TEXT_WIDTH - 4);\n for (let di = 0; di < detailLines.length; di++) {\n const line = detailLines[di] ?? '';\n const prefix = di === 0 ? ' ↳ ' : ' ';\n elements.push(\n <Box key={`${row.key}:d:${di}`} paddingX={1}>\n <Text>{c.dim(`${prefix}${line}`)}</Text>\n </Box>,\n );\n }\n }\n }\n\n return (\n <Box flexDirection=\"column\">\n <Panel maxWidth={PALETTE_WIDTH}>{elements}</Panel>\n <Text>{c.dim(LIST_NAV_HINT)}</Text>\n </Box>\n );\n}\n","// Output-search primitives (moved from the retired `overlays/SearchMode.ts`).\n//\n// Pure, framework-free functions the palette's `output` corpus consumes:\n// `computeMatches` turns a query into the line indices that contain it. The\n// `/` dispatch prefix makes '/' unusable as a search key, so Ctrl+F (or the\n// palette `Tab` switch) is the entry into this corpus.\n\n/**\n * Line indices whose (case-insensitive) text contains `query`, in line order.\n * An empty query matches nothing (`[]`) — the search only starts once the user\n * types, and an empty query must never be treated as \"matches every line\".\n */\nexport function computeMatches(lines: readonly string[], query: string): number[] {\n if (query.length === 0) return [];\n const needle = query.toLowerCase();\n const out: number[] = [];\n for (let i = 0; i < lines.length; i++) {\n if ((lines[i] ?? '').toLowerCase().includes(needle)) out.push(i);\n }\n return out;\n}\n","// Pure row-building for the single command surface (v2). The App owns the\n// query + active row + key routing; this module derives the visible rows for a\n// corpus so the App can resolve the active row into a dispatch (Enter) while\n// the presentational `Palette` renders the same rows — one source of truth for\n// what the palette shows and what a selection runs.\n\nimport type { HomeAction, HomeSection } from '../commands/sections.js';\nimport { HELP_ENTRIES } from '../hints.js';\nimport type { FuzzyMatcher } from './matcher.js';\nimport { computeMatches } from './output.js';\nimport type { PaletteCommand } from './types.js';\n\n/** The palette's active corpus. */\nexport type Corpus = 'commands' | 'output' | 'help';\n\n/** All corpora, in `Tab`-cycle order. */\nexport const CORPORA: readonly Corpus[] = ['commands', 'output', 'help'];\n\nconst MATCH_LIMIT = 20;\n\n/** How many rows the palette renders at once (the sliding window size). */\nexport const VISIBLE_ROWS = 10;\n\n/** A rendered palette row. `argv` is null for non-dispatchable rows. */\nexport interface PaletteRow {\n key: string;\n primary: string;\n secondary: string;\n argv: readonly string[] | null;\n destructive: boolean;\n group: string | null;\n}\n\n/** Inputs to {@link buildPaletteRows}. */\nexport interface BuildRowsInput {\n corpus: Corpus;\n query: string;\n commands: readonly PaletteCommand[];\n matcher: FuzzyMatcher;\n recent: readonly PaletteCommand[];\n homeSections: readonly HomeSection[];\n outputLines: readonly string[];\n}\n\n/** Flatten curated home sections into `{ group, action }` rows. */\nfunction flattenHome(sections: readonly HomeSection[]): { group: string; action: HomeAction }[] {\n const out: { group: string; action: HomeAction }[] = [];\n for (const section of sections) {\n for (const action of section.items) out.push({ group: section.label, action });\n }\n return out;\n}\n\n/** `recent` entries that still exist in `commands`, in recent order. */\nfunction recentDeduped(\n recent: readonly PaletteCommand[],\n commands: readonly PaletteCommand[],\n): PaletteCommand[] {\n const known = new Set(commands.map((cmd) => cmd.id));\n return recent.filter((cmd) => known.has(cmd.id));\n}\n\n/** Build the visible rows for the active corpus + query. */\nexport function buildPaletteRows(input: BuildRowsInput): PaletteRow[] {\n const { corpus, query, commands, matcher, recent, homeSections, outputLines } = input;\n\n if (corpus === 'help') {\n return HELP_ENTRIES.map((e) => ({\n key: `help:${e.keys}`,\n primary: e.keys,\n secondary: e.desc,\n argv: null,\n destructive: false,\n group: 'keybindings',\n }));\n }\n\n if (corpus === 'output') {\n const matches = computeMatches(outputLines, query);\n if (query.length > 0 && matches.length === 0) {\n // A typed filter with zero hits is an explicit empty state — never list\n // the full output under a misleading \"matches\" header.\n return [\n {\n key: 'empty',\n primary: '(no matches)',\n secondary: `nothing matches \"${query}\"`,\n argv: null,\n destructive: false,\n group: null,\n },\n ];\n }\n if (matches.length === 0) {\n if (outputLines.length === 0) {\n return [\n {\n key: 'empty',\n primary: '(no output)',\n secondary: 'run a /command first',\n argv: null,\n destructive: false,\n group: null,\n },\n ];\n }\n // Empty query: browse the full output.\n return outputLines.map((line, i) => ({\n key: `out:${i}`,\n primary: line,\n secondary: String(i + 1),\n argv: null,\n destructive: false,\n group: null,\n }));\n }\n return matches.map((i) => ({\n key: `out:${i}`,\n primary: outputLines[i] ?? '',\n secondary: String(i + 1),\n argv: null,\n destructive: false,\n group: 'matches',\n }));\n }\n\n // commands corpus.\n if (query.length === 0) {\n const rows: PaletteRow[] = [];\n const recents = recentDeduped(recent, commands);\n const recentIds = new Set(recents.map((r) => r.id));\n for (const cmd of recents) {\n rows.push({\n key: `recent:${cmd.id}`,\n primary: cmd.label,\n secondary: cmd.description,\n argv: cmd.argv,\n destructive: cmd.destructive,\n group: 'recent',\n });\n }\n const homeIds = new Set<string>();\n for (const { group, action } of flattenHome(homeSections)) {\n // Skip a curated action already shown in the recents section, so a command\n // run recently never appears twice (recents + its section) on one screen.\n if (recentIds.has(action.id)) continue;\n const argv = action.dispatch ?? [action.id];\n homeIds.add(action.id);\n rows.push({\n key: `home:${action.id}`,\n primary: action.label,\n secondary: action.hint,\n argv,\n destructive: action.destructive ?? false,\n group,\n });\n }\n for (const cmd of commands) {\n // Skip commands already shown as a recent or as a curated quick action —\n // the curated label wins over the raw leaf label (one row per command).\n if (recentIds.has(cmd.id) || homeIds.has(cmd.id)) continue;\n rows.push({\n key: `cmd:${cmd.id}`,\n primary: cmd.label,\n secondary: cmd.description,\n argv: cmd.argv,\n destructive: cmd.destructive,\n group: cmd.category,\n });\n }\n return rows;\n }\n\n // Non-empty query: fuzzy-rank the full command list.\n return matcher.search(query, commands, MATCH_LIMIT).map((m) => ({\n key: `cmd:${m.item.id}`,\n primary: m.item.label,\n secondary: m.item.description,\n argv: m.item.argv,\n destructive: m.item.destructive,\n group: null,\n }));\n}\n","// Top status bar. Renders a one-line summary of the live snapshot: host, mode\n// (from the active workflow task, if any), phase (or \"idle\"), and daemon\n// health. Degrades cleanly — when the payload is null (project uninitialized,\n// snapshot in flight, or the daemon fully down), every field shows a dash and\n// the daemon cell reads \"down\" so the user is never looking at empty space.\n\nimport { Text } from 'ink';\nimport type { ReactElement } from 'react';\nimport type { StatusPayload } from '../commands/status.js';\nimport { c } from '../theme.js';\n\ninterface StatusBarProps {\n payload: StatusPayload | null;\n /** When true, the snapshot is being (re)loaded — shown as a dim hint. */\n loading?: boolean;\n}\n\nfunction Cell({\n label,\n value,\n accent,\n}: {\n label: string;\n value: string;\n accent?: boolean;\n}): ReactElement {\n return (\n <Text>\n <Text>{c.dim(`${label}:`)}</Text> <Text>{accent ? c.accent(value) : value}</Text>\n </Text>\n );\n}\n\nexport function StatusBar({ payload, loading }: StatusBarProps): ReactElement {\n const host = payload?.host ?? '—';\n const mode = payload?.workflow?.mode ?? '—';\n const phase = payload?.workflow?.phase ?? (loading ? '…' : 'idle');\n const daemonRunning = payload?.daemon.running === true;\n const daemon = payload === null && loading ? '…' : daemonRunning ? 'up' : 'down';\n\n return (\n <Text>\n <Cell label=\"host\" value={host} accent />\n <Text>{c.dim(' · ')}</Text>\n <Cell label=\"mode\" value={mode} />\n <Text>{c.dim(' · ')}</Text>\n <Cell label=\"phase\" value={phase} />\n <Text>{c.dim(' · ')}</Text>\n <Text>\n {c.dim('daemon:')} {daemonRunning ? c.ok(daemon) : c.warn(daemon)}\n </Text>\n </Text>\n );\n}\n","// C3 — palette command-history persistence.\n//\n// The palette shows the user's recently-run commands above the full list on an\n// empty query. That recency data lives on disk so it survives sessions. The file\n// is keyed by canonical ProjectId — `~/.noir/<projectId>/tui-history.json` (NOT a\n// filesystem path) — so it respects the `.noir/` single-source-of-truth invariant\n// (CLAUDE.md): a project's recents are isolated from every other project. The\n// file is a simple newest-first JSON array of `{ argv, id }` (id is the\n// space-joined argv — the same stable dispatch key the registry uses).\n//\n// Opt-out: set `NOIR_DISABLE_TUI_HISTORY=1` to make persistence in-memory only\n// (loadRecent/recordRecent become no-ops). Useful for ephemeral/CI shells.\n//\n// Bounds: `MAX_ENTRIES` (50) caps the file so it never grows without bound, and\n// every write is atomic via the shared `atomicWriteFile` (@noir-ai/core — the\n// same helper daemon/lifecycle.ts and update-check.ts use) so a crash mid-write\n// never leaves a half-written JSON blob. A corrupt file (manual edit, truncated\n// write from an older build) degrades to `[]` rather than throwing — recency is\n// a nice-to-have, never a crash.\n//\n// Test seam: `__setNoirHome` overrides the home dir so the offline suite can\n// point at a tmpdir instead of the real `~/.noir` (mirrors `NOIR_DAEMON_JSON`).\n\nimport { existsSync, mkdirSync, readFileSync } from 'node:fs';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\nimport { atomicWriteFile } from '@noir-ai/core';\n\n/** A single entry in the persisted recent-commands list. */\nexport interface RecentEntry {\n /** The raw argv the user selected (e.g. `['context','search','foo']`). */\n readonly argv: readonly string[];\n /** Space-joined argv — the stable dispatch key (e.g. `context search foo`). */\n readonly id: string;\n}\n\n/** Bounded history size — the palette only needs a handful of recents. */\nconst MAX_ENTRIES = 50;\n\n/** The env var that disables palette-history persistence (in-memory only). */\nexport const TUI_HISTORY_DISABLE_ENV = 'NOIR_DISABLE_TUI_HISTORY';\n\nlet testHome: string | null = null;\n\n/**\n * Test override for the Noir home dir. Pass `null` to restore the real\n * `~/.noir` resolution. Never called from production code.\n */\nexport function __setNoirHome(home: string | null): void {\n testHome = home;\n}\n\n/** The user-global Noir home (test override wins when set). */\nfunction homeDir(): string {\n return testHome ?? join(homedir(), '.noir');\n}\n\n/**\n * Path of the palette history file for a project:\n * `<home>/<projectId>/tui-history.json`. ProjectId-keyed so recents are isolated\n * per project (respects the `.noir/` single-source-of-truth invariant).\n */\nfunction historyFile(projectId: string): string {\n return join(homeDir(), projectId, 'tui-history.json');\n}\n\n/**\n * Whether palette history persistence is enabled. Honors\n * `NOIR_DISABLE_TUI_HISTORY` (any non-empty value disables it → in-memory only).\n */\nexport function isHistoryEnabled(): boolean {\n const v = process.env[TUI_HISTORY_DISABLE_ENV];\n return v === undefined || v === '';\n}\n\n/**\n * Load the persisted recent commands for `projectId`, newest first. Returns `[]`\n * when persistence is disabled, the file is missing/empty/corrupt — recency is\n * best-effort and must never throw.\n */\nexport function loadRecent(projectId: string): RecentEntry[] {\n if (!isHistoryEnabled()) return [];\n const file = historyFile(projectId);\n try {\n if (!existsSync(file)) return [];\n const raw = readFileSync(file, 'utf8');\n const parsed: unknown = JSON.parse(raw);\n if (!Array.isArray(parsed)) return [];\n const entries: RecentEntry[] = [];\n for (const item of parsed) {\n if (typeof item !== 'object' || item === null) continue;\n const argv = (item as { argv?: unknown }).argv;\n const id = (item as { id?: unknown }).id;\n if (!Array.isArray(argv) || typeof id !== 'string') continue;\n if (!argv.every((tok): tok is string => typeof tok === 'string')) continue;\n entries.push({ argv, id });\n }\n return entries;\n } catch {\n return [];\n }\n}\n\n/**\n * Record a dispatched command as the newest recent entry for `projectId`.\n * Adjacent duplicates are dropped (re-running the same command once is one\n * entry); re-running a command from deeper in the list moves it to the front.\n * The persisted list is capped at {@link MAX_ENTRIES}. No-op when persistence is\n * disabled. Best-effort: a failed write is swallowed (recency is a nice-to-have\n * — a read-only home or a full disk must not break command dispatch).\n */\nexport function recordRecent(projectId: string, argv: readonly string[]): void {\n if (argv.length === 0) return;\n if (!isHistoryEnabled()) return;\n const entry: RecentEntry = { argv, id: argv.join(' ') };\n const current = loadRecent(projectId).filter((e) => e.id !== entry.id);\n const next = [entry, ...current].slice(0, MAX_ENTRIES);\n try {\n const dir = join(homeDir(), projectId);\n mkdirSync(dir, { recursive: true });\n atomicWriteFile(historyFile(projectId), `${JSON.stringify(next, null, 2)}\\n`);\n } catch {\n // Recency is a nice-to-have — a read-only home (or a full disk) must not\n // break command dispatch.\n }\n}\n"],"mappings":"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","names":["Box","Text","useState","Text","jsx","Text","Text","jsx","jsxs","Text","Text","jsx","jsxs","Text","Box","Text","Box","jsx","Box","jsx","jsxs","Box","Text","Box","Text","jsx","jsxs","Box","Text","prefix","Text","jsx","jsxs","Text","jsx","jsxs","useState","c","Box","Text","jsx","c"]}