@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,474 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.runFinalize = runFinalize;
4
+ exports.createFinalizeCommand = createFinalizeCommand;
5
+ const commander_1 = require("commander");
6
+ const node_path_1 = require("node:path");
7
+ const node_fs_1 = require("node:fs");
8
+ const node_child_process_1 = require("node:child_process");
9
+ const closeout_librarian_types_js_1 = require("../cognition/closeout-librarian-types.js");
10
+ const loader_js_1 = require("../config/loader.js");
11
+ const checkpoint_js_1 = require("../loop/checkpoint.js");
12
+ const artifact_policy_js_1 = require("./artifact-policy.js");
13
+ const git_custody_js_1 = require("../loop/git-custody.js");
14
+ const store_js_1 = require("../cluster-state/store.js");
15
+ const canon_check_js_1 = require("../smartdocs-engine/canon-check.js");
16
+ const _01_map_update_js_1 = require("./steps/01-map-update.js");
17
+ const _02_map_validate_js_1 = require("./steps/02-map-validate.js");
18
+ const _03_schema_validate_js_1 = require("./steps/03-schema-validate.js");
19
+ const _04_run_checks_js_1 = require("./steps/04-run-checks.js");
20
+ const _05_generate_report_js_1 = require("./steps/05-generate-report.js");
21
+ const _06_commit_js_1 = require("./steps/06-commit.js");
22
+ const _07_push_js_1 = require("./steps/07-push.js");
23
+ const _08_create_pr_js_1 = require("./steps/08-create-pr.js");
24
+ const _09_update_state_js_1 = require("./steps/09-update-state.js");
25
+ const _10_append_jsonl_js_1 = require("./steps/10-append-jsonl.js");
26
+ const _11_update_linear_js_1 = require("./steps/11-update-linear.js");
27
+ const _12_archive_js_1 = require("./steps/12-archive.js");
28
+ const local_graph_js_1 = require("../tracker/local-graph.js");
29
+ const index_js_1 = require("../tracker/sync/index.js");
30
+ const finalize_evidence_js_1 = require("../loop/finalize-evidence.js");
31
+ const delivery_integrity_js_1 = require("./delivery-integrity.js");
32
+ function getBranch(repoRoot) {
33
+ try {
34
+ return (0, node_child_process_1.execFileSync)("git", ["rev-parse", "--abbrev-ref", "HEAD"], {
35
+ cwd: repoRoot,
36
+ encoding: "utf-8",
37
+ }).trim();
38
+ }
39
+ catch (err) {
40
+ const msg = err instanceof Error ? err.message : String(err);
41
+ throw new Error(`Failed to get current branch in ${repoRoot}: ${msg}`);
42
+ }
43
+ }
44
+ function normalizeBranchName(branch) {
45
+ return branch.toLowerCase().replace(/_/g, "-");
46
+ }
47
+ function extractClusterSlug(clusterId) {
48
+ const match = clusterId.match(/([A-Z]+-\d+)/);
49
+ return match ? normalizeBranchName(match[1]) : normalizeBranchName(clusterId);
50
+ }
51
+ function validateStateFilePath(stateFile) {
52
+ const normalizedPath = stateFile.replace(/\\/g, "/");
53
+ const debugPath = ".taskchain_artifacts/polaris-run/current-state.json";
54
+ const legacyPath = ".polaris/runs/current-state.json";
55
+ if (normalizedPath.endsWith(debugPath)) {
56
+ process.stderr.write(`finalize aborted: state file at compatibility/debug path — ${stateFile}\n` +
57
+ `Canonical state files must be at .polaris/clusters/<cluster-id>/state.json or custom path.\n`);
58
+ process.exit(1);
59
+ }
60
+ if (normalizedPath.endsWith(legacyPath)) {
61
+ process.stderr.write(`finalize aborted: state file at legacy path — ${stateFile}\n` +
62
+ `Canonical state files must be at .polaris/clusters/<cluster-id>/state.json or custom path.\n`);
63
+ process.exit(1);
64
+ }
65
+ }
66
+ function validateClusterIdMatchesBranch(clusterId, branch) {
67
+ const clusterSlug = extractClusterSlug(clusterId);
68
+ const normalizedBranch = normalizeBranchName(branch);
69
+ const slugPattern = new RegExp(`(^|-)${clusterSlug.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}(-|$)`);
70
+ if (!slugPattern.test(normalizedBranch)) {
71
+ process.stderr.write(`finalize aborted: cluster_id mismatch — state.cluster_id "${clusterId}" ` +
72
+ `does not match current branch "${branch}".\n` +
73
+ `Expected branch to contain slug "${clusterSlug}" (normalized from "${clusterId}").\n`);
74
+ process.exit(1);
75
+ }
76
+ }
77
+ function validateStateBranchMatchesGitBranch(stateBranch, branch) {
78
+ if (!stateBranch || stateBranch.trim() === "") {
79
+ return;
80
+ }
81
+ if (stateBranch !== branch) {
82
+ process.stderr.write(`finalize aborted: state.branch mismatch — state.branch "${stateBranch}" ` +
83
+ `does not match current git branch "${branch}".\n`);
84
+ process.exit(1);
85
+ }
86
+ }
87
+ /**
88
+ * Check that the Closeout Librarian has run and its result passes the gate.
89
+ * Returns null if finalize may proceed; returns a human-readable blocker string if not.
90
+ */
91
+ function checkLibrarianGate(repoRoot, clusterId) {
92
+ const packetsDir = (0, node_path_1.join)(repoRoot, ".polaris", "clusters", clusterId, "packets");
93
+ let packetFiles = [];
94
+ try {
95
+ packetFiles = (0, node_fs_1.readdirSync)(packetsDir)
96
+ .filter((f) => f.startsWith("librarian-packet-") && f.endsWith(".json"))
97
+ .sort();
98
+ }
99
+ catch {
100
+ // directory absent — no packet has been generated
101
+ }
102
+ const latestPacket = packetFiles
103
+ .map((file) => (0, node_path_1.join)(packetsDir, file))
104
+ .sort((a, b) => {
105
+ try {
106
+ return (0, node_fs_1.statSync)(b).mtimeMs - (0, node_fs_1.statSync)(a).mtimeMs;
107
+ }
108
+ catch {
109
+ return b.localeCompare(a);
110
+ }
111
+ })[0];
112
+ if (!latestPacket) {
113
+ return ("Closeout Librarian has not been dispatched for this cluster.\n" +
114
+ ` 1. Generate packet: npm run polaris -- librarian packet ${clusterId} --state-file <state-file>\n` +
115
+ ` 2. Dispatch the Librarian with the generated packet path as the sole session prompt.\n` +
116
+ ` 3. Wait for the Librarian to write its sealed result.\n` +
117
+ ` 4. Re-run finalize.\n` +
118
+ `Use --skip-librarian to bypass this gate for backward compatibility.`);
119
+ }
120
+ let packetJson;
121
+ try {
122
+ packetJson = JSON.parse((0, node_fs_1.readFileSync)(latestPacket, "utf-8"));
123
+ }
124
+ catch {
125
+ return `Cannot read Librarian packet at ${latestPacket}. Regenerate with: npm run polaris -- librarian packet ${clusterId}`;
126
+ }
127
+ const resultPath = packetJson["result_path"];
128
+ if (typeof resultPath !== "string") {
129
+ return `Librarian packet is malformed: missing result_path. Regenerate with: npm run polaris -- librarian packet ${clusterId}`;
130
+ }
131
+ if (!(0, node_fs_1.existsSync)(resultPath)) {
132
+ return ("Closeout Librarian has not written its sealed result yet.\n" +
133
+ ` Expected result at: ${resultPath}\n` +
134
+ ` Dispatch the Librarian session and wait for it to write its sealed result, then re-run finalize.`);
135
+ }
136
+ let resultJson;
137
+ try {
138
+ resultJson = JSON.parse((0, node_fs_1.readFileSync)(resultPath, "utf-8"));
139
+ }
140
+ catch {
141
+ return `Cannot read Librarian result at ${resultPath}. The file may be corrupt.`;
142
+ }
143
+ const validationErrors = (0, closeout_librarian_types_js_1.validateCloseoutLibrarianResult)(resultJson);
144
+ if (validationErrors.length > 0) {
145
+ return `Librarian result is invalid: ${validationErrors.join("; ")}`;
146
+ }
147
+ // Cross-validate dispatch_id and run_id
148
+ const result = resultJson;
149
+ if (packetJson["dispatch_id"] !== result.dispatch_id) {
150
+ return `Librarian result dispatch_id mismatch (packet: ${packetJson["dispatch_id"]}, result: ${result.dispatch_id}). Regenerate and re-dispatch.`;
151
+ }
152
+ if (packetJson["run_id"] !== result.run_id) {
153
+ return `Librarian result run_id mismatch (packet: ${packetJson["run_id"]}, result: ${result.run_id}).`;
154
+ }
155
+ // Validate files_committed against packet scope constraints
156
+ const allowedWritePaths = (packetJson["allowed_write_paths"] ?? []);
157
+ const prohibitedWritePaths = (packetJson["prohibited_write_paths"] ?? []);
158
+ const filesCommitted = result.files_committed ?? [];
159
+ for (const file of filesCommitted) {
160
+ const prohibitedMatch = prohibitedWritePaths.find((pattern) => (0, git_custody_js_1.patternMatchesPath)(pattern, file));
161
+ if (prohibitedMatch) {
162
+ return `Librarian wrote to prohibited path: ${file} (matched pattern: ${prohibitedMatch})`;
163
+ }
164
+ const allowedMatch = allowedWritePaths.find((pattern) => (0, git_custody_js_1.patternMatchesPath)(pattern, file));
165
+ if (allowedMatch)
166
+ continue; // explicitly allowed
167
+ return `Librarian wrote to out-of-scope path: ${file} (not in allowed_write_paths)`;
168
+ }
169
+ try {
170
+ return (0, closeout_librarian_types_js_1.checkLibrarianResultGate)(result);
171
+ }
172
+ catch (err) {
173
+ return `Librarian result gate error: ${err instanceof Error ? err.message : String(err)}`;
174
+ }
175
+ }
176
+ async function runFinalize(options) {
177
+ const { repoRoot, stateFile, dryRun, skipDelivery, skipLibrarian } = options;
178
+ const config = (0, loader_js_1.loadConfig)(repoRoot);
179
+ // Step 1: polaris map update --changed
180
+ console.log("[1/14] Updating map..."); // Step count updated
181
+ (0, _01_map_update_js_1.stepMapUpdate)(repoRoot);
182
+ // Step 2: polaris map validate — fail fast
183
+ console.log("[2/14] Validating map..."); // Step count updated
184
+ (0, _02_map_validate_js_1.stepMapValidate)(repoRoot);
185
+ // Step 3: Validate current-state.json schema
186
+ console.log("[3/14] Validating current-state.json schema..."); // Step count updated
187
+ let rawState;
188
+ try {
189
+ rawState = (0, checkpoint_js_1.readState)(stateFile);
190
+ }
191
+ catch (err) {
192
+ const msg = err instanceof Error ? err.message : String(err);
193
+ process.stderr.write(`finalize aborted: cannot read state file ${stateFile}: ${msg}\n`);
194
+ process.exit(1);
195
+ }
196
+ (0, _03_schema_validate_js_1.stepSchemaValidate)(rawState);
197
+ let state = rawState;
198
+ // Preflight: state file authority gate (must run before Step 4)
199
+ const branch = getBranch(repoRoot);
200
+ validateStateFilePath(stateFile);
201
+ validateClusterIdMatchesBranch(state.cluster_id, branch);
202
+ validateStateBranchMatchesGitBranch(state.branch, branch);
203
+ // Step 4: Run configured checks
204
+ const checks = config.finalize?.runChecks ?? [];
205
+ if (checks.length > 0) {
206
+ console.log(`[4/14] Running ${checks.length} configured check(s) and staging preflight...`); // Step count updated
207
+ }
208
+ else {
209
+ console.log("[4/14] Running staging preflight..."); // Step count updated
210
+ }
211
+ (0, _04_run_checks_js_1.stepRunChecks)(repoRoot, checks, { activeClusterId: state.cluster_id, skipDelivery });
212
+ // Step 4.5: Canon reconciliation check
213
+ const canonCheckEnabled = config.canon?.checkOnFinalize !== false;
214
+ if (canonCheckEnabled) {
215
+ console.log("[4.5/14] Running canon reconciliation check..."); // Step count updated
216
+ let changedFiles = [];
217
+ try {
218
+ const baseBranch = config.finalize?.targetBranch ?? "main";
219
+ const diffOutput = (0, node_child_process_1.execFileSync)("git", ["diff", "--name-only", `${baseBranch}...HEAD`], { cwd: repoRoot, encoding: "utf-8" });
220
+ changedFiles = diffOutput.trim().split("\n").filter(Boolean);
221
+ }
222
+ catch (err) {
223
+ // Fail closed: if git diff fails, we cannot determine changed files for canon check
224
+ const msg = err instanceof Error ? err.message : String(err);
225
+ console.error(`Error: git diff failed during canon check: ${msg}`);
226
+ throw new Error(`Canon check cannot proceed: git diff failed: ${msg}`);
227
+ }
228
+ const artifactDirForCheck = state.artifact_dir ?? (0, node_path_1.join)(repoRoot, ".taskchain_artifacts", "polaris-run");
229
+ const telemetryFileForCheck = (0, node_path_1.join)(artifactDirForCheck, "runs", state.run_id, "telemetry.jsonl");
230
+ const canonResult = (0, canon_check_js_1.runCanonCheck)({
231
+ repoRoot,
232
+ changedFiles,
233
+ childId: undefined,
234
+ runId: state.run_id,
235
+ telemetryFile: telemetryFileForCheck,
236
+ });
237
+ if (canonResult.outcome === "stale-implementation") {
238
+ const conflict = canonResult.conflicts.find((c) => c.type === "stale-implementation");
239
+ process.stderr.write([
240
+ `Canon conflict halt — finalize blocked. PR will not be created.`,
241
+ `Canon file: ${conflict?.canonFile ?? "unknown"}`,
242
+ `Statement: ${conflict?.statement ?? ""}`,
243
+ `Affected file: ${conflict?.changedFile ?? ""}`,
244
+ `Detail: ${conflict?.detail ?? ""}`,
245
+ `Resolution: Update the canon file or implement the missing piece before finalizing.`,
246
+ ].join("\n") + "\n");
247
+ process.exit(1);
248
+ }
249
+ }
250
+ // Step 5: Generate run-report.md (written once, never updated)
251
+ console.log("[5/14] Generating run-report.md..."); // Step count updated
252
+ const reportPath = (0, _05_generate_report_js_1.stepGenerateReport)(repoRoot, state, branch, true);
253
+ if (dryRun) {
254
+ console.log("[6–14/14] Dry run — skipping reconciliation, commit and delivery.");
255
+ console.log("Finalize dry run complete.");
256
+ return;
257
+ }
258
+ // Step 5.5: Implementation evidence gate
259
+ // Require at least one non-artifact staged file before committing. A finalize
260
+ // commit with only Polaris artifact files means no real implementation work
261
+ // was recorded — abort to prevent a phantom delivery.
262
+ {
263
+ const stagedOutput = (0, node_child_process_1.execFileSync)("git", ["diff", "--cached", "--name-only"], {
264
+ cwd: repoRoot,
265
+ encoding: "utf-8",
266
+ }).trim();
267
+ const stagedFiles = stagedOutput ? stagedOutput.split("\n").filter(Boolean) : [];
268
+ const implFiles = stagedFiles.filter((f) => (0, artifact_policy_js_1.classifyArtifactPath)(f, state.cluster_id) === "non-artifact");
269
+ if (implFiles.length === 0) {
270
+ const evidenceReport = (0, finalize_evidence_js_1.verifyCompletedChildFinalizeEvidence)(repoRoot, stateFile);
271
+ if (!evidenceReport.ok) {
272
+ process.stderr.write("finalize aborted: No implementation evidence found. " +
273
+ "No non-artifact source files are staged and canonical completed-child evidence failed.\n" +
274
+ `${(0, finalize_evidence_js_1.formatFinalizeEvidenceFailures)(evidenceReport.failures)}\n`);
275
+ process.exit(1);
276
+ }
277
+ }
278
+ }
279
+ // Step 5.6: Branch custody verification
280
+ // When the cluster state records a delivery_branch and base_branch (set by dispatch),
281
+ // verify that base..delivery_branch contains at least one non-artifact source change
282
+ // and that no completed child's commit is already reachable from the base branch.
283
+ //
284
+ // Skipped when no custody record is present (backward compatibility with runs
285
+ // that did not go through the custody-aware dispatch path) or when
286
+ // loop.allowBranchDivergence is true (direct-main mode).
287
+ {
288
+ const clusterState = (0, store_js_1.readClusterStateSync)(state.cluster_id, repoRoot);
289
+ const baseBranch = clusterState?.base_branch;
290
+ const deliveryBranch = clusterState?.delivery_branch;
291
+ const directMainMode = config.loop?.allowBranchDivergence === true;
292
+ if (!directMainMode && baseBranch && deliveryBranch) {
293
+ // Assert finalize is running on the recorded delivery branch.
294
+ if (branch !== deliveryBranch) {
295
+ process.stderr.write(`finalize aborted: branch custody violation — not on delivery branch. ` +
296
+ `Expected "${deliveryBranch}", got "${branch}".\n`);
297
+ process.exit(1);
298
+ }
299
+ const hasImplChanges = (0, git_custody_js_1.hasNonArtifactSourceChanges)(repoRoot, baseBranch, state.cluster_id, deliveryBranch);
300
+ if (!hasImplChanges) {
301
+ process.stderr.write(`finalize aborted: branch custody violation — no non-artifact source changes found in ` +
302
+ `${baseBranch}...${deliveryBranch}. Child commits may already be on the base branch, ` +
303
+ `or no implementation work was recorded on this delivery branch.\n`);
304
+ process.exit(1);
305
+ }
306
+ // Check each completed child's commit to verify it is not already on the base branch.
307
+ for (const childId of state.completed_children) {
308
+ const commitHash = clusterState.commits?.[childId] ??
309
+ state.completed_children_results?.[childId]?.commit ??
310
+ null;
311
+ if (!commitHash)
312
+ continue;
313
+ const custodyError = (0, git_custody_js_1.verifyChildCommitCustody)(repoRoot, commitHash, deliveryBranch, baseBranch);
314
+ if (custodyError) {
315
+ process.stderr.write(`finalize aborted: branch custody violation for ${childId}: ${custodyError}\n`);
316
+ process.exit(1);
317
+ }
318
+ }
319
+ }
320
+ }
321
+ // Step 5.7: Unconditional delivery integrity gate
322
+ // Verifies the delivery branch contains actual implementation work relative to the base branch.
323
+ // Runs regardless of whether branch custody records were established in cluster state,
324
+ // closing the gap that allowed PR #93 to claim delivery when implementation was already on main.
325
+ {
326
+ const directMainMode = config.loop?.allowBranchDivergence === true;
327
+ if (!directMainMode) {
328
+ const clusterStateForIntegrity = (0, store_js_1.readClusterStateSync)(state.cluster_id, repoRoot);
329
+ const integrityBaseBranch = clusterStateForIntegrity?.base_branch ??
330
+ config.finalize?.targetBranch ??
331
+ "main";
332
+ const childCommits = {};
333
+ for (const childId of state.completed_children) {
334
+ const commit = clusterStateForIntegrity?.commits?.[childId] ??
335
+ state.completed_children_results?.[childId]?.commit ??
336
+ null;
337
+ if (commit)
338
+ childCommits[childId] = commit;
339
+ }
340
+ const integrityResult = (0, delivery_integrity_js_1.validateDeliveryIntegrity)({
341
+ repoRoot,
342
+ currentBranch: branch,
343
+ baseBranch: integrityBaseBranch,
344
+ clusterId: state.cluster_id,
345
+ completedChildren: state.completed_children,
346
+ childCommits,
347
+ });
348
+ if (!integrityResult.ok) {
349
+ process.stderr.write(`finalize aborted: delivery integrity check failed (${integrityResult.kind}) — ${integrityResult.reason}\n`);
350
+ process.exit(1);
351
+ }
352
+ }
353
+ }
354
+ // Step 6: Tracker Reconciliation
355
+ // LinearAdapter is sync-in only; only McpBridgeAdapter supports full reconciliation.
356
+ const trackerType = config.tracker?.adapter;
357
+ if (!trackerType) {
358
+ console.log("[6/14] Tracker not configured — skipping reconciliation.");
359
+ }
360
+ else if (trackerType === "linear") {
361
+ console.log("[6/14] Linear adapter is sync-in only — skipping reconciliation (use mcp-bridge for two-way sync).");
362
+ }
363
+ else if (trackerType === "mcp-bridge") {
364
+ console.log("[6/14] Running tracker reconciliation...");
365
+ try {
366
+ const localGraph = await local_graph_js_1.LocalGraph.load(state.cluster_id, repoRoot);
367
+ const { McpBridgeAdapter } = await import("../tracker/adapters/mcp-bridge.js");
368
+ const trackerAdapter = new McpBridgeAdapter();
369
+ const trackerSyncService = new index_js_1.TrackerSyncService(trackerAdapter, localGraph, {
370
+ repoRoot,
371
+ clusterId: state.cluster_id,
372
+ });
373
+ await trackerSyncService.ready;
374
+ const reconciliationReport = await trackerSyncService.reconcile(dryRun);
375
+ console.log("Tracker Reconciliation Report:", reconciliationReport);
376
+ if (reconciliationReport.conflictsDetectedCount > 0 || reconciliationReport.failedMutationsCount > 0) {
377
+ const summary = reconciliationReport.details.join(" | ");
378
+ throw new Error(`tracker reconciliation requires attention (conflicts=${reconciliationReport.conflictsDetectedCount}, failed=${reconciliationReport.failedMutationsCount})${summary ? `: ${summary}` : ""}`);
379
+ }
380
+ }
381
+ catch (error) {
382
+ console.error("Error during tracker reconciliation:", error);
383
+ process.stderr.write(`finalize aborted: tracker reconciliation failed: ${error instanceof Error ? error.message : String(error)}\n`);
384
+ process.exit(1);
385
+ }
386
+ }
387
+ else {
388
+ console.warn(`[6/14] Unknown tracker adapter '${trackerType}' — skipping reconciliation.`);
389
+ }
390
+ // Step 7: Single final commit: source changes + durable Polaris artifacts
391
+ console.log("[7/14] Committing durable Polaris state + map..."); // Step count updated
392
+ const resolvedStateFile = (0, node_path_1.resolve)(stateFile);
393
+ (0, _06_commit_js_1.stepCommit)(repoRoot, state, resolvedStateFile, reportPath);
394
+ if (skipDelivery) {
395
+ console.log("[8–14/14] Delivery skipped (--skip-delivery).");
396
+ console.log("polaris finalize steps 1–7 complete.");
397
+ return;
398
+ }
399
+ // Step 8: Closeout Librarian gate
400
+ if (!skipLibrarian) {
401
+ console.log("[8/14] Checking Closeout Librarian gate...");
402
+ const librarianBlocker = checkLibrarianGate(repoRoot, state.cluster_id);
403
+ if (librarianBlocker) {
404
+ process.stderr.write(`finalize aborted: Closeout Librarian gate failed.\n${librarianBlocker}\n`);
405
+ process.exit(1);
406
+ }
407
+ console.log("[8/14] Closeout Librarian gate passed.");
408
+ }
409
+ else {
410
+ console.log("[8/14] Closeout Librarian gate skipped (--skip-librarian).");
411
+ }
412
+ // Step 9: git push
413
+ console.log("[9/14] Pushing branch...");
414
+ (0, _07_push_js_1.stepPush)(repoRoot, branch);
415
+ // Step 10: Create draft PR
416
+ const prDraft = config.finalize?.prDraft ?? true;
417
+ console.log("[10/14] Creating draft PR...");
418
+ const prUrl = (0, _08_create_pr_js_1.stepCreatePr)(repoRoot, branch, state, prDraft);
419
+ // Step 11: Write PR URL to current-state.json
420
+ console.log("[11/14] Writing PR URL to state...");
421
+ state = (0, _09_update_state_js_1.stepUpdateState)(resolvedStateFile, state, prUrl);
422
+ // Step 12: Append JSONL events
423
+ console.log("[12/14] Appending JSONL events...");
424
+ const artifactDir = state.artifact_dir ?? (0, node_path_1.join)(repoRoot, ".taskchain_artifacts", "polaris-run");
425
+ const telemetryFile = (0, node_path_1.join)(artifactDir, "runs", state.run_id, "telemetry.jsonl");
426
+ (0, _10_append_jsonl_js_1.stepAppendJsonl)(telemetryFile, state, prUrl);
427
+ // Step 13: Update Linear parent issue
428
+ console.log("[13/14] Updating Linear...");
429
+ const linearEnabled = config.tracker?.linear?.enabled ?? false;
430
+ const lifecyclePolicy = config.tracker?.lifecyclePolicy;
431
+ await (0, _11_update_linear_js_1.stepUpdateLinear)(state, branch, prUrl, true, linearEnabled, state.cluster_id, lifecyclePolicy);
432
+ // Step 14: Archive run snapshot
433
+ console.log("[14/14] Archiving run snapshot...");
434
+ (0, _12_archive_js_1.stepArchive)(repoRoot, state, resolvedStateFile, reportPath);
435
+ console.log("polaris finalize complete.");
436
+ }
437
+ function failMissingSubcommand(command, commandName) {
438
+ const unknownSubcommand = command.args[0];
439
+ const message = unknownSubcommand
440
+ ? `error: unknown command '${unknownSubcommand}' for '${commandName}'. Run '${commandName} --help'.`
441
+ : `error: missing command for '${commandName}'. Run '${commandName} --help'.`;
442
+ command.error(message, {
443
+ code: "commander.missingCommand",
444
+ exitCode: 1,
445
+ });
446
+ }
447
+ function createFinalizeCommand(handlers = {}) {
448
+ const finalizeHandler = handlers.runFinalize ?? runFinalize;
449
+ const repoRootDefault = handlers.repoRoot ?? process.cwd();
450
+ const finalize = new commander_1.Command("finalize")
451
+ .description("manual/operator-triggered delivery; finalize run performs delivery unless --dry-run or --skip-delivery is supplied")
452
+ .showHelpAfterError()
453
+ .showSuggestionAfterError();
454
+ finalize.action(() => failMissingSubcommand(finalize, "polaris finalize"));
455
+ finalize
456
+ .command("run")
457
+ .description("mutating: run manual/operator-triggered finalize and perform delivery")
458
+ .option("-r, --repo-root <path>", "Repository root", repoRootDefault)
459
+ .option("--state-file <path>", "Path to current-state.json")
460
+ .option("--dry-run", "non-mutating preview: validate and generate report without committing or pushing")
461
+ .option("--skip-delivery", "perform local finalize steps only; skip push/PR/Linear/archive")
462
+ .option("--skip-librarian", "skip the Closeout Librarian gate (backward compatibility only)")
463
+ .action((options) => {
464
+ const repoRoot = options.repoRoot;
465
+ const stateFile = options.stateFile ??
466
+ (0, node_path_1.join)(repoRoot, ".taskchain_artifacts", "polaris-run", "current-state.json");
467
+ finalizeHandler({ repoRoot, stateFile, dryRun: options.dryRun, skipDelivery: options.skipDelivery, skipLibrarian: options.skipLibrarian })
468
+ .catch((err) => {
469
+ process.stderr.write(`finalize error: ${err instanceof Error ? err.message : String(err)}\n`);
470
+ process.exit(1);
471
+ });
472
+ });
473
+ return finalize;
474
+ }