@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,217 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.isAllowedException = isAllowedException;
4
+ exports.migrateDocs = migrateDocs;
5
+ exports.printMigrateResults = printMigrateResults;
6
+ const node_child_process_1 = require("node:child_process");
7
+ const node_fs_1 = require("node:fs");
8
+ const node_path_1 = require("node:path");
9
+ const smartdoc_ignore_js_1 = require("./smartdoc-ignore.js");
10
+ /** Basenames that are always allowed regardless of location. */
11
+ const ALLOWED_BASENAMES = new Set([
12
+ "README.md",
13
+ "POLARIS.md",
14
+ "CHANGELOG.md",
15
+ "LICENSE.md",
16
+ "AGENTS.md",
17
+ "CLAUDE.md",
18
+ "GEMINI.md",
19
+ "COPILOT.md",
20
+ ]);
21
+ /**
22
+ * Directory prefixes (relative to repo root, forward-slash notation) where
23
+ * markdown files may live without being migrated.
24
+ */
25
+ const ALLOWED_DIR_PREFIXES = [
26
+ ".agents/",
27
+ ".codex/",
28
+ ".claude/",
29
+ ".gemini/",
30
+ ".github/",
31
+ ".polaris/",
32
+ ".taskchain_artifacts/",
33
+ "generated/",
34
+ "summaries/",
35
+ "smartdocs/",
36
+ ];
37
+ function isAllowedException(relPath, repoRoot) {
38
+ const name = (0, node_path_1.basename)(relPath);
39
+ if (ALLOWED_BASENAMES.has(name)) {
40
+ return { allowed: true, reason: `allowed basename: ${name}` };
41
+ }
42
+ for (const prefix of ALLOWED_DIR_PREFIXES) {
43
+ if (relPath.startsWith(prefix)) {
44
+ return { allowed: true, reason: `in allowed directory: ${prefix}` };
45
+ }
46
+ }
47
+ if (repoRoot) {
48
+ const eligibility = (0, smartdoc_ignore_js_1.isIngestIneligible)(relPath, repoRoot);
49
+ if (eligibility.ineligible) {
50
+ return {
51
+ allowed: true,
52
+ reason: eligibility.reason,
53
+ endpointArtifactReason: "smartdocignore-endpoint-artifact",
54
+ };
55
+ }
56
+ }
57
+ return { allowed: false };
58
+ }
59
+ function findMarkdownFiles(repoRoot) {
60
+ try {
61
+ const output = (0, node_child_process_1.execFileSync)("git", ["ls-files", "--cached", "--others", "--exclude-standard", "*.md"], { cwd: repoRoot, encoding: "utf-8" });
62
+ return output
63
+ .split("\n")
64
+ .map((l) => l.trim())
65
+ .filter((l) => l.length > 0 && l.endsWith(".md"));
66
+ }
67
+ catch {
68
+ // Fallback if not a git repo: use find
69
+ const output = (0, node_child_process_1.execFileSync)("find", [".", "-name", "*.md", "-not", "-path", "./.git/*"], { cwd: repoRoot, encoding: "utf-8" });
70
+ return output
71
+ .split("\n")
72
+ .map((l) => l.trim().replace(/^\.\//, ""))
73
+ .filter((l) => l.length > 0 && l.endsWith(".md"));
74
+ }
75
+ }
76
+ function uniqueDestination(filePath) {
77
+ if (!(0, node_fs_1.existsSync)(filePath))
78
+ return filePath;
79
+ const dir = (0, node_path_1.dirname)(filePath);
80
+ const name = (0, node_path_1.basename)(filePath, ".md");
81
+ let index = 2;
82
+ let candidate = (0, node_path_1.join)(dir, `${name}-${index}.md`);
83
+ while ((0, node_fs_1.existsSync)(candidate)) {
84
+ index += 1;
85
+ candidate = (0, node_path_1.join)(dir, `${name}-${index}.md`);
86
+ }
87
+ return candidate;
88
+ }
89
+ function makeMigrationRunId() {
90
+ const date = new Date().toISOString().slice(0, 10);
91
+ const seq = String(Date.now()).slice(-4);
92
+ return `polaris-docs-migrate-${date}-${seq}`;
93
+ }
94
+ function batchFiles(files, batchSize = 4) {
95
+ const batches = [];
96
+ for (let i = 0; i < files.length; i += batchSize) {
97
+ batches.push(files.slice(i, i + batchSize));
98
+ }
99
+ return batches;
100
+ }
101
+ /**
102
+ * Migrates markdown files in a repository into smartdocs/raw/, records provenance for moved files, and summarizes the migration.
103
+ *
104
+ * @param options - Migration options including the repository root, an optional dry-run flag, and an optional migration run identifier.
105
+ * - `repoRoot`: Path to the repository root containing markdown files to evaluate and migrate.
106
+ * - `dryRun`: When true, no files are moved or written; results describe what would have happened.
107
+ * - `migrationRunId`: If provided, use this identifier for provenance records; otherwise a new id is generated.
108
+ * @returns An object summarizing the migration:
109
+ * - `results`: Per-file results showing original path, current path, classification (`"allowed-exception"` or `"migrated"`), and optional fields such as `exceptionReason`, `endpointArtifactReason`, or `destination`.
110
+ * - `migrationRunId`: The migration run identifier used for this operation.
111
+ * - `provenancePath`: Relative path to the written provenance JSON file when not a dry run and provenance was recorded; `null` otherwise.
112
+ * - `ingestBatches`: Array of batches (arrays) of destination paths suitable for ingestion.
113
+ * - `dryRun`: Boolean reflecting whether the operation was a dry run.
114
+ */
115
+ function migrateDocs(options) {
116
+ const repoRoot = (0, node_path_1.resolve)(options.repoRoot);
117
+ const migrationRunId = options.migrationRunId ?? makeMigrationRunId();
118
+ const rawDir = (0, node_path_1.resolve)(repoRoot, "smartdocs/raw");
119
+ const allMd = findMarkdownFiles(repoRoot);
120
+ const results = [];
121
+ const toMigrate = [];
122
+ for (const relPath of allMd) {
123
+ const check = isAllowedException(relPath, repoRoot);
124
+ if (check.allowed) {
125
+ results.push({
126
+ originalPath: relPath,
127
+ currentPath: relPath,
128
+ classification: "allowed-exception",
129
+ exceptionReason: check.reason,
130
+ endpointArtifactReason: check.endpointArtifactReason,
131
+ });
132
+ }
133
+ else {
134
+ toMigrate.push(relPath);
135
+ }
136
+ }
137
+ if (!options.dryRun && toMigrate.length > 0) {
138
+ (0, node_fs_1.mkdirSync)(rawDir, { recursive: true });
139
+ }
140
+ const provenanceRecords = [];
141
+ for (const relPath of toMigrate) {
142
+ const absSource = (0, node_path_1.resolve)(repoRoot, relPath);
143
+ const destFile = uniqueDestination((0, node_path_1.join)(rawDir, (0, node_path_1.basename)(relPath)));
144
+ const relDest = (0, node_path_1.relative)(repoRoot, destFile).replace(/\\/g, "/");
145
+ if (!options.dryRun) {
146
+ (0, node_fs_1.mkdirSync)((0, node_path_1.dirname)(destFile), { recursive: true });
147
+ (0, node_fs_1.renameSync)(absSource, destFile);
148
+ provenanceRecords.push({
149
+ originalPath: relPath,
150
+ currentPath: relDest,
151
+ migratedAt: new Date().toISOString(),
152
+ migrationRunId,
153
+ });
154
+ }
155
+ results.push({
156
+ originalPath: relPath,
157
+ currentPath: options.dryRun ? relPath : relDest,
158
+ classification: "migrated",
159
+ destination: relDest,
160
+ });
161
+ }
162
+ let provenancePath = null;
163
+ if (!options.dryRun && provenanceRecords.length > 0) {
164
+ const provDir = (0, node_path_1.resolve)(repoRoot, ".taskchain_artifacts", "polaris-docs-migrate", migrationRunId);
165
+ (0, node_fs_1.mkdirSync)(provDir, { recursive: true });
166
+ const absProvPath = (0, node_path_1.join)(provDir, "provenance.json");
167
+ (0, node_fs_1.writeFileSync)(absProvPath, JSON.stringify(provenanceRecords, null, 2) + "\n", "utf-8");
168
+ provenancePath = (0, node_path_1.relative)(repoRoot, absProvPath).replace(/\\/g, "/");
169
+ }
170
+ // Build ingest batch paths: where files will land in smartdocs/raw/
171
+ const migratedDestPaths = results
172
+ .filter((r) => r.classification === "migrated")
173
+ .map((r) => r.destination ?? `smartdocs/raw/${(0, node_path_1.basename)(r.originalPath)}`);
174
+ const ingestBatches = batchFiles(migratedDestPaths, 4);
175
+ return { results, migrationRunId, provenancePath, ingestBatches, dryRun: Boolean(options.dryRun) };
176
+ }
177
+ /**
178
+ * Prints a human-readable summary of a migration run to stdout.
179
+ *
180
+ * The summary includes the migration run ID, number of files to migrate, each migrated
181
+ * file and its destination (or the default `raw/<basename>`), allowed exceptions with
182
+ * their reasons, ingest batches rendered as `polaris docs ingest --file <path>` commands,
183
+ * and the provenance file path when present. A "[dry-run] " prefix is added when `result.dryRun`
184
+ * is true.
185
+ *
186
+ * @param result - The migration result object containing per-file classifications, ingest batches,
187
+ * provenance path, and the `dryRun` flag
188
+ */
189
+ function printMigrateResults(result) {
190
+ const prefix = result.dryRun ? "[dry-run] " : "";
191
+ const migrated = result.results.filter((r) => r.classification === "migrated");
192
+ const exceptions = result.results.filter((r) => r.classification === "allowed-exception");
193
+ console.log(`\n${prefix}Migration run: ${result.migrationRunId}`);
194
+ console.log(`${prefix}Files to migrate: ${migrated.length}`);
195
+ for (const r of migrated) {
196
+ const dest = r.destination ?? `raw/${(0, node_path_1.basename)(r.originalPath)}`;
197
+ console.log(` ${r.originalPath} -> ${dest}`);
198
+ }
199
+ if (exceptions.length > 0) {
200
+ console.log(`\n${prefix}Allowed exceptions (not moved): ${exceptions.length}`);
201
+ for (const r of exceptions) {
202
+ console.log(` ${r.originalPath} [${r.exceptionReason}]`);
203
+ }
204
+ }
205
+ if (result.ingestBatches.length > 0) {
206
+ console.log(`\n${prefix}Ingest cluster batches (${result.ingestBatches.length} batch${result.ingestBatches.length === 1 ? "" : "es"}):`);
207
+ result.ingestBatches.forEach((batch, i) => {
208
+ console.log(` Batch ${i + 1}:`);
209
+ for (const f of batch) {
210
+ console.log(` polaris docs ingest --file ${f}`);
211
+ }
212
+ });
213
+ }
214
+ if (result.provenancePath) {
215
+ console.log(`\nProvenance written to: ${result.provenancePath}`);
216
+ }
217
+ }
@@ -0,0 +1,200 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const node_child_process_1 = require("node:child_process");
4
+ const node_fs_1 = require("node:fs");
5
+ const node_path_1 = require("node:path");
6
+ const node_fs_2 = require("node:fs");
7
+ const node_os_1 = require("node:os");
8
+ const vitest_1 = require("vitest");
9
+ const migrate_js_1 = require("./migrate.js");
10
+ // ---------------------------------------------------------------------------
11
+ // isAllowedException
12
+ // ---------------------------------------------------------------------------
13
+ (0, vitest_1.describe)("isAllowedException", () => {
14
+ (0, vitest_1.it)("allows README.md in any directory", () => {
15
+ (0, vitest_1.expect)((0, migrate_js_1.isAllowedException)("README.md").allowed).toBe(true);
16
+ (0, vitest_1.expect)((0, migrate_js_1.isAllowedException)("src/README.md").allowed).toBe(true);
17
+ (0, vitest_1.expect)((0, migrate_js_1.isAllowedException)("some/deep/path/README.md").allowed).toBe(true);
18
+ });
19
+ (0, vitest_1.it)("allows POLARIS.md in any directory", () => {
20
+ (0, vitest_1.expect)((0, migrate_js_1.isAllowedException)("POLARIS.md").allowed).toBe(true);
21
+ (0, vitest_1.expect)((0, migrate_js_1.isAllowedException)("src/cli/POLARIS.md").allowed).toBe(true);
22
+ });
23
+ (0, vitest_1.it)("allows CHANGELOG.md and LICENSE.md", () => {
24
+ (0, vitest_1.expect)((0, migrate_js_1.isAllowedException)("CHANGELOG.md").allowed).toBe(true);
25
+ (0, vitest_1.expect)((0, migrate_js_1.isAllowedException)("LICENSE.md").allowed).toBe(true);
26
+ });
27
+ (0, vitest_1.it)("does NOT allow arbitrary docs/ files (docs/ is a migration source, not an exception)", () => {
28
+ (0, vitest_1.expect)((0, migrate_js_1.isAllowedException)("docs/spec/foo.md").allowed).toBe(false);
29
+ (0, vitest_1.expect)((0, migrate_js_1.isAllowedException)("docs/raw/bar.md").allowed).toBe(false);
30
+ });
31
+ (0, vitest_1.it)("allows anything under .agents/, .codex/, .claude/, .taskchain_artifacts/", () => {
32
+ (0, vitest_1.expect)((0, migrate_js_1.isAllowedException)(".agents/instructions.md").allowed).toBe(true);
33
+ (0, vitest_1.expect)((0, migrate_js_1.isAllowedException)(".codex/skills/foo/SKILL.md").allowed).toBe(true);
34
+ (0, vitest_1.expect)((0, migrate_js_1.isAllowedException)(".claude/CLAUDE.md").allowed).toBe(true);
35
+ (0, vitest_1.expect)((0, migrate_js_1.isAllowedException)(".taskchain_artifacts/run/notes.md").allowed).toBe(true);
36
+ });
37
+ (0, vitest_1.it)("allows anything under .polaris/skills/, .gemini/, .github/skills/", () => {
38
+ (0, vitest_1.expect)((0, migrate_js_1.isAllowedException)(".polaris/skills/polaris-run/SKILL.md").allowed).toBe(true);
39
+ (0, vitest_1.expect)((0, migrate_js_1.isAllowedException)(".gemini/skills/polaris-run/SKILL.md").allowed).toBe(true);
40
+ (0, vitest_1.expect)((0, migrate_js_1.isAllowedException)(".github/skills/polaris-run/SKILL.md").allowed).toBe(true);
41
+ });
42
+ (0, vitest_1.it)("does NOT allow arbitrary markdown files", () => {
43
+ (0, vitest_1.expect)((0, migrate_js_1.isAllowedException)("src/some-feature/NOTES.md").allowed).toBe(false);
44
+ (0, vitest_1.expect)((0, migrate_js_1.isAllowedException)("planning/ideas.md").allowed).toBe(false);
45
+ (0, vitest_1.expect)((0, migrate_js_1.isAllowedException)("scratch.md").allowed).toBe(false);
46
+ });
47
+ (0, vitest_1.it)("allows AGENTS.md, CLAUDE.md, GEMINI.md, COPILOT.md in any directory", () => {
48
+ (0, vitest_1.expect)((0, migrate_js_1.isAllowedException)("AGENTS.md").allowed).toBe(true);
49
+ (0, vitest_1.expect)((0, migrate_js_1.isAllowedException)("src/AGENTS.md").allowed).toBe(true);
50
+ (0, vitest_1.expect)((0, migrate_js_1.isAllowedException)("CLAUDE.md").allowed).toBe(true);
51
+ (0, vitest_1.expect)((0, migrate_js_1.isAllowedException)("src/CLAUDE.md").allowed).toBe(true);
52
+ (0, vitest_1.expect)((0, migrate_js_1.isAllowedException)("GEMINI.md").allowed).toBe(true);
53
+ (0, vitest_1.expect)((0, migrate_js_1.isAllowedException)("src/GEMINI.md").allowed).toBe(true);
54
+ (0, vitest_1.expect)((0, migrate_js_1.isAllowedException)("COPILOT.md").allowed).toBe(true);
55
+ });
56
+ (0, vitest_1.it)("allows files in smartdocs/, generated/, summaries/", () => {
57
+ (0, vitest_1.expect)((0, migrate_js_1.isAllowedException)("smartdocs/some-doc.md").allowed).toBe(true);
58
+ (0, vitest_1.expect)((0, migrate_js_1.isAllowedException)("generated/output.md").allowed).toBe(true);
59
+ (0, vitest_1.expect)((0, migrate_js_1.isAllowedException)("summaries/summary.md").allowed).toBe(true);
60
+ });
61
+ });
62
+ // ---------------------------------------------------------------------------
63
+ // migrateDocs — dry-run
64
+ // ---------------------------------------------------------------------------
65
+ function makeGitRepo() {
66
+ const repoRoot = (0, node_fs_2.mkdtempSync)((0, node_path_1.join)((0, node_os_1.tmpdir)(), "polaris-migrate-"));
67
+ (0, node_child_process_1.execFileSync)("git", ["init"], { cwd: repoRoot });
68
+ (0, node_child_process_1.execFileSync)("git", ["config", "user.email", "test@test.com"], { cwd: repoRoot });
69
+ (0, node_child_process_1.execFileSync)("git", ["config", "user.name", "Test"], { cwd: repoRoot });
70
+ return repoRoot;
71
+ }
72
+ function addTrackedFile(repoRoot, relPath, content = "# Doc\n\nContent") {
73
+ const absPath = (0, node_path_1.join)(repoRoot, relPath);
74
+ (0, node_fs_1.mkdirSync)((0, node_path_1.join)(repoRoot, relPath.split("/").slice(0, -1).join("/")), { recursive: true });
75
+ (0, node_fs_1.writeFileSync)(absPath, content, "utf-8");
76
+ (0, node_child_process_1.execFileSync)("git", ["add", relPath], { cwd: repoRoot });
77
+ }
78
+ (0, vitest_1.describe)("migrateDocs --dry-run", () => {
79
+ let repoRoot;
80
+ (0, vitest_1.beforeEach)(() => {
81
+ repoRoot = makeGitRepo();
82
+ });
83
+ (0, vitest_1.it)("reports files to migrate and allowed exceptions, does not move files", () => {
84
+ addTrackedFile(repoRoot, "README.md");
85
+ addTrackedFile(repoRoot, "planning/ideas.md");
86
+ addTrackedFile(repoRoot, "docs/spec/existing.md");
87
+ const result = (0, migrate_js_1.migrateDocs)({ repoRoot, dryRun: true, migrationRunId: "test-migrate-001" });
88
+ (0, vitest_1.expect)(result.dryRun).toBe(true);
89
+ (0, vitest_1.expect)(result.migrationRunId).toBe("test-migrate-001");
90
+ const migrated = result.results.filter((r) => r.classification === "migrated");
91
+ const exceptions = result.results.filter((r) => r.classification === "allowed-exception");
92
+ (0, vitest_1.expect)(migrated).toHaveLength(2);
93
+ const migratedPaths = migrated.map((r) => r.originalPath);
94
+ (0, vitest_1.expect)(migratedPaths).toContain("planning/ideas.md");
95
+ (0, vitest_1.expect)(migratedPaths).toContain("docs/spec/existing.md");
96
+ (0, vitest_1.expect)(exceptions.length).toBeGreaterThanOrEqual(1);
97
+ // Files must NOT have been moved
98
+ (0, vitest_1.expect)((0, node_fs_1.existsSync)((0, node_path_1.join)(repoRoot, "planning/ideas.md"))).toBe(true);
99
+ (0, vitest_1.expect)((0, node_fs_1.existsSync)((0, node_path_1.join)(repoRoot, "smartdocs/docs/raw/ideas.md"))).toBe(false);
100
+ // No provenance written in dry-run
101
+ (0, vitest_1.expect)(result.provenancePath).toBeNull();
102
+ });
103
+ (0, vitest_1.it)("produces ingest batches of at most 4 files", () => {
104
+ for (let i = 0; i < 9; i++) {
105
+ addTrackedFile(repoRoot, `planning/doc${i}.md`);
106
+ }
107
+ const result = (0, migrate_js_1.migrateDocs)({ repoRoot, dryRun: true, migrationRunId: "test-migrate-002" });
108
+ const allBatched = result.ingestBatches.flat();
109
+ (0, vitest_1.expect)(allBatched).toHaveLength(9);
110
+ for (const batch of result.ingestBatches) {
111
+ (0, vitest_1.expect)(batch.length).toBeLessThanOrEqual(4);
112
+ }
113
+ });
114
+ });
115
+ // ---------------------------------------------------------------------------
116
+ // migrateDocs — actual migration
117
+ // ---------------------------------------------------------------------------
118
+ (0, vitest_1.describe)("migrateDocs (live)", () => {
119
+ let repoRoot;
120
+ (0, vitest_1.beforeEach)(() => {
121
+ repoRoot = makeGitRepo();
122
+ });
123
+ (0, vitest_1.it)("moves files to smartdocs/docs/raw/, writes provenance JSON", () => {
124
+ addTrackedFile(repoRoot, "README.md");
125
+ addTrackedFile(repoRoot, "scratch/notes.md", "# Notes");
126
+ const result = (0, migrate_js_1.migrateDocs)({ repoRoot, dryRun: false, migrationRunId: "test-migrate-live-001" });
127
+ (0, vitest_1.expect)(result.dryRun).toBe(false);
128
+ const migrated = result.results.filter((r) => r.classification === "migrated");
129
+ (0, vitest_1.expect)(migrated).toHaveLength(1);
130
+ (0, vitest_1.expect)(migrated[0].originalPath).toBe("scratch/notes.md");
131
+ (0, vitest_1.expect)(migrated[0].currentPath).toBe("smartdocs/docs/raw/notes.md");
132
+ // File should now exist in smartdocs/docs/raw/
133
+ (0, vitest_1.expect)((0, node_fs_1.existsSync)((0, node_path_1.join)(repoRoot, "smartdocs/docs/raw/notes.md"))).toBe(true);
134
+ // File should no longer exist at original location
135
+ (0, vitest_1.expect)((0, node_fs_1.existsSync)((0, node_path_1.join)(repoRoot, "scratch/notes.md"))).toBe(false);
136
+ // Provenance written
137
+ (0, vitest_1.expect)(result.provenancePath).not.toBeNull();
138
+ const provContent = JSON.parse((0, node_fs_1.readFileSync)((0, node_path_1.join)(repoRoot, result.provenancePath), "utf-8"));
139
+ (0, vitest_1.expect)(provContent).toHaveLength(1);
140
+ (0, vitest_1.expect)(provContent[0].originalPath).toBe("scratch/notes.md");
141
+ (0, vitest_1.expect)(provContent[0].currentPath).toBe("smartdocs/docs/raw/notes.md");
142
+ (0, vitest_1.expect)(provContent[0].migrationRunId).toBe("test-migrate-live-001");
143
+ (0, vitest_1.expect)(provContent[0].migratedAt).toBeTruthy();
144
+ });
145
+ (0, vitest_1.it)("excludes AGENTS.md, CLAUDE.md, GEMINI.md from migration queue by default", () => {
146
+ addTrackedFile(repoRoot, "AGENTS.md", "# Agents");
147
+ addTrackedFile(repoRoot, "CLAUDE.md", "# Claude");
148
+ addTrackedFile(repoRoot, "GEMINI.md", "# Gemini");
149
+ addTrackedFile(repoRoot, "scratch/notes.md", "# Notes");
150
+ const result = (0, migrate_js_1.migrateDocs)({ repoRoot, dryRun: true, migrationRunId: "test-endpoint-001" });
151
+ const migrated = result.results.filter((r) => r.classification === "migrated");
152
+ const exceptions = result.results.filter((r) => r.classification === "allowed-exception");
153
+ // Only scratch/notes.md should be migrated
154
+ (0, vitest_1.expect)(migrated).toHaveLength(1);
155
+ (0, vitest_1.expect)(migrated[0].originalPath).toBe("scratch/notes.md");
156
+ // AGENTS.md, CLAUDE.md, GEMINI.md should be exceptions
157
+ const exceptionPaths = exceptions.map((r) => r.originalPath);
158
+ (0, vitest_1.expect)(exceptionPaths).toContain("AGENTS.md");
159
+ (0, vitest_1.expect)(exceptionPaths).toContain("CLAUDE.md");
160
+ (0, vitest_1.expect)(exceptionPaths).toContain("GEMINI.md");
161
+ });
162
+ (0, vitest_1.it)("does not re-migrate files in smartdocs/", () => {
163
+ addTrackedFile(repoRoot, "smartdocs/smart-doc.md", "# Smart Doc");
164
+ addTrackedFile(repoRoot, "scratch/notes.md", "# Notes");
165
+ const result = (0, migrate_js_1.migrateDocs)({ repoRoot, dryRun: true, migrationRunId: "test-endpoint-002" });
166
+ const migrated = result.results.filter((r) => r.classification === "migrated");
167
+ const exceptions = result.results.filter((r) => r.classification === "allowed-exception");
168
+ (0, vitest_1.expect)(migrated).toHaveLength(1);
169
+ (0, vitest_1.expect)(migrated[0].originalPath).toBe("scratch/notes.md");
170
+ const exceptionPaths = exceptions.map((r) => r.originalPath);
171
+ (0, vitest_1.expect)(exceptionPaths).toContain("smartdocs/smart-doc.md");
172
+ });
173
+ (0, vitest_1.it)("respects .smartdocignore custom patterns in migrate", () => {
174
+ // Write a .smartdocignore with a custom pattern
175
+ (0, node_fs_1.writeFileSync)((0, node_path_1.join)(repoRoot, ".smartdocignore"), "custom-ignore/**\n", "utf-8");
176
+ (0, node_child_process_1.execFileSync)("git", ["add", ".smartdocignore"], { cwd: repoRoot });
177
+ addTrackedFile(repoRoot, "custom-ignore/secret.md", "# Secret");
178
+ addTrackedFile(repoRoot, "scratch/notes.md", "# Notes");
179
+ const result = (0, migrate_js_1.migrateDocs)({ repoRoot, dryRun: true, migrationRunId: "test-endpoint-003" });
180
+ const migrated = result.results.filter((r) => r.classification === "migrated");
181
+ const exceptions = result.results.filter((r) => r.classification === "allowed-exception");
182
+ (0, vitest_1.expect)(migrated).toHaveLength(1);
183
+ (0, vitest_1.expect)(migrated[0].originalPath).toBe("scratch/notes.md");
184
+ const smartdocExceptions = exceptions.filter((r) => r.endpointArtifactReason === "smartdocignore-endpoint-artifact");
185
+ (0, vitest_1.expect)(smartdocExceptions.length).toBeGreaterThanOrEqual(1);
186
+ const ignoredPaths = smartdocExceptions.map((r) => r.originalPath);
187
+ (0, vitest_1.expect)(ignoredPaths).toContain("custom-ignore/secret.md");
188
+ });
189
+ (0, vitest_1.it)("handles filename collisions by uniquifying destination", () => {
190
+ (0, node_fs_1.mkdirSync)((0, node_path_1.join)(repoRoot, "smartdocs/docs/raw"), { recursive: true });
191
+ (0, node_fs_1.writeFileSync)((0, node_path_1.join)(repoRoot, "smartdocs/docs/raw/notes.md"), "# Existing", "utf-8");
192
+ (0, node_child_process_1.execFileSync)("git", ["add", "smartdocs/docs/raw/notes.md"], { cwd: repoRoot });
193
+ addTrackedFile(repoRoot, "scratch/notes.md", "# Incoming");
194
+ const result = (0, migrate_js_1.migrateDocs)({ repoRoot, dryRun: false, migrationRunId: "test-migrate-live-002" });
195
+ const migrated = result.results.filter((r) => r.classification === "migrated");
196
+ (0, vitest_1.expect)(migrated).toHaveLength(1);
197
+ (0, vitest_1.expect)(migrated[0].currentPath).toBe("smartdocs/docs/raw/notes-2.md");
198
+ (0, vitest_1.expect)((0, node_fs_1.existsSync)((0, node_path_1.join)(repoRoot, "smartdocs/docs/raw/notes-2.md"))).toBe(true);
199
+ });
200
+ });