@narrativetrace/cli 0.1.3 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/doctor/doc-urls.ts","../src/doctor/finding.ts","../src/doctor/checks/approval-traces.ts","../src/doctor/checks/llms-before-you-start.ts","../src/semver-lite.ts","../src/doctor/checks/node-engine.ts","../src/doctor/checks/output-env.ts","../src/doctor/checks/parameter-arg0.ts","../src/doctor/checks/redaction-proof.ts","../src/doctor/checks/reporter-subpath.ts","../src/doctor/checks/sibling-packages.ts","../src/doctor/checks/silent-sink.ts","../src/doctor/checks/trace-object-keys.ts","../src/doctor/checks/vitest-peer.ts","../src/doctor/doctor.ts","../src/doctor/render.ts","../src/cli.ts","../src/doctor/environment.ts","../src/cli-bin.ts"],"sourcesContent":["// SPDX-License-Identifier: BUSL-1.1\n// Licensed under the Business Source License 1.1 (see LICENSE); Change Date: four years from publication; Change License: Apache-2.0\n// Copyright (c) 2026 Empower Agile\n/**\n * Public doc anchors every finding points at. The TypeScript runtime's guides are not yet\n * published on narrativetrace.ai (only the Java docs are, as of 2026-09 — see the doctor P1 run's\n * report for the amendment note); this repository is public on GitHub\n * (`publishConfig.access: \"public\"` on every package), so a stable blob link into `documentation/`\n * on `main` is the honest \"public docs URL\" today. Swap the base once the TS guides land on the\n * site — the anchors (GitHub's own heading slugs) do not change.\n */\nconst BASE = \"https://github.com/narrativetrace/narrativetrace-typescript/blob/main/documentation/\";\n\nexport const DOC = {\n installationPrerequisites: `${BASE}installation-guide.md#prerequisites`,\n installationDependencies: `${BASE}installation-guide.md#1-add-dependencies`,\n vitestConfiguration: `${BASE}configuration-guide.md#2-vitest-configuration`,\n whereSettingsComeFrom: `${BASE}configuration-guide.md#2b-where-settings-come-from`,\n proxyOptions: `${BASE}configuration-guide.md#6-proxy-options`,\n eventPipelineBuffering: `${BASE}configuration-guide.md#8-event-pipeline-buffering-bufferedeventconsumer`,\n noTraceFilesWritten: `${BASE}troubleshooting.md#no-trace-files-are-written`,\n manualParameterNames: `${BASE}troubleshooting.md#parameters-show-as-arg0-arg1`,\n redactionSurfaceBySurface: `${BASE}privacy-and-redaction.md#redaction-surface-by-surface`,\n approvalTracesEndToEnd: `${BASE}structural-trace-format.md#approval-traces-end-to-end`,\n sixtySecondsNewProject: `${BASE}sixty-seconds.md#1-new-project-add-the-packages`,\n} as const;\n","// SPDX-License-Identifier: BUSL-1.1\n// Licensed under the Business Source License 1.1 (see LICENSE); Change Date: four years from publication; Change License: Apache-2.0\n// Copyright (c) 2026 Empower Agile\nimport type { Finding, FindingStatus } from \"./types.js\";\n\n/** A passing finding: no fix needed, by construction (see {@link Finding.fix}). */\nexport function pass(id: string, message: string, docUrl: string): Finding {\n return { id, status: \"pass\" as FindingStatus, message, fix: \"\", docUrl };\n}\n\n/** A failing finding: `fix` is mandatory — a fail with nothing to do about it is a wording bug. */\nexport function fail(id: string, message: string, fix: string, docUrl: string): Finding {\n return { id, status: \"fail\" as FindingStatus, message, fix, docUrl };\n}\n","// SPDX-License-Identifier: BUSL-1.1\n// Licensed under the Business Source License 1.1 (see LICENSE); Change Date: four years from publication; Change License: Apache-2.0\n// Copyright (c) 2026 Empower Agile\nimport { DOC } from \"../doc-urls.js\";\nimport { fail, pass } from \"../finding.js\";\nimport type { DoctorCheck } from \"../types.js\";\n\nconst ID = \"trap.approval-traces\";\nconst FIX =\n \"Review each .received.nt diff against its .approved.nt baseline, then run pnpm run approve-narratives (or narrativetrace-approve) to promote it, or delete it if the change was wrong — never commit a .received.nt file.\";\n\n/**\n * Approval traces (`.approved.nt` reviewed baselines, `.received.nt` written on a mismatch) landed\n * in the runtime's structural-trace layer. A `.received.nt` sitting in the approved directory is a\n * reviewed-but-not-yet-resolved diff — stale ones are exactly what `what-to-commit.md` warns never\n * to commit, and exactly what a doctor run should surface before someone else does.\n */\nexport const checkApprovalTraces: DoctorCheck = (snapshot) => {\n const paths = [...snapshot.approvedDirFiles.keys()];\n if (paths.length === 0) {\n return pass(\n ID,\n \"no approval traces configured yet — nothing to check\",\n DOC.approvalTracesEndToEnd,\n );\n }\n const received = paths.filter((p) => p.endsWith(\".received.nt\"));\n if (received.length > 0) {\n const message = `${received.length} stale received trace(s) found: ${received.join(\", \")}`;\n return fail(ID, message, FIX, DOC.approvalTracesEndToEnd);\n }\n const approved = paths.filter((p) => p.endsWith(\".approved.nt\"));\n const message = `${approved.length} approved trace(s) found, no pending received diffs`;\n return pass(ID, message, DOC.approvalTracesEndToEnd);\n};\n","// SPDX-License-Identifier: BUSL-1.1\n// Licensed under the Business Source License 1.1 (see LICENSE); Change Date: four years from publication; Change License: Apache-2.0\n// Copyright (c) 2026 Empower Agile\nimport { DOC } from \"../doc-urls.js\";\nimport { fail, pass } from \"../finding.js\";\nimport type { DoctorCheck } from \"../types.js\";\n\nconst ID = \"trap.llms-before-you-start\";\nconst PLAIN_JS = /\\.js$/;\nconst ESM_IMPORT = /^\\s*import\\s/m;\nconst FIX =\n \"Run `npm pkg set type=module` before `npm add` — without it, Node throws SyntaxError: Cannot use import statement outside a module (pnpm/yarn default to it and never hit this).\";\n\n/**\n * `llms.txt`'s first \"before you start\" trap: a plain `.js` file using `import` syntax with no\n * `\"type\": \"module\"` in `package.json` throws `SyntaxError: Cannot use import statement outside a\n * module` the moment Node loads it — npm's default (unlike pnpm/yarn) does not set this for you.\n */\nexport const checkLlmsBeforeYouStart: DoctorCheck = (snapshot) => {\n if (snapshot.rootPackageJson?.type === \"module\") {\n return pass(ID, 'package.json declares \"type\": \"module\"', DOC.sixtySecondsNewProject);\n }\n const offender = [...snapshot.sourceFiles].find(\n ([path, content]) => PLAIN_JS.test(path) && ESM_IMPORT.test(content),\n );\n if (!offender) {\n const message = 'no plain .js file uses ESM import syntax without \"type\": \"module\"';\n return pass(ID, message, DOC.sixtySecondsNewProject);\n }\n const [path] = offender;\n const message = `${path} uses ESM import syntax but package.json has no \"type\": \"module\"`;\n return fail(ID, message, FIX, DOC.sixtySecondsNewProject);\n};\n","// SPDX-License-Identifier: BUSL-1.1\n// Licensed under the Business Source License 1.1 (see LICENSE); Change Date: four years from publication; Change License: Apache-2.0\n// Copyright (c) 2026 Empower Agile\n/**\n * Minimal semver range matcher covering exactly the range shapes this repository's own\n * `package.json` files use (`>=20`, `^1.0.0 || ^2.0.0 || ^3.0.0`, `1.x`): the doctor never needs to\n * parse an arbitrary npm range, only the ones NarrativeTrace itself declares in `engines` and\n * `peerDependencies`. A real `semver` dependency would cover forms this codebase never emits.\n */\n\nexport interface Version {\n readonly major: number;\n readonly minor: number;\n readonly patch: number;\n}\n\n/** Parses `\"20.11.0\"`, `\"v20.11.0\"`, `\"20\"`, or `\"20.11\"` — missing parts default to zero. */\nexport function parseVersion(raw: string): Version | undefined {\n const cleaned = raw.trim().replace(/^v/, \"\");\n const match = /^(\\d+)(?:\\.(\\d+))?(?:\\.(\\d+))?/.exec(cleaned);\n if (!match) return undefined;\n return {\n major: Number(match[1]),\n minor: match[2] === undefined ? 0 : Number(match[2]),\n patch: match[3] === undefined ? 0 : Number(match[3]),\n };\n}\n\n/** Three-way compare, standard sign convention: negative if `left` < `right`, positive if greater. */\nexport function compareVersions(left: Version, right: Version): number {\n if (left.major !== right.major) return left.major - right.major;\n if (left.minor !== right.minor) return left.minor - right.minor;\n return left.patch - right.patch;\n}\n\nfunction satisfiesGte(version: Version, floor: Version): boolean {\n return compareVersions(version, floor) >= 0;\n}\n\n/** Standard caret semantics: `^1.2.3` := `>=1.2.3 <2.0.0`; `^0.2.3` := `>=0.2.3 <0.3.0`; `^0.0.3` := `>=0.0.3 <0.0.4`. */\nfunction satisfiesCaret(version: Version, base: Version): boolean {\n if (compareVersions(version, base) < 0) return false;\n if (base.major > 0) return version.major === base.major;\n if (base.minor > 0) return version.major === 0 && version.minor === base.minor;\n return version.major === 0 && version.minor === 0 && version.patch === base.patch;\n}\n\n/**\n * One `||`-separated clause: `^x.y.z`, `>=x.y.z`, `x.x`/`x.y.x` (caret-equivalent), or an exact\n * version. `trimmed` must already be whitespace-trimmed — {@link satisfiesRange} does that once\n * for every clause it splits out, so the prefix checks below (`startsWith(\"^\")`) see it without a\n * leading space.\n */\nfunction satisfiesClause(version: Version, trimmed: string): boolean {\n if (trimmed.startsWith(\"^\")) {\n const base = parseVersion(trimmed.slice(1));\n return base !== undefined && satisfiesCaret(version, base);\n }\n if (trimmed.startsWith(\">=\")) {\n const floor = parseVersion(trimmed.slice(2));\n return floor !== undefined && satisfiesGte(version, floor);\n }\n if (/\\.x\\b/.test(trimmed)) {\n const base = parseVersion(trimmed.replace(/\\.x/g, \".0\"));\n return base !== undefined && satisfiesCaret(version, base);\n }\n const exact = parseVersion(trimmed);\n return exact !== undefined && compareVersions(version, exact) === 0;\n}\n\n/**\n * Whether `versionRaw` satisfies `range` (`||`-separated clauses; a version satisfies the range if\n * it satisfies any one clause). Unparseable input on either side is a mismatch, never a throw — a\n * doctor check reports a finding, it does not crash the run.\n */\nexport function satisfiesRange(versionRaw: string, range: string): boolean {\n const version = parseVersion(versionRaw);\n if (!version) return false;\n // Stryker disable next-line MethodExpression: dropping .filter(Boolean) is equivalent here —\n // an empty clause (from \"||\" or a trailing/leading \"||\") only ever adds a `satisfiesClause(v,\n // \"\")` call to the .some() chain, and that always returns false (parseVersion(\"\") is\n // undefined, and \"\" matches none of the prefix checks either), so it can never flip the\n // overall result. The filter is documentation of intent, not a behavior the type checker or a\n // mutation test can observe.\n return range\n .split(\"||\")\n .map((clause) => clause.trim())\n .filter(Boolean)\n .some((clause) => satisfiesClause(version, clause));\n}\n","// SPDX-License-Identifier: BUSL-1.1\n// Licensed under the Business Source License 1.1 (see LICENSE); Change Date: four years from publication; Change License: Apache-2.0\n// Copyright (c) 2026 Empower Agile\nimport { satisfiesRange } from \"../../semver-lite.js\";\nimport { DOC } from \"../doc-urls.js\";\nimport { fail, pass } from \"../finding.js\";\nimport type { DoctorCheck } from \"../types.js\";\n\nconst ID = \"toolchain.node-engine\";\nconst DEFAULT_ENGINE_RANGE = \">=20\";\n\n/** Node version required by whichever core NarrativeTrace package is installed, else the repo default. */\nfunction requiredRange(snapshot: Parameters<DoctorCheck>[0]): string {\n const core = snapshot.installedPackages.get(\"@narrativetrace/core\");\n const coreNode = snapshot.installedPackages.get(\"@narrativetrace/core-node\");\n return core?.engines?.node ?? coreNode?.engines?.node ?? DEFAULT_ENGINE_RANGE;\n}\n\n/** Node engines (Installation Guide §Prerequisites): the running Node must satisfy the installed package's `engines.node`. */\nexport const checkNodeEngine: DoctorCheck = (snapshot) => {\n const required = requiredRange(snapshot);\n if (satisfiesRange(snapshot.nodeVersion, required)) {\n return pass(\n ID,\n `Node ${snapshot.nodeVersion} satisfies the required ${required}`,\n DOC.installationPrerequisites,\n );\n }\n return fail(\n ID,\n `Node ${snapshot.nodeVersion} does not satisfy the required ${required}`,\n `Upgrade Node to a version satisfying ${required} (nvm, volta, asdf, or your CI image).`,\n DOC.installationPrerequisites,\n );\n};\n","// SPDX-License-Identifier: BUSL-1.1\n// Licensed under the Business Source License 1.1 (see LICENSE); Change Date: four years from publication; Change License: Apache-2.0\n// Copyright (c) 2026 Empower Agile\nimport { DOC } from \"../doc-urls.js\";\nimport { fail, pass } from \"../finding.js\";\nimport type { DoctorCheck } from \"../types.js\";\n\nconst ID = \"config.output-env\";\nconst VALID_VALUES = new Set([\"true\", \"false\"]);\n\n/** `NARRATIVETRACE_OUTPUT`, if set, must be exactly `\"true\"` or `\"false\"` (case-insensitive). */\nexport const checkOutputEnv: DoctorCheck = (snapshot) => {\n const raw = snapshot.env.NARRATIVETRACE_OUTPUT;\n if (raw === undefined) {\n return pass(\n ID,\n \"NARRATIVETRACE_OUTPUT is not set — output stays on its default (on)\",\n DOC.whereSettingsComeFrom,\n );\n }\n if (VALID_VALUES.has(raw.toLowerCase())) {\n return pass(ID, `NARRATIVETRACE_OUTPUT=${raw}`, DOC.whereSettingsComeFrom);\n }\n return fail(\n ID,\n `NARRATIVETRACE_OUTPUT is set to '${raw}', which is neither \"true\" nor \"false\"`,\n \"Set NARRATIVETRACE_OUTPUT=true or NARRATIVETRACE_OUTPUT=false (or unset it) — any other value is read as a truthy string, most likely turning output on when you meant to turn it off.\",\n DOC.whereSettingsComeFrom,\n );\n};\n","// SPDX-License-Identifier: BUSL-1.1\n// Licensed under the Business Source License 1.1 (see LICENSE); Change Date: four years from publication; Change License: Apache-2.0\n// Copyright (c) 2026 Empower Agile\nimport { DOC } from \"../doc-urls.js\";\nimport { fail, pass } from \"../finding.js\";\nimport type { DoctorCheck } from \"../types.js\";\n\nconst ID = \"trap.parameter-arg0\";\nconst ARG_PLACEHOLDER = /\\barg0\\b/;\nconst FIX =\n 'Pass parameter names explicitly: traceObject(target, context, { methodName: [\"paramA\", \"paramB\"] }) — required for classes you do not own, or when a build tool strips them.';\n\n/**\n * Parameter names of classes you don't own (or a build that strips them) are lost at compile\n * time and render as `arg0`, `arg1`, ... Doctor reads already-rendered output, if any exists, and\n * flags the tell-tale placeholder rather than guessing from source.\n */\nexport const checkParameterArg0: DoctorCheck = (snapshot) => {\n if (snapshot.outputFiles.size === 0) {\n const message = \"no rendered output found yet — run your tests or app once to check this\";\n return pass(ID, message, DOC.manualParameterNames);\n }\n const offender = [...snapshot.outputFiles].find(([, content]) => ARG_PLACEHOLDER.test(content));\n if (!offender) {\n const message = \"rendered output carries real parameter names — no arg0 placeholders found\";\n return pass(ID, message, DOC.manualParameterNames);\n }\n const [path] = offender;\n const message = `rendered output shows arg0-style placeholders (first seen in ${path}) — parameter names were not captured`;\n return fail(ID, message, FIX, DOC.manualParameterNames);\n};\n","// SPDX-License-Identifier: BUSL-1.1\n// Licensed under the Business Source License 1.1 (see LICENSE); Change Date: four years from publication; Change License: Apache-2.0\n// Copyright (c) 2026 Empower Agile\nimport { DOC } from \"../doc-urls.js\";\nimport { fail, pass } from \"../finding.js\";\nimport type { DoctorCheck } from \"../types.js\";\n\nconst ID = \"trap.redaction-proof\";\nconst TEST_FILE = /\\.(test|spec)\\.[cm]?[jt]sx?$/;\nconst REDACTED_ASSERTION = /\\[REDACTED\\]/;\n\n/**\n * Redaction is a security property; the trap named across every study is trusting it by\n * inspection rather than proving it — importing the redaction primitives and never asserting on\n * their output. This looks for a test that actually asserts the literal `[REDACTED]` marker.\n */\nexport const checkRedactionProof: DoctorCheck = (snapshot) => {\n const testFiles = [...snapshot.sourceFiles].filter(([path]) => TEST_FILE.test(path));\n const proven = testFiles.some(([, content]) => REDACTED_ASSERTION.test(content));\n if (proven) {\n return pass(\n ID,\n \"a test asserts [REDACTED] for a deny-listed parameter name\",\n DOC.redactionSurfaceBySurface,\n );\n }\n return fail(\n ID,\n \"no test asserts [REDACTED] — redaction is unproven\",\n 'Render a call with a deny-listed parameter name (e.g. \"password\", \"token\") in a test and assert the output contains \"[REDACTED]\" — and that a neighboring, non-sensitive value is still present, so an over-broad redaction also fails.',\n DOC.redactionSurfaceBySurface,\n );\n};\n","// SPDX-License-Identifier: BUSL-1.1\n// Licensed under the Business Source License 1.1 (see LICENSE); Change Date: four years from publication; Change License: Apache-2.0\n// Copyright (c) 2026 Empower Agile\nimport { DOC } from \"../doc-urls.js\";\nimport { fail, pass } from \"../finding.js\";\nimport type { DoctorCheck } from \"../types.js\";\n\nconst ID = \"config.reporter-subpath\";\nconst VITEST_CONFIG_NAME = /(^|\\/)vitest\\.config\\.[cm]?[jt]s$/;\nconst REPORTER_NAMES = /\\b(ClaritySuiteReporter|GlossarySuiteReporter|StructuralSuiteReporter)\\b/;\nconst ROOT_IMPORT = /from\\s+[\"']@narrativetrace\\/vitest[\"']/;\nconst SUBPATH_IMPORT = /from\\s+[\"']@narrativetrace\\/vitest\\/reporters[\"']/;\n\nfunction importsFromRoot(content: string): boolean {\n return REPORTER_NAMES.test(content) && ROOT_IMPORT.test(content) && !SUBPATH_IMPORT.test(content);\n}\n\n/**\n * `ClaritySuiteReporter`/`GlossarySuiteReporter`/`StructuralSuiteReporter` must be imported from\n * the `/reporters` subpath — importing them from the package root also loads `vitest` itself,\n * which crashes config loading on every version (llms.txt \"Before you start\").\n */\nexport const checkReporterSubpath: DoctorCheck = (snapshot) => {\n const configs = [...snapshot.sourceFiles].filter(([path]) => VITEST_CONFIG_NAME.test(path));\n const offender = configs.find(([, content]) => importsFromRoot(content));\n if (offender) {\n const [path] = offender;\n return fail(\n ID,\n `${path} imports a NarrativeTrace vitest reporter from the package root, not the /reporters subpath`,\n 'Import reporters from \"@narrativetrace/vitest/reporters\" — importing from the package root also loads vitest itself and crashes config loading.',\n DOC.vitestConfiguration,\n );\n }\n const message =\n configs.length === 0\n ? \"no vitest.config found — nothing to check\"\n : \"every registered reporter is imported from the /reporters subpath\";\n return pass(ID, message, DOC.vitestConfiguration);\n};\n","// SPDX-License-Identifier: BUSL-1.1\n// Licensed under the Business Source License 1.1 (see LICENSE); Change Date: four years from publication; Change License: Apache-2.0\n// Copyright (c) 2026 Empower Agile\nimport { DOC } from \"../doc-urls.js\";\nimport { fail, pass } from \"../finding.js\";\nimport type { DoctorCheck } from \"../types.js\";\n\nconst ID = \"toolchain.sibling-packages\";\n\n/**\n * `@narrativetrace/vitest` depends on five sibling `@narrativetrace/*` packages (clarity,\n * core-node, diagrams, glossary, proxy — not peers, regular dependencies). Under pnpm's default\n * strict layout those resolve fine from inside `@narrativetrace/vitest`'s own `node_modules`, but a\n * consumer that also imports one of them directly needs it resolvable from ITS OWN root too, or\n * pnpm's non-hoisting layout hands the app a second, unrelated copy. This check reads the sibling\n * list from the installed package itself (never a hardcoded list — it tracks the dependency as it\n * grows) and confirms each one resolves from the consumer.\n */\nexport const checkSiblingPackages: DoctorCheck = (snapshot) => {\n const ntVitest = snapshot.installedPackages.get(\"@narrativetrace/vitest\");\n if (!ntVitest) {\n const message = \"@narrativetrace/vitest is not installed — nothing to check\";\n return pass(ID, message, DOC.installationDependencies);\n }\n const siblings = Object.keys(ntVitest.dependencies ?? {}).filter((n) =>\n n.startsWith(\"@narrativetrace/\"),\n );\n const unresolved = siblings.filter((name) => !snapshot.installedPackages.has(name));\n if (unresolved.length === 0) {\n const message = `all ${siblings.length} sibling package(s) of @narrativetrace/vitest resolve from the consumer`;\n return pass(ID, message, DOC.installationDependencies);\n }\n const message = `${unresolved.length} sibling package(s) of @narrativetrace/vitest do not resolve from the consumer: ${unresolved.join(\", \")}`;\n const fix = `Add ${unresolved.join(\", \")} as explicit direct dependencies — pnpm's strict layout does not hoist a dependency's own transitive dependencies to your project root.`;\n return fail(ID, message, fix, DOC.installationDependencies);\n};\n","// SPDX-License-Identifier: BUSL-1.1\n// Licensed under the Business Source License 1.1 (see LICENSE); Change Date: four years from publication; Change License: Apache-2.0\n// Copyright (c) 2026 Empower Agile\nimport { DOC } from \"../doc-urls.js\";\nimport { fail, pass } from \"../finding.js\";\nimport type { DoctorCheck } from \"../types.js\";\n\nconst ID = \"trap.silent-sink\";\nconst TRACE_OBJECT_CALL = /\\btraceObject\\s*\\(/;\nconst SINK_SIGNAL =\n /\\b(BufferedEventConsumer|captureTrace|registerConsumer|createNarrativeTest|narrativeTest)\\b|@narrativetrace\\/(vitest|pino|winston|opentelemetry|observability)\\b/;\n\n/**\n * The silent-sink trap: `traceObject()` proxies calls into events, but nothing narrates unless a\n * consumer/sink is attached (`BufferedEventConsumer`, `captureTrace()`, a log/OTel bridge, or the\n * vitest integration, which is its own sink). Wrapping without one of these is a project that looks\n * instrumented and narrates to nowhere.\n */\nexport const checkSilentSink: DoctorCheck = (snapshot) => {\n const contents = [...snapshot.sourceFiles.values()];\n if (!contents.some((content) => TRACE_OBJECT_CALL.test(content))) {\n return pass(ID, \"traceObject() is not used — nothing to check\", DOC.noTraceFilesWritten);\n }\n if (contents.some((content) => SINK_SIGNAL.test(content))) {\n return pass(\n ID,\n \"traceObject() is used and a consumer/sink is attached\",\n DOC.noTraceFilesWritten,\n );\n }\n return fail(\n ID,\n \"traceObject() is used but no consumer or sink (BufferedEventConsumer, captureTrace(), a log/OTel bridge, or @narrativetrace/vitest) was found\",\n \"Attach a sink: pass a BufferedEventConsumer to your pipeline, call captureTrace() and do something with the tree, or wire a log/OTel bridge — otherwise every traced call narrates to nowhere.\",\n DOC.noTraceFilesWritten,\n );\n};\n","// SPDX-License-Identifier: BUSL-1.1\n// Licensed under the Business Source License 1.1 (see LICENSE); Change Date: four years from publication; Change License: Apache-2.0\n// Copyright (c) 2026 Empower Agile\nimport { DOC } from \"../doc-urls.js\";\nimport { fail, pass } from \"../finding.js\";\nimport type { DoctorCheck } from \"../types.js\";\n\nconst ID = \"config.trace-object-keys\";\n\n// The valid nested shape is `methods: { methodName: { params: [...], ... } }` — a per-method\n// config OBJECT. The trap is skipping the method-config level and putting the param array\n// straight under a method name (`methods: { methodName: [...] }`), which now throws naming the\n// accepted per-method keys rather than the silent no-op it used to be. `[^{}]*` stops the match at\n// the first nested `{`, so the legitimate form (an object, not an array, under the method name)\n// never matches here.\nconst OLD_SHAPE = /\\bmethods\\s*:\\s*\\{[^{}]*:\\s*\\[/;\n\n/**\n * `traceObject`'s options used to silently no-op when a per-method entry skipped straight to an\n * array instead of the `{ params: [...] }` object (now throws, naming the accepted keys) — a\n * source file still shaped that way needs the method-config object added back, not just an\n * upgrade.\n */\nexport const checkTraceObjectKeys: DoctorCheck = (snapshot) => {\n const offender = [...snapshot.sourceFiles].find(([, content]) => OLD_SHAPE.test(content));\n if (offender) {\n const [path] = offender;\n return fail(\n ID,\n `${path} calls traceObject(...) with a method entry that skips the per-method config object`,\n \"Nest the parameter names under params: traceObject(target, context, { methods: { methodName: { params: [...] } } }) — a bare array under the method name throws.\",\n DOC.proxyOptions,\n );\n }\n return pass(\n ID,\n \"no traceObject(...) call uses the old { methods: { ... } } option shape\",\n DOC.proxyOptions,\n );\n};\n","// SPDX-License-Identifier: BUSL-1.1\n// Licensed under the Business Source License 1.1 (see LICENSE); Change Date: four years from publication; Change License: Apache-2.0\n// Copyright (c) 2026 Empower Agile\nimport { satisfiesRange } from \"../../semver-lite.js\";\nimport { DOC } from \"../doc-urls.js\";\nimport { fail, pass } from \"../finding.js\";\nimport type { DoctorCheck, Finding, PackageJsonLike } from \"../types.js\";\n\nconst ID = \"toolchain.vitest-peer\";\n\nfunction noVitestInstalled(range: string): Finding {\n const message = `@narrativetrace/vitest requires a peer vitest@${range}, but no vitest install was found`;\n const fix = `Install a vitest version satisfying ${range} (npm add -D vitest, then npm ci for a clean lockfile install).`;\n return fail(ID, message, fix, DOC.vitestConfiguration);\n}\n\nfunction mismatchedVitest(range: string, installed: string): Finding {\n const message = `vitest@${installed} does not satisfy @narrativetrace/vitest's declared peer range ${range}`;\n const fix = `Install a vitest version satisfying ${range}, then reinstall clean (rm -rf node_modules && npm ci) — a mismatched peer here is the one failure mode that breaks the library's own build.`;\n return fail(ID, message, fix, DOC.vitestConfiguration);\n}\n\nfunction evaluateInstalledVitest(range: string, vitest: PackageJsonLike | undefined): Finding {\n if (!vitest?.version) return noVitestInstalled(range);\n if (satisfiesRange(vitest.version, range)) {\n const message = `vitest@${vitest.version} satisfies the declared peer range ${range}`;\n return pass(ID, message, DOC.vitestConfiguration);\n }\n return mismatchedVitest(range, vitest.version);\n}\n\n/** The installed `vitest` version must satisfy `@narrativetrace/vitest`'s declared peer range. */\nexport const checkVitestPeer: DoctorCheck = (snapshot) => {\n const ntVitest = snapshot.installedPackages.get(\"@narrativetrace/vitest\");\n const range = ntVitest?.peerDependencies?.vitest;\n if (!ntVitest || !range) {\n return pass(\n ID,\n \"@narrativetrace/vitest is not installed — nothing to check\",\n DOC.vitestConfiguration,\n );\n }\n return evaluateInstalledVitest(range, snapshot.installedPackages.get(\"vitest\"));\n};\n","// SPDX-License-Identifier: BUSL-1.1\n// Licensed under the Business Source License 1.1 (see LICENSE); Change Date: four years from publication; Change License: Apache-2.0\n// Copyright (c) 2026 Empower Agile\nimport { checkApprovalTraces } from \"./checks/approval-traces.js\";\nimport { checkLlmsBeforeYouStart } from \"./checks/llms-before-you-start.js\";\nimport { checkNodeEngine } from \"./checks/node-engine.js\";\nimport { checkOutputEnv } from \"./checks/output-env.js\";\nimport { checkParameterArg0 } from \"./checks/parameter-arg0.js\";\nimport { checkRedactionProof } from \"./checks/redaction-proof.js\";\nimport { checkReporterSubpath } from \"./checks/reporter-subpath.js\";\nimport { checkSiblingPackages } from \"./checks/sibling-packages.js\";\nimport { checkSilentSink } from \"./checks/silent-sink.js\";\nimport { checkTraceObjectKeys } from \"./checks/trace-object-keys.js\";\nimport { checkVitestPeer } from \"./checks/vitest-peer.js\";\nimport type { DoctorCheck, DoctorReport, DoctorSnapshot } from \"./types.js\";\n\n/**\n * Every check `narrativetrace doctor` runs, in stable, documented order. Adding a check means\n * appending here — the id is what stays stable across releases, not the position.\n */\nexport const DOCTOR_CHECKS: readonly DoctorCheck[] = [\n checkNodeEngine,\n checkVitestPeer,\n checkSiblingPackages,\n checkOutputEnv,\n checkReporterSubpath,\n checkTraceObjectKeys,\n checkSilentSink,\n checkParameterArg0,\n checkRedactionProof,\n checkApprovalTraces,\n checkLlmsBeforeYouStart,\n];\n\n/** Runs every check over `snapshot` and derives the process exit code. Read-only: mutates nothing. */\nexport function runDoctor(snapshot: DoctorSnapshot): DoctorReport {\n const findings = DOCTOR_CHECKS.map((check) => check(snapshot));\n const exitCode = findings.some((f) => f.status === \"fail\") ? 1 : 0;\n return { findings, exitCode };\n}\n","// SPDX-License-Identifier: BUSL-1.1\n// Licensed under the Business Source License 1.1 (see LICENSE); Change Date: four years from publication; Change License: Apache-2.0\n// Copyright (c) 2026 Empower Agile\nimport type { DoctorReport, Finding } from \"./types.js\";\n\nfunction renderFinding(finding: Finding): string[] {\n const tag = finding.status === \"fail\" ? \"FAIL\" : \"PASS\";\n const lines = [`[${tag}] ${finding.id} — ${finding.message}`];\n if (finding.status === \"fail\") {\n lines.push(` fix: ${finding.fix}`, ` docs: ${finding.docUrl}`);\n }\n lines.push(\"\");\n return lines;\n}\n\n/** Human-readable default output: one block per finding, worst-first (failures before passes). */\nexport function renderHuman(report: DoctorReport): string {\n const failing = report.findings.filter((f) => f.status === \"fail\");\n const passing = report.findings.filter((f) => f.status === \"pass\");\n const header = `narrativetrace doctor — ${report.findings.length} check(s), ${failing.length} finding(s)`;\n const summary =\n failing.length === 0\n ? \"All checks passed.\"\n : `${failing.length} finding(s). Exit code ${report.exitCode}.`;\n const body = [...failing, ...passing].flatMap(renderFinding);\n return [header, \"\", ...body, summary].join(\"\\n\");\n}\n\n/** Machine-readable `--json` output: the report verbatim, stable field names. */\nexport function renderJson(report: DoctorReport): string {\n return JSON.stringify(report, null, 2);\n}\n","// SPDX-License-Identifier: BUSL-1.1\n// Licensed under the Business Source License 1.1 (see LICENSE); Change Date: four years from publication; Change License: Apache-2.0\n// Copyright (c) 2026 Empower Agile\nimport { runDoctor } from \"./doctor/doctor.js\";\nimport { renderHuman, renderJson } from \"./doctor/render.js\";\nimport type { DoctorSnapshot, Env } from \"./doctor/types.js\";\n\nconst USAGE = `narrativetrace — one CLI over NarrativeTrace's open artifact formats\n\nUsage:\n narrativetrace doctor [--json]\n\nCommands:\n doctor Read-only project diagnosis: toolchain, configuration, and known traps. Zero network.\n\nOptions:\n --json Machine-readable output instead of human text.\n --help Show this message.`;\n\nconst DOCTOR_USAGE = `narrativetrace doctor [--json]\n\nRead-only. Checks toolchain/install state, configuration, and known traps against the current\nproject. Exit 0 = clean, 1 = findings, 2 = could not run.`;\n\nexport interface CliDeps {\n readonly cwd: string;\n readonly env: Env;\n readonly buildSnapshot: (cwd: string, env: Env) => DoctorSnapshot;\n readonly log: (message: string) => void;\n readonly error: (message: string) => void;\n}\n\n/** Runs `doctor` once argv has been recognized as that command. Returns the process exit code. */\nfunction runDoctorCommand(rest: readonly string[], deps: CliDeps): number {\n if (rest.includes(\"--help\") || rest.includes(\"-h\")) {\n deps.log(DOCTOR_USAGE);\n return 0;\n }\n const json = rest.includes(\"--json\");\n const unknown = rest.filter((arg) => arg !== \"--json\");\n if (unknown.length > 0) {\n deps.error(`Unknown argument(s) for doctor: ${unknown.join(\", \")}\\n\\n${DOCTOR_USAGE}`);\n return 2;\n }\n const snapshot = deps.buildSnapshot(deps.cwd, deps.env);\n if (!snapshot.rootPackageJson) {\n deps.error(`Could not run: no readable package.json found at ${deps.cwd}`);\n return 2;\n }\n const report = runDoctor(snapshot);\n deps.log(json ? renderJson(report) : renderHuman(report));\n return report.exitCode;\n}\n\n/** Parses argv and runs the requested command. Returns the process exit code. */\nexport function runCli(argv: string[], deps: CliDeps): number {\n const [verb, ...rest] = argv;\n if (verb === undefined) {\n deps.error(USAGE);\n return 2;\n }\n if (verb === \"--help\" || verb === \"-h\") {\n deps.log(USAGE);\n return 0;\n }\n if (verb !== \"doctor\") {\n deps.error(`Unknown command: ${verb}\\n\\n${USAGE}`);\n return 2;\n }\n return runDoctorCommand(rest, deps);\n}\n","// SPDX-License-Identifier: BUSL-1.1\n// Licensed under the Business Source License 1.1 (see LICENSE); Change Date: four years from publication; Change License: Apache-2.0\n// Copyright (c) 2026 Empower Agile\nimport { readdirSync, readFileSync, statSync } from \"node:fs\";\nimport { createRequire } from \"node:module\";\nimport { join, relative } from \"node:path\";\nimport type { DoctorSnapshot, Env, PackageJsonLike } from \"./types.js\";\n\nconst EXCLUDED_DIRS = new Set([\n // Stryker disable next-line StringLiteral: equivalent — every dot-prefixed entry name is\n // already excluded earlier, in visitEntry's leading-dot check (the only exception there is\n // \".env\", which isn't a directory this set would ever mention), so \".git\" never actually\n // reaches this set's `.has()` check.\n \".git\",\n // Stryker disable next-line StringLiteral: same equivalence as \".git\" above.\n \".turbo\",\n // Stryker disable next-line StringLiteral: same equivalence as \".git\" above.\n \".stryker-tmp\",\n // Not dot-prefixed, so NOT equivalent — reaching this set's `.has()` check is the only thing\n // that excludes each of the four names below; each is covered by a real test.\n \"node_modules\",\n \"dist\",\n \"build\",\n \"coverage\",\n]);\n\nconst SOURCE_EXTENSIONS = [\".ts\", \".tsx\", \".js\", \".jsx\", \".mjs\", \".cjs\", \".mts\", \".cts\"];\n\n/** Well-known package names the checks resolve directly; siblings of @narrativetrace/vitest are added dynamically. */\nconst BASE_PACKAGES = [\n \"vitest\",\n \"@narrativetrace/core\",\n \"@narrativetrace/core-node\",\n \"@narrativetrace/vitest\",\n];\n\nconst MAX_FILES = 20_000;\n\ntype Bucket = \"output\" | \"approved\" | \"source\" | \"skip\";\n\ninterface WalkState {\n readonly sourceFiles: Map<string, string>;\n readonly outputFiles: Map<string, string>;\n readonly approvedDirFiles: Map<string, string>;\n visited: number;\n}\n\n// Stryker disable BlockStatement: the three functions below whose catch block is just `return\n// undefined;` are equivalent under mutation — an emptied `catch {}` falls off the end of the\n// function and implicitly returns `undefined` too. No test can observe a difference between the\n// explicit and implicit forms. Restored below, before safeRead/listDirectory, whose catch blocks\n// return \"\" / [] respectively and are NOT equivalent (a real behavior change is observable there).\n\nfunction readJson(path: string): PackageJsonLike | undefined {\n try {\n return JSON.parse(readFileSync(path, \"utf8\")) as PackageJsonLike;\n } catch {\n return undefined;\n }\n}\n\nfunction resolvePackageJson(name: string, cwd: string): PackageJsonLike | undefined {\n try {\n const require = createRequire(join(cwd, \"package.json\"));\n return readJson(require.resolve(`${name}/package.json`));\n } catch {\n return undefined;\n }\n}\n\n/** `undefined` when `path` cannot be stat'd at all (a dangling symlink, a permission error, a race). */\nfunction isDirectorySafe(path: string): boolean | undefined {\n try {\n return statSync(path).isDirectory();\n } catch {\n return undefined;\n }\n}\n\n// Stryker restore BlockStatement\n\nfunction safeRead(path: string): string {\n try {\n return readFileSync(path, \"utf8\");\n } catch {\n return \"\";\n }\n}\n\nfunction listDirectory(dir: string): string[] {\n try {\n return readdirSync(dir);\n } catch {\n return [];\n }\n}\n\nfunction classify(rel: string, outputDirName: string, approvedDirName: string): Bucket {\n const topSegment = rel.split(\"/\")[0];\n if (topSegment === outputDirName) return \"output\";\n if (topSegment === approvedDirName) return \"approved\";\n // Stryker disable next-line StringLiteral: the \"source\" branch string is equivalent — bucketFor\n // below routes anything that isn't \"output\" or \"approved\" into sourceFiles by default, so\n // whether this literal reads \"source\" or something else never changes which map a file lands\n // in. The \"skip\" branch is NOT equivalent (a real behavior change is observable there) and is\n // exercised by a real test.\n return SOURCE_EXTENSIONS.some((ext) => rel.endsWith(ext)) ? \"source\" : \"skip\";\n}\n\nfunction bucketFor(state: WalkState, kind: Bucket): Map<string, string> {\n return kind === \"output\"\n ? state.outputFiles\n : kind === \"approved\"\n ? state.approvedDirFiles\n : state.sourceFiles;\n}\n\ninterface WalkContext {\n readonly state: WalkState;\n readonly root: string;\n readonly output: string;\n readonly approved: string;\n readonly queue: string[];\n}\n\n/** Visits one directory entry: enqueues a subdirectory, or files it into the right bucket. */\nfunction visitEntry(ctx: WalkContext, dir: string, entry: string): void {\n if (entry.startsWith(\".\") && entry !== \".env\") return;\n const full = join(dir, entry);\n const isDir = isDirectorySafe(full);\n if (isDir === undefined) return;\n if (isDir) {\n if (!EXCLUDED_DIRS.has(entry)) ctx.queue.push(full);\n return;\n }\n ctx.state.visited++;\n const rel = relative(ctx.root, full);\n const kind = classify(rel, ctx.output, ctx.approved);\n if (kind === \"skip\") return;\n bucketFor(ctx.state, kind).set(rel, safeRead(full));\n}\n\n/**\n * Walks `root` breadth-first, bucketing files into source (extension-filtered), the output\n * directory, and the approved-trace directory — excluding `node_modules`/build/coverage noise.\n * Bounded by {@link MAX_FILES} so a doctor run in a huge repo degrades to a partial scan rather\n * than hanging. The outer loop's own `state.visited < MAX_FILES` half of that bound is equivalent\n * under mutation — the inner loop's `if (state.visited >= MAX_FILES) break;` enforces the exact\n * same cap on its own, before any further entry is ever visited, so weakening the outer guard only\n * costs a few extra, immediately aborted `listDirectory` calls on already-queued directories; no\n * test can observe a different `WalkState`.\n */\nfunction walk(root: string, output: string, approved: string): WalkState {\n const state: WalkState = {\n sourceFiles: new Map(),\n outputFiles: new Map(),\n approvedDirFiles: new Map(),\n visited: 0,\n };\n const ctx: WalkContext = { state, root, output, approved, queue: [root] };\n // Stryker disable next-line ConditionalExpression,EqualityOperator: see the doc comment above.\n while (ctx.queue.length > 0 && state.visited < MAX_FILES) {\n const dir = ctx.queue.shift() as string;\n for (const entry of listDirectory(dir)) {\n if (state.visited >= MAX_FILES) break;\n visitEntry(ctx, dir, entry);\n }\n }\n return state;\n}\n\nfunction resolveBasePackages(cwd: string): Map<string, PackageJsonLike> {\n const installed = new Map<string, PackageJsonLike>();\n for (const name of BASE_PACKAGES) {\n const pkg = resolvePackageJson(name, cwd);\n if (pkg) installed.set(name, pkg);\n }\n return installed;\n}\n\n/** Resolves `@narrativetrace/vitest`'s own `@narrativetrace/*` dependencies — the sibling check's data. */\nfunction resolveVitestSiblings(cwd: string, installed: Map<string, PackageJsonLike>): void {\n const ntVitest = installed.get(\"@narrativetrace/vitest\");\n for (const name of Object.keys(ntVitest?.dependencies ?? {})) {\n if (!name.startsWith(\"@narrativetrace/\") || installed.has(name)) continue;\n const pkg = resolvePackageJson(name, cwd);\n if (pkg) installed.set(name, pkg);\n }\n}\n\nfunction resolveInstalledPackages(cwd: string): Map<string, PackageJsonLike> {\n const installed = resolveBasePackages(cwd);\n resolveVitestSiblings(cwd, installed);\n return installed;\n}\n\n/** Builds a {@link DoctorSnapshot} from the real filesystem rooted at `cwd`. The one impure module. */\nexport function buildSnapshot(cwd: string, env: Env): DoctorSnapshot {\n const output = env.NARRATIVETRACE_OUTPUT_DIR ?? \"narrativetrace-output\";\n const approved = env.NARRATIVETRACE_APPROVED_DIR ?? \"narratives\";\n const { sourceFiles, outputFiles, approvedDirFiles } = walk(cwd, output, approved);\n return {\n cwd,\n nodeVersion: process.version.replace(/^v/, \"\"),\n env,\n rootPackageJson: readJson(join(cwd, \"package.json\")),\n sourceFiles,\n outputFiles,\n approvedDirFiles,\n installedPackages: resolveInstalledPackages(cwd),\n };\n}\n","#!/usr/bin/env node\n// SPDX-License-Identifier: BUSL-1.1\n// Licensed under the Business Source License 1.1 (see LICENSE); Change Date: four years from publication; Change License: Apache-2.0\n// Copyright (c) 2026 Empower Agile\nimport { runCli } from \"./cli.js\";\nimport { buildSnapshot } from \"./doctor/environment.js\";\n\nconst exitCode = runCli(process.argv.slice(2), {\n cwd: process.cwd(),\n env: process.env,\n buildSnapshot,\n log: (message) => process.stdout.write(`${message}\\n`),\n error: (message) => process.stderr.write(`${message}\\n`),\n});\n\nprocess.exit(exitCode);\n"],"mappings":";;;;AAWA,IAAM,OAAO;AAEN,IAAM,MAAM;AAAA,EACjB,2BAA2B,GAAG,IAAI;AAAA,EAClC,0BAA0B,GAAG,IAAI;AAAA,EACjC,qBAAqB,GAAG,IAAI;AAAA,EAC5B,uBAAuB,GAAG,IAAI;AAAA,EAC9B,cAAc,GAAG,IAAI;AAAA,EACrB,wBAAwB,GAAG,IAAI;AAAA,EAC/B,qBAAqB,GAAG,IAAI;AAAA,EAC5B,sBAAsB,GAAG,IAAI;AAAA,EAC7B,2BAA2B,GAAG,IAAI;AAAA,EAClC,wBAAwB,GAAG,IAAI;AAAA,EAC/B,wBAAwB,GAAG,IAAI;AACjC;;;ACnBO,SAAS,KAAK,IAAY,SAAiB,QAAyB;AACzE,SAAO,EAAE,IAAI,QAAQ,QAAyB,SAAS,KAAK,IAAI,OAAO;AACzE;AAGO,SAAS,KAAK,IAAY,SAAiB,KAAa,QAAyB;AACtF,SAAO,EAAE,IAAI,QAAQ,QAAyB,SAAS,KAAK,OAAO;AACrE;;;ACNA,IAAM,KAAK;AACX,IAAM,MACJ;AAQK,IAAM,sBAAmC,CAAC,aAAa;AAC5D,QAAM,QAAQ,CAAC,GAAG,SAAS,iBAAiB,KAAK,CAAC;AAClD,MAAI,MAAM,WAAW,GAAG;AACtB,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA,IAAI;AAAA,IACN;AAAA,EACF;AACA,QAAM,WAAW,MAAM,OAAO,CAAC,MAAM,EAAE,SAAS,cAAc,CAAC;AAC/D,MAAI,SAAS,SAAS,GAAG;AACvB,UAAMA,WAAU,GAAG,SAAS,MAAM,mCAAmC,SAAS,KAAK,IAAI,CAAC;AACxF,WAAO,KAAK,IAAIA,UAAS,KAAK,IAAI,sBAAsB;AAAA,EAC1D;AACA,QAAM,WAAW,MAAM,OAAO,CAAC,MAAM,EAAE,SAAS,cAAc,CAAC;AAC/D,QAAM,UAAU,GAAG,SAAS,MAAM;AAClC,SAAO,KAAK,IAAI,SAAS,IAAI,sBAAsB;AACrD;;;AC3BA,IAAMC,MAAK;AACX,IAAM,WAAW;AACjB,IAAM,aAAa;AACnB,IAAMC,OACJ;AAOK,IAAM,0BAAuC,CAAC,aAAa;AAChE,MAAI,SAAS,iBAAiB,SAAS,UAAU;AAC/C,WAAO,KAAKD,KAAI,0CAA0C,IAAI,sBAAsB;AAAA,EACtF;AACA,QAAM,WAAW,CAAC,GAAG,SAAS,WAAW,EAAE;AAAA,IACzC,CAAC,CAACE,OAAM,OAAO,MAAM,SAAS,KAAKA,KAAI,KAAK,WAAW,KAAK,OAAO;AAAA,EACrE;AACA,MAAI,CAAC,UAAU;AACb,UAAMC,WAAU;AAChB,WAAO,KAAKH,KAAIG,UAAS,IAAI,sBAAsB;AAAA,EACrD;AACA,QAAM,CAAC,IAAI,IAAI;AACf,QAAM,UAAU,GAAG,IAAI;AACvB,SAAO,KAAKH,KAAI,SAASC,MAAK,IAAI,sBAAsB;AAC1D;;;ACfO,SAAS,aAAa,KAAkC;AAC7D,QAAM,UAAU,IAAI,KAAK,EAAE,QAAQ,MAAM,EAAE;AAC3C,QAAM,QAAQ,iCAAiC,KAAK,OAAO;AAC3D,MAAI,CAAC,MAAO,QAAO;AACnB,SAAO;AAAA,IACL,OAAO,OAAO,MAAM,CAAC,CAAC;AAAA,IACtB,OAAO,MAAM,CAAC,MAAM,SAAY,IAAI,OAAO,MAAM,CAAC,CAAC;AAAA,IACnD,OAAO,MAAM,CAAC,MAAM,SAAY,IAAI,OAAO,MAAM,CAAC,CAAC;AAAA,EACrD;AACF;AAGO,SAAS,gBAAgB,MAAe,OAAwB;AACrE,MAAI,KAAK,UAAU,MAAM,MAAO,QAAO,KAAK,QAAQ,MAAM;AAC1D,MAAI,KAAK,UAAU,MAAM,MAAO,QAAO,KAAK,QAAQ,MAAM;AAC1D,SAAO,KAAK,QAAQ,MAAM;AAC5B;AAEA,SAAS,aAAa,SAAkB,OAAyB;AAC/D,SAAO,gBAAgB,SAAS,KAAK,KAAK;AAC5C;AAGA,SAAS,eAAe,SAAkB,MAAwB;AAChE,MAAI,gBAAgB,SAAS,IAAI,IAAI,EAAG,QAAO;AAC/C,MAAI,KAAK,QAAQ,EAAG,QAAO,QAAQ,UAAU,KAAK;AAClD,MAAI,KAAK,QAAQ,EAAG,QAAO,QAAQ,UAAU,KAAK,QAAQ,UAAU,KAAK;AACzE,SAAO,QAAQ,UAAU,KAAK,QAAQ,UAAU,KAAK,QAAQ,UAAU,KAAK;AAC9E;AAQA,SAAS,gBAAgB,SAAkB,SAA0B;AACnE,MAAI,QAAQ,WAAW,GAAG,GAAG;AAC3B,UAAM,OAAO,aAAa,QAAQ,MAAM,CAAC,CAAC;AAC1C,WAAO,SAAS,UAAa,eAAe,SAAS,IAAI;AAAA,EAC3D;AACA,MAAI,QAAQ,WAAW,IAAI,GAAG;AAC5B,UAAM,QAAQ,aAAa,QAAQ,MAAM,CAAC,CAAC;AAC3C,WAAO,UAAU,UAAa,aAAa,SAAS,KAAK;AAAA,EAC3D;AACA,MAAI,QAAQ,KAAK,OAAO,GAAG;AACzB,UAAM,OAAO,aAAa,QAAQ,QAAQ,QAAQ,IAAI,CAAC;AACvD,WAAO,SAAS,UAAa,eAAe,SAAS,IAAI;AAAA,EAC3D;AACA,QAAM,QAAQ,aAAa,OAAO;AAClC,SAAO,UAAU,UAAa,gBAAgB,SAAS,KAAK,MAAM;AACpE;AAOO,SAAS,eAAe,YAAoB,OAAwB;AACzE,QAAM,UAAU,aAAa,UAAU;AACvC,MAAI,CAAC,QAAS,QAAO;AAOrB,SAAO,MACJ,MAAM,IAAI,EACV,IAAI,CAAC,WAAW,OAAO,KAAK,CAAC,EAC7B,OAAO,OAAO,EACd,KAAK,CAAC,WAAW,gBAAgB,SAAS,MAAM,CAAC;AACtD;;;ACjFA,IAAMG,MAAK;AACX,IAAM,uBAAuB;AAG7B,SAAS,cAAc,UAA8C;AACnE,QAAM,OAAO,SAAS,kBAAkB,IAAI,sBAAsB;AAClE,QAAM,WAAW,SAAS,kBAAkB,IAAI,2BAA2B;AAC3E,SAAO,MAAM,SAAS,QAAQ,UAAU,SAAS,QAAQ;AAC3D;AAGO,IAAM,kBAA+B,CAAC,aAAa;AACxD,QAAM,WAAW,cAAc,QAAQ;AACvC,MAAI,eAAe,SAAS,aAAa,QAAQ,GAAG;AAClD,WAAO;AAAA,MACLA;AAAA,MACA,QAAQ,SAAS,WAAW,2BAA2B,QAAQ;AAAA,MAC/D,IAAI;AAAA,IACN;AAAA,EACF;AACA,SAAO;AAAA,IACLA;AAAA,IACA,QAAQ,SAAS,WAAW,kCAAkC,QAAQ;AAAA,IACtE,wCAAwC,QAAQ;AAAA,IAChD,IAAI;AAAA,EACN;AACF;;;AC3BA,IAAMC,MAAK;AACX,IAAM,eAAe,oBAAI,IAAI,CAAC,QAAQ,OAAO,CAAC;AAGvC,IAAM,iBAA8B,CAAC,aAAa;AACvD,QAAM,MAAM,SAAS,IAAI;AACzB,MAAI,QAAQ,QAAW;AACrB,WAAO;AAAA,MACLA;AAAA,MACA;AAAA,MACA,IAAI;AAAA,IACN;AAAA,EACF;AACA,MAAI,aAAa,IAAI,IAAI,YAAY,CAAC,GAAG;AACvC,WAAO,KAAKA,KAAI,yBAAyB,GAAG,IAAI,IAAI,qBAAqB;AAAA,EAC3E;AACA,SAAO;AAAA,IACLA;AAAA,IACA,oCAAoC,GAAG;AAAA,IACvC;AAAA,IACA,IAAI;AAAA,EACN;AACF;;;ACtBA,IAAMC,MAAK;AACX,IAAM,kBAAkB;AACxB,IAAMC,OACJ;AAOK,IAAM,qBAAkC,CAAC,aAAa;AAC3D,MAAI,SAAS,YAAY,SAAS,GAAG;AACnC,UAAMC,WAAU;AAChB,WAAO,KAAKF,KAAIE,UAAS,IAAI,oBAAoB;AAAA,EACnD;AACA,QAAM,WAAW,CAAC,GAAG,SAAS,WAAW,EAAE,KAAK,CAAC,CAAC,EAAE,OAAO,MAAM,gBAAgB,KAAK,OAAO,CAAC;AAC9F,MAAI,CAAC,UAAU;AACb,UAAMA,WAAU;AAChB,WAAO,KAAKF,KAAIE,UAAS,IAAI,oBAAoB;AAAA,EACnD;AACA,QAAM,CAAC,IAAI,IAAI;AACf,QAAM,UAAU,gEAAgE,IAAI;AACpF,SAAO,KAAKF,KAAI,SAASC,MAAK,IAAI,oBAAoB;AACxD;;;ACvBA,IAAME,MAAK;AACX,IAAM,YAAY;AAClB,IAAM,qBAAqB;AAOpB,IAAM,sBAAmC,CAAC,aAAa;AAC5D,QAAM,YAAY,CAAC,GAAG,SAAS,WAAW,EAAE,OAAO,CAAC,CAAC,IAAI,MAAM,UAAU,KAAK,IAAI,CAAC;AACnF,QAAM,SAAS,UAAU,KAAK,CAAC,CAAC,EAAE,OAAO,MAAM,mBAAmB,KAAK,OAAO,CAAC;AAC/E,MAAI,QAAQ;AACV,WAAO;AAAA,MACLA;AAAA,MACA;AAAA,MACA,IAAI;AAAA,IACN;AAAA,EACF;AACA,SAAO;AAAA,IACLA;AAAA,IACA;AAAA,IACA;AAAA,IACA,IAAI;AAAA,EACN;AACF;;;ACzBA,IAAMC,MAAK;AACX,IAAM,qBAAqB;AAC3B,IAAM,iBAAiB;AACvB,IAAM,cAAc;AACpB,IAAM,iBAAiB;AAEvB,SAAS,gBAAgB,SAA0B;AACjD,SAAO,eAAe,KAAK,OAAO,KAAK,YAAY,KAAK,OAAO,KAAK,CAAC,eAAe,KAAK,OAAO;AAClG;AAOO,IAAM,uBAAoC,CAAC,aAAa;AAC7D,QAAM,UAAU,CAAC,GAAG,SAAS,WAAW,EAAE,OAAO,CAAC,CAAC,IAAI,MAAM,mBAAmB,KAAK,IAAI,CAAC;AAC1F,QAAM,WAAW,QAAQ,KAAK,CAAC,CAAC,EAAE,OAAO,MAAM,gBAAgB,OAAO,CAAC;AACvE,MAAI,UAAU;AACZ,UAAM,CAAC,IAAI,IAAI;AACf,WAAO;AAAA,MACLA;AAAA,MACA,GAAG,IAAI;AAAA,MACP;AAAA,MACA,IAAI;AAAA,IACN;AAAA,EACF;AACA,QAAM,UACJ,QAAQ,WAAW,IACf,mDACA;AACN,SAAO,KAAKA,KAAI,SAAS,IAAI,mBAAmB;AAClD;;;AChCA,IAAMC,MAAK;AAWJ,IAAM,uBAAoC,CAAC,aAAa;AAC7D,QAAM,WAAW,SAAS,kBAAkB,IAAI,wBAAwB;AACxE,MAAI,CAAC,UAAU;AACb,UAAMC,WAAU;AAChB,WAAO,KAAKD,KAAIC,UAAS,IAAI,wBAAwB;AAAA,EACvD;AACA,QAAM,WAAW,OAAO,KAAK,SAAS,gBAAgB,CAAC,CAAC,EAAE;AAAA,IAAO,CAAC,MAChE,EAAE,WAAW,kBAAkB;AAAA,EACjC;AACA,QAAM,aAAa,SAAS,OAAO,CAAC,SAAS,CAAC,SAAS,kBAAkB,IAAI,IAAI,CAAC;AAClF,MAAI,WAAW,WAAW,GAAG;AAC3B,UAAMA,WAAU,OAAO,SAAS,MAAM;AACtC,WAAO,KAAKD,KAAIC,UAAS,IAAI,wBAAwB;AAAA,EACvD;AACA,QAAM,UAAU,GAAG,WAAW,MAAM,mFAAmF,WAAW,KAAK,IAAI,CAAC;AAC5I,QAAM,MAAM,OAAO,WAAW,KAAK,IAAI,CAAC;AACxC,SAAO,KAAKD,KAAI,SAAS,KAAK,IAAI,wBAAwB;AAC5D;;;AC5BA,IAAME,MAAK;AACX,IAAM,oBAAoB;AAC1B,IAAM,cACJ;AAQK,IAAM,kBAA+B,CAAC,aAAa;AACxD,QAAM,WAAW,CAAC,GAAG,SAAS,YAAY,OAAO,CAAC;AAClD,MAAI,CAAC,SAAS,KAAK,CAAC,YAAY,kBAAkB,KAAK,OAAO,CAAC,GAAG;AAChE,WAAO,KAAKA,KAAI,qDAAgD,IAAI,mBAAmB;AAAA,EACzF;AACA,MAAI,SAAS,KAAK,CAAC,YAAY,YAAY,KAAK,OAAO,CAAC,GAAG;AACzD,WAAO;AAAA,MACLA;AAAA,MACA;AAAA,MACA,IAAI;AAAA,IACN;AAAA,EACF;AACA,SAAO;AAAA,IACLA;AAAA,IACA;AAAA,IACA;AAAA,IACA,IAAI;AAAA,EACN;AACF;;;AC7BA,IAAMC,OAAK;AAQX,IAAM,YAAY;AAQX,IAAM,uBAAoC,CAAC,aAAa;AAC7D,QAAM,WAAW,CAAC,GAAG,SAAS,WAAW,EAAE,KAAK,CAAC,CAAC,EAAE,OAAO,MAAM,UAAU,KAAK,OAAO,CAAC;AACxF,MAAI,UAAU;AACZ,UAAM,CAAC,IAAI,IAAI;AACf,WAAO;AAAA,MACLA;AAAA,MACA,GAAG,IAAI;AAAA,MACP;AAAA,MACA,IAAI;AAAA,IACN;AAAA,EACF;AACA,SAAO;AAAA,IACLA;AAAA,IACA;AAAA,IACA,IAAI;AAAA,EACN;AACF;;;AC/BA,IAAMC,OAAK;AAEX,SAAS,kBAAkB,OAAwB;AACjD,QAAM,UAAU,iDAAiD,KAAK;AACtE,QAAM,MAAM,uCAAuC,KAAK;AACxD,SAAO,KAAKA,MAAI,SAAS,KAAK,IAAI,mBAAmB;AACvD;AAEA,SAAS,iBAAiB,OAAe,WAA4B;AACnE,QAAM,UAAU,UAAU,SAAS,kEAAkE,KAAK;AAC1G,QAAM,MAAM,uCAAuC,KAAK;AACxD,SAAO,KAAKA,MAAI,SAAS,KAAK,IAAI,mBAAmB;AACvD;AAEA,SAAS,wBAAwB,OAAe,QAA8C;AAC5F,MAAI,CAAC,QAAQ,QAAS,QAAO,kBAAkB,KAAK;AACpD,MAAI,eAAe,OAAO,SAAS,KAAK,GAAG;AACzC,UAAM,UAAU,UAAU,OAAO,OAAO,sCAAsC,KAAK;AACnF,WAAO,KAAKA,MAAI,SAAS,IAAI,mBAAmB;AAAA,EAClD;AACA,SAAO,iBAAiB,OAAO,OAAO,OAAO;AAC/C;AAGO,IAAM,kBAA+B,CAAC,aAAa;AACxD,QAAM,WAAW,SAAS,kBAAkB,IAAI,wBAAwB;AACxE,QAAM,QAAQ,UAAU,kBAAkB;AAC1C,MAAI,CAAC,YAAY,CAAC,OAAO;AACvB,WAAO;AAAA,MACLA;AAAA,MACA;AAAA,MACA,IAAI;AAAA,IACN;AAAA,EACF;AACA,SAAO,wBAAwB,OAAO,SAAS,kBAAkB,IAAI,QAAQ,CAAC;AAChF;;;ACvBO,IAAM,gBAAwC;AAAA,EACnD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAGO,SAAS,UAAU,UAAwC;AAChE,QAAM,WAAW,cAAc,IAAI,CAAC,UAAU,MAAM,QAAQ,CAAC;AAC7D,QAAMC,YAAW,SAAS,KAAK,CAAC,MAAM,EAAE,WAAW,MAAM,IAAI,IAAI;AACjE,SAAO,EAAE,UAAU,UAAAA,UAAS;AAC9B;;;AClCA,SAAS,cAAc,SAA4B;AACjD,QAAM,MAAM,QAAQ,WAAW,SAAS,SAAS;AACjD,QAAM,QAAQ,CAAC,IAAI,GAAG,KAAK,QAAQ,EAAE,WAAM,QAAQ,OAAO,EAAE;AAC5D,MAAI,QAAQ,WAAW,QAAQ;AAC7B,UAAM,KAAK,WAAW,QAAQ,GAAG,IAAI,WAAW,QAAQ,MAAM,EAAE;AAAA,EAClE;AACA,QAAM,KAAK,EAAE;AACb,SAAO;AACT;AAGO,SAAS,YAAY,QAA8B;AACxD,QAAM,UAAU,OAAO,SAAS,OAAO,CAAC,MAAM,EAAE,WAAW,MAAM;AACjE,QAAM,UAAU,OAAO,SAAS,OAAO,CAAC,MAAM,EAAE,WAAW,MAAM;AACjE,QAAM,SAAS,gCAA2B,OAAO,SAAS,MAAM,cAAc,QAAQ,MAAM;AAC5F,QAAM,UACJ,QAAQ,WAAW,IACf,uBACA,GAAG,QAAQ,MAAM,0BAA0B,OAAO,QAAQ;AAChE,QAAM,OAAO,CAAC,GAAG,SAAS,GAAG,OAAO,EAAE,QAAQ,aAAa;AAC3D,SAAO,CAAC,QAAQ,IAAI,GAAG,MAAM,OAAO,EAAE,KAAK,IAAI;AACjD;AAGO,SAAS,WAAW,QAA8B;AACvD,SAAO,KAAK,UAAU,QAAQ,MAAM,CAAC;AACvC;;;ACxBA,IAAM,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAYd,IAAM,eAAe;AAAA;AAAA;AAAA;AAcrB,SAAS,iBAAiB,MAAyB,MAAuB;AACxE,MAAI,KAAK,SAAS,QAAQ,KAAK,KAAK,SAAS,IAAI,GAAG;AAClD,SAAK,IAAI,YAAY;AACrB,WAAO;AAAA,EACT;AACA,QAAM,OAAO,KAAK,SAAS,QAAQ;AACnC,QAAM,UAAU,KAAK,OAAO,CAAC,QAAQ,QAAQ,QAAQ;AACrD,MAAI,QAAQ,SAAS,GAAG;AACtB,SAAK,MAAM,mCAAmC,QAAQ,KAAK,IAAI,CAAC;AAAA;AAAA,EAAO,YAAY,EAAE;AACrF,WAAO;AAAA,EACT;AACA,QAAM,WAAW,KAAK,cAAc,KAAK,KAAK,KAAK,GAAG;AACtD,MAAI,CAAC,SAAS,iBAAiB;AAC7B,SAAK,MAAM,oDAAoD,KAAK,GAAG,EAAE;AACzE,WAAO;AAAA,EACT;AACA,QAAM,SAAS,UAAU,QAAQ;AACjC,OAAK,IAAI,OAAO,WAAW,MAAM,IAAI,YAAY,MAAM,CAAC;AACxD,SAAO,OAAO;AAChB;AAGO,SAAS,OAAO,MAAgB,MAAuB;AAC5D,QAAM,CAAC,MAAM,GAAG,IAAI,IAAI;AACxB,MAAI,SAAS,QAAW;AACtB,SAAK,MAAM,KAAK;AAChB,WAAO;AAAA,EACT;AACA,MAAI,SAAS,YAAY,SAAS,MAAM;AACtC,SAAK,IAAI,KAAK;AACd,WAAO;AAAA,EACT;AACA,MAAI,SAAS,UAAU;AACrB,SAAK,MAAM,oBAAoB,IAAI;AAAA;AAAA,EAAO,KAAK,EAAE;AACjD,WAAO;AAAA,EACT;AACA,SAAO,iBAAiB,MAAM,IAAI;AACpC;;;ACnEA,qBAAoD;AACpD,yBAA8B;AAC9B,uBAA+B;AAG/B,IAAM,gBAAgB,oBAAI,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA,EAK5B;AAAA;AAAA,EAEA;AAAA;AAAA,EAEA;AAAA;AAAA;AAAA,EAGA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAED,IAAM,oBAAoB,CAAC,OAAO,QAAQ,OAAO,QAAQ,QAAQ,QAAQ,QAAQ,MAAM;AAGvF,IAAM,gBAAgB;AAAA,EACpB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEA,IAAM,YAAY;AAiBlB,SAAS,SAAS,MAA2C;AAC3D,MAAI;AACF,WAAO,KAAK,UAAM,6BAAa,MAAM,MAAM,CAAC;AAAA,EAC9C,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,mBAAmB,MAAc,KAA0C;AAClF,MAAI;AACF,UAAMC,eAAU,sCAAc,uBAAK,KAAK,cAAc,CAAC;AACvD,WAAO,SAASA,SAAQ,QAAQ,GAAG,IAAI,eAAe,CAAC;AAAA,EACzD,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAGA,SAAS,gBAAgB,MAAmC;AAC1D,MAAI;AACF,eAAO,yBAAS,IAAI,EAAE,YAAY;AAAA,EACpC,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAIA,SAAS,SAAS,MAAsB;AACtC,MAAI;AACF,eAAO,6BAAa,MAAM,MAAM;AAAA,EAClC,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,cAAc,KAAuB;AAC5C,MAAI;AACF,eAAO,4BAAY,GAAG;AAAA,EACxB,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AACF;AAEA,SAAS,SAAS,KAAa,eAAuB,iBAAiC;AACrF,QAAM,aAAa,IAAI,MAAM,GAAG,EAAE,CAAC;AACnC,MAAI,eAAe,cAAe,QAAO;AACzC,MAAI,eAAe,gBAAiB,QAAO;AAM3C,SAAO,kBAAkB,KAAK,CAAC,QAAQ,IAAI,SAAS,GAAG,CAAC,IAAI,WAAW;AACzE;AAEA,SAAS,UAAU,OAAkB,MAAmC;AACtE,SAAO,SAAS,WACZ,MAAM,cACN,SAAS,aACP,MAAM,mBACN,MAAM;AACd;AAWA,SAAS,WAAW,KAAkB,KAAa,OAAqB;AACtE,MAAI,MAAM,WAAW,GAAG,KAAK,UAAU,OAAQ;AAC/C,QAAM,WAAO,uBAAK,KAAK,KAAK;AAC5B,QAAM,QAAQ,gBAAgB,IAAI;AAClC,MAAI,UAAU,OAAW;AACzB,MAAI,OAAO;AACT,QAAI,CAAC,cAAc,IAAI,KAAK,EAAG,KAAI,MAAM,KAAK,IAAI;AAClD;AAAA,EACF;AACA,MAAI,MAAM;AACV,QAAM,UAAM,2BAAS,IAAI,MAAM,IAAI;AACnC,QAAM,OAAO,SAAS,KAAK,IAAI,QAAQ,IAAI,QAAQ;AACnD,MAAI,SAAS,OAAQ;AACrB,YAAU,IAAI,OAAO,IAAI,EAAE,IAAI,KAAK,SAAS,IAAI,CAAC;AACpD;AAYA,SAAS,KAAK,MAAc,QAAgB,UAA6B;AACvE,QAAM,QAAmB;AAAA,IACvB,aAAa,oBAAI,IAAI;AAAA,IACrB,aAAa,oBAAI,IAAI;AAAA,IACrB,kBAAkB,oBAAI,IAAI;AAAA,IAC1B,SAAS;AAAA,EACX;AACA,QAAM,MAAmB,EAAE,OAAO,MAAM,QAAQ,UAAU,OAAO,CAAC,IAAI,EAAE;AAExE,SAAO,IAAI,MAAM,SAAS,KAAK,MAAM,UAAU,WAAW;AACxD,UAAM,MAAM,IAAI,MAAM,MAAM;AAC5B,eAAW,SAAS,cAAc,GAAG,GAAG;AACtC,UAAI,MAAM,WAAW,UAAW;AAChC,iBAAW,KAAK,KAAK,KAAK;AAAA,IAC5B;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,oBAAoB,KAA2C;AACtE,QAAM,YAAY,oBAAI,IAA6B;AACnD,aAAW,QAAQ,eAAe;AAChC,UAAM,MAAM,mBAAmB,MAAM,GAAG;AACxC,QAAI,IAAK,WAAU,IAAI,MAAM,GAAG;AAAA,EAClC;AACA,SAAO;AACT;AAGA,SAAS,sBAAsB,KAAa,WAA+C;AACzF,QAAM,WAAW,UAAU,IAAI,wBAAwB;AACvD,aAAW,QAAQ,OAAO,KAAK,UAAU,gBAAgB,CAAC,CAAC,GAAG;AAC5D,QAAI,CAAC,KAAK,WAAW,kBAAkB,KAAK,UAAU,IAAI,IAAI,EAAG;AACjE,UAAM,MAAM,mBAAmB,MAAM,GAAG;AACxC,QAAI,IAAK,WAAU,IAAI,MAAM,GAAG;AAAA,EAClC;AACF;AAEA,SAAS,yBAAyB,KAA2C;AAC3E,QAAM,YAAY,oBAAoB,GAAG;AACzC,wBAAsB,KAAK,SAAS;AACpC,SAAO;AACT;AAGO,SAAS,cAAc,KAAa,KAA0B;AACnE,QAAM,SAAS,IAAI,6BAA6B;AAChD,QAAM,WAAW,IAAI,+BAA+B;AACpD,QAAM,EAAE,aAAa,aAAa,iBAAiB,IAAI,KAAK,KAAK,QAAQ,QAAQ;AACjF,SAAO;AAAA,IACL;AAAA,IACA,aAAa,QAAQ,QAAQ,QAAQ,MAAM,EAAE;AAAA,IAC7C;AAAA,IACA,iBAAiB,aAAS,uBAAK,KAAK,cAAc,CAAC;AAAA,IACnD;AAAA,IACA;AAAA,IACA;AAAA,IACA,mBAAmB,yBAAyB,GAAG;AAAA,EACjD;AACF;;;AC5MA,IAAM,WAAW,OAAO,QAAQ,KAAK,MAAM,CAAC,GAAG;AAAA,EAC7C,KAAK,QAAQ,IAAI;AAAA,EACjB,KAAK,QAAQ;AAAA,EACb;AAAA,EACA,KAAK,CAAC,YAAY,QAAQ,OAAO,MAAM,GAAG,OAAO;AAAA,CAAI;AAAA,EACrD,OAAO,CAAC,YAAY,QAAQ,OAAO,MAAM,GAAG,OAAO;AAAA,CAAI;AACzD,CAAC;AAED,QAAQ,KAAK,QAAQ;","names":["message","ID","FIX","path","message","ID","ID","ID","FIX","message","ID","ID","ID","message","ID","ID","ID","exitCode","require"]}
1
+ {"version":3,"sources":["../../../node_modules/.pnpm/tsup@8.5.1_@swc+core@1.15.18_postcss@8.5.6_tsx@4.21.0_typescript@5.9.3_yaml@2.9.0/node_modules/tsup/assets/cjs_shims.js","../src/cli-bin.ts","../src/carrier-locator.ts","../src/cli.ts","../src/installer-arguments.ts"],"sourcesContent":["// Shim globals in cjs bundle\n// There's a weird bug that esbuild will always inject importMetaUrl\n// if we export it as `const importMetaUrl = ... __filename ...`\n// But using a function will not cause this issue\n\nconst getImportMetaUrl = () => \n typeof document === \"undefined\" \n ? new URL(`file:${__filename}`).href \n : (document.currentScript && document.currentScript.tagName.toUpperCase() === 'SCRIPT') \n ? document.currentScript.src \n : new URL(\"main.js\", document.baseURI).href;\n\nexport const importMetaUrl = /* @__PURE__ */ getImportMetaUrl()\n","#!/usr/bin/env node\n// SPDX-License-Identifier: BUSL-1.1\n// Licensed under the Business Source License 1.1 (see LICENSE); Change Date: four years from publication; Change License: Apache-2.0\n// Copyright (c) 2026 Empower Agile\nimport { buildSnapshot } from \"@narrativetrace/tooling\";\nimport { cliPackageDirectory, openCarrierFor } from \"./carrier-locator.js\";\nimport { runCli } from \"./cli.js\";\n\nconst cwd = process.cwd();\n\nconst exitCode = runCli(process.argv.slice(2), {\n cwd,\n env: process.env,\n buildSnapshot: (c, e) => buildSnapshot(c, e, cliPackageDirectory()),\n openCarrier: (from) => openCarrierFor(cwd, from),\n log: (message) => process.stdout.write(`${message}\\n`),\n print: (text) => process.stdout.write(text),\n error: (message) => process.stderr.write(`${message}\\n`),\n});\n\nprocess.exit(exitCode);\n","// SPDX-License-Identifier: BUSL-1.1\n// Licensed under the Business Source License 1.1 (see LICENSE); Change Date: four years from publication; Change License: Apache-2.0\n// Copyright (c) 2026 Empower Agile\nimport { dirname } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { type Carrier, resolveCarrier } from \"@narrativetrace/tooling\";\n\n/**\n * Where this launcher looks for the skills carrier it installs from.\n *\n * INTENT: one place knows that the running CLI bundles a copy of the carrier, and where. Everything\n * else about resolution — the order of the homes, what makes a carrier valid — belongs to\n * `@narrativetrace/tooling`'s `resolveCarrier`, so both entry points can never disagree about it.\n *\n * @llmNote Zero network, by construction: the three homes are a path a person named, the project's own\n * `node_modules`, and this package's own directory. D4 rules the npm cache unreadable, so `--from`\n * takes a path and a coordinate is never looked up.\n *\n * @sideEffects Reads the carrier's files once, through `resolveCarrier`.\n */\n\n/**\n * This CLI package's own root — the directory whose `skills/` holds the carrier it bundles.\n *\n * @llmNote Derived from this module's own location, which is one directory below the package root in\n * BOTH layouts this code runs in: `src/` under vitest, and `dist/` in the published package. A\n * `process.argv[1]`-based answer would be wrong under the bin shim, and a `process.cwd()`-based one\n * would be the consumer's project.\n */\nexport function cliPackageDirectory(): string {\n return dirname(dirname(fileURLToPath(import.meta.url)));\n}\n\n/**\n * Opens the carrier for one run: `--from` when a path was given, else the `@narrativetrace/skills` the\n * PROJECT resolves, else the copy this CLI bundles.\n *\n * @param projectDirectory the consumer project the install is for\n * @param from the directory a person named with `--from`, or `undefined`\n * @throws {TypeError} when the named path holds no carrier, or when no home does.\n */\nexport function openCarrierFor(projectDirectory: string, from: string | undefined): Carrier {\n return resolveCarrier({ projectDirectory, bundledDirectory: cliPackageDirectory(), from });\n}\n","// SPDX-License-Identifier: BUSL-1.1\n// Licensed under the Business Source License 1.1 (see LICENSE); Change Date: four years from publication; Change License: Apache-2.0\n// Copyright (c) 2026 Empower Agile\nimport {\n applyPlan,\n type Carrier,\n carrierVersionWarning,\n type DoctorSnapshot,\n type Env,\n type InitPlan,\n type ProjectState,\n planExitCode,\n planInstall,\n planUninstall,\n readProjectState,\n renderHuman,\n renderJson,\n renderPlan,\n renderReport,\n reportExitCode,\n runDoctor,\n} from \"@narrativetrace/tooling\";\nimport { type InstallerArguments, parseInstallerArguments } from \"./installer-arguments.js\";\n\nconst USAGE = `narrativetrace — one CLI over NarrativeTrace's open artifact formats\n\nUsage:\n narrativetrace doctor [--json]\n narrativetrace init [--dry-run] [--write-existing] [--force] [--only <half>] [--vendor <vendor>]\n [--from <dir>] [--json]\n narrativetrace uninstall [--dry-run] [--only <half>] [--json]\n\nCommands:\n doctor Read-only project diagnosis: toolchain, configuration, and known traps. Zero network.\n init Installs the NarrativeTrace agent skills and the AGENTS.md section into this project.\n uninstall Removes exactly what init wrote, and nothing beside it.\n\nOptions:\n --json Machine-readable output instead of human text.\n --help Show this message.`;\n\nconst DOCTOR_USAGE = `narrativetrace doctor [--json]\n\nRead-only. Checks toolchain/install state, configuration, and known traps against the current\nproject. Exit 0 = clean, 1 = findings, 2 = could not run.`;\n\nconst INSTALLER_OPTIONS = ` --dry-run Show the plan and the unified diff. Writes nothing, always exits 0.\n --write-existing Permission to touch an AGENTS.md or CLAUDE.md that is already there.\n --force Permission to overwrite a skill directory somebody else owns.\n --only <half> skills | agents-md. Both halves by default.\n --vendor <vendor> claude | none. Detected from the project by default.\n --from <dir> A directory holding the carrier: a checked-out @narrativetrace/skills, or an\n unpacked tarball of one. The copy bundled with this CLI by default.\n --json Machine-readable output instead of human text.\n\nExit 0 = applied (or a dry run), 1 = something was refused, 2 = could not run.`;\n\nconst INIT_USAGE = `narrativetrace init [options]\n\nCopies the NarrativeTrace agent skills into .agents/skills/ (and .claude/skills/ where the project\nis one of that vendor's) and writes one marked section into AGENTS.md. Zero network.\n\nRun it again to refresh: this CLI installs no build hook and schedules nothing, so a re-run IS the\nrefresh. On a project that already carries the skills it rewrites only our own pages and our own\nmarked section, and leaves everything else where it is.\n\n${INSTALLER_OPTIONS}`;\n\n/**\n * Only the three flags an uninstall uses, plus one line about the rest.\n *\n * @llmNote Java's uninstall help prints the install-only flags too, which makes its own help untrue\n * about `--force` and `--from`. The parser is still shared — one flag reader for both verbs — so the\n * flags stay ACCEPTED; they are simply not advertised where they do nothing.\n */\nconst UNINSTALL_OPTIONS = ` --dry-run Show the plan and the unified diff. Removes nothing, always exits 0.\n --only <half> skills | agents-md. Both halves by default.\n --json Machine-readable output instead of human text.\n\nThe install-only flags (--write-existing, --force, --vendor, --from) are accepted and ignored: there\nis no carrier to open and no permission to ask for when removing what this tool itself wrote.\n\nExit 0 = removed (or a dry run), 1 = something was refused, 2 = could not run.`;\n\nconst UNINSTALL_USAGE = `narrativetrace uninstall [options]\n\nRemoves exactly what init wrote: skill directories carrying its provenance line, the marked\nsection, and the one @AGENTS.md import line. Never touches anything else.\n\n${UNINSTALL_OPTIONS}`;\n\n/** What to type when no carrier could be opened — this CLI never fetches one. */\nconst CARRIER_HINT = `Nothing was fetched: this command makes no network call. Point --from at a carrier you have:\n --from node_modules/@narrativetrace/skills\n npm pack @narrativetrace/skills && tar xzf narrativetrace-skills-*.tgz && narrativetrace init --from package`;\n\n/** Everything the launcher reads from the outside world, injectable for hermetic tests. */\nexport interface CliDeps {\n readonly cwd: string;\n readonly env: Env;\n readonly buildSnapshot: (cwd: string, env: Env) => DoctorSnapshot;\n /** Opens the carrier a run installs from; `from` is whatever `--from` named, or `undefined`. */\n readonly openCarrier: (from: string | undefined) => Carrier;\n /** One line of human text. */\n readonly log: (message: string) => void;\n /** A rendered report, verbatim — it brings its own trailing newline. */\n readonly print: (text: string) => void;\n /** One line of diagnosis: a usage error, a refusal's reason, or the version note. */\n readonly error: (message: string) => void;\n}\n\n/** Runs `doctor` once argv has been recognized as that command. Returns the process exit code. */\nfunction runDoctorCommand(rest: readonly string[], deps: CliDeps): number {\n if (rest.includes(\"--help\") || rest.includes(\"-h\")) {\n deps.log(DOCTOR_USAGE);\n return 0;\n }\n const json = rest.includes(\"--json\");\n const unknown = rest.filter((arg) => arg !== \"--json\");\n if (unknown.length > 0) {\n deps.error(`Unknown argument(s) for doctor: ${unknown.join(\", \")}\\n\\n${DOCTOR_USAGE}`);\n return 2;\n }\n const snapshot = deps.buildSnapshot(deps.cwd, deps.env);\n if (!snapshot.rootPackageJson) {\n deps.error(`Could not run: no readable package.json found at ${deps.cwd}`);\n return 2;\n }\n const report = runDoctor(snapshot);\n deps.log(json ? renderJson(report) : renderHuman(report));\n return report.exitCode;\n}\n\n/**\n * What the plan did, or what it would do.\n *\n * @llmNote Both forms come from the library's own `renderPlan`/`renderReport`, so this launcher and\n * any later entry point cannot drift apart on what a dry run shows. A dry run is never applied: the\n * executor refuses one outright, and the exit code is 0 even when something was refused (D12).\n */\nfunction report(plan: InitPlan, parsed: InstallerArguments, deps: CliDeps): number {\n const options = { json: parsed.json };\n if (parsed.options.dryRun) {\n deps.print(renderPlan(plan, options));\n return planExitCode(plan);\n }\n const executed = applyPlan(plan, deps.cwd);\n deps.print(renderReport(executed, options));\n return reportExitCode(executed);\n}\n\n/**\n * The shared ending of both verbs: read the project once, plan, then show or apply.\n *\n * @llmNote A project that cannot be read is exit 1, not 2: the command was typed correctly, it could\n * not do the work. Exit 2 is reserved for a command line nobody could act on.\n */\nfunction runPlan(\n planner: (state: ProjectState) => InitPlan,\n parsed: InstallerArguments,\n deps: CliDeps,\n): number {\n try {\n return report(planner(readProjectState(deps.cwd, deps.env)), parsed, deps);\n } catch (cause) {\n deps.error((cause as Error).message);\n return 1;\n }\n}\n\n/**\n * D4's one line, on stderr: the pages about to land belong to a different release than the project\n * resolves. A note, never a refusal — and never on stdout, which carries the report alone so that\n * `--json` stays parseable and a human still sees this in a terminal.\n */\nfunction noteVersions(carrier: Carrier, state: ProjectState, deps: CliDeps): void {\n const warning = carrierVersionWarning(carrier, state);\n if (warning !== undefined) deps.error(warning);\n}\n\n/**\n * The carrier is opened BEFORE the project is read: a run that cannot find its skills has nothing to\n * plan, and finding that out after walking the project would only delay the same message.\n */\nfunction runInit(parsed: InstallerArguments, deps: CliDeps): number {\n let carrier: Carrier;\n try {\n carrier = deps.openCarrier(parsed.from);\n } catch (cause) {\n deps.error(`${(cause as Error).message}\\n\\n${CARRIER_HINT}`);\n return 1;\n }\n return runPlan(\n (state) => {\n noteVersions(carrier, state, deps);\n return planInstall(state, carrier, parsed.options);\n },\n parsed,\n deps,\n );\n}\n\n/** The two installer verbs: same flags, same output, one plans an install and one its removal. */\nfunction runInstaller(install: boolean, rest: readonly string[], deps: CliDeps): number {\n const parsed = parseInstallerArguments(rest);\n const usage = install ? INIT_USAGE : UNINSTALL_USAGE;\n if (parsed.help) {\n deps.log(usage);\n return 0;\n }\n if (parsed.error !== undefined) {\n deps.error(`${parsed.error}\\n\\n${usage}`);\n return 2;\n }\n return install\n ? runInit(parsed, deps)\n : runPlan((state) => planUninstall(state, parsed.options), parsed, deps);\n}\n\n/** Parses argv and runs the requested command. Returns the process exit code. */\nexport function runCli(argv: string[], deps: CliDeps): number {\n const [verb, ...rest] = argv;\n if (verb === undefined) {\n deps.error(USAGE);\n return 2;\n }\n if (verb === \"--help\" || verb === \"-h\") {\n deps.log(USAGE);\n return 0;\n }\n if (verb === \"doctor\") return runDoctorCommand(rest, deps);\n if (verb === \"init\" || verb === \"uninstall\") {\n return runInstaller(verb === \"init\", rest, deps);\n }\n deps.error(`Unknown command: ${verb}\\n\\n${USAGE}`);\n return 2;\n}\n","// SPDX-License-Identifier: BUSL-1.1\n// Licensed under the Business Source License 1.1 (see LICENSE); Change Date: four years from publication; Change License: Apache-2.0\n// Copyright (c) 2026 Empower Agile\nimport { type InitOptions, initOptions } from \"@narrativetrace/tooling\";\n\n/**\n * What `narrativetrace init` and `narrativetrace uninstall` were asked to do, read out of the\n * arguments that follow the verb and nothing else.\n *\n * INTENT: keeps every flag decision in one pure function, so the verbs themselves stay a handful of\n * lines over the installer library — the shape the `doctor` verb already has.\n *\n * @sideEffects None. A pure function of the argument list.\n */\n\n/** The flags that carry a value, written either `--flag value` or `--flag=value`. */\nconst VALUE_FLAGS = new Set([\"--only\", \"--vendor\", \"--from\"]);\n\n/** One command line, read. */\nexport interface InstallerArguments {\n /** What the installer library was asked for. */\n readonly options: InitOptions;\n /** The carrier a person named, or `undefined` for the usual search order. */\n readonly from: string | undefined;\n /** Whether to print the machine-readable envelope instead of human text. */\n readonly json: boolean;\n /** Whether the verb's usage was asked for. */\n readonly help: boolean;\n /** Why the command line could not be read, or `undefined` when it could. */\n readonly error: string | undefined;\n}\n\n/** One pass over the arguments; mutable so each flag stays one readable line. */\ninterface Reading {\n draft: Partial<InitOptions>;\n from: string | undefined;\n json: boolean;\n help: boolean;\n error: string | undefined;\n}\n\n/**\n * Every flag that carries no value, and what each turns on.\n *\n * @llmNote A `Map`, not an object literal: a table looked up by an ARGUMENT must answer for the names\n * it holds and nothing else. With an object here, `init toString` read as a known switch — accepted,\n * and the install applied — and `init __proto__` crashed with \"turnOn is not a function\", because\n * `Object.prototype` answered both lookups. A `Map` has no prototype chain to inherit from.\n */\nconst SWITCHES = new Map<string, (reading: Reading) => void>([\n [\n \"--dry-run\",\n (reading) => {\n reading.draft.dryRun = true;\n },\n ],\n [\n \"--write-existing\",\n (reading) => {\n reading.draft.writeExisting = true;\n },\n ],\n [\n \"--force\",\n (reading) => {\n reading.draft.force = true;\n },\n ],\n [\n \"--json\",\n (reading) => {\n reading.json = true;\n },\n ],\n [\n \"--help\",\n (reading) => {\n reading.help = true;\n },\n ],\n [\n \"-h\",\n (reading) => {\n reading.help = true;\n },\n ],\n]);\n\n/** The first problem is the one reported: a later flag names one nobody has read yet. */\nfunction fail(reading: Reading, message: string): void {\n reading.error ??= message;\n}\n\nfunction readScope(value: string, reading: Reading): void {\n if (value === \"skills\" || value === \"agents-md\") reading.draft.scope = value;\n else fail(reading, `--only takes skills or agents-md, got \"${value}\"`);\n}\n\nfunction readVendor(value: string, reading: Reading): void {\n if (value === \"claude\") reading.draft.vendorClaude = \"on\";\n else if (value === \"none\") reading.draft.vendorClaude = \"off\";\n else fail(reading, `--vendor takes claude or none, got \"${value}\"`);\n}\n\n/**\n * Why the next argument cannot be this flag's value, or `undefined` when it can.\n *\n * @llmNote A value that reads as the NEXT FLAG is refused rather than taken, which Java's parser does\n * not do. `init --from --dry-run` there means \"install for real, from a carrier called `--dry-run`\" —\n * a misread that APPLIES where the person asked to preview. The escape hatch is the `=` spelling,\n * which says the value out loud.\n */\nfunction nextFlagMessage(name: string, value: string): string {\n return (\n `${name} needs a value, and \"${value}\" reads as the next flag — write ${name}=${value} if it` +\n \" really is the value\"\n );\n}\n\n/**\n * A flag and its value; `false` when the value is unusable, so nothing was consumed and the argument\n * is left for the loop to read as whatever it is.\n *\n * @param spelledOut whether the value came from the `--flag=value` spelling, which says it out loud\n * @llmNote A value that reads as the NEXT FLAG is refused rather than taken, which Java's parser does\n * not do. `init --from --dry-run` there means \"install for real, from a carrier called `--dry-run`\" —\n * a misread that APPLIES where the person asked to preview. The `=` spelling is the escape hatch.\n */\nfunction readValued(\n name: string,\n value: string | undefined,\n spelledOut: boolean,\n reading: Reading,\n): boolean {\n if (value === undefined || value === \"\") {\n fail(reading, `${name} needs a value`);\n return false;\n }\n if (!spelledOut && value.startsWith(\"--\")) {\n fail(reading, nextFlagMessage(name, value));\n return false;\n }\n if (name === \"--only\") readScope(value, reading);\n else if (name === \"--vendor\") readVendor(value, reading);\n else reading.from = value;\n return true;\n}\n\n/** One argument, split at its first `=`: the flag's name, and the value it spelled out, if any. */\ninterface SplitArgument {\n /** Everything before the first `=`, or the whole argument when it carries none. */\n readonly name: string;\n /** Everything after the first `=`, or `undefined` when the argument carries none. */\n readonly spelled: string | undefined;\n}\n\n/**\n * Splits one argument.\n *\n * @llmNote The one place that decides where a name ends, so `--from=/carriers/a=b` keeps every `=`\n * after the first, and the four readings that used to repeat this arithmetic cannot disagree about it.\n */\nfunction splitArgument(argument: string): SplitArgument {\n const equals = argument.indexOf(\"=\");\n return equals < 0\n ? { name: argument, spelled: undefined }\n : { name: argument.slice(0, equals), spelled: argument.slice(equals + 1) };\n}\n\n/**\n * Reads one argument and returns the index of the last one it consumed.\n *\n * @llmNote A switch given a value (`--force=false`) is refused, not read as the switch alone — the\n * other deviation from Java's parser, and the dangerous direction of the same class: there, a person\n * spelling out `--force=false` would be granting exactly the permission they meant to withhold.\n */\nfunction readOne(args: readonly string[], index: number, reading: Reading): number {\n const argument = args[index] as string;\n const { name, spelled } = splitArgument(argument);\n const turnOn = SWITCHES.get(name);\n if (turnOn !== undefined) {\n if (spelled === undefined) turnOn(reading);\n else fail(reading, `${name} takes no value, got \"${argument}\"`);\n return index;\n }\n if (!VALUE_FLAGS.has(name)) {\n fail(reading, `unknown option: \"${argument}\"`);\n return index;\n }\n const valueIndex = spelled === undefined ? index + 1 : index;\n const value = spelled ?? args[valueIndex];\n return readValued(name, value, spelled !== undefined, reading) ? valueIndex : index;\n}\n\n/**\n * Reads the arguments that follow `init` or `uninstall`.\n *\n * @throws {TypeError} when given no argument list at all.\n */\nexport function parseInstallerArguments(args: readonly string[]): InstallerArguments {\n if (args == null) throw new TypeError(\"a command line is a list of arguments, never null\");\n const reading: Reading = {\n draft: {},\n from: undefined,\n json: false,\n help: false,\n error: undefined,\n };\n for (let index = 0; index < args.length; index += 1) index = readOne(args, index, reading);\n return Object.freeze({\n options: initOptions(reading.draft),\n from: reading.from,\n json: reading.json,\n help: reading.help,\n error: reading.error,\n });\n}\n"],"mappings":"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","names":["import_tooling","import_tooling","import_tooling","report"]}
@@ -1 +1,2 @@
1
1
  #!/usr/bin/env node
2
+ import '@narrativetrace/tooling';
package/dist/cli-bin.d.ts CHANGED
@@ -1 +1,2 @@
1
1
  #!/usr/bin/env node
2
+ import '@narrativetrace/tooling';
package/dist/cli-bin.js CHANGED
@@ -1,19 +1,158 @@
1
1
  #!/usr/bin/env node
2
+
3
+ // src/cli-bin.ts
4
+ import { buildSnapshot } from "@narrativetrace/tooling";
5
+
6
+ // src/carrier-locator.ts
7
+ import { dirname } from "path";
8
+ import { fileURLToPath } from "url";
9
+ import { resolveCarrier } from "@narrativetrace/tooling";
10
+ function cliPackageDirectory() {
11
+ return dirname(dirname(fileURLToPath(import.meta.url)));
12
+ }
13
+ function openCarrierFor(projectDirectory, from) {
14
+ return resolveCarrier({ projectDirectory, bundledDirectory: cliPackageDirectory(), from });
15
+ }
16
+
17
+ // src/cli.ts
2
18
  import {
3
- buildSnapshot,
19
+ applyPlan,
20
+ carrierVersionWarning,
21
+ planExitCode,
22
+ planInstall,
23
+ planUninstall,
24
+ readProjectState,
4
25
  renderHuman,
5
26
  renderJson,
27
+ renderPlan,
28
+ renderReport,
29
+ reportExitCode,
6
30
  runDoctor
7
- } from "./chunk-WUK4GWFW.js";
31
+ } from "@narrativetrace/tooling";
32
+
33
+ // src/installer-arguments.ts
34
+ import { initOptions } from "@narrativetrace/tooling";
35
+ var VALUE_FLAGS = /* @__PURE__ */ new Set(["--only", "--vendor", "--from"]);
36
+ var SWITCHES = /* @__PURE__ */ new Map([
37
+ [
38
+ "--dry-run",
39
+ (reading) => {
40
+ reading.draft.dryRun = true;
41
+ }
42
+ ],
43
+ [
44
+ "--write-existing",
45
+ (reading) => {
46
+ reading.draft.writeExisting = true;
47
+ }
48
+ ],
49
+ [
50
+ "--force",
51
+ (reading) => {
52
+ reading.draft.force = true;
53
+ }
54
+ ],
55
+ [
56
+ "--json",
57
+ (reading) => {
58
+ reading.json = true;
59
+ }
60
+ ],
61
+ [
62
+ "--help",
63
+ (reading) => {
64
+ reading.help = true;
65
+ }
66
+ ],
67
+ [
68
+ "-h",
69
+ (reading) => {
70
+ reading.help = true;
71
+ }
72
+ ]
73
+ ]);
74
+ function fail(reading, message) {
75
+ reading.error ??= message;
76
+ }
77
+ function readScope(value, reading) {
78
+ if (value === "skills" || value === "agents-md") reading.draft.scope = value;
79
+ else fail(reading, `--only takes skills or agents-md, got "${value}"`);
80
+ }
81
+ function readVendor(value, reading) {
82
+ if (value === "claude") reading.draft.vendorClaude = "on";
83
+ else if (value === "none") reading.draft.vendorClaude = "off";
84
+ else fail(reading, `--vendor takes claude or none, got "${value}"`);
85
+ }
86
+ function nextFlagMessage(name, value) {
87
+ return `${name} needs a value, and "${value}" reads as the next flag \u2014 write ${name}=${value} if it really is the value`;
88
+ }
89
+ function readValued(name, value, spelledOut, reading) {
90
+ if (value === void 0 || value === "") {
91
+ fail(reading, `${name} needs a value`);
92
+ return false;
93
+ }
94
+ if (!spelledOut && value.startsWith("--")) {
95
+ fail(reading, nextFlagMessage(name, value));
96
+ return false;
97
+ }
98
+ if (name === "--only") readScope(value, reading);
99
+ else if (name === "--vendor") readVendor(value, reading);
100
+ else reading.from = value;
101
+ return true;
102
+ }
103
+ function splitArgument(argument) {
104
+ const equals = argument.indexOf("=");
105
+ return equals < 0 ? { name: argument, spelled: void 0 } : { name: argument.slice(0, equals), spelled: argument.slice(equals + 1) };
106
+ }
107
+ function readOne(args, index, reading) {
108
+ const argument = args[index];
109
+ const { name, spelled } = splitArgument(argument);
110
+ const turnOn = SWITCHES.get(name);
111
+ if (turnOn !== void 0) {
112
+ if (spelled === void 0) turnOn(reading);
113
+ else fail(reading, `${name} takes no value, got "${argument}"`);
114
+ return index;
115
+ }
116
+ if (!VALUE_FLAGS.has(name)) {
117
+ fail(reading, `unknown option: "${argument}"`);
118
+ return index;
119
+ }
120
+ const valueIndex = spelled === void 0 ? index + 1 : index;
121
+ const value = spelled ?? args[valueIndex];
122
+ return readValued(name, value, spelled !== void 0, reading) ? valueIndex : index;
123
+ }
124
+ function parseInstallerArguments(args) {
125
+ if (args == null) throw new TypeError("a command line is a list of arguments, never null");
126
+ const reading = {
127
+ draft: {},
128
+ from: void 0,
129
+ json: false,
130
+ help: false,
131
+ error: void 0
132
+ };
133
+ for (let index = 0; index < args.length; index += 1) index = readOne(args, index, reading);
134
+ return Object.freeze({
135
+ options: initOptions(reading.draft),
136
+ from: reading.from,
137
+ json: reading.json,
138
+ help: reading.help,
139
+ error: reading.error
140
+ });
141
+ }
8
142
 
9
143
  // src/cli.ts
10
144
  var USAGE = `narrativetrace \u2014 one CLI over NarrativeTrace's open artifact formats
11
145
 
12
146
  Usage:
13
147
  narrativetrace doctor [--json]
148
+ narrativetrace init [--dry-run] [--write-existing] [--force] [--only <half>] [--vendor <vendor>]
149
+ [--from <dir>] [--json]
150
+ narrativetrace uninstall [--dry-run] [--only <half>] [--json]
14
151
 
15
152
  Commands:
16
- doctor Read-only project diagnosis: toolchain, configuration, and known traps. Zero network.
153
+ doctor Read-only project diagnosis: toolchain, configuration, and known traps. Zero network.
154
+ init Installs the NarrativeTrace agent skills and the AGENTS.md section into this project.
155
+ uninstall Removes exactly what init wrote, and nothing beside it.
17
156
 
18
157
  Options:
19
158
  --json Machine-readable output instead of human text.
@@ -22,6 +161,43 @@ var DOCTOR_USAGE = `narrativetrace doctor [--json]
22
161
 
23
162
  Read-only. Checks toolchain/install state, configuration, and known traps against the current
24
163
  project. Exit 0 = clean, 1 = findings, 2 = could not run.`;
164
+ var INSTALLER_OPTIONS = ` --dry-run Show the plan and the unified diff. Writes nothing, always exits 0.
165
+ --write-existing Permission to touch an AGENTS.md or CLAUDE.md that is already there.
166
+ --force Permission to overwrite a skill directory somebody else owns.
167
+ --only <half> skills | agents-md. Both halves by default.
168
+ --vendor <vendor> claude | none. Detected from the project by default.
169
+ --from <dir> A directory holding the carrier: a checked-out @narrativetrace/skills, or an
170
+ unpacked tarball of one. The copy bundled with this CLI by default.
171
+ --json Machine-readable output instead of human text.
172
+
173
+ Exit 0 = applied (or a dry run), 1 = something was refused, 2 = could not run.`;
174
+ var INIT_USAGE = `narrativetrace init [options]
175
+
176
+ Copies the NarrativeTrace agent skills into .agents/skills/ (and .claude/skills/ where the project
177
+ is one of that vendor's) and writes one marked section into AGENTS.md. Zero network.
178
+
179
+ Run it again to refresh: this CLI installs no build hook and schedules nothing, so a re-run IS the
180
+ refresh. On a project that already carries the skills it rewrites only our own pages and our own
181
+ marked section, and leaves everything else where it is.
182
+
183
+ ${INSTALLER_OPTIONS}`;
184
+ var UNINSTALL_OPTIONS = ` --dry-run Show the plan and the unified diff. Removes nothing, always exits 0.
185
+ --only <half> skills | agents-md. Both halves by default.
186
+ --json Machine-readable output instead of human text.
187
+
188
+ The install-only flags (--write-existing, --force, --vendor, --from) are accepted and ignored: there
189
+ is no carrier to open and no permission to ask for when removing what this tool itself wrote.
190
+
191
+ Exit 0 = removed (or a dry run), 1 = something was refused, 2 = could not run.`;
192
+ var UNINSTALL_USAGE = `narrativetrace uninstall [options]
193
+
194
+ Removes exactly what init wrote: skill directories carrying its provenance line, the marked
195
+ section, and the one @AGENTS.md import line. Never touches anything else.
196
+
197
+ ${UNINSTALL_OPTIONS}`;
198
+ var CARRIER_HINT = `Nothing was fetched: this command makes no network call. Point --from at a carrier you have:
199
+ --from node_modules/@narrativetrace/skills
200
+ npm pack @narrativetrace/skills && tar xzf narrativetrace-skills-*.tgz && narrativetrace init --from package`;
25
201
  function runDoctorCommand(rest, deps) {
26
202
  if (rest.includes("--help") || rest.includes("-h")) {
27
203
  deps.log(DOCTOR_USAGE);
@@ -40,9 +216,65 @@ ${DOCTOR_USAGE}`);
40
216
  deps.error(`Could not run: no readable package.json found at ${deps.cwd}`);
41
217
  return 2;
42
218
  }
43
- const report = runDoctor(snapshot);
44
- deps.log(json ? renderJson(report) : renderHuman(report));
45
- return report.exitCode;
219
+ const report2 = runDoctor(snapshot);
220
+ deps.log(json ? renderJson(report2) : renderHuman(report2));
221
+ return report2.exitCode;
222
+ }
223
+ function report(plan, parsed, deps) {
224
+ const options = { json: parsed.json };
225
+ if (parsed.options.dryRun) {
226
+ deps.print(renderPlan(plan, options));
227
+ return planExitCode(plan);
228
+ }
229
+ const executed = applyPlan(plan, deps.cwd);
230
+ deps.print(renderReport(executed, options));
231
+ return reportExitCode(executed);
232
+ }
233
+ function runPlan(planner, parsed, deps) {
234
+ try {
235
+ return report(planner(readProjectState(deps.cwd, deps.env)), parsed, deps);
236
+ } catch (cause) {
237
+ deps.error(cause.message);
238
+ return 1;
239
+ }
240
+ }
241
+ function noteVersions(carrier, state, deps) {
242
+ const warning = carrierVersionWarning(carrier, state);
243
+ if (warning !== void 0) deps.error(warning);
244
+ }
245
+ function runInit(parsed, deps) {
246
+ let carrier;
247
+ try {
248
+ carrier = deps.openCarrier(parsed.from);
249
+ } catch (cause) {
250
+ deps.error(`${cause.message}
251
+
252
+ ${CARRIER_HINT}`);
253
+ return 1;
254
+ }
255
+ return runPlan(
256
+ (state) => {
257
+ noteVersions(carrier, state, deps);
258
+ return planInstall(state, carrier, parsed.options);
259
+ },
260
+ parsed,
261
+ deps
262
+ );
263
+ }
264
+ function runInstaller(install, rest, deps) {
265
+ const parsed = parseInstallerArguments(rest);
266
+ const usage = install ? INIT_USAGE : UNINSTALL_USAGE;
267
+ if (parsed.help) {
268
+ deps.log(usage);
269
+ return 0;
270
+ }
271
+ if (parsed.error !== void 0) {
272
+ deps.error(`${parsed.error}
273
+
274
+ ${usage}`);
275
+ return 2;
276
+ }
277
+ return install ? runInit(parsed, deps) : runPlan((state) => planUninstall(state, parsed.options), parsed, deps);
46
278
  }
47
279
  function runCli(argv, deps) {
48
280
  const [verb, ...rest] = argv;
@@ -54,22 +286,26 @@ function runCli(argv, deps) {
54
286
  deps.log(USAGE);
55
287
  return 0;
56
288
  }
57
- if (verb !== "doctor") {
58
- deps.error(`Unknown command: ${verb}
289
+ if (verb === "doctor") return runDoctorCommand(rest, deps);
290
+ if (verb === "init" || verb === "uninstall") {
291
+ return runInstaller(verb === "init", rest, deps);
292
+ }
293
+ deps.error(`Unknown command: ${verb}
59
294
 
60
295
  ${USAGE}`);
61
- return 2;
62
- }
63
- return runDoctorCommand(rest, deps);
296
+ return 2;
64
297
  }
65
298
 
66
299
  // src/cli-bin.ts
300
+ var cwd = process.cwd();
67
301
  var exitCode = runCli(process.argv.slice(2), {
68
- cwd: process.cwd(),
302
+ cwd,
69
303
  env: process.env,
70
- buildSnapshot,
304
+ buildSnapshot: (c, e) => buildSnapshot(c, e, cliPackageDirectory()),
305
+ openCarrier: (from) => openCarrierFor(cwd, from),
71
306
  log: (message) => process.stdout.write(`${message}
72
307
  `),
308
+ print: (text) => process.stdout.write(text),
73
309
  error: (message) => process.stderr.write(`${message}
74
310
  `)
75
311
  });
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cli.ts","../src/cli-bin.ts"],"sourcesContent":["// SPDX-License-Identifier: BUSL-1.1\n// Licensed under the Business Source License 1.1 (see LICENSE); Change Date: four years from publication; Change License: Apache-2.0\n// Copyright (c) 2026 Empower Agile\nimport { runDoctor } from \"./doctor/doctor.js\";\nimport { renderHuman, renderJson } from \"./doctor/render.js\";\nimport type { DoctorSnapshot, Env } from \"./doctor/types.js\";\n\nconst USAGE = `narrativetrace — one CLI over NarrativeTrace's open artifact formats\n\nUsage:\n narrativetrace doctor [--json]\n\nCommands:\n doctor Read-only project diagnosis: toolchain, configuration, and known traps. Zero network.\n\nOptions:\n --json Machine-readable output instead of human text.\n --help Show this message.`;\n\nconst DOCTOR_USAGE = `narrativetrace doctor [--json]\n\nRead-only. Checks toolchain/install state, configuration, and known traps against the current\nproject. Exit 0 = clean, 1 = findings, 2 = could not run.`;\n\nexport interface CliDeps {\n readonly cwd: string;\n readonly env: Env;\n readonly buildSnapshot: (cwd: string, env: Env) => DoctorSnapshot;\n readonly log: (message: string) => void;\n readonly error: (message: string) => void;\n}\n\n/** Runs `doctor` once argv has been recognized as that command. Returns the process exit code. */\nfunction runDoctorCommand(rest: readonly string[], deps: CliDeps): number {\n if (rest.includes(\"--help\") || rest.includes(\"-h\")) {\n deps.log(DOCTOR_USAGE);\n return 0;\n }\n const json = rest.includes(\"--json\");\n const unknown = rest.filter((arg) => arg !== \"--json\");\n if (unknown.length > 0) {\n deps.error(`Unknown argument(s) for doctor: ${unknown.join(\", \")}\\n\\n${DOCTOR_USAGE}`);\n return 2;\n }\n const snapshot = deps.buildSnapshot(deps.cwd, deps.env);\n if (!snapshot.rootPackageJson) {\n deps.error(`Could not run: no readable package.json found at ${deps.cwd}`);\n return 2;\n }\n const report = runDoctor(snapshot);\n deps.log(json ? renderJson(report) : renderHuman(report));\n return report.exitCode;\n}\n\n/** Parses argv and runs the requested command. Returns the process exit code. */\nexport function runCli(argv: string[], deps: CliDeps): number {\n const [verb, ...rest] = argv;\n if (verb === undefined) {\n deps.error(USAGE);\n return 2;\n }\n if (verb === \"--help\" || verb === \"-h\") {\n deps.log(USAGE);\n return 0;\n }\n if (verb !== \"doctor\") {\n deps.error(`Unknown command: ${verb}\\n\\n${USAGE}`);\n return 2;\n }\n return runDoctorCommand(rest, deps);\n}\n","#!/usr/bin/env node\n// SPDX-License-Identifier: BUSL-1.1\n// Licensed under the Business Source License 1.1 (see LICENSE); Change Date: four years from publication; Change License: Apache-2.0\n// Copyright (c) 2026 Empower Agile\nimport { runCli } from \"./cli.js\";\nimport { buildSnapshot } from \"./doctor/environment.js\";\n\nconst exitCode = runCli(process.argv.slice(2), {\n cwd: process.cwd(),\n env: process.env,\n buildSnapshot,\n log: (message) => process.stdout.write(`${message}\\n`),\n error: (message) => process.stderr.write(`${message}\\n`),\n});\n\nprocess.exit(exitCode);\n"],"mappings":";;;;;;;;;AAOA,IAAM,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAYd,IAAM,eAAe;AAAA;AAAA;AAAA;AAcrB,SAAS,iBAAiB,MAAyB,MAAuB;AACxE,MAAI,KAAK,SAAS,QAAQ,KAAK,KAAK,SAAS,IAAI,GAAG;AAClD,SAAK,IAAI,YAAY;AACrB,WAAO;AAAA,EACT;AACA,QAAM,OAAO,KAAK,SAAS,QAAQ;AACnC,QAAM,UAAU,KAAK,OAAO,CAAC,QAAQ,QAAQ,QAAQ;AACrD,MAAI,QAAQ,SAAS,GAAG;AACtB,SAAK,MAAM,mCAAmC,QAAQ,KAAK,IAAI,CAAC;AAAA;AAAA,EAAO,YAAY,EAAE;AACrF,WAAO;AAAA,EACT;AACA,QAAM,WAAW,KAAK,cAAc,KAAK,KAAK,KAAK,GAAG;AACtD,MAAI,CAAC,SAAS,iBAAiB;AAC7B,SAAK,MAAM,oDAAoD,KAAK,GAAG,EAAE;AACzE,WAAO;AAAA,EACT;AACA,QAAM,SAAS,UAAU,QAAQ;AACjC,OAAK,IAAI,OAAO,WAAW,MAAM,IAAI,YAAY,MAAM,CAAC;AACxD,SAAO,OAAO;AAChB;AAGO,SAAS,OAAO,MAAgB,MAAuB;AAC5D,QAAM,CAAC,MAAM,GAAG,IAAI,IAAI;AACxB,MAAI,SAAS,QAAW;AACtB,SAAK,MAAM,KAAK;AAChB,WAAO;AAAA,EACT;AACA,MAAI,SAAS,YAAY,SAAS,MAAM;AACtC,SAAK,IAAI,KAAK;AACd,WAAO;AAAA,EACT;AACA,MAAI,SAAS,UAAU;AACrB,SAAK,MAAM,oBAAoB,IAAI;AAAA;AAAA,EAAO,KAAK,EAAE;AACjD,WAAO;AAAA,EACT;AACA,SAAO,iBAAiB,MAAM,IAAI;AACpC;;;AC/DA,IAAM,WAAW,OAAO,QAAQ,KAAK,MAAM,CAAC,GAAG;AAAA,EAC7C,KAAK,QAAQ,IAAI;AAAA,EACjB,KAAK,QAAQ;AAAA,EACb;AAAA,EACA,KAAK,CAAC,YAAY,QAAQ,OAAO,MAAM,GAAG,OAAO;AAAA,CAAI;AAAA,EACrD,OAAO,CAAC,YAAY,QAAQ,OAAO,MAAM,GAAG,OAAO;AAAA,CAAI;AACzD,CAAC;AAED,QAAQ,KAAK,QAAQ;","names":[]}
1
+ {"version":3,"sources":["../src/cli-bin.ts","../src/carrier-locator.ts","../src/cli.ts","../src/installer-arguments.ts"],"sourcesContent":["#!/usr/bin/env node\n// SPDX-License-Identifier: BUSL-1.1\n// Licensed under the Business Source License 1.1 (see LICENSE); Change Date: four years from publication; Change License: Apache-2.0\n// Copyright (c) 2026 Empower Agile\nimport { buildSnapshot } from \"@narrativetrace/tooling\";\nimport { cliPackageDirectory, openCarrierFor } from \"./carrier-locator.js\";\nimport { runCli } from \"./cli.js\";\n\nconst cwd = process.cwd();\n\nconst exitCode = runCli(process.argv.slice(2), {\n cwd,\n env: process.env,\n buildSnapshot: (c, e) => buildSnapshot(c, e, cliPackageDirectory()),\n openCarrier: (from) => openCarrierFor(cwd, from),\n log: (message) => process.stdout.write(`${message}\\n`),\n print: (text) => process.stdout.write(text),\n error: (message) => process.stderr.write(`${message}\\n`),\n});\n\nprocess.exit(exitCode);\n","// SPDX-License-Identifier: BUSL-1.1\n// Licensed under the Business Source License 1.1 (see LICENSE); Change Date: four years from publication; Change License: Apache-2.0\n// Copyright (c) 2026 Empower Agile\nimport { dirname } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { type Carrier, resolveCarrier } from \"@narrativetrace/tooling\";\n\n/**\n * Where this launcher looks for the skills carrier it installs from.\n *\n * INTENT: one place knows that the running CLI bundles a copy of the carrier, and where. Everything\n * else about resolution — the order of the homes, what makes a carrier valid — belongs to\n * `@narrativetrace/tooling`'s `resolveCarrier`, so both entry points can never disagree about it.\n *\n * @llmNote Zero network, by construction: the three homes are a path a person named, the project's own\n * `node_modules`, and this package's own directory. D4 rules the npm cache unreadable, so `--from`\n * takes a path and a coordinate is never looked up.\n *\n * @sideEffects Reads the carrier's files once, through `resolveCarrier`.\n */\n\n/**\n * This CLI package's own root — the directory whose `skills/` holds the carrier it bundles.\n *\n * @llmNote Derived from this module's own location, which is one directory below the package root in\n * BOTH layouts this code runs in: `src/` under vitest, and `dist/` in the published package. A\n * `process.argv[1]`-based answer would be wrong under the bin shim, and a `process.cwd()`-based one\n * would be the consumer's project.\n */\nexport function cliPackageDirectory(): string {\n return dirname(dirname(fileURLToPath(import.meta.url)));\n}\n\n/**\n * Opens the carrier for one run: `--from` when a path was given, else the `@narrativetrace/skills` the\n * PROJECT resolves, else the copy this CLI bundles.\n *\n * @param projectDirectory the consumer project the install is for\n * @param from the directory a person named with `--from`, or `undefined`\n * @throws {TypeError} when the named path holds no carrier, or when no home does.\n */\nexport function openCarrierFor(projectDirectory: string, from: string | undefined): Carrier {\n return resolveCarrier({ projectDirectory, bundledDirectory: cliPackageDirectory(), from });\n}\n","// SPDX-License-Identifier: BUSL-1.1\n// Licensed under the Business Source License 1.1 (see LICENSE); Change Date: four years from publication; Change License: Apache-2.0\n// Copyright (c) 2026 Empower Agile\nimport {\n applyPlan,\n type Carrier,\n carrierVersionWarning,\n type DoctorSnapshot,\n type Env,\n type InitPlan,\n type ProjectState,\n planExitCode,\n planInstall,\n planUninstall,\n readProjectState,\n renderHuman,\n renderJson,\n renderPlan,\n renderReport,\n reportExitCode,\n runDoctor,\n} from \"@narrativetrace/tooling\";\nimport { type InstallerArguments, parseInstallerArguments } from \"./installer-arguments.js\";\n\nconst USAGE = `narrativetrace — one CLI over NarrativeTrace's open artifact formats\n\nUsage:\n narrativetrace doctor [--json]\n narrativetrace init [--dry-run] [--write-existing] [--force] [--only <half>] [--vendor <vendor>]\n [--from <dir>] [--json]\n narrativetrace uninstall [--dry-run] [--only <half>] [--json]\n\nCommands:\n doctor Read-only project diagnosis: toolchain, configuration, and known traps. Zero network.\n init Installs the NarrativeTrace agent skills and the AGENTS.md section into this project.\n uninstall Removes exactly what init wrote, and nothing beside it.\n\nOptions:\n --json Machine-readable output instead of human text.\n --help Show this message.`;\n\nconst DOCTOR_USAGE = `narrativetrace doctor [--json]\n\nRead-only. Checks toolchain/install state, configuration, and known traps against the current\nproject. Exit 0 = clean, 1 = findings, 2 = could not run.`;\n\nconst INSTALLER_OPTIONS = ` --dry-run Show the plan and the unified diff. Writes nothing, always exits 0.\n --write-existing Permission to touch an AGENTS.md or CLAUDE.md that is already there.\n --force Permission to overwrite a skill directory somebody else owns.\n --only <half> skills | agents-md. Both halves by default.\n --vendor <vendor> claude | none. Detected from the project by default.\n --from <dir> A directory holding the carrier: a checked-out @narrativetrace/skills, or an\n unpacked tarball of one. The copy bundled with this CLI by default.\n --json Machine-readable output instead of human text.\n\nExit 0 = applied (or a dry run), 1 = something was refused, 2 = could not run.`;\n\nconst INIT_USAGE = `narrativetrace init [options]\n\nCopies the NarrativeTrace agent skills into .agents/skills/ (and .claude/skills/ where the project\nis one of that vendor's) and writes one marked section into AGENTS.md. Zero network.\n\nRun it again to refresh: this CLI installs no build hook and schedules nothing, so a re-run IS the\nrefresh. On a project that already carries the skills it rewrites only our own pages and our own\nmarked section, and leaves everything else where it is.\n\n${INSTALLER_OPTIONS}`;\n\n/**\n * Only the three flags an uninstall uses, plus one line about the rest.\n *\n * @llmNote Java's uninstall help prints the install-only flags too, which makes its own help untrue\n * about `--force` and `--from`. The parser is still shared — one flag reader for both verbs — so the\n * flags stay ACCEPTED; they are simply not advertised where they do nothing.\n */\nconst UNINSTALL_OPTIONS = ` --dry-run Show the plan and the unified diff. Removes nothing, always exits 0.\n --only <half> skills | agents-md. Both halves by default.\n --json Machine-readable output instead of human text.\n\nThe install-only flags (--write-existing, --force, --vendor, --from) are accepted and ignored: there\nis no carrier to open and no permission to ask for when removing what this tool itself wrote.\n\nExit 0 = removed (or a dry run), 1 = something was refused, 2 = could not run.`;\n\nconst UNINSTALL_USAGE = `narrativetrace uninstall [options]\n\nRemoves exactly what init wrote: skill directories carrying its provenance line, the marked\nsection, and the one @AGENTS.md import line. Never touches anything else.\n\n${UNINSTALL_OPTIONS}`;\n\n/** What to type when no carrier could be opened — this CLI never fetches one. */\nconst CARRIER_HINT = `Nothing was fetched: this command makes no network call. Point --from at a carrier you have:\n --from node_modules/@narrativetrace/skills\n npm pack @narrativetrace/skills && tar xzf narrativetrace-skills-*.tgz && narrativetrace init --from package`;\n\n/** Everything the launcher reads from the outside world, injectable for hermetic tests. */\nexport interface CliDeps {\n readonly cwd: string;\n readonly env: Env;\n readonly buildSnapshot: (cwd: string, env: Env) => DoctorSnapshot;\n /** Opens the carrier a run installs from; `from` is whatever `--from` named, or `undefined`. */\n readonly openCarrier: (from: string | undefined) => Carrier;\n /** One line of human text. */\n readonly log: (message: string) => void;\n /** A rendered report, verbatim — it brings its own trailing newline. */\n readonly print: (text: string) => void;\n /** One line of diagnosis: a usage error, a refusal's reason, or the version note. */\n readonly error: (message: string) => void;\n}\n\n/** Runs `doctor` once argv has been recognized as that command. Returns the process exit code. */\nfunction runDoctorCommand(rest: readonly string[], deps: CliDeps): number {\n if (rest.includes(\"--help\") || rest.includes(\"-h\")) {\n deps.log(DOCTOR_USAGE);\n return 0;\n }\n const json = rest.includes(\"--json\");\n const unknown = rest.filter((arg) => arg !== \"--json\");\n if (unknown.length > 0) {\n deps.error(`Unknown argument(s) for doctor: ${unknown.join(\", \")}\\n\\n${DOCTOR_USAGE}`);\n return 2;\n }\n const snapshot = deps.buildSnapshot(deps.cwd, deps.env);\n if (!snapshot.rootPackageJson) {\n deps.error(`Could not run: no readable package.json found at ${deps.cwd}`);\n return 2;\n }\n const report = runDoctor(snapshot);\n deps.log(json ? renderJson(report) : renderHuman(report));\n return report.exitCode;\n}\n\n/**\n * What the plan did, or what it would do.\n *\n * @llmNote Both forms come from the library's own `renderPlan`/`renderReport`, so this launcher and\n * any later entry point cannot drift apart on what a dry run shows. A dry run is never applied: the\n * executor refuses one outright, and the exit code is 0 even when something was refused (D12).\n */\nfunction report(plan: InitPlan, parsed: InstallerArguments, deps: CliDeps): number {\n const options = { json: parsed.json };\n if (parsed.options.dryRun) {\n deps.print(renderPlan(plan, options));\n return planExitCode(plan);\n }\n const executed = applyPlan(plan, deps.cwd);\n deps.print(renderReport(executed, options));\n return reportExitCode(executed);\n}\n\n/**\n * The shared ending of both verbs: read the project once, plan, then show or apply.\n *\n * @llmNote A project that cannot be read is exit 1, not 2: the command was typed correctly, it could\n * not do the work. Exit 2 is reserved for a command line nobody could act on.\n */\nfunction runPlan(\n planner: (state: ProjectState) => InitPlan,\n parsed: InstallerArguments,\n deps: CliDeps,\n): number {\n try {\n return report(planner(readProjectState(deps.cwd, deps.env)), parsed, deps);\n } catch (cause) {\n deps.error((cause as Error).message);\n return 1;\n }\n}\n\n/**\n * D4's one line, on stderr: the pages about to land belong to a different release than the project\n * resolves. A note, never a refusal — and never on stdout, which carries the report alone so that\n * `--json` stays parseable and a human still sees this in a terminal.\n */\nfunction noteVersions(carrier: Carrier, state: ProjectState, deps: CliDeps): void {\n const warning = carrierVersionWarning(carrier, state);\n if (warning !== undefined) deps.error(warning);\n}\n\n/**\n * The carrier is opened BEFORE the project is read: a run that cannot find its skills has nothing to\n * plan, and finding that out after walking the project would only delay the same message.\n */\nfunction runInit(parsed: InstallerArguments, deps: CliDeps): number {\n let carrier: Carrier;\n try {\n carrier = deps.openCarrier(parsed.from);\n } catch (cause) {\n deps.error(`${(cause as Error).message}\\n\\n${CARRIER_HINT}`);\n return 1;\n }\n return runPlan(\n (state) => {\n noteVersions(carrier, state, deps);\n return planInstall(state, carrier, parsed.options);\n },\n parsed,\n deps,\n );\n}\n\n/** The two installer verbs: same flags, same output, one plans an install and one its removal. */\nfunction runInstaller(install: boolean, rest: readonly string[], deps: CliDeps): number {\n const parsed = parseInstallerArguments(rest);\n const usage = install ? INIT_USAGE : UNINSTALL_USAGE;\n if (parsed.help) {\n deps.log(usage);\n return 0;\n }\n if (parsed.error !== undefined) {\n deps.error(`${parsed.error}\\n\\n${usage}`);\n return 2;\n }\n return install\n ? runInit(parsed, deps)\n : runPlan((state) => planUninstall(state, parsed.options), parsed, deps);\n}\n\n/** Parses argv and runs the requested command. Returns the process exit code. */\nexport function runCli(argv: string[], deps: CliDeps): number {\n const [verb, ...rest] = argv;\n if (verb === undefined) {\n deps.error(USAGE);\n return 2;\n }\n if (verb === \"--help\" || verb === \"-h\") {\n deps.log(USAGE);\n return 0;\n }\n if (verb === \"doctor\") return runDoctorCommand(rest, deps);\n if (verb === \"init\" || verb === \"uninstall\") {\n return runInstaller(verb === \"init\", rest, deps);\n }\n deps.error(`Unknown command: ${verb}\\n\\n${USAGE}`);\n return 2;\n}\n","// SPDX-License-Identifier: BUSL-1.1\n// Licensed under the Business Source License 1.1 (see LICENSE); Change Date: four years from publication; Change License: Apache-2.0\n// Copyright (c) 2026 Empower Agile\nimport { type InitOptions, initOptions } from \"@narrativetrace/tooling\";\n\n/**\n * What `narrativetrace init` and `narrativetrace uninstall` were asked to do, read out of the\n * arguments that follow the verb and nothing else.\n *\n * INTENT: keeps every flag decision in one pure function, so the verbs themselves stay a handful of\n * lines over the installer library — the shape the `doctor` verb already has.\n *\n * @sideEffects None. A pure function of the argument list.\n */\n\n/** The flags that carry a value, written either `--flag value` or `--flag=value`. */\nconst VALUE_FLAGS = new Set([\"--only\", \"--vendor\", \"--from\"]);\n\n/** One command line, read. */\nexport interface InstallerArguments {\n /** What the installer library was asked for. */\n readonly options: InitOptions;\n /** The carrier a person named, or `undefined` for the usual search order. */\n readonly from: string | undefined;\n /** Whether to print the machine-readable envelope instead of human text. */\n readonly json: boolean;\n /** Whether the verb's usage was asked for. */\n readonly help: boolean;\n /** Why the command line could not be read, or `undefined` when it could. */\n readonly error: string | undefined;\n}\n\n/** One pass over the arguments; mutable so each flag stays one readable line. */\ninterface Reading {\n draft: Partial<InitOptions>;\n from: string | undefined;\n json: boolean;\n help: boolean;\n error: string | undefined;\n}\n\n/**\n * Every flag that carries no value, and what each turns on.\n *\n * @llmNote A `Map`, not an object literal: a table looked up by an ARGUMENT must answer for the names\n * it holds and nothing else. With an object here, `init toString` read as a known switch — accepted,\n * and the install applied — and `init __proto__` crashed with \"turnOn is not a function\", because\n * `Object.prototype` answered both lookups. A `Map` has no prototype chain to inherit from.\n */\nconst SWITCHES = new Map<string, (reading: Reading) => void>([\n [\n \"--dry-run\",\n (reading) => {\n reading.draft.dryRun = true;\n },\n ],\n [\n \"--write-existing\",\n (reading) => {\n reading.draft.writeExisting = true;\n },\n ],\n [\n \"--force\",\n (reading) => {\n reading.draft.force = true;\n },\n ],\n [\n \"--json\",\n (reading) => {\n reading.json = true;\n },\n ],\n [\n \"--help\",\n (reading) => {\n reading.help = true;\n },\n ],\n [\n \"-h\",\n (reading) => {\n reading.help = true;\n },\n ],\n]);\n\n/** The first problem is the one reported: a later flag names one nobody has read yet. */\nfunction fail(reading: Reading, message: string): void {\n reading.error ??= message;\n}\n\nfunction readScope(value: string, reading: Reading): void {\n if (value === \"skills\" || value === \"agents-md\") reading.draft.scope = value;\n else fail(reading, `--only takes skills or agents-md, got \"${value}\"`);\n}\n\nfunction readVendor(value: string, reading: Reading): void {\n if (value === \"claude\") reading.draft.vendorClaude = \"on\";\n else if (value === \"none\") reading.draft.vendorClaude = \"off\";\n else fail(reading, `--vendor takes claude or none, got \"${value}\"`);\n}\n\n/**\n * Why the next argument cannot be this flag's value, or `undefined` when it can.\n *\n * @llmNote A value that reads as the NEXT FLAG is refused rather than taken, which Java's parser does\n * not do. `init --from --dry-run` there means \"install for real, from a carrier called `--dry-run`\" —\n * a misread that APPLIES where the person asked to preview. The escape hatch is the `=` spelling,\n * which says the value out loud.\n */\nfunction nextFlagMessage(name: string, value: string): string {\n return (\n `${name} needs a value, and \"${value}\" reads as the next flag — write ${name}=${value} if it` +\n \" really is the value\"\n );\n}\n\n/**\n * A flag and its value; `false` when the value is unusable, so nothing was consumed and the argument\n * is left for the loop to read as whatever it is.\n *\n * @param spelledOut whether the value came from the `--flag=value` spelling, which says it out loud\n * @llmNote A value that reads as the NEXT FLAG is refused rather than taken, which Java's parser does\n * not do. `init --from --dry-run` there means \"install for real, from a carrier called `--dry-run`\" —\n * a misread that APPLIES where the person asked to preview. The `=` spelling is the escape hatch.\n */\nfunction readValued(\n name: string,\n value: string | undefined,\n spelledOut: boolean,\n reading: Reading,\n): boolean {\n if (value === undefined || value === \"\") {\n fail(reading, `${name} needs a value`);\n return false;\n }\n if (!spelledOut && value.startsWith(\"--\")) {\n fail(reading, nextFlagMessage(name, value));\n return false;\n }\n if (name === \"--only\") readScope(value, reading);\n else if (name === \"--vendor\") readVendor(value, reading);\n else reading.from = value;\n return true;\n}\n\n/** One argument, split at its first `=`: the flag's name, and the value it spelled out, if any. */\ninterface SplitArgument {\n /** Everything before the first `=`, or the whole argument when it carries none. */\n readonly name: string;\n /** Everything after the first `=`, or `undefined` when the argument carries none. */\n readonly spelled: string | undefined;\n}\n\n/**\n * Splits one argument.\n *\n * @llmNote The one place that decides where a name ends, so `--from=/carriers/a=b` keeps every `=`\n * after the first, and the four readings that used to repeat this arithmetic cannot disagree about it.\n */\nfunction splitArgument(argument: string): SplitArgument {\n const equals = argument.indexOf(\"=\");\n return equals < 0\n ? { name: argument, spelled: undefined }\n : { name: argument.slice(0, equals), spelled: argument.slice(equals + 1) };\n}\n\n/**\n * Reads one argument and returns the index of the last one it consumed.\n *\n * @llmNote A switch given a value (`--force=false`) is refused, not read as the switch alone — the\n * other deviation from Java's parser, and the dangerous direction of the same class: there, a person\n * spelling out `--force=false` would be granting exactly the permission they meant to withhold.\n */\nfunction readOne(args: readonly string[], index: number, reading: Reading): number {\n const argument = args[index] as string;\n const { name, spelled } = splitArgument(argument);\n const turnOn = SWITCHES.get(name);\n if (turnOn !== undefined) {\n if (spelled === undefined) turnOn(reading);\n else fail(reading, `${name} takes no value, got \"${argument}\"`);\n return index;\n }\n if (!VALUE_FLAGS.has(name)) {\n fail(reading, `unknown option: \"${argument}\"`);\n return index;\n }\n const valueIndex = spelled === undefined ? index + 1 : index;\n const value = spelled ?? args[valueIndex];\n return readValued(name, value, spelled !== undefined, reading) ? valueIndex : index;\n}\n\n/**\n * Reads the arguments that follow `init` or `uninstall`.\n *\n * @throws {TypeError} when given no argument list at all.\n */\nexport function parseInstallerArguments(args: readonly string[]): InstallerArguments {\n if (args == null) throw new TypeError(\"a command line is a list of arguments, never null\");\n const reading: Reading = {\n draft: {},\n from: undefined,\n json: false,\n help: false,\n error: undefined,\n };\n for (let index = 0; index < args.length; index += 1) index = readOne(args, index, reading);\n return Object.freeze({\n options: initOptions(reading.draft),\n from: reading.from,\n json: reading.json,\n help: reading.help,\n error: reading.error,\n });\n}\n"],"mappings":"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","names":["report"]}