@noir-ai/cli 1.3.0-beta.4 → 1.3.0-beta.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/bin.js CHANGED
@@ -466,16 +466,17 @@ import { SUPPORTED_HOSTS } from "@noir-ai/adapters";
466
466
  import { loadProjectInfo as loadProjectInfo3 } from "@noir-ai/core";
467
467
 
468
468
  // src/banner.ts
469
+ import gradient from "gradient-string";
469
470
  import pc from "picocolors";
470
471
  var NOIR_BLOCK = [
471
- "\u2588\u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2557 ",
472
- "\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557",
473
- "\u2588\u2588\u2554\u2588\u2588\u2557 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551",
474
- "\u2588\u2588\u2551\u255A\u2588\u2588\u2557\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2551",
475
- "\u2588\u2588\u2551 \u255A\u2588\u2588\u2588\u2588\u2551\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551",
476
- "\u255A\u2550\u255D \u255A\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D"
472
+ "\u2588\u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 ",
473
+ "\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2551 \u2588\u2588\u2554\u2550\u2550\u2550\u2588\u2588\u2557 \u2588\u2588\u2551 \u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557",
474
+ "\u2588\u2588\u2554\u2588\u2588\u2557 \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D",
475
+ "\u2588\u2588\u2551\u255A\u2588\u2588\u2557\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2551",
476
+ "\u2588\u2588\u2551 \u255A\u2588\u2588\u2588\u2588\u2551 \u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551",
477
+ "\u255A\u2550\u255D \u255A\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u255D"
477
478
  ];
478
- var ROW_COLORS = [pc.magenta, pc.magentaBright, pc.blue, pc.blueBright, pc.cyan, pc.cyanBright];
479
+ var NOIR_GRADIENT = gradient("#a855f7", "#3b82f6", "#06b6d4");
479
480
  var NOIR_TAGLINE = "discipline, context, and memory layer for agentic CLIs";
480
481
  function renderBanner(opts = {}) {
481
482
  const width = opts.width ?? process.stdout.columns ?? 80;
@@ -483,7 +484,8 @@ function renderBanner(opts = {}) {
483
484
  if (width < 50) {
484
485
  return color ? `${pc.magenta("\u25C6")} noir` : "\u25C6 noir";
485
486
  }
486
- return NOIR_BLOCK.map((line, i) => color ? (ROW_COLORS[i] ?? pc.cyan)(line) : line).join("\n");
487
+ const block = NOIR_BLOCK.join("\n");
488
+ return color ? NOIR_GRADIENT.multiline(block) : block;
487
489
  }
488
490
  function shouldShowBanner(opts) {
489
491
  if (opts.quiet === true || opts.json === true) return false;
package/dist/bin.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/bin.ts","../src/daemon-client.ts","../src/commands/context.ts","../src/commands/daemon.ts","../src/commands/home.ts","../src/banner.ts","../src/commands/memory.ts","../src/commands/skills.ts","../src/commands/status.ts","../src/commands/task.ts"],"sourcesContent":["// `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 HomeDeps, home } from './commands/home.js';\nimport {\n memoryConsolidate,\n memoryForget,\n memoryRecall,\n memorySave,\n memorySessions,\n} from './commands/memory.js';\nimport { skillsList, skillsSync } from './commands/skills.js';\nimport { type StatusOptions, status } from './commands/status.js';\nimport { taskAdvance, taskNew, taskNext, taskStatus } from './commands/task.js';\nimport { init } from './init.js';\nimport { type CliOptions, EXIT, fail, handleError, inferExitCode, NoirCliError } from './output.js';\nimport { serve } from './serve.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// 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 };\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\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 DS-4). 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 .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 });\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 .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 (opts: {\n transport?: string;\n url?: string;\n upgrade?: boolean;\n force?: boolean;\n host?: string;\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 await init(process.cwd(), {\n transport,\n url: opts.url,\n ...(upgrade ? { upgrade } : {}),\n ...(force ? { force } : {}),\n ...(host !== undefined ? { host } : {}),\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 .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: { transport?: string; url?: string; force?: boolean; host?: string },\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 const { create } = await import('./commands/create.js');\n await create(dir, {\n transport,\n url: opts.url,\n ...(force ? { force } : {}),\n ...(host !== undefined ? { host } : {}),\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 (preserve hand-edits inside <!-- noir:* --> markers)',\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(async (opts: { host?: string; force?: boolean; merge?: boolean }) => {\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 // Single-positional regression anchor: when no `--host`/`--force`/`--merge`\n // is given, call `sync(cwd)` exactly (bin.test.ts pins this). Only spread\n // the opts bag when a flag was explicit so the default-args snapshot\n // stays green.\n if (host === undefined && !force && !merge) {\n await sync(process.cwd());\n } else {\n await sync(process.cwd(), {\n ...(host !== undefined ? { host } : {}),\n ...(force ? { force } : {}),\n ...(merge ? { merge } : {}),\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 — foreground-honest start/stop/status/restart (S9 t6).\n // `start` accepts `--detach`, which is recognized (documented in --help) but\n // refused inside the action with exit 2 \"not implemented (tracked: v1.x)\".\n const daemonGrp = program.command('daemon').description('control the Noir daemon');\n daemonGrp\n .command('start')\n .description('start the Noir daemon (foreground; backgrounding deferred)')\n .option('--detach', 'run in the background (not yet implemented; exits 2)')\n .action(async (...args: unknown[]) => {\n const cmd = trailingCmd(args);\n const g = cmd.optsWithGlobals();\n const detach = g.detach === true;\n await daemonStart({ ...toCliOptions(g), ...(detach ? { detach } : {}) });\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/t5/t6) -----\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 (S6)');\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', 'ignore content-hash caching (recognized; not yet honored)')\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 (S7)');\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 t6, S5).\n const skillsGrp = program.command('skills').description('builtin skills (S5)');\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.action(() => {\n throw new NoirCliError(EXIT.USAGE, 'Usage: noir skills list|sync');\n });\n\n const taskGrp = program.command('task').description('workflow task control (S4)');\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 .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 await taskNew({\n ...toCliOptions(g),\n slug,\n ...(mode === undefined ? {} : { mode }),\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 .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 });\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.action(() => {\n throw new NoirCliError(EXIT.USAGE, 'Usage: noir task new|status|advance|next');\n });\n\n // Bare `noir` (no subcommand): the home router (S9 t4). Interactive TTY →\n // @clack menu; non-interactive → `status` (human) or `status --json`\n // (machine). `dispatch` re-parses a fresh program so home/menu actions inherit\n // t5/t6 work and own their own exit codes. status is probe-only (C1): bare\n // `noir` in CI never auto-starts a daemon and exits 0 even when down.\n const 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 };\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// ---------------------------------------------------------------------------\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 S4/S6/S7. 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 DS-4 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 { loadProjectInfo, NOIR_VERSION, type ProjectInfo } from '@noir-ai/core';\nimport { ensureDaemonRunning, pidAlive, readDaemonRecord } from '@noir-ai/daemon';\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 DS-6). Stable across releases. */\nexport const DAEMON_DOWN_HINT = 'daemon not reachable — try `noir daemon start`';\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 const res = await fetch(`http://127.0.0.1:${rec.port}/health`);\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","// S9 t5 — `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 DS-4): `--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 { callDaemonTool, type DaemonClientOptions } from '../daemon-client.js';\nimport { type CliOptions, EXIT, fail, info, log, table } from '../output.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\nexport async function contextSearch(opts: ContextSearchOptions): Promise<void> {\n const limit = parseLimit(opts.limit, 'context search', opts);\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 ? ' [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 /** Recognized for future content-hash-bypass; not yet honored by the daemon. */\n force?: boolean;\n}\n\nexport async function contextIndex(opts: ContextIndexOptions): Promise<void> {\n // `--force` is part of the S9 §7 signature, but the daemon's context_index\n // tool does not accept a force flag yet (content-hash incremental is always\n // on). Rather than silently ignore it, surface the gap honestly so a user\n // scripting `--force` learns it's a no-op rather than assuming a full reindex.\n if (opts.force === true) {\n info(\n 'context index: --force is recognized but not yet honored (content-hash is always incremental).',\n opts,\n );\n }\n const args: Record<string, unknown> =\n opts.paths && opts.paths.length > 0 ? { paths: opts.paths } : {};\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 ? ' [degraded: vectors skipped]' : '';\n log(`context index — ${scope}${flag}`, opts);\n table(\n [\n { Field: 'Indexed (new)', Value: data.indexed },\n { Field: 'Skipped (unchanged)', Value: data.skipped },\n { Field: 'Deleted (removed)', Value: data.deleted },\n { Field: 'Failed', Value: data.failed },\n { Field: 'Total chunks', Value: data.totalChunks },\n ],\n ['Field', 'Value'],\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 ? ' [degraded]' : '';\n log(`context status — ${data.projectId}${flag}`, opts);\n table(\n [\n { Field: 'Project', Value: data.projectId },\n { Field: 'Docs', Value: data.docCount },\n { Field: 'Vectors', Value: data.vecCount },\n { Field: 'Indexed files', Value: data.indexedFiles },\n { Field: 'Embedder', Value: describeEmbedder(data.embedder) },\n { Field: 'Degraded', Value: data.degraded ? 'yes' : 'no' },\n ],\n ['Field', 'Value'],\n opts,\n );\n}\n","// S9 t6 — `noir daemon {start,stop,status,restart}`.\n//\n// Honest foreground daemon UX (S9 DS-6 / spec §8). `noir daemon start` runs the\n// daemon in-process FOREGROUND (it never silently forks): `ensureDaemonRunning`\n// (from @noir-ai/daemon) either starts a fresh in-process HTTP server — whose\n// listen handle + idle timer + SIGINT/SIGTERM handlers (installed inside\n// `startHttpServer`) keep this CLI process alive until idle-stop or a signal —\n// or reuses an already-healthy one and exits. Detached/socket-activated\n// spawning is deferred, so `--detach` is wired (documented in `--help`) but\n// refuses with exit 2 (USAGE) and a stable \"tracked: v1.x\" message rather than\n// surprise-forking.\n//\n// Stream discipline (S9 DS-4): `--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); `--detach` → exit 2; an\n// uninitialized project (`loadProjectInfo` throws) → exit 1 with the hint.\n\nimport { loadProjectInfo } from '@noir-ai/core';\nimport {\n clearDaemonRecord,\n ensureDaemonRunning,\n pidAlive,\n readDaemonRecord,\n} from '@noir-ai/daemon';\nimport { type CliOptions, EXIT, fail, info, log } 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 (recognized-but-refused) `--detach` flag. */\nexport interface DaemonStartOptions extends DaemonOptions {\n detach?: boolean;\n}\n\n/** v1 daemon mode is foreground-only; `--detach` is tracked for v1.x. */\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// ---------------------------------------------------------------------------\n// `noir daemon start` (foreground-honest; `--detach` → exit 2)\n// ---------------------------------------------------------------------------\n/**\n * Start the Noir daemon in the foreground (or report an already-running one).\n *\n * - `--detach` is recognized but NOT implemented in v1 → exit 2 (USAGE) with a\n * stable \"tracked: v1.x\" message, so scripting against it fails honestly\n * instead of surprise-forking.\n * - When `ensureDaemonRunning` STARTS a daemon, the in-process HTTP server\n * keeps this process alive (foreground) until SIGINT/SIGTERM/idle-timeout;\n * the function returns but the process does not exit. We deliberately do NOT\n * call `ensured.stop()` — that would tear down the daemon we just started.\n * - When a healthy daemon is REUSED, this process reports it and exits.\n *\n * `--json` emits `{ok:true, data:{url,port,pid,mode,reused:false}}` to stdout\n * before the process blocks (so a `--json` caller still gets the one envelope).\n */\nexport async function daemonStart(opts: DaemonStartOptions): Promise<void> {\n if (opts.detach === true) {\n // Wired (appears in `--help`) but refused: detached/socket-activated\n // spawning is deliberate v0 debt (blueprint §9). Stable message + exit 2.\n fail(EXIT.USAGE, 'not implemented (tracked: v1.x)', opts);\n }\n\n const project = loadProjectInfo(process.cwd());\n const ensured = await ensureDaemonRunning({\n project,\n idleTimeoutSec: project.config.daemon.idleTimeoutSec,\n });\n\n if (ensured.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 (backgrounding deferred to v1.x). 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 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 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 log(`Stopped Noir daemon (pid ${rec.pid}).`, opts);\n } else {\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 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 clearDaemonRecord();\n fail(\n EXIT.DAEMON_DOWN,\n 'Noir daemon is not running (port unresponsive; stale record removed).',\n opts,\n );\n }\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 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 foreground one.\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 * `start` blocks foreground once it brings up a daemon, so `restart` blocks too\n * — the honest foreground behavior.\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","// S9 t4 — `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 select menu (intro + quick actions), dispatching the\n// chosen action through the SAME commander program the bin uses, so the\n// menu automatically inherits t5/t6 implementations as they 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 (C1): 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// `@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` as an injected callback (provided by\n// bin.ts) so this module has NO import edge back to bin.ts (which would be\n// circular: bin imports home). That also makes the menu unit-testable without\n// commander — tests pass a fake callback + mock @clack.\n\nimport { type HostId, SUPPORTED_HOSTS } from '@noir-ai/adapters';\nimport { loadProjectInfo } from '@noir-ai/core';\nimport { NOIR_TAGLINE, renderBanner, shouldShowBanner } from '../banner.js';\nimport { type CliOptions, EXIT, fail, isInteractive } from '../output.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\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/** One-line summary of the CLI command surface (shown under the banner). */\nconst COMMANDS_HINT =\n 'Commands: init · create · sync · status · context · memory · skills · task · daemon · doctor';\n\n/**\n * Host-direction line: tell the user to open their configured host CLI to do\n * the actual development (Noir is the orchestration/context/memory brain; the\n * host is the execution engine — blueprint D1 / BYO-agent). Host-agnostic via\n * the S10 `SUPPORTED_HOSTS` registry; lists the alternatives so a multi-host\n * user knows their options.\n */\nfunction hostDirection(host: HostId): string {\n const others = SUPPORTED_HOSTS.filter((h) => h !== host);\n return `→ host: ${host}. Open \\`${host}\\` to start development — Noir set the rules, skills, and memory; ${host} runs the code. (other hosts: ${others.join(', ')})`;\n}\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 */\nexport async function home(opts: CliOptions, deps: HomeDeps): Promise<void> {\n if (isInteractive(opts)) {\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 // (C1) — 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/** 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 if (shouldShowBanner(opts)) {\n const host = project?.host ?? 'claude';\n process.stderr.write(\n `\\n${renderBanner()}\\n${NOIR_TAGLINE}\\n\\n${hostDirection(host)}\\n${COMMANDS_HINT}\\n\\n`,\n );\n }\n clack.intro(project ? `noir — ${project.name}` : 'noir');\n\n const choice = await clack.select({\n message: 'What would you like to do?',\n initialValue: 'status',\n options: [\n { value: 'status', label: 'Status', hint: 'project + daemon + store snapshot' },\n { value: 'index', label: 'Index project', hint: '(re)index files into context' },\n { value: 'recall', label: 'Recall memory', hint: 'search cross-session memory' },\n { value: 'next', label: 'Next task', hint: 'suggest next phase + skill' },\n { value: 'daemon', label: 'Start daemon', hint: 'foreground daemon' },\n { value: 'sync', label: 'Sync skills', hint: 're-emit builtin skills' },\n { value: 'exit', label: 'Exit' },\n ],\n });\n\n if (clack.isCancel(choice)) {\n clack.cancel('Cancelled.');\n // exit 5 (CANCELLED). Plain-text fail: the interactive branch implies\n // !--json, so the {ok,error} envelope does not apply here.\n fail(EXIT.CANCELLED, 'cancelled', opts);\n }\n\n const argv = await argvForChoice(choice as string, clack, opts);\n if (argv === null) {\n // \"Exit\" — nothing to dispatch.\n clack.outro('bye');\n return;\n }\n await deps.dispatch(argv);\n clack.outro('done');\n}\n\n/**\n * Map a menu choice to the sub-command argv, prompting for any required\n * argument the menu can't supply inline. Returns `null` for \"Exit\" (no\n * dispatch). A cancel at a sub-prompt → exit 5.\n */\nasync function argvForChoice(\n choice: string,\n clack: typeof import('@clack/prompts'),\n opts: CliOptions,\n): Promise<string[] | null> {\n switch (choice) {\n case 'status':\n return ['status'];\n case 'index':\n return ['context', 'index'];\n case 'next':\n return ['task', 'next'];\n case 'daemon':\n return ['daemon', 'start'];\n case 'sync':\n return ['sync'];\n case 'exit':\n return null;\n case 'recall': {\n // memory recall needs a query — collect it inline so dispatch doesn't\n // immediately bounce with commander's \"missing required argument\".\n const query = await clack.text({\n message: 'Recall query:',\n placeholder: 'e.g. auth flow, ContextEngine, deploy steps',\n });\n if (clack.isCancel(query)) {\n clack.cancel('Cancelled.');\n fail(EXIT.CANCELLED, 'cancelled', opts);\n }\n return ['memory', 'recall', String(query)];\n }\n default:\n // select constrains values to the listed options; defensive default.\n return null;\n }\n}\n","// SP-B — Noir banner.\n//\n// Pre-rendered ASCII wordmark (\"noir\" in a chunky block font, generated OFFLINE\n// so startup pays zero font-engine cost) with a faux gradient via picocolors.\n// Guardrails: the ONLY caller is the interactive home arm (so CI / non-TTY /\n// NO_COLOR / --json / --no-input never reach it — `isInteractive` gates that);\n// `shouldShowBanner` additionally skips under `--quiet` and `NOIR_NO_BANNER`.\n// No animation by default (accessibility — animations are opt-in later).\nimport pc from 'picocolors';\nimport type { CliOptions } from './output.js';\n\n// \"noir\" in an ANSI-Shadow-style block face. Pre-rendered (not figlet at\n// runtime) so output is deterministic + startup is free. Unicode block glyphs\n// degrade to a readable wordmark even when ANSI color is stripped.\nconst NOIR_BLOCK = [\n '███╗ ██╗ ██████╗ ██╗ ██╗ █████╗ ',\n '████╗ ██║██╔═══██╗██║ ██║██╔══██╗',\n '██╔██╗ ██║██║ ██║███████║███████║',\n '██║╚██╗██║██║ ██║██╔══██║██╔══██║',\n '██║ ╚████║╚██████╔╝██║ ██║██║ ██║',\n '╚═╝ ╚═══╝ ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝',\n];\n\n// Faux gradient (magenta → blue → cyan) using only picocolors' built-in shades\n// (no gradient-string dep). Row-by-row so the wordmark reads top→bottom as a\n// cooling gradient — the \"noir\" aesthetic.\nconst ROW_COLORS = [pc.magenta, pc.magentaBright, pc.blue, pc.blueBright, pc.cyan, pc.cyanBright];\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 picocolors faux-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. `color:false` emits\n * pure text (zero ANSI) for snapshots / CI / NO_COLOR — picocolors itself also\n * auto-strips under NO_COLOR, but the explicit flag keeps this deterministic\n * for tests.\n */\nexport function renderBanner(opts: BannerOptions = {}): string {\n const width = opts.width ?? process.stdout.columns ?? 80;\n const color = opts.color ?? true;\n if (width < 50) {\n return color ? `${pc.magenta('◆')} noir` : '◆ noir';\n }\n return NOIR_BLOCK.map((line, i) => (color ? (ROW_COLORS[i] ?? pc.cyan)(line) : line)).join('\\n');\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","// S9 t5 — `noir memory {recall,save,sessions,forget,consolidate}`.\n//\n// Thin MCP-client commands over the running daemon's S7 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/DS-6): 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 { callDaemonTool, type DaemonClientOptions, withDaemon } from '../daemon-client.js';\nimport { type CliOptions, EXIT, fail, info, isInteractive, log, table } from '../output.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\nexport async function memoryRecall(opts: MemoryRecallOptions): Promise<void> {\n const limit = parseLimit(opts.limit, 'memory recall', opts);\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 ? ' [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 (DS-9: never truncate the DATA; display shows it whole\n // in a readable block rather than a cramped table cell).\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) => (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<{ Field: string; Value: unknown }> = [];\n for (const key of ['id', 'type', 'importance', 'ts', 'source', 'project', 'sessionId']) {\n if (obs[key] !== undefined) rows.push({ Field: key, Value: obs[key] });\n }\n if (rows.length > 0) table(rows, ['Field', 'Value'], 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 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\n if (opts.json === true) {\n process.stdout.write(`${JSON.stringify({ ok: true, data })}\\n`);\n return;\n }\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","// S9 t6 — `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 discoverAll,\n emitSkillsToDir,\n type IntegrationSkill,\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 31 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-brainstorm': 'discovery',\n 'noir-intake': 'discovery',\n 'noir-clarify': 'discovery',\n 'noir-explore': 'discovery',\n 'noir-spec': 'spec',\n 'noir-plan': 'plan',\n 'noir-execute': 'execute',\n 'noir-tdd': 'execute',\n 'noir-debug': 'execute',\n 'noir-subagent': 'execute',\n 'noir-parallel': 'execute',\n 'noir-verify': 'verify',\n 'noir-review': 'verify',\n 'noir-security': 'verify',\n 'noir-test': 'verify',\n 'noir-document': 'document',\n 'noir-readme': 'document',\n 'noir-commit': 'git',\n 'noir-branch': 'git',\n 'noir-pr': 'git',\n 'noir-worktree': 'git',\n 'noir-recall': 'memory',\n 'noir-remember': 'memory',\n 'noir-checkpoint': 'memory',\n 'noir-context': 'context',\n 'noir-frontend': 'domain',\n 'noir-backend': 'domain',\n 'noir-doctor': 'meta',\n 'noir-skill-author': 'meta',\n 'noir-sync': 'meta',\n 'noir-wrap': '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}\n\nfunction toRow(s: BuiltinSkill, kind: 'builtin' | 'integration' = 'builtin'): SkillRow {\n const description =\n typeof s.frontmatter.description === 'string' ? s.frontmatter.description : '';\n return { name: s.name, category: categoryOf(s.name), description, kind };\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 33 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 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 Description: truncate(r.description, 80),\n })),\n ['Skill', 'Kind', 'Category', '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 // T2: 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","// 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 C2-clean exit-4 envelope. Only\n// `status` is probe-only — in-process read fallback for the active commands is\n// deferred to v1.x (DS-5).\n//\n// Stream discipline (S9 DS-4): `--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, log, table } from '../output.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 */\nasync function tryTool<T>(caller: DaemonToolCaller, name: string): Promise<T | null> {\n try {\n return await caller.callTool<T>(name);\n } catch {\n // Engine absent (tool not registered), transport hiccup, or non-JSON text.\n // All are non-fatal for an optional section; report it as unavailable.\n return null;\n }\n}\n\nfunction pickStore(s: StoreStatusResult | null): StatusPayload['store'] {\n if (s?.ok !== true) return null;\n return {\n docCount: s.docCount,\n vecCount: s.vecCount,\n dbPath: s.dbPath,\n degraded: s.degraded === true,\n };\n}\n\nfunction describeEmbedder(e: ContextStatusResult['embedder']): string {\n if (!e || e.kind === 'none') return 'none (BM25-only)';\n const model = typeof e.model === 'string' && e.model.length > 0 ? e.model : '<unset>';\n return `${e.kind} · ${model} (${e.dim}-dim)`;\n}\n\nfunction pickContext(c: ContextStatusResult | null): StatusPayload['context'] {\n if (c?.ok !== true) return null;\n return {\n docCount: c.docCount,\n vecCount: c.vecCount,\n indexedFiles: c.indexedFiles,\n embedder: describeEmbedder(c.embedder),\n degraded: c.degraded === true,\n };\n}\n\nfunction pickWorkflow(w: WorkflowStatusResult | null): StatusPayload['workflow'] {\n // `workflow_status` returns `{ok:false,error:'no active task'}` (data) when no\n // task is active — normalize that to `null` so the payload's `workflow` field\n // cleanly means \"active task snapshot present\".\n if (w?.ok !== true) return null;\n return {\n taskId: w.taskId,\n phase: w.phase,\n state: w.state,\n mode: w.mode,\n nextGate: w.nextGate,\n degraded: w.degraded === true,\n };\n}\n\nfunction pickMemory(m: MemorySessionsResult | null): StatusPayload['memory'] {\n if (m?.ok !== true || !Array.isArray(m.sessions)) return null;\n let observations = 0;\n for (const s of m.sessions) observations += s.count;\n return { sessions: m.sessions.length, observations };\n}\n\n/**\n * Build the normalized payload from in-process project info + the daemon probe\n * + the (all-optional) count-tool results. Daemon `running`/`pid`/`uptimeSec`\n * come from the probe (the honest liveness source); `transport` is enriched from\n * `host_status` when that tool is reachable, else omitted. Every other section is\n * `null` when its engine is absent OR the daemon is down.\n */\nfunction buildPayload(\n project: ProjectInfo,\n probe: DaemonProbe,\n host: HostStatusResult | null,\n store: StoreStatusResult | null,\n context: ContextStatusResult | null,\n workflow: WorkflowStatusResult | null,\n memory: MemorySessionsResult | null,\n): StatusPayload {\n return {\n noir: NOIR_VERSION,\n project: { id: project.id, name: project.name },\n host: project.config.host,\n daemon: {\n running: probe.running,\n ...(probe.pid !== undefined ? { pid: probe.pid } : {}),\n ...(probe.uptimeSec !== undefined ? { uptimeSec: probe.uptimeSec } : {}),\n ...(host && typeof host.transport === 'string' ? { transport: host.transport } : {}),\n },\n store: pickStore(store),\n context: pickContext(context),\n workflow: pickWorkflow(workflow),\n memory: pickMemory(memory),\n };\n}\n\n// ---------------------------------------------------------------------------\n// Human rendering (stderr). A two-column Field/Value table is the leanest\n// readable shape for a status snapshot; cli-table3 is auto-stripped under\n// NO_COLOR / non-TTY and the whole call is a no-op under --json.\n// ---------------------------------------------------------------------------\nfunction formatDuration(sec?: number): string {\n if (typeof sec !== 'number' || sec < 0) return 'unknown';\n if (sec < 60) return `${sec}s`;\n if (sec < 3600) return `${Math.floor(sec / 60)}m ${sec % 60}s`;\n return `${Math.floor(sec / 3600)}h ${Math.floor((sec % 3600) / 60)}m`;\n}\n\nfunction 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\nfunction describeStore(s: StatusPayload['store']): string {\n if (!s) return 'unavailable (store engine not wired)';\n const flag = s.degraded ? ' [degraded: read-only]' : '';\n return `${s.docCount} docs / ${s.vecCount} vecs${flag}`;\n}\n\nfunction describeContext(c: StatusPayload['context']): string {\n if (!c) return 'unavailable (context engine not wired)';\n const flag = c.degraded ? ' [degraded]' : '';\n return `${c.docCount} docs, ${c.vecCount} vecs, ${c.indexedFiles} files · embedder ${c.embedder}${flag}`;\n}\n\nfunction 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 ? ' [degraded]' : '';\n return `${w.phase} (${w.state}, ${w.mode}) · task ${w.taskId}${gate}${flag}`;\n}\n\nfunction 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 + table both go to stderr (table is a no-op under --json; we only\n // render human when opts.json is false, but passing opts keeps --quiet honest).\n log(`noir status — ${p.project.name} (${p.project.id})`, opts);\n table(\n [\n { Field: 'Project', Value: `${p.project.name} (${p.project.id})` },\n { Field: 'Host', Value: p.host },\n { Field: 'Noir', Value: p.noir },\n { Field: 'Daemon', Value: describeDaemon(p.daemon) },\n { Field: 'Store', Value: describeStore(p.store) },\n { Field: 'Context', Value: describeContext(p.context) },\n { Field: 'Workflow', Value: describeWorkflow(p.workflow) },\n { Field: 'Memory', Value: describeMemory(p.memory) },\n ],\n ['Field', 'Value'],\n opts,\n );\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 // In-process project info — no daemon round-trip. Uninitialized → exit 1.\n const project = loadProjectInfo(process.cwd());\n // Probe — never starts a daemon. A down daemon is reported + exit 0.\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 const payload = buildPayload(project, probe, host, store, context, workflow, memory);\n\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 t5 — `noir task {new,status,advance,next}`.\n//\n// Thin MCP-client commands over the daemon's S4 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 { callDaemonTool, type DaemonClientOptions } from '../daemon-client.js';\nimport { type CliOptions, EXIT, fail, info, log, table } from '../output.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}\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// ---------------------------------------------------------------------------\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// ---------------------------------------------------------------------------\nconst PHASE_SKILL: Readonly<Record<string, string>> = {\n intake: 'noir-intake',\n clarify: 'noir-clarify',\n spec: 'noir-spec',\n plan: 'noir-plan',\n execute: 'noir-execute',\n verify: 'noir-verify',\n document: 'noir-document',\n};\n\nfunction skillFor(phase: string | null | undefined): string | null {\n if (typeof phase !== 'string') return null;\n return PHASE_SKILL[phase] ?? null;\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 ? ' [degraded]' : '';\n log(`task status — ${s.taskId}${flag}`, opts);\n table(\n [\n { Field: 'Task', Value: s.taskId },\n { Field: 'Phase', Value: s.phase },\n { Field: 'State', Value: s.state },\n { Field: 'Mode', Value: s.mode },\n { Field: 'Next gate', Value: s.nextGate ?? '—' },\n { Field: 'Updated', Value: formatStamp(s.updatedAt) },\n ],\n ['Field', 'Value'],\n opts,\n );\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\nexport async function taskStatus(opts: TaskStatusOptions): Promise<void> {\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 ? ' [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}\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 // 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 },\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}\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 if (opts.json === true) {\n process.stdout.write(`${JSON.stringify({ ok: true, data: res })}\\n`);\n return;\n }\n renderStatusRow(res, opts);\n}\n"],"mappings":"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","names":["SUPPORTED_HOSTS","NOIR_VERSION","loadProjectInfo","ensureDaemonRunning","pidAlive","readDaemonRecord","loadProjectInfo","ensureDaemonRunning","readDaemonRecord","pidAlive","loadProjectInfo","info","loadProjectInfo","parseLimit","toHit","failTool","loadProjectInfo","loadProjectInfo","data","loadProjectInfo","NOIR_VERSION","describeEmbedder","NOIR_VERSION","loadProjectInfo","program","NOIR_VERSION","SUPPORTED_HOSTS"]}
1
+ {"version":3,"sources":["../src/bin.ts","../src/daemon-client.ts","../src/commands/context.ts","../src/commands/daemon.ts","../src/commands/home.ts","../src/banner.ts","../src/commands/memory.ts","../src/commands/skills.ts","../src/commands/status.ts","../src/commands/task.ts"],"sourcesContent":["// `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 HomeDeps, home } from './commands/home.js';\nimport {\n memoryConsolidate,\n memoryForget,\n memoryRecall,\n memorySave,\n memorySessions,\n} from './commands/memory.js';\nimport { skillsList, skillsSync } from './commands/skills.js';\nimport { type StatusOptions, status } from './commands/status.js';\nimport { taskAdvance, taskNew, taskNext, taskStatus } from './commands/task.js';\nimport { init } from './init.js';\nimport { type CliOptions, EXIT, fail, handleError, inferExitCode, NoirCliError } from './output.js';\nimport { serve } from './serve.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// 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 };\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\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 DS-4). 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 .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 });\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 .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 (opts: {\n transport?: string;\n url?: string;\n upgrade?: boolean;\n force?: boolean;\n host?: string;\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 await init(process.cwd(), {\n transport,\n url: opts.url,\n ...(upgrade ? { upgrade } : {}),\n ...(force ? { force } : {}),\n ...(host !== undefined ? { host } : {}),\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 .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: { transport?: string; url?: string; force?: boolean; host?: string },\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 const { create } = await import('./commands/create.js');\n await create(dir, {\n transport,\n url: opts.url,\n ...(force ? { force } : {}),\n ...(host !== undefined ? { host } : {}),\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 (preserve hand-edits inside <!-- noir:* --> markers)',\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(async (opts: { host?: string; force?: boolean; merge?: boolean }) => {\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 // Single-positional regression anchor: when no `--host`/`--force`/`--merge`\n // is given, call `sync(cwd)` exactly (bin.test.ts pins this). Only spread\n // the opts bag when a flag was explicit so the default-args snapshot\n // stays green.\n if (host === undefined && !force && !merge) {\n await sync(process.cwd());\n } else {\n await sync(process.cwd(), {\n ...(host !== undefined ? { host } : {}),\n ...(force ? { force } : {}),\n ...(merge ? { merge } : {}),\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 — foreground-honest start/stop/status/restart (S9 t6).\n // `start` accepts `--detach`, which is recognized (documented in --help) but\n // refused inside the action with exit 2 \"not implemented (tracked: v1.x)\".\n const daemonGrp = program.command('daemon').description('control the Noir daemon');\n daemonGrp\n .command('start')\n .description('start the Noir daemon (foreground; backgrounding deferred)')\n .option('--detach', 'run in the background (not yet implemented; exits 2)')\n .action(async (...args: unknown[]) => {\n const cmd = trailingCmd(args);\n const g = cmd.optsWithGlobals();\n const detach = g.detach === true;\n await daemonStart({ ...toCliOptions(g), ...(detach ? { detach } : {}) });\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/t5/t6) -----\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 (S6)');\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', 'ignore content-hash caching (recognized; not yet honored)')\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 (S7)');\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 t6, S5).\n const skillsGrp = program.command('skills').description('builtin skills (S5)');\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.action(() => {\n throw new NoirCliError(EXIT.USAGE, 'Usage: noir skills list|sync');\n });\n\n const taskGrp = program.command('task').description('workflow task control (S4)');\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 .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 await taskNew({\n ...toCliOptions(g),\n slug,\n ...(mode === undefined ? {} : { mode }),\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 .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 });\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.action(() => {\n throw new NoirCliError(EXIT.USAGE, 'Usage: noir task new|status|advance|next');\n });\n\n // Bare `noir` (no subcommand): the home router (S9 t4). Interactive TTY →\n // @clack menu; non-interactive → `status` (human) or `status --json`\n // (machine). `dispatch` re-parses a fresh program so home/menu actions inherit\n // t5/t6 work and own their own exit codes. status is probe-only (C1): bare\n // `noir` in CI never auto-starts a daemon and exits 0 even when down.\n const 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 };\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// ---------------------------------------------------------------------------\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 S4/S6/S7. 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 DS-4 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 { loadProjectInfo, NOIR_VERSION, type ProjectInfo } from '@noir-ai/core';\nimport { ensureDaemonRunning, pidAlive, readDaemonRecord } from '@noir-ai/daemon';\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 DS-6). Stable across releases. */\nexport const DAEMON_DOWN_HINT = 'daemon not reachable — try `noir daemon start`';\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 const res = await fetch(`http://127.0.0.1:${rec.port}/health`);\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","// S9 t5 — `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 DS-4): `--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 { callDaemonTool, type DaemonClientOptions } from '../daemon-client.js';\nimport { type CliOptions, EXIT, fail, info, log, table } from '../output.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\nexport async function contextSearch(opts: ContextSearchOptions): Promise<void> {\n const limit = parseLimit(opts.limit, 'context search', opts);\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 ? ' [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 /** Recognized for future content-hash-bypass; not yet honored by the daemon. */\n force?: boolean;\n}\n\nexport async function contextIndex(opts: ContextIndexOptions): Promise<void> {\n // `--force` is part of the S9 §7 signature, but the daemon's context_index\n // tool does not accept a force flag yet (content-hash incremental is always\n // on). Rather than silently ignore it, surface the gap honestly so a user\n // scripting `--force` learns it's a no-op rather than assuming a full reindex.\n if (opts.force === true) {\n info(\n 'context index: --force is recognized but not yet honored (content-hash is always incremental).',\n opts,\n );\n }\n const args: Record<string, unknown> =\n opts.paths && opts.paths.length > 0 ? { paths: opts.paths } : {};\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 ? ' [degraded: vectors skipped]' : '';\n log(`context index — ${scope}${flag}`, opts);\n table(\n [\n { Field: 'Indexed (new)', Value: data.indexed },\n { Field: 'Skipped (unchanged)', Value: data.skipped },\n { Field: 'Deleted (removed)', Value: data.deleted },\n { Field: 'Failed', Value: data.failed },\n { Field: 'Total chunks', Value: data.totalChunks },\n ],\n ['Field', 'Value'],\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 ? ' [degraded]' : '';\n log(`context status — ${data.projectId}${flag}`, opts);\n table(\n [\n { Field: 'Project', Value: data.projectId },\n { Field: 'Docs', Value: data.docCount },\n { Field: 'Vectors', Value: data.vecCount },\n { Field: 'Indexed files', Value: data.indexedFiles },\n { Field: 'Embedder', Value: describeEmbedder(data.embedder) },\n { Field: 'Degraded', Value: data.degraded ? 'yes' : 'no' },\n ],\n ['Field', 'Value'],\n opts,\n );\n}\n","// S9 t6 — `noir daemon {start,stop,status,restart}`.\n//\n// Honest foreground daemon UX (S9 DS-6 / spec §8). `noir daemon start` runs the\n// daemon in-process FOREGROUND (it never silently forks): `ensureDaemonRunning`\n// (from @noir-ai/daemon) either starts a fresh in-process HTTP server — whose\n// listen handle + idle timer + SIGINT/SIGTERM handlers (installed inside\n// `startHttpServer`) keep this CLI process alive until idle-stop or a signal —\n// or reuses an already-healthy one and exits. Detached/socket-activated\n// spawning is deferred, so `--detach` is wired (documented in `--help`) but\n// refuses with exit 2 (USAGE) and a stable \"tracked: v1.x\" message rather than\n// surprise-forking.\n//\n// Stream discipline (S9 DS-4): `--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); `--detach` → exit 2; an\n// uninitialized project (`loadProjectInfo` throws) → exit 1 with the hint.\n\nimport { loadProjectInfo } from '@noir-ai/core';\nimport {\n clearDaemonRecord,\n ensureDaemonRunning,\n pidAlive,\n readDaemonRecord,\n} from '@noir-ai/daemon';\nimport { type CliOptions, EXIT, fail, info, log } 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 (recognized-but-refused) `--detach` flag. */\nexport interface DaemonStartOptions extends DaemonOptions {\n detach?: boolean;\n}\n\n/** v1 daemon mode is foreground-only; `--detach` is tracked for v1.x. */\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// ---------------------------------------------------------------------------\n// `noir daemon start` (foreground-honest; `--detach` → exit 2)\n// ---------------------------------------------------------------------------\n/**\n * Start the Noir daemon in the foreground (or report an already-running one).\n *\n * - `--detach` is recognized but NOT implemented in v1 → exit 2 (USAGE) with a\n * stable \"tracked: v1.x\" message, so scripting against it fails honestly\n * instead of surprise-forking.\n * - When `ensureDaemonRunning` STARTS a daemon, the in-process HTTP server\n * keeps this process alive (foreground) until SIGINT/SIGTERM/idle-timeout;\n * the function returns but the process does not exit. We deliberately do NOT\n * call `ensured.stop()` — that would tear down the daemon we just started.\n * - When a healthy daemon is REUSED, this process reports it and exits.\n *\n * `--json` emits `{ok:true, data:{url,port,pid,mode,reused:false}}` to stdout\n * before the process blocks (so a `--json` caller still gets the one envelope).\n */\nexport async function daemonStart(opts: DaemonStartOptions): Promise<void> {\n if (opts.detach === true) {\n // Wired (appears in `--help`) but refused: detached/socket-activated\n // spawning is deliberate v0 debt (blueprint §9). Stable message + exit 2.\n fail(EXIT.USAGE, 'not implemented (tracked: v1.x)', opts);\n }\n\n const project = loadProjectInfo(process.cwd());\n const ensured = await ensureDaemonRunning({\n project,\n idleTimeoutSec: project.config.daemon.idleTimeoutSec,\n });\n\n if (ensured.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 (backgrounding deferred to v1.x). 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 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 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 log(`Stopped Noir daemon (pid ${rec.pid}).`, opts);\n } else {\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 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 clearDaemonRecord();\n fail(\n EXIT.DAEMON_DOWN,\n 'Noir daemon is not running (port unresponsive; stale record removed).',\n opts,\n );\n }\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 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 foreground one.\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 * `start` blocks foreground once it brings up a daemon, so `restart` blocks too\n * — the honest foreground behavior.\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","// S9 t4 — `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 select menu (intro + quick actions), dispatching the\n// chosen action through the SAME commander program the bin uses, so the\n// menu automatically inherits t5/t6 implementations as they 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 (C1): 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// `@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` as an injected callback (provided by\n// bin.ts) so this module has NO import edge back to bin.ts (which would be\n// circular: bin imports home). That also makes the menu unit-testable without\n// commander — tests pass a fake callback + mock @clack.\n\nimport { type HostId, SUPPORTED_HOSTS } from '@noir-ai/adapters';\nimport { loadProjectInfo } from '@noir-ai/core';\nimport { NOIR_TAGLINE, renderBanner, shouldShowBanner } from '../banner.js';\nimport { type CliOptions, EXIT, fail, isInteractive } from '../output.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\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/** One-line summary of the CLI command surface (shown under the banner). */\nconst COMMANDS_HINT =\n 'Commands: init · create · sync · status · context · memory · skills · task · daemon · doctor';\n\n/**\n * Host-direction line: tell the user to open their configured host CLI to do\n * the actual development (Noir is the orchestration/context/memory brain; the\n * host is the execution engine — blueprint D1 / BYO-agent). Host-agnostic via\n * the S10 `SUPPORTED_HOSTS` registry; lists the alternatives so a multi-host\n * user knows their options.\n */\nfunction hostDirection(host: HostId): string {\n const others = SUPPORTED_HOSTS.filter((h) => h !== host);\n return `→ host: ${host}. Open \\`${host}\\` to start development — Noir set the rules, skills, and memory; ${host} runs the code. (other hosts: ${others.join(', ')})`;\n}\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 */\nexport async function home(opts: CliOptions, deps: HomeDeps): Promise<void> {\n if (isInteractive(opts)) {\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 // (C1) — 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/** 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 if (shouldShowBanner(opts)) {\n const host = project?.host ?? 'claude';\n process.stderr.write(\n `\\n${renderBanner()}\\n${NOIR_TAGLINE}\\n\\n${hostDirection(host)}\\n${COMMANDS_HINT}\\n\\n`,\n );\n }\n clack.intro(project ? `noir — ${project.name}` : 'noir');\n\n const choice = await clack.select({\n message: 'What would you like to do?',\n initialValue: 'status',\n options: [\n { value: 'status', label: 'Status', hint: 'project + daemon + store snapshot' },\n { value: 'index', label: 'Index project', hint: '(re)index files into context' },\n { value: 'recall', label: 'Recall memory', hint: 'search cross-session memory' },\n { value: 'next', label: 'Next task', hint: 'suggest next phase + skill' },\n { value: 'daemon', label: 'Start daemon', hint: 'foreground daemon' },\n { value: 'sync', label: 'Sync skills', hint: 're-emit builtin skills' },\n { value: 'exit', label: 'Exit' },\n ],\n });\n\n if (clack.isCancel(choice)) {\n clack.cancel('Cancelled.');\n // exit 5 (CANCELLED). Plain-text fail: the interactive branch implies\n // !--json, so the {ok,error} envelope does not apply here.\n fail(EXIT.CANCELLED, 'cancelled', opts);\n }\n\n const argv = await argvForChoice(choice as string, clack, opts);\n if (argv === null) {\n // \"Exit\" — nothing to dispatch.\n clack.outro('bye');\n return;\n }\n await deps.dispatch(argv);\n clack.outro('done');\n}\n\n/**\n * Map a menu choice to the sub-command argv, prompting for any required\n * argument the menu can't supply inline. Returns `null` for \"Exit\" (no\n * dispatch). A cancel at a sub-prompt → exit 5.\n */\nasync function argvForChoice(\n choice: string,\n clack: typeof import('@clack/prompts'),\n opts: CliOptions,\n): Promise<string[] | null> {\n switch (choice) {\n case 'status':\n return ['status'];\n case 'index':\n return ['context', 'index'];\n case 'next':\n return ['task', 'next'];\n case 'daemon':\n return ['daemon', 'start'];\n case 'sync':\n return ['sync'];\n case 'exit':\n return null;\n case 'recall': {\n // memory recall needs a query — collect it inline so dispatch doesn't\n // immediately bounce with commander's \"missing required argument\".\n const query = await clack.text({\n message: 'Recall query:',\n placeholder: 'e.g. auth flow, ContextEngine, deploy steps',\n });\n if (clack.isCancel(query)) {\n clack.cancel('Cancelled.');\n fail(EXIT.CANCELLED, 'cancelled', opts);\n }\n return ['memory', 'recall', String(query)];\n }\n default:\n // select constrains values to the listed options; defensive default.\n return null;\n }\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 pc from 'picocolors';\nimport type { CliOptions } from './output.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 — a cool, dark gradient (purple → blue → cyan) applied\n// smoothly across the wordmark by gradient-string (vertical, top → bottom).\nconst NOIR_GRADIENT = gradient('#a855f7', '#3b82f6', '#06b6d4');\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. `color:false` emits\n * pure text (zero ANSI) for snapshots / CI / NO_COLOR.\n */\nexport function renderBanner(opts: BannerOptions = {}): string {\n const width = opts.width ?? process.stdout.columns ?? 80;\n const color = opts.color ?? true;\n if (width < 50) {\n return color ? `${pc.magenta('◆')} noir` : '◆ noir';\n }\n const block = NOIR_BLOCK.join('\\n');\n return color ? NOIR_GRADIENT.multiline(block) : 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","// S9 t5 — `noir memory {recall,save,sessions,forget,consolidate}`.\n//\n// Thin MCP-client commands over the running daemon's S7 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/DS-6): 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 { callDaemonTool, type DaemonClientOptions, withDaemon } from '../daemon-client.js';\nimport { type CliOptions, EXIT, fail, info, isInteractive, log, table } from '../output.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\nexport async function memoryRecall(opts: MemoryRecallOptions): Promise<void> {\n const limit = parseLimit(opts.limit, 'memory recall', opts);\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 ? ' [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 (DS-9: never truncate the DATA; display shows it whole\n // in a readable block rather than a cramped table cell).\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) => (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<{ Field: string; Value: unknown }> = [];\n for (const key of ['id', 'type', 'importance', 'ts', 'source', 'project', 'sessionId']) {\n if (obs[key] !== undefined) rows.push({ Field: key, Value: obs[key] });\n }\n if (rows.length > 0) table(rows, ['Field', 'Value'], 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 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\n if (opts.json === true) {\n process.stdout.write(`${JSON.stringify({ ok: true, data })}\\n`);\n return;\n }\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","// S9 t6 — `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 discoverAll,\n emitSkillsToDir,\n type IntegrationSkill,\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 31 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-brainstorm': 'discovery',\n 'noir-intake': 'discovery',\n 'noir-clarify': 'discovery',\n 'noir-explore': 'discovery',\n 'noir-spec': 'spec',\n 'noir-plan': 'plan',\n 'noir-execute': 'execute',\n 'noir-tdd': 'execute',\n 'noir-debug': 'execute',\n 'noir-subagent': 'execute',\n 'noir-parallel': 'execute',\n 'noir-verify': 'verify',\n 'noir-review': 'verify',\n 'noir-security': 'verify',\n 'noir-test': 'verify',\n 'noir-document': 'document',\n 'noir-readme': 'document',\n 'noir-commit': 'git',\n 'noir-branch': 'git',\n 'noir-pr': 'git',\n 'noir-worktree': 'git',\n 'noir-recall': 'memory',\n 'noir-remember': 'memory',\n 'noir-checkpoint': 'memory',\n 'noir-context': 'context',\n 'noir-frontend': 'domain',\n 'noir-backend': 'domain',\n 'noir-doctor': 'meta',\n 'noir-skill-author': 'meta',\n 'noir-sync': 'meta',\n 'noir-wrap': '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}\n\nfunction toRow(s: BuiltinSkill, kind: 'builtin' | 'integration' = 'builtin'): SkillRow {\n const description =\n typeof s.frontmatter.description === 'string' ? s.frontmatter.description : '';\n return { name: s.name, category: categoryOf(s.name), description, kind };\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 33 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 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 Description: truncate(r.description, 80),\n })),\n ['Skill', 'Kind', 'Category', '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 // T2: 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","// 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 C2-clean exit-4 envelope. Only\n// `status` is probe-only — in-process read fallback for the active commands is\n// deferred to v1.x (DS-5).\n//\n// Stream discipline (S9 DS-4): `--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, log, table } from '../output.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 */\nasync function tryTool<T>(caller: DaemonToolCaller, name: string): Promise<T | null> {\n try {\n return await caller.callTool<T>(name);\n } catch {\n // Engine absent (tool not registered), transport hiccup, or non-JSON text.\n // All are non-fatal for an optional section; report it as unavailable.\n return null;\n }\n}\n\nfunction pickStore(s: StoreStatusResult | null): StatusPayload['store'] {\n if (s?.ok !== true) return null;\n return {\n docCount: s.docCount,\n vecCount: s.vecCount,\n dbPath: s.dbPath,\n degraded: s.degraded === true,\n };\n}\n\nfunction describeEmbedder(e: ContextStatusResult['embedder']): string {\n if (!e || e.kind === 'none') return 'none (BM25-only)';\n const model = typeof e.model === 'string' && e.model.length > 0 ? e.model : '<unset>';\n return `${e.kind} · ${model} (${e.dim}-dim)`;\n}\n\nfunction pickContext(c: ContextStatusResult | null): StatusPayload['context'] {\n if (c?.ok !== true) return null;\n return {\n docCount: c.docCount,\n vecCount: c.vecCount,\n indexedFiles: c.indexedFiles,\n embedder: describeEmbedder(c.embedder),\n degraded: c.degraded === true,\n };\n}\n\nfunction pickWorkflow(w: WorkflowStatusResult | null): StatusPayload['workflow'] {\n // `workflow_status` returns `{ok:false,error:'no active task'}` (data) when no\n // task is active — normalize that to `null` so the payload's `workflow` field\n // cleanly means \"active task snapshot present\".\n if (w?.ok !== true) return null;\n return {\n taskId: w.taskId,\n phase: w.phase,\n state: w.state,\n mode: w.mode,\n nextGate: w.nextGate,\n degraded: w.degraded === true,\n };\n}\n\nfunction pickMemory(m: MemorySessionsResult | null): StatusPayload['memory'] {\n if (m?.ok !== true || !Array.isArray(m.sessions)) return null;\n let observations = 0;\n for (const s of m.sessions) observations += s.count;\n return { sessions: m.sessions.length, observations };\n}\n\n/**\n * Build the normalized payload from in-process project info + the daemon probe\n * + the (all-optional) count-tool results. Daemon `running`/`pid`/`uptimeSec`\n * come from the probe (the honest liveness source); `transport` is enriched from\n * `host_status` when that tool is reachable, else omitted. Every other section is\n * `null` when its engine is absent OR the daemon is down.\n */\nfunction buildPayload(\n project: ProjectInfo,\n probe: DaemonProbe,\n host: HostStatusResult | null,\n store: StoreStatusResult | null,\n context: ContextStatusResult | null,\n workflow: WorkflowStatusResult | null,\n memory: MemorySessionsResult | null,\n): StatusPayload {\n return {\n noir: NOIR_VERSION,\n project: { id: project.id, name: project.name },\n host: project.config.host,\n daemon: {\n running: probe.running,\n ...(probe.pid !== undefined ? { pid: probe.pid } : {}),\n ...(probe.uptimeSec !== undefined ? { uptimeSec: probe.uptimeSec } : {}),\n ...(host && typeof host.transport === 'string' ? { transport: host.transport } : {}),\n },\n store: pickStore(store),\n context: pickContext(context),\n workflow: pickWorkflow(workflow),\n memory: pickMemory(memory),\n };\n}\n\n// ---------------------------------------------------------------------------\n// Human rendering (stderr). A two-column Field/Value table is the leanest\n// readable shape for a status snapshot; cli-table3 is auto-stripped under\n// NO_COLOR / non-TTY and the whole call is a no-op under --json.\n// ---------------------------------------------------------------------------\nfunction formatDuration(sec?: number): string {\n if (typeof sec !== 'number' || sec < 0) return 'unknown';\n if (sec < 60) return `${sec}s`;\n if (sec < 3600) return `${Math.floor(sec / 60)}m ${sec % 60}s`;\n return `${Math.floor(sec / 3600)}h ${Math.floor((sec % 3600) / 60)}m`;\n}\n\nfunction 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\nfunction describeStore(s: StatusPayload['store']): string {\n if (!s) return 'unavailable (store engine not wired)';\n const flag = s.degraded ? ' [degraded: read-only]' : '';\n return `${s.docCount} docs / ${s.vecCount} vecs${flag}`;\n}\n\nfunction describeContext(c: StatusPayload['context']): string {\n if (!c) return 'unavailable (context engine not wired)';\n const flag = c.degraded ? ' [degraded]' : '';\n return `${c.docCount} docs, ${c.vecCount} vecs, ${c.indexedFiles} files · embedder ${c.embedder}${flag}`;\n}\n\nfunction 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 ? ' [degraded]' : '';\n return `${w.phase} (${w.state}, ${w.mode}) · task ${w.taskId}${gate}${flag}`;\n}\n\nfunction 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 + table both go to stderr (table is a no-op under --json; we only\n // render human when opts.json is false, but passing opts keeps --quiet honest).\n log(`noir status — ${p.project.name} (${p.project.id})`, opts);\n table(\n [\n { Field: 'Project', Value: `${p.project.name} (${p.project.id})` },\n { Field: 'Host', Value: p.host },\n { Field: 'Noir', Value: p.noir },\n { Field: 'Daemon', Value: describeDaemon(p.daemon) },\n { Field: 'Store', Value: describeStore(p.store) },\n { Field: 'Context', Value: describeContext(p.context) },\n { Field: 'Workflow', Value: describeWorkflow(p.workflow) },\n { Field: 'Memory', Value: describeMemory(p.memory) },\n ],\n ['Field', 'Value'],\n opts,\n );\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 // In-process project info — no daemon round-trip. Uninitialized → exit 1.\n const project = loadProjectInfo(process.cwd());\n // Probe — never starts a daemon. A down daemon is reported + exit 0.\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 const payload = buildPayload(project, probe, host, store, context, workflow, memory);\n\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 t5 — `noir task {new,status,advance,next}`.\n//\n// Thin MCP-client commands over the daemon's S4 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 { callDaemonTool, type DaemonClientOptions } from '../daemon-client.js';\nimport { type CliOptions, EXIT, fail, info, log, table } from '../output.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}\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// ---------------------------------------------------------------------------\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// ---------------------------------------------------------------------------\nconst PHASE_SKILL: Readonly<Record<string, string>> = {\n intake: 'noir-intake',\n clarify: 'noir-clarify',\n spec: 'noir-spec',\n plan: 'noir-plan',\n execute: 'noir-execute',\n verify: 'noir-verify',\n document: 'noir-document',\n};\n\nfunction skillFor(phase: string | null | undefined): string | null {\n if (typeof phase !== 'string') return null;\n return PHASE_SKILL[phase] ?? null;\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 ? ' [degraded]' : '';\n log(`task status — ${s.taskId}${flag}`, opts);\n table(\n [\n { Field: 'Task', Value: s.taskId },\n { Field: 'Phase', Value: s.phase },\n { Field: 'State', Value: s.state },\n { Field: 'Mode', Value: s.mode },\n { Field: 'Next gate', Value: s.nextGate ?? '—' },\n { Field: 'Updated', Value: formatStamp(s.updatedAt) },\n ],\n ['Field', 'Value'],\n opts,\n );\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\nexport async function taskStatus(opts: TaskStatusOptions): Promise<void> {\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 ? ' [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}\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 // 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 },\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}\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 if (opts.json === true) {\n process.stdout.write(`${JSON.stringify({ ok: true, data: res })}\\n`);\n return;\n }\n renderStatusRow(res, opts);\n}\n"],"mappings":"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","names":["SUPPORTED_HOSTS","NOIR_VERSION","loadProjectInfo","ensureDaemonRunning","pidAlive","readDaemonRecord","loadProjectInfo","ensureDaemonRunning","readDaemonRecord","pidAlive","loadProjectInfo","info","loadProjectInfo","parseLimit","toHit","failTool","loadProjectInfo","loadProjectInfo","data","loadProjectInfo","NOIR_VERSION","describeEmbedder","NOIR_VERSION","loadProjectInfo","program","NOIR_VERSION","SUPPORTED_HOSTS"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@noir-ai/cli",
3
- "version": "1.3.0-beta.4",
3
+ "version": "1.3.0-beta.5",
4
4
  "description": "Noir CLI — the `noir` command tree (commander + @clack/prompts), the shell entry point to the Noir AI toolkit.",
5
5
  "license": "MIT",
6
6
  "author": "agaaaptr",
@@ -50,16 +50,17 @@
50
50
  "@modelcontextprotocol/client": "^2.0.0-beta.5",
51
51
  "cli-table3": "^0.6.5",
52
52
  "commander": "^12.1.0",
53
+ "gradient-string": "^3.0.0",
53
54
  "ora": "^8.1.0",
54
55
  "picocolors": "^1.1.1",
55
- "@noir-ai/adapters": "1.3.0-beta.4",
56
- "@noir-ai/core": "1.3.0-beta.4",
57
- "@noir-ai/create": "1.3.0-beta.4",
58
- "@noir-ai/skills": "1.3.0-beta.4",
59
- "@noir-ai/daemon": "1.3.0-beta.4",
60
- "@noir-ai/model": "1.3.0-beta.4",
61
- "@noir-ai/context": "1.3.0-beta.4",
62
- "@noir-ai/store": "1.3.0-beta.4"
56
+ "@noir-ai/adapters": "1.3.0-beta.5",
57
+ "@noir-ai/core": "1.3.0-beta.5",
58
+ "@noir-ai/daemon": "1.3.0-beta.5",
59
+ "@noir-ai/create": "1.3.0-beta.5",
60
+ "@noir-ai/model": "1.3.0-beta.5",
61
+ "@noir-ai/skills": "1.3.0-beta.5",
62
+ "@noir-ai/context": "1.3.0-beta.5",
63
+ "@noir-ai/store": "1.3.0-beta.5"
63
64
  },
64
65
  "devDependencies": {
65
66
  "@types/node": "^26.1.1"