@lsctech/polaris 0.1.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.
Files changed (316) hide show
  1. package/README.md +87 -0
  2. package/dist/__mocks__/tool-server-linear.js +34 -0
  3. package/dist/cli/adopt-approve.js +60 -0
  4. package/dist/cli/adopt-cognition.js +199 -0
  5. package/dist/cli/adopt-instructions.js +143 -0
  6. package/dist/cli/adopt-rules.js +169 -0
  7. package/dist/cli/adopt-scan.js +25 -0
  8. package/dist/cli/adopt-smartdocs.js +192 -0
  9. package/dist/cli/adoption-inventory.js +350 -0
  10. package/dist/cli/adoption-plan.js +222 -0
  11. package/dist/cli/args.js +28 -0
  12. package/dist/cli/args.test.js +30 -0
  13. package/dist/cli/branding.js +41 -0
  14. package/dist/cli/graph.js +358 -0
  15. package/dist/cli/index.js +127 -0
  16. package/dist/cli/index.test.js +162 -0
  17. package/dist/cli/init-detect.js +61 -0
  18. package/dist/cli/init.js +492 -0
  19. package/dist/cli/init.test.js +259 -0
  20. package/dist/cli/librarian.js +32 -0
  21. package/dist/cli/medic.js +96 -0
  22. package/dist/cli/startup.test.js +23 -0
  23. package/dist/cli/tracker.js +130 -0
  24. package/dist/cli/tracker.test.js +126 -0
  25. package/dist/cli/version.js +10 -0
  26. package/dist/cli/version.test.js +11 -0
  27. package/dist/cli/worker.js +287 -0
  28. package/dist/cluster-state/fixtures/test-clusters.json +19 -0
  29. package/dist/cluster-state/store.js +302 -0
  30. package/dist/cluster-state/store.test.js +145 -0
  31. package/dist/cluster-state/types.js +2 -0
  32. package/dist/cognition/archive.js +158 -0
  33. package/dist/cognition/closeout-librarian-types.js +161 -0
  34. package/dist/cognition/cognition.test.js +623 -0
  35. package/dist/cognition/index.js +41 -0
  36. package/dist/cognition/librarian-dispatch.js +391 -0
  37. package/dist/cognition/librarian-dispatch.test.js +247 -0
  38. package/dist/cognition/librarian-packet.js +313 -0
  39. package/dist/cognition/librarian-types.js +57 -0
  40. package/dist/cognition/route-cognition-delta.js +350 -0
  41. package/dist/cognition/summary-delta.js +279 -0
  42. package/dist/cognition/validate.js +162 -0
  43. package/dist/config/defaults.js +98 -0
  44. package/dist/config/doctor.js +273 -0
  45. package/dist/config/index.js +14 -0
  46. package/dist/config/loader.js +58 -0
  47. package/dist/config/provider-detect.js +60 -0
  48. package/dist/config/provider-detect.test.js +119 -0
  49. package/dist/config/schema.js +2 -0
  50. package/dist/config/show.js +44 -0
  51. package/dist/config/show.test.js +42 -0
  52. package/dist/config/validator.js +675 -0
  53. package/dist/config/validator.test.js +77 -0
  54. package/dist/docs/canon-check.js +334 -0
  55. package/dist/docs/canon-check.test.js +207 -0
  56. package/dist/docs/doctrine.js +133 -0
  57. package/dist/docs/doctrine.test.js +139 -0
  58. package/dist/docs/index.js +168 -0
  59. package/dist/docs/index.test.js +83 -0
  60. package/dist/docs/ingest.js +295 -0
  61. package/dist/docs/ingest.test.js +71 -0
  62. package/dist/docs/migrate.js +165 -0
  63. package/dist/docs/migrate.test.js +136 -0
  64. package/dist/docs/seed-instructions.js +147 -0
  65. package/dist/docs/seed-instructions.test.js +137 -0
  66. package/dist/docs/validate-instructions.js +267 -0
  67. package/dist/docs/validate-instructions.test.js +238 -0
  68. package/dist/finalize/artifact-policy.js +214 -0
  69. package/dist/finalize/artifact-policy.test.js +84 -0
  70. package/dist/finalize/delivery-integrity.js +141 -0
  71. package/dist/finalize/finalize.test.js +210 -0
  72. package/dist/finalize/github.js +41 -0
  73. package/dist/finalize/index.js +474 -0
  74. package/dist/finalize/linear.js +213 -0
  75. package/dist/finalize/run-report.js +47 -0
  76. package/dist/finalize/steps/01-map-update.js +11 -0
  77. package/dist/finalize/steps/02-map-validate.js +11 -0
  78. package/dist/finalize/steps/03-schema-validate.js +11 -0
  79. package/dist/finalize/steps/04-run-checks.js +118 -0
  80. package/dist/finalize/steps/05-generate-report.js +14 -0
  81. package/dist/finalize/steps/06-commit.js +39 -0
  82. package/dist/finalize/steps/07-push.js +10 -0
  83. package/dist/finalize/steps/08-create-pr.js +9 -0
  84. package/dist/finalize/steps/09-update-state.js +9 -0
  85. package/dist/finalize/steps/10-append-jsonl.js +23 -0
  86. package/dist/finalize/steps/11-update-linear.js +22 -0
  87. package/dist/finalize/steps/12-archive.js +21 -0
  88. package/dist/graph/adapter/c/adapter.js +45 -0
  89. package/dist/graph/adapter/c/extract.js +135 -0
  90. package/dist/graph/adapter/c/index.js +10 -0
  91. package/dist/graph/adapter/c/runtime.js +67 -0
  92. package/dist/graph/adapter/cpp/adapter.js +45 -0
  93. package/dist/graph/adapter/cpp/extract.js +159 -0
  94. package/dist/graph/adapter/cpp/index.js +10 -0
  95. package/dist/graph/adapter/cpp/runtime.js +61 -0
  96. package/dist/graph/adapter/csharp/adapter.js +45 -0
  97. package/dist/graph/adapter/csharp/extract.js +127 -0
  98. package/dist/graph/adapter/csharp/index.js +10 -0
  99. package/dist/graph/adapter/csharp/runtime.js +61 -0
  100. package/dist/graph/adapter/dart/adapter.js +56 -0
  101. package/dist/graph/adapter/dart/extract.js +130 -0
  102. package/dist/graph/adapter/dart/index.js +10 -0
  103. package/dist/graph/adapter/dart/runtime.js +61 -0
  104. package/dist/graph/adapter/go/adapter.js +45 -0
  105. package/dist/graph/adapter/go/extract.js +112 -0
  106. package/dist/graph/adapter/go/index.js +10 -0
  107. package/dist/graph/adapter/go/runtime.js +58 -0
  108. package/dist/graph/adapter/kotlin-java/extract-common.js +83 -0
  109. package/dist/graph/adapter/kotlin-java/index.js +15 -0
  110. package/dist/graph/adapter/kotlin-java/java-adapter.js +45 -0
  111. package/dist/graph/adapter/kotlin-java/java-extract.js +42 -0
  112. package/dist/graph/adapter/kotlin-java/kotlin-adapter.js +48 -0
  113. package/dist/graph/adapter/kotlin-java/kotlin-extract.js +58 -0
  114. package/dist/graph/adapter/kotlin-java/runtime.js +75 -0
  115. package/dist/graph/adapter/python/adapter.js +45 -0
  116. package/dist/graph/adapter/python/extract.js +121 -0
  117. package/dist/graph/adapter/python/index.js +10 -0
  118. package/dist/graph/adapter/python/runtime.js +70 -0
  119. package/dist/graph/adapter/registry.js +82 -0
  120. package/dist/graph/adapter/rust/adapter.js +45 -0
  121. package/dist/graph/adapter/rust/extract.js +110 -0
  122. package/dist/graph/adapter/rust/index.js +10 -0
  123. package/dist/graph/adapter/rust/runtime.js +74 -0
  124. package/dist/graph/adapter/shell/adapter.js +34 -0
  125. package/dist/graph/adapter/shell/extract.js +98 -0
  126. package/dist/graph/adapter/shell/index.js +8 -0
  127. package/dist/graph/adapter/svelte/adapter.js +91 -0
  128. package/dist/graph/adapter/svelte/extract.js +41 -0
  129. package/dist/graph/adapter/svelte/index.js +8 -0
  130. package/dist/graph/adapter/swift/adapter.js +45 -0
  131. package/dist/graph/adapter/swift/extract.js +120 -0
  132. package/dist/graph/adapter/swift/index.js +10 -0
  133. package/dist/graph/adapter/swift/runtime.js +70 -0
  134. package/dist/graph/adapter/types.js +2 -0
  135. package/dist/graph/adapter/typescript-javascript/adapter.js +72 -0
  136. package/dist/graph/adapter/typescript-javascript/extract.js +115 -0
  137. package/dist/graph/adapter/typescript-javascript/index.js +10 -0
  138. package/dist/graph/adapter/typescript-javascript/runtime.js +97 -0
  139. package/dist/graph/capability/index.js +105 -0
  140. package/dist/graph/governance.js +104 -0
  141. package/dist/graph/parser/extract.js +5 -0
  142. package/dist/graph/parser/loader.js +2 -0
  143. package/dist/graph/parser/pipeline.js +194 -0
  144. package/dist/graph/query/index.js +277 -0
  145. package/dist/graph/query/types.js +5 -0
  146. package/dist/graph/resolver/build-edges.js +211 -0
  147. package/dist/graph/resolver/index.js +23 -0
  148. package/dist/graph/resolver/resolve-imports.js +168 -0
  149. package/dist/graph/store/adapter.js +132 -0
  150. package/dist/graph/store/queries.js +124 -0
  151. package/dist/graph/store/types.js +4 -0
  152. package/dist/ignore/defaults.js +41 -0
  153. package/dist/ignore/parser.js +39 -0
  154. package/dist/lint/map-reference-validator.js +72 -0
  155. package/dist/loop/abort.js +188 -0
  156. package/dist/loop/abort.test.js +151 -0
  157. package/dist/loop/adapters/__tests__/terminal-cli.test.js +92 -0
  158. package/dist/loop/adapters/agent-subtask.js +137 -0
  159. package/dist/loop/adapters/agent-subtask.test.js +151 -0
  160. package/dist/loop/adapters/cli-subtask-bridge.js +108 -0
  161. package/dist/loop/adapters/index.js +9 -0
  162. package/dist/loop/adapters/registry.js +17 -0
  163. package/dist/loop/adapters/terminal-cli.js +403 -0
  164. package/dist/loop/adapters/types.js +2 -0
  165. package/dist/loop/adapters/worker-instructions.js +85 -0
  166. package/dist/loop/body-parser.js +226 -0
  167. package/dist/loop/bootstrap-packet.js +97 -0
  168. package/dist/loop/bootstrap-packet.test.js +171 -0
  169. package/dist/loop/branch-governance.js +54 -0
  170. package/dist/loop/budget.js +63 -0
  171. package/dist/loop/budget.test.js +163 -0
  172. package/dist/loop/checkpoint.js +325 -0
  173. package/dist/loop/compact-return.js +59 -0
  174. package/dist/loop/continue.js +645 -0
  175. package/dist/loop/continue.test.js +337 -0
  176. package/dist/loop/dispatch-boundary.js +335 -0
  177. package/dist/loop/dispatch-state.js +223 -0
  178. package/dist/loop/dispatch-state.test.js +186 -0
  179. package/dist/loop/dispatch.js +1236 -0
  180. package/dist/loop/dispatch.test.js +499 -0
  181. package/dist/loop/ephemeral-smoke.test.js +160 -0
  182. package/dist/loop/evidence-backfill.js +216 -0
  183. package/dist/loop/execution-adapter.js +141 -0
  184. package/dist/loop/execution-adapter.test.js +66 -0
  185. package/dist/loop/finalize-evidence.js +169 -0
  186. package/dist/loop/git-custody.js +250 -0
  187. package/dist/loop/impl-packet-input.js +38 -0
  188. package/dist/loop/index.js +270 -0
  189. package/dist/loop/ledger.js +49 -0
  190. package/dist/loop/ledger.test.js +127 -0
  191. package/dist/loop/lifecycle-dispatch.js +348 -0
  192. package/dist/loop/lifecycle-dispatch.test.js +318 -0
  193. package/dist/loop/lifecycle.js +93 -0
  194. package/dist/loop/lifecycle.test.js +150 -0
  195. package/dist/loop/orphan-recovery.js +276 -0
  196. package/dist/loop/orphan-recovery.test.js +236 -0
  197. package/dist/loop/parent.js +1566 -0
  198. package/dist/loop/parent.test.js +738 -0
  199. package/dist/loop/provider-sealed-packet.test.js +164 -0
  200. package/dist/loop/resume.js +295 -0
  201. package/dist/loop/resume.test.js +172 -0
  202. package/dist/loop/run-bootstrap.js +234 -0
  203. package/dist/loop/run-preflight.js +203 -0
  204. package/dist/loop/status.js +665 -0
  205. package/dist/loop/status.test.js +235 -0
  206. package/dist/loop/wait.js +86 -0
  207. package/dist/loop/worker-packet.js +406 -0
  208. package/dist/loop/worker-packet.test.js +243 -0
  209. package/dist/loop/worker-prompt.js +260 -0
  210. package/dist/loop/worker-prompt.test.js +247 -0
  211. package/dist/loop/worker.js +498 -0
  212. package/dist/loop/worker.test.js +372 -0
  213. package/dist/map/atlas.js +77 -0
  214. package/dist/map/backfill.js +171 -0
  215. package/dist/map/backfill.test.js +120 -0
  216. package/dist/map/index.js +255 -0
  217. package/dist/map/inference.js +73 -0
  218. package/dist/map/inference.test.js +35 -0
  219. package/dist/map/query.js +157 -0
  220. package/dist/map/query.test.js +174 -0
  221. package/dist/map/update.js +355 -0
  222. package/dist/map/update.test.js +67 -0
  223. package/dist/map/validate.js +153 -0
  224. package/dist/map/validate.test.js +90 -0
  225. package/dist/map/welfare.js +86 -0
  226. package/dist/mcp/lib/invoke.js +35 -0
  227. package/dist/mcp/lib/redact.js +24 -0
  228. package/dist/mcp/lib/redact.test.js +112 -0
  229. package/dist/mcp/lib/root.js +41 -0
  230. package/dist/mcp/lib/root.test.js +114 -0
  231. package/dist/mcp/server.js +15 -0
  232. package/dist/mcp/tools/claim-child.js +119 -0
  233. package/dist/mcp/tools/claim-child.test.js +69 -0
  234. package/dist/mcp/tools/current-state.js +73 -0
  235. package/dist/mcp/tools/current-state.test.js +114 -0
  236. package/dist/mcp/tools/dispatch-result.js +186 -0
  237. package/dist/mcp/tools/dispatch-result.test.js +109 -0
  238. package/dist/mcp/tools/index.js +222 -0
  239. package/dist/mcp/tools/index.test.js +172 -0
  240. package/dist/mcp/tools/linear.js +74 -0
  241. package/dist/mcp/tools/loop-continue.js +159 -0
  242. package/dist/mcp/tools/loop-continue.test.js +186 -0
  243. package/dist/mcp/tools/loop-dry-run.js +15 -0
  244. package/dist/mcp/tools/status.js +65 -0
  245. package/dist/medic/chart-id.js +75 -0
  246. package/dist/medic/chart-schema.js +139 -0
  247. package/dist/runs/index.js +119 -0
  248. package/dist/runs/index.test.js +184 -0
  249. package/dist/runs/ledger-tail.js +15 -0
  250. package/dist/runs/list.js +29 -0
  251. package/dist/runs/reconcile.js +74 -0
  252. package/dist/runs/show.js +10 -0
  253. package/dist/runtime/audit/logger.js +15 -0
  254. package/dist/runtime/audit/reader.js +42 -0
  255. package/dist/runtime/checkpoint.js +89 -0
  256. package/dist/runtime/continuation/confirmed.js +225 -0
  257. package/dist/runtime/continuation/confirmed.test.js +421 -0
  258. package/dist/runtime/continuation/dry-run.js +74 -0
  259. package/dist/runtime/execution-window.js +106 -0
  260. package/dist/runtime/scheduling/child-selector.js +16 -0
  261. package/dist/runtime/state.js +43 -0
  262. package/dist/runtime/status.js +46 -0
  263. package/dist/runtime/verification/envelope.js +80 -0
  264. package/dist/runtime/verification/fingerprint.js +26 -0
  265. package/dist/skill-packet/cli.test.js +105 -0
  266. package/dist/skill-packet/generator.js +225 -0
  267. package/dist/skill-packet/generator.test.js +159 -0
  268. package/dist/skill-packet/index.js +49 -0
  269. package/dist/skill-packet/types.js +2 -0
  270. package/dist/smartdocs-engine/audit.js +194 -0
  271. package/dist/smartdocs-engine/audit.test.js +122 -0
  272. package/dist/smartdocs-engine/canon-check.js +340 -0
  273. package/dist/smartdocs-engine/canon-check.test.js +234 -0
  274. package/dist/smartdocs-engine/doctrine.js +633 -0
  275. package/dist/smartdocs-engine/doctrine.test.js +374 -0
  276. package/dist/smartdocs-engine/index.js +456 -0
  277. package/dist/smartdocs-engine/index.test.js +82 -0
  278. package/dist/smartdocs-engine/ingest.js +495 -0
  279. package/dist/smartdocs-engine/ingest.test.js +163 -0
  280. package/dist/smartdocs-engine/migrate.js +217 -0
  281. package/dist/smartdocs-engine/migrate.test.js +200 -0
  282. package/dist/smartdocs-engine/seed-instructions.js +335 -0
  283. package/dist/smartdocs-engine/seed-instructions.test.js +275 -0
  284. package/dist/smartdocs-engine/smartdoc-ignore.js +258 -0
  285. package/dist/smartdocs-engine/smartdoc-ignore.test.js +146 -0
  286. package/dist/smartdocs-engine/validate-instructions.js +366 -0
  287. package/dist/smartdocs-engine/validate-instructions.test.js +283 -0
  288. package/dist/tracker/adapters/github/index.js +305 -0
  289. package/dist/tracker/adapters/jira/index.js +293 -0
  290. package/dist/tracker/adapters/linear/http-errors.test.js +51 -0
  291. package/dist/tracker/adapters/linear/index.js +621 -0
  292. package/dist/tracker/adapters/linear/index.test.js +238 -0
  293. package/dist/tracker/adapters/linear.js +50 -0
  294. package/dist/tracker/adapters/local/index.js +10 -0
  295. package/dist/tracker/adapters/local-file/index.js +159 -0
  296. package/dist/tracker/adapters/mcp-bridge.js +158 -0
  297. package/dist/tracker/adapters/mcp-bridge.test.js +12 -0
  298. package/dist/tracker/adapters/spec/index.js +146 -0
  299. package/dist/tracker/capabilities.js +2 -0
  300. package/dist/tracker/index.js +49 -0
  301. package/dist/tracker/lifecycle-policy.js +139 -0
  302. package/dist/tracker/lifecycle-transition.js +164 -0
  303. package/dist/tracker/local-graph.js +98 -0
  304. package/dist/tracker/migration.js +56 -0
  305. package/dist/tracker/schema.js +86 -0
  306. package/dist/tracker/sync/index.js +404 -0
  307. package/dist/tracker/sync/queue-store.js +95 -0
  308. package/dist/tracker/sync/queue-store.test.js +104 -0
  309. package/dist/tracker/types.js +11 -0
  310. package/dist/types/linear.js +3 -0
  311. package/dist/types/result-packet.js +12 -0
  312. package/dist/types/runtime-state.js +2 -0
  313. package/dist/types/work-contract.js +2 -0
  314. package/dist/utils/monotonic-timestamp.js +13 -0
  315. package/dist/utils/monotonic-timestamp.test.js +19 -0
  316. package/package.json +64 -0
@@ -0,0 +1,456 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createDocsCommand = createDocsCommand;
4
+ exports.createDoctrineCommand = createDoctrineCommand;
5
+ const node_fs_1 = require("node:fs");
6
+ const node_path_1 = require("node:path");
7
+ const commander_1 = require("commander");
8
+ const ingest_js_1 = require("./ingest.js");
9
+ const migrate_js_1 = require("./migrate.js");
10
+ const seed_instructions_js_1 = require("./seed-instructions.js");
11
+ const validate_instructions_js_1 = require("./validate-instructions.js");
12
+ const doctrine_js_1 = require("./doctrine.js");
13
+ const audit_js_1 = require("./audit.js");
14
+ /**
15
+ * Build and return the top-level "docs" Commander command group for Polaris docs lifecycle workflows.
16
+ *
17
+ * @param options - Optional configuration. If `options.repoRoot` is omitted, the current working directory is used as the repository root for subcommands.
18
+ * @returns The configured `Command` implementing the `docs` command and its subcommands.
19
+ */
20
+ function createDocsCommand(options = {}) {
21
+ const defaultRepoRoot = options.repoRoot ?? process.cwd();
22
+ const docs = new commander_1.Command("docs").description("Polaris docs lifecycle commands");
23
+ docs
24
+ .command("init")
25
+ .description("Create the Smart Docs canonical scaffold under smartdocs/")
26
+ .option("--dry-run", "Print what would be created without writing directories")
27
+ .option("-r, --repo-root <path>", "Repository root", defaultRepoRoot)
28
+ .action((options) => {
29
+ try {
30
+ const result = (0, ingest_js_1.ensureDocsScaffold)(options.repoRoot, { dryRun: options.dryRun });
31
+ const createLabel = options.dryRun ? "[dry-run] would create" : "created";
32
+ for (const dir of result.created) {
33
+ console.log(`${createLabel}: ${dir}`);
34
+ }
35
+ for (const dir of result.existing) {
36
+ console.log(`already exists: ${dir}`);
37
+ }
38
+ console.log(`\nDone. ${result.created.length} ${options.dryRun ? "would be created" : "created"}, ${result.existing.length} already exists.`);
39
+ }
40
+ catch (err) {
41
+ console.error(`polaris docs init: ${err instanceof Error ? err.message : String(err)}`);
42
+ process.exit(1);
43
+ }
44
+ });
45
+ docs
46
+ .command("ingest [path]")
47
+ .description("Classify and place docs into the smartdocs/ canonical authority structure")
48
+ .option("--file <path>", "Single file to ingest")
49
+ .option("--batch <cluster-id>", "Cluster ID for bounded batch ingest (reads .polaris/docs-ingest/<cluster-id>.json)")
50
+ .option("--cluster <id>", "Alias for --batch")
51
+ .option("--files <paths...>", "Bounded batch file list")
52
+ .option("--dry-run", "Classify and report without moving files")
53
+ .option("--approve-authority", "Allow placement in high-authority docs areas")
54
+ .option("-r, --repo-root <path>", "Repository root", defaultRepoRoot)
55
+ .action((pathArg, options) => {
56
+ const clusterId = options.batch ?? options.cluster;
57
+ // Validate clusterId
58
+ if (clusterId && !/^[A-Za-z0-9_-]+$/.test(clusterId)) {
59
+ console.error(`polaris docs ingest: invalid cluster ID "${clusterId}" - must contain only alphanumeric, underscore, or hyphen characters`);
60
+ process.exit(1);
61
+ }
62
+ let files = options.files ?? (options.file ? [options.file] : pathArg ? [pathArg] : []);
63
+ if (clusterId && files.length === 0) {
64
+ const batchFile = (0, node_path_1.join)(options.repoRoot, ".polaris", "docs-ingest", `${clusterId}.json`);
65
+ try {
66
+ const rawContent = (0, node_fs_1.readFileSync)(batchFile, "utf-8");
67
+ const batch = JSON.parse(rawContent);
68
+ // Validate parsed batch structure
69
+ if (typeof batch !== "object" || batch === null || Array.isArray(batch)) {
70
+ console.error(`polaris docs ingest: batch file ${batchFile} must contain a JSON object`);
71
+ process.exit(1);
72
+ }
73
+ if (!("files" in batch) || !Array.isArray(batch.files)) {
74
+ console.error(`polaris docs ingest: batch file ${batchFile} must contain a "files" array`);
75
+ process.exit(1);
76
+ }
77
+ // Validate each file path
78
+ for (const file of batch.files) {
79
+ if (typeof file !== "string") {
80
+ console.error(`polaris docs ingest: batch file ${batchFile} contains non-string file entry`);
81
+ process.exit(1);
82
+ }
83
+ if (file.includes("..") || file.includes("\\") || file.startsWith("/")) {
84
+ console.error(`polaris docs ingest: batch file ${batchFile} contains invalid file path "${file}" (contains "..", path separators, or is absolute)`);
85
+ process.exit(1);
86
+ }
87
+ }
88
+ // Validate resolved paths are within ingest directory
89
+ const ingestDir = (0, node_path_1.resolve)(options.repoRoot, ".polaris/docs-ingest");
90
+ for (const file of batch.files) {
91
+ const resolvedPath = (0, node_path_1.resolve)(ingestDir, file);
92
+ if (!resolvedPath.startsWith(ingestDir)) {
93
+ console.error(`polaris docs ingest: file path "${file}" resolves outside ingest directory`);
94
+ process.exit(1);
95
+ }
96
+ }
97
+ files = batch.files;
98
+ }
99
+ catch (err) {
100
+ console.error(`polaris docs ingest: cannot read batch file ${batchFile}: ${err instanceof Error ? err.message : String(err)}`);
101
+ process.exit(1);
102
+ }
103
+ }
104
+ if (files.length === 0) {
105
+ console.error("polaris docs ingest: provide at least one file via --file, --files, --batch, or a path argument");
106
+ process.exit(1);
107
+ }
108
+ try {
109
+ const results = (0, ingest_js_1.ingestDocs)(files, {
110
+ repoRoot: options.repoRoot,
111
+ dryRun: options.dryRun,
112
+ clusterId,
113
+ approveAuthority: options.approveAuthority,
114
+ });
115
+ (0, ingest_js_1.printIngestResults)(results);
116
+ }
117
+ catch (err) {
118
+ console.error(err instanceof Error ? err.message : String(err));
119
+ process.exit(1);
120
+ }
121
+ });
122
+ docs
123
+ .command("migrate")
124
+ .description("Find scattered markdown files, move them to smartdocs/raw/, and produce an ingest cluster list")
125
+ .option("--dry-run", "Show plan without moving files")
126
+ .option("--migration-run-id <id>", "Override the generated migration run ID")
127
+ .option("-r, --repo-root <path>", "Repository root", defaultRepoRoot)
128
+ .action((options) => {
129
+ try {
130
+ const result = (0, migrate_js_1.migrateDocs)({
131
+ repoRoot: options.repoRoot,
132
+ dryRun: options.dryRun,
133
+ migrationRunId: options.migrationRunId,
134
+ });
135
+ (0, migrate_js_1.printMigrateResults)(result);
136
+ }
137
+ catch (err) {
138
+ console.error(err instanceof Error ? err.message : String(err));
139
+ process.exit(1);
140
+ }
141
+ });
142
+ docs
143
+ .command("migrate-provenance")
144
+ .description("Migrate .provenance.json sidecars into paired .md file frontmatter and delete the sidecars")
145
+ .option("--dry-run", "Report what would be migrated without writing or deleting anything")
146
+ .option("-r, --repo-root <path>", "Repository root", defaultRepoRoot)
147
+ .action((options) => {
148
+ try {
149
+ const result = (0, doctrine_js_1.migrateProvenance)({ repoRoot: options.repoRoot, dryRun: options.dryRun });
150
+ if (options.dryRun) {
151
+ const wouldStamp = result.records.filter((r) => r.status === "skipped-dry-run");
152
+ const noMd = result.records.filter((r) => r.status === "skipped-no-md");
153
+ console.log(`[dry-run] would stamp ${wouldStamp.length} file(s), skip ${noMd.length} orphaned sidecar(s)`);
154
+ for (const r of wouldStamp) {
155
+ console.log(` stamp: ${r.mdFile} (sidecar: ${r.sidecar})`);
156
+ }
157
+ for (const r of noMd) {
158
+ console.log(` orphan (no .md): ${r.sidecar}`);
159
+ }
160
+ }
161
+ else {
162
+ console.log(`migrate-provenance complete — stamped: ${result.stamped}, skipped: ${result.skipped}, errors: ${result.errors}`);
163
+ for (const r of result.records) {
164
+ if (r.status === "stamped") {
165
+ console.log(` stamped: ${r.mdFile}`);
166
+ }
167
+ else if (r.status === "error") {
168
+ console.log(` error: ${r.mdFile} — ${r.error}`);
169
+ }
170
+ else if (r.status === "skipped-no-md") {
171
+ console.log(` orphan: ${r.sidecar}`);
172
+ }
173
+ }
174
+ if (result.stamped > 0) {
175
+ console.log(`lifecycle: ${result.lifecyclePath}`);
176
+ }
177
+ }
178
+ }
179
+ catch (err) {
180
+ console.error(err instanceof Error ? err.message : String(err));
181
+ process.exit(1);
182
+ }
183
+ });
184
+ docs
185
+ .command("seed-instructions [path]")
186
+ .description("Generate a draft POLARIS.md for a directory using atlas signals")
187
+ .option("-r, --repo-root <path>", "Repository root", defaultRepoRoot)
188
+ .option("--all", "Generate drafts for all directories lacking a POLARIS.md")
189
+ .option("--dry-run", "Print what would be written without writing files")
190
+ .option("--include-agent-folders", "Include .codex, .claude, .agents folders (default: skip)")
191
+ .option("--include-hidden", "Include all hidden directories starting with . (default: skip)")
192
+ .option("--include-root", "Include root directory (default: skip for POLARIS.md)")
193
+ .action((pathArg, options) => {
194
+ if (options.all) {
195
+ const { written, skippedExists, skippedDraft, skippedIneligible, skippedRoot, } = (0, seed_instructions_js_1.seedInstructionsAll)(options.repoRoot, {
196
+ dryRun: options.dryRun,
197
+ includeAgentFolders: options.includeAgentFolders,
198
+ includeHidden: options.includeHidden,
199
+ includeRoot: options.includeRoot,
200
+ });
201
+ for (const dir of written) {
202
+ console.log(`${options.dryRun ? "[dry-run] would write" : "written"}: ${dir}/POLARIS.md`);
203
+ }
204
+ for (const dir of skippedExists) {
205
+ console.log(`skipped (human-edited): ${dir}/POLARIS.md`);
206
+ }
207
+ for (const dir of skippedDraft) {
208
+ console.log(`skipped (draft exists): ${dir}/POLARIS.md`);
209
+ }
210
+ if (options.dryRun) {
211
+ if (skippedRoot) {
212
+ console.log(`\nSkipped (root):`);
213
+ console.log(` ${skippedRoot.path}/ (${skippedRoot.reason})`);
214
+ }
215
+ if (skippedIneligible.length > 0) {
216
+ // Group by category
217
+ const byCategory = {};
218
+ for (const entry of skippedIneligible) {
219
+ const cat = entry.category || "other";
220
+ if (!byCategory[cat])
221
+ byCategory[cat] = [];
222
+ byCategory[cat].push(entry);
223
+ }
224
+ for (const [category, entries] of Object.entries(byCategory)) {
225
+ console.log(`\nSkipped (${category}):`);
226
+ for (const entry of entries) {
227
+ console.log(` ${entry.path}/ (${entry.reason})`);
228
+ }
229
+ }
230
+ }
231
+ }
232
+ const rootCount = skippedRoot ? 1 : 0;
233
+ console.log(`\nDone. ${written.length} written, ${skippedExists.length} skipped (exists), ${skippedDraft.length} skipped (draft), ${rootCount} skipped (root), ${skippedIneligible.length} skipped (ineligible).`);
234
+ return;
235
+ }
236
+ if (!pathArg) {
237
+ console.error("Error: provide a <path> argument or use --all");
238
+ process.exit(1);
239
+ }
240
+ const result = (0, seed_instructions_js_1.seedInstructions)(pathArg, options.repoRoot, { dryRun: options.dryRun });
241
+ if (result === "written") {
242
+ const label = options.dryRun ? "[dry-run] would write" : "written";
243
+ console.log(`${label}: ${pathArg}/POLARIS.md`);
244
+ }
245
+ else if (result === "skipped-exists") {
246
+ console.warn(`warning: ${pathArg}/POLARIS.md already exists (no draft marker) — skipped`);
247
+ }
248
+ else {
249
+ console.log(`skipped (draft exists): ${pathArg}/POLARIS.md`);
250
+ }
251
+ });
252
+ docs
253
+ .command("seed-summary [path]")
254
+ .description("Generate a draft SUMMARY.md for a directory using atlas signals")
255
+ .option("-r, --repo-root <path>", "Repository root", defaultRepoRoot)
256
+ .option("--all", "Generate drafts for all directories lacking a SUMMARY.md")
257
+ .option("--dry-run", "Print what would be written without writing files")
258
+ .option("--include-agent-folders", "Include .codex, .claude, .agents folders (default: skip)")
259
+ .option("--include-hidden", "Include all hidden directories starting with . (default: skip)")
260
+ .option("--include-root", "Include root directory (default: skip)")
261
+ .action((pathArg, options) => {
262
+ if (options.all) {
263
+ const { written, skippedExists, skippedDraft, skippedIneligible, skippedRoot, } = (0, seed_instructions_js_1.seedSummaryAll)(options.repoRoot, {
264
+ dryRun: options.dryRun,
265
+ includeAgentFolders: options.includeAgentFolders,
266
+ includeHidden: options.includeHidden,
267
+ includeRoot: options.includeRoot,
268
+ });
269
+ for (const dir of written) {
270
+ console.log(`${options.dryRun ? "[dry-run] would write" : "written"}: ${dir}/SUMMARY.md`);
271
+ }
272
+ for (const dir of skippedExists) {
273
+ console.log(`skipped (human-edited): ${dir}/SUMMARY.md`);
274
+ }
275
+ for (const dir of skippedDraft) {
276
+ console.log(`skipped (draft exists): ${dir}/SUMMARY.md`);
277
+ }
278
+ if (options.dryRun) {
279
+ if (skippedRoot) {
280
+ console.log(`\nSkipped (root):`);
281
+ console.log(` ${skippedRoot.path}/ (${skippedRoot.reason})`);
282
+ }
283
+ if (skippedIneligible.length > 0) {
284
+ // Group by category
285
+ const byCategory = {};
286
+ for (const entry of skippedIneligible) {
287
+ const cat = entry.category || "other";
288
+ if (!byCategory[cat])
289
+ byCategory[cat] = [];
290
+ byCategory[cat].push(entry);
291
+ }
292
+ for (const [category, entries] of Object.entries(byCategory)) {
293
+ console.log(`\nSkipped (${category}):`);
294
+ for (const entry of entries) {
295
+ console.log(` ${entry.path}/ (${entry.reason})`);
296
+ }
297
+ }
298
+ }
299
+ }
300
+ const rootCount = skippedRoot ? 1 : 0;
301
+ console.log(`\nDone. ${written.length} written, ${skippedExists.length} skipped (exists), ${skippedDraft.length} skipped (draft), ${rootCount} skipped (root), ${skippedIneligible.length} skipped (ineligible).`);
302
+ return;
303
+ }
304
+ if (!pathArg) {
305
+ console.error("Error: provide a <path> argument or use --all");
306
+ process.exit(1);
307
+ }
308
+ const result = (0, seed_instructions_js_1.seedSummary)(pathArg, options.repoRoot, { dryRun: options.dryRun });
309
+ if (result === "written") {
310
+ const label = options.dryRun ? "[dry-run] would write" : "written";
311
+ console.log(`${label}: ${pathArg}/SUMMARY.md`);
312
+ }
313
+ else if (result === "skipped-exists") {
314
+ console.warn(`warning: ${pathArg}/SUMMARY.md already exists (no draft marker) — skipped`);
315
+ }
316
+ else {
317
+ console.log(`skipped (draft exists): ${pathArg}/SUMMARY.md`);
318
+ }
319
+ });
320
+ docs
321
+ .command("audit")
322
+ .description("Scan repo for files at risk of recursive ingestion")
323
+ .option("--json", "Emit AuditResult as JSON")
324
+ .option("--output <path>", "Write markdown findings report to file")
325
+ .option("-r, --repo-root <path>", "Repository root", defaultRepoRoot)
326
+ .action((options) => {
327
+ if (options.json && options.output) {
328
+ console.error("Error: --json and --output are mutually exclusive; provide only one");
329
+ process.exit(1);
330
+ }
331
+ try {
332
+ const result = (0, audit_js_1.auditIngestRiskSurface)(options.repoRoot);
333
+ if (options.json) {
334
+ console.log(JSON.stringify(result, null, 2));
335
+ }
336
+ else if (options.output) {
337
+ (0, node_fs_1.writeFileSync)(options.output, (0, audit_js_1.formatAuditMarkdown)(result), "utf-8");
338
+ console.log(`written: ${options.output}`);
339
+ }
340
+ else {
341
+ console.log((0, audit_js_1.formatAuditSummaryTable)(result));
342
+ }
343
+ }
344
+ catch (err) {
345
+ console.error(err instanceof Error ? err.message : String(err));
346
+ process.exit(1);
347
+ }
348
+ });
349
+ docs
350
+ .command("validate-instructions")
351
+ .description("Check all POLARIS.md files for staleness, broken links, and missing coverage")
352
+ .option("--path <dir>", "Validate only the given directory")
353
+ .option("--fix", "Write POLARIS.draft.md for stale or missing files")
354
+ .option("-r, --repo-root <path>", "Repository root", defaultRepoRoot)
355
+ .action((options) => {
356
+ const report = (0, validate_instructions_js_1.validateInstructions)({
357
+ path: options.path,
358
+ fix: options.fix,
359
+ repoRoot: options.repoRoot,
360
+ });
361
+ (0, validate_instructions_js_1.printReport)(report);
362
+ if (report.hasErrors) {
363
+ process.exit(1);
364
+ }
365
+ });
366
+ return docs;
367
+ }
368
+ /**
369
+ * Build and return the "doctrine" Commander command group that registers doctrine lifecycle and spec-promotion subcommands.
370
+ *
371
+ * The returned command contains subcommands: `draft`, `promote`, `deprecate`, and `spec-promote`, each wired to their respective handlers and options.
372
+ *
373
+ * @returns A configured Commander `Command` representing the `doctrine` command group
374
+ */
375
+ function createDoctrineCommand() {
376
+ const doctrine = new commander_1.Command("doctrine").description("Polaris doctrine lifecycle commands");
377
+ doctrine
378
+ .command("draft <path>")
379
+ .description("Move a doc from smartdocs/raw/ or smartdocs/doctrine/raw/ to docs/doctrine/candidate/")
380
+ .option("-r, --repo-root <path>", "Repository root", process.cwd())
381
+ .option("--run-id <id>", "Override the generated doctrine run ID")
382
+ .action((path, options) => {
383
+ try {
384
+ const result = (0, doctrine_js_1.doctrineDraft)(path, { repoRoot: options.repoRoot, runId: options.runId });
385
+ console.log(`drafted: ${result.destination}`);
386
+ console.log(`provenance: ${result.lifecyclePath}`);
387
+ }
388
+ catch (err) {
389
+ console.error(err instanceof Error ? err.message : String(err));
390
+ process.exit(1);
391
+ }
392
+ });
393
+ doctrine
394
+ .command("promote <path>")
395
+ .description("Move a doc from smartdocs/doctrine/candidate/ to smartdocs/doctrine/active/")
396
+ .option("-r, --repo-root <path>", "Repository root", process.cwd())
397
+ .option("--run-id <id>", "Override the generated doctrine run ID")
398
+ .action((path, options) => {
399
+ try {
400
+ const result = (0, doctrine_js_1.doctrinePromote)(path, {
401
+ repoRoot: options.repoRoot,
402
+ runId: options.runId
403
+ });
404
+ console.log(`promoted: ${result.destination}`);
405
+ console.log(`provenance: ${result.lifecyclePath}`);
406
+ }
407
+ catch (err) {
408
+ console.error(err instanceof Error ? err.message : String(err));
409
+ process.exit(1);
410
+ }
411
+ });
412
+ doctrine
413
+ .command("deprecate <path>")
414
+ .description("Move a doc from smartdocs/doctrine/active/ to smartdocs/doctrine/deprecated/")
415
+ .option("-r, --repo-root <path>", "Repository root", process.cwd())
416
+ .option("--run-id <id>", "Override the generated doctrine run ID")
417
+ .action((path, options) => {
418
+ try {
419
+ const result = (0, doctrine_js_1.doctrineDeprecate)(path, {
420
+ repoRoot: options.repoRoot,
421
+ runId: options.runId,
422
+ });
423
+ console.log(`deprecated: ${result.destination}`);
424
+ console.log(`provenance: ${result.lifecyclePath}`);
425
+ }
426
+ catch (err) {
427
+ console.error(err instanceof Error ? err.message : String(err));
428
+ process.exit(1);
429
+ }
430
+ });
431
+ doctrine
432
+ .command("spec-promote <path>")
433
+ .description("Promote a raw spec from smartdocs/raw/ to smartdocs/specs/active/ after conflict check")
434
+ .option("-r, --repo-root <path>", "Repository root", process.cwd())
435
+ .option("--run-id <id>", "Override the generated run ID")
436
+ .option("--approve", "Proceed despite detected conflicts")
437
+ .action((path, options) => {
438
+ try {
439
+ const result = (0, doctrine_js_1.specPromote)(path, {
440
+ repoRoot: options.repoRoot,
441
+ runId: options.runId,
442
+ approve: options.approve,
443
+ });
444
+ console.log(result.report);
445
+ if (result.halted) {
446
+ process.exit(1);
447
+ }
448
+ console.log(`promoted: ${result.destination}`);
449
+ }
450
+ catch (err) {
451
+ console.error(err instanceof Error ? err.message : String(err));
452
+ process.exit(1);
453
+ }
454
+ });
455
+ return doctrine;
456
+ }
@@ -0,0 +1,82 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const node_fs_1 = require("node:fs");
4
+ const node_fs_2 = require("node:fs");
5
+ const node_os_1 = require("node:os");
6
+ const node_path_1 = require("node:path");
7
+ const vitest_1 = require("vitest");
8
+ const ingest_js_1 = require("./ingest.js");
9
+ const index_js_1 = require("./index.js");
10
+ function makeRepo() {
11
+ const repoRoot = (0, node_fs_2.mkdtempSync)((0, node_path_1.join)((0, node_os_1.tmpdir)(), "polaris-docs-init-"));
12
+ (0, node_fs_1.mkdirSync)((0, node_path_1.join)(repoRoot, ".polaris", "map"), { recursive: true });
13
+ (0, node_fs_1.writeFileSync)((0, node_path_1.join)(repoRoot, "polaris.config.json"), JSON.stringify({ repo: { sidecarOutputPath: ".polaris/map" } }), "utf-8");
14
+ (0, node_fs_1.writeFileSync)((0, node_path_1.join)(repoRoot, ".polaris", "map", "file-routes.json"), "{}\n", "utf-8");
15
+ (0, node_fs_1.writeFileSync)((0, node_path_1.join)(repoRoot, ".polaris", "map", "needs-review.json"), "{}\n", "utf-8");
16
+ return repoRoot;
17
+ }
18
+ function configureForTest(command, output) {
19
+ command.exitOverride();
20
+ command.configureOutput({
21
+ writeOut: (value) => {
22
+ output.stdout += value;
23
+ },
24
+ writeErr: (value) => {
25
+ output.stderr += value;
26
+ },
27
+ });
28
+ for (const subcommand of command.commands) {
29
+ configureForTest(subcommand, output);
30
+ }
31
+ }
32
+ async function runDocsCommand(repoRoot, argv) {
33
+ const output = { stdout: "", stderr: "" };
34
+ const command = (0, index_js_1.createDocsCommand)({ repoRoot });
35
+ configureForTest(command, output);
36
+ const log = vitest_1.vi.spyOn(console, "log").mockImplementation((value = "") => {
37
+ output.stdout += `${String(value)}\n`;
38
+ });
39
+ const warn = vitest_1.vi.spyOn(console, "warn").mockImplementation((value = "") => {
40
+ output.stderr += `${String(value)}\n`;
41
+ });
42
+ const error = vitest_1.vi.spyOn(console, "error").mockImplementation((value = "") => {
43
+ output.stderr += `${String(value)}\n`;
44
+ });
45
+ try {
46
+ await command.parseAsync(["node", "polaris", ...argv], { from: "node" });
47
+ }
48
+ finally {
49
+ log.mockRestore();
50
+ warn.mockRestore();
51
+ error.mockRestore();
52
+ }
53
+ return output;
54
+ }
55
+ (0, vitest_1.describe)("docs init command", () => {
56
+ (0, vitest_1.it)("dry-runs the Smart Docs scaffold without creating directories", async () => {
57
+ const repoRoot = makeRepo();
58
+ const output = await runDocsCommand(repoRoot, ["init", "--dry-run"]);
59
+ (0, vitest_1.expect)(output.stdout).toContain("[dry-run] would create");
60
+ (0, vitest_1.expect)(output.stdout).toContain(`${ingest_js_1.CANONICAL_TARGET}/raw`);
61
+ (0, vitest_1.expect)((0, node_fs_1.existsSync)((0, node_path_1.join)(repoRoot, ingest_js_1.CANONICAL_TARGET))).toBe(false);
62
+ });
63
+ (0, vitest_1.it)("creates the Smart Docs scaffold and is idempotent", async () => {
64
+ const repoRoot = makeRepo();
65
+ const first = await runDocsCommand(repoRoot, ["init"]);
66
+ const second = await runDocsCommand(repoRoot, ["init"]);
67
+ (0, vitest_1.expect)(first.stdout).toContain("created");
68
+ (0, vitest_1.expect)(first.stdout).toContain(`${ingest_js_1.CANONICAL_TARGET}/doctrine/active`);
69
+ (0, vitest_1.expect)(second.stdout).toContain("already exists");
70
+ (0, vitest_1.expect)((0, node_fs_1.existsSync)((0, node_path_1.join)(repoRoot, ingest_js_1.CANONICAL_TARGET, "runtime", "summaries"))).toBe(true);
71
+ (0, vitest_1.expect)((0, node_fs_1.existsSync)((0, node_path_1.join)(repoRoot, ingest_js_1.CANONICAL_TARGET, "raw"))).toBe(true);
72
+ (0, vitest_1.expect)((0, node_fs_1.existsSync)((0, node_path_1.join)(repoRoot, ingest_js_1.CANONICAL_TARGET, "doctrine", "active"))).toBe(true);
73
+ });
74
+ (0, vitest_1.it)("unblocks docs ingest after initialization", async () => {
75
+ const repoRoot = makeRepo();
76
+ await runDocsCommand(repoRoot, ["init"]);
77
+ (0, node_fs_1.writeFileSync)((0, node_path_1.join)(repoRoot, "smartdocs", "docs", "raw", "smart-docs.md"), "# Smart Docs Spec\n\nAcceptance Criteria\n", "utf-8");
78
+ const output = await runDocsCommand(repoRoot, ["ingest", "--file", "smartdocs/docs/raw/smart-docs.md"]);
79
+ (0, vitest_1.expect)(output.stdout).toContain(`${ingest_js_1.CANONICAL_TARGET}/raw/smart-docs.md`);
80
+ (0, vitest_1.expect)((0, node_fs_1.existsSync)((0, node_path_1.join)(repoRoot, ingest_js_1.CANONICAL_TARGET, "raw", "smart-docs.md"))).toBe(true);
81
+ });
82
+ });