@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,645 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.runLoopContinue = runLoopContinue;
4
+ const node_path_1 = require("node:path");
5
+ const node_fs_1 = require("node:fs");
6
+ const node_crypto_1 = require("node:crypto");
7
+ const node_child_process_1 = require("node:child_process");
8
+ const store_js_1 = require("../cluster-state/store.js");
9
+ const git_custody_js_1 = require("./git-custody.js");
10
+ const checkpoint_js_1 = require("./checkpoint.js");
11
+ const bootstrap_packet_js_1 = require("./bootstrap-packet.js");
12
+ const loader_js_1 = require("../config/loader.js");
13
+ const canon_check_js_1 = require("../smartdocs-engine/canon-check.js");
14
+ const dispatch_boundary_js_1 = require("./dispatch-boundary.js");
15
+ const ledger_js_1 = require("./ledger.js");
16
+ const librarian_dispatch_js_1 = require("../cognition/librarian-dispatch.js");
17
+ /** Resolves the expected sealed result file path for a child from its dispatch metadata. */
18
+ function resolveResultFileForChild(state, childId) {
19
+ const meta = state.open_children_meta?.[childId];
20
+ return meta?.result_file ?? meta?.dispatch_record?.expected_result_path ?? null;
21
+ }
22
+ /**
23
+ * Verifies that a completed child has adequate sealed-result evidence before checkpointing.
24
+ * When a worker has pre-moved itself into completed_children, falls through to full evidence
25
+ * check if a result file is present rather than accepting stale state.
26
+ */
27
+ function verifyCompletionEvidenceForContinue(state, completedChild, repoRoot) {
28
+ const resultFile = resolveResultFileForChild(state, completedChild);
29
+ const resolvedResultFile = resultFile
30
+ ? (0, node_path_1.isAbsolute)(resultFile)
31
+ ? resultFile
32
+ : (0, node_path_1.resolve)(repoRoot, resultFile)
33
+ : null;
34
+ if (state.completed_children.includes(completedChild)) {
35
+ // Worker pre-moved itself into completed_children (protocol violation, but tolerated).
36
+ // Fall through to full evidence check when a result file exists; otherwise accept as-is.
37
+ if (!resolvedResultFile || !(0, node_fs_1.existsSync)(resolvedResultFile)) {
38
+ return { ok: true, commit: state.last_commit ?? "", rawValidation: undefined, resultFile: "" };
39
+ }
40
+ }
41
+ if (!resultFile || !resolvedResultFile) {
42
+ return {
43
+ ok: false,
44
+ reason: `cannot checkpoint ${completedChild}: no result_file evidence found in state metadata`,
45
+ };
46
+ }
47
+ if (!(0, node_fs_1.existsSync)(resolvedResultFile)) {
48
+ return {
49
+ ok: false,
50
+ reason: `cannot checkpoint ${completedChild}: expected result file is missing (${resultFile})`,
51
+ };
52
+ }
53
+ let parsed;
54
+ try {
55
+ const content = (0, node_fs_1.readFileSync)(resolvedResultFile, "utf-8");
56
+ const raw = JSON.parse(content);
57
+ if (typeof raw !== "object" || raw === null || Array.isArray(raw)) {
58
+ return {
59
+ ok: false,
60
+ reason: `cannot checkpoint ${completedChild}: result file has invalid JSON shape`,
61
+ };
62
+ }
63
+ parsed = raw;
64
+ }
65
+ catch (error) {
66
+ return {
67
+ ok: false,
68
+ reason: `cannot checkpoint ${completedChild}: failed to read result file (${error instanceof Error ? error.message : String(error)})`,
69
+ };
70
+ }
71
+ const status = String(parsed["status"] ?? "").trim().toLowerCase();
72
+ if (!["done", "success"].includes(status)) {
73
+ return {
74
+ ok: false,
75
+ reason: `cannot checkpoint ${completedChild}: result status is "${status || "unknown"}" (expected done/success)`,
76
+ };
77
+ }
78
+ const commit = String(parsed["commit"] ?? parsed["commit_hash"] ?? "").trim();
79
+ if (!commit) {
80
+ if (!readPacketFlag(state, completedChild, repoRoot, "artifact_only")) {
81
+ return {
82
+ ok: false,
83
+ reason: `cannot checkpoint ${completedChild}: result file is missing commit evidence`,
84
+ };
85
+ }
86
+ return { ok: true, commit: "", rawValidation: parsed["validation"], resultFile };
87
+ }
88
+ // Reject placeholder strings that are not valid git hashes (hex, ≥7 chars)
89
+ if (!/^[0-9a-f]{7,}$/i.test(commit)) {
90
+ return {
91
+ ok: false,
92
+ reason: `cannot checkpoint ${completedChild}: result commit "${commit}" is not a valid git hash (expected hex string of ≥7 chars)`,
93
+ };
94
+ }
95
+ return { ok: true, commit, rawValidation: parsed["validation"], resultFile };
96
+ }
97
+ function resolvePacketPath(state, childId, repoRoot) {
98
+ const dispatchRecord = state.open_children_meta?.[childId]?.dispatch_record;
99
+ const packetPath = dispatchRecord?.packet_path;
100
+ if (!packetPath)
101
+ return null;
102
+ return (0, node_path_1.isAbsolute)(packetPath) ? packetPath : (0, node_path_1.resolve)(repoRoot, packetPath);
103
+ }
104
+ function readPacketFlag(state, childId, repoRoot, flag) {
105
+ const packetPath = resolvePacketPath(state, childId, repoRoot);
106
+ if (!packetPath || !(0, node_fs_1.existsSync)(packetPath))
107
+ return undefined;
108
+ try {
109
+ const packet = JSON.parse((0, node_fs_1.readFileSync)(packetPath, "utf-8"));
110
+ const fromRoot = packet[flag];
111
+ if (fromRoot !== undefined)
112
+ return fromRoot;
113
+ const instructions = packet["instructions"];
114
+ if (instructions && typeof instructions === "object" && !Array.isArray(instructions)) {
115
+ return instructions[flag];
116
+ }
117
+ return undefined;
118
+ }
119
+ catch {
120
+ return undefined;
121
+ }
122
+ }
123
+ function readPacketAllowedScope(state, childId, repoRoot) {
124
+ const packetPath = resolvePacketPath(state, childId, repoRoot);
125
+ if (!packetPath || !(0, node_fs_1.existsSync)(packetPath))
126
+ return [];
127
+ try {
128
+ const packet = JSON.parse((0, node_fs_1.readFileSync)(packetPath, "utf-8"));
129
+ const instructions = packet["instructions"];
130
+ if (!instructions || typeof instructions !== "object" || Array.isArray(instructions))
131
+ return [];
132
+ const allowedScope = instructions["allowed_scope"];
133
+ if (!Array.isArray(allowedScope))
134
+ return [];
135
+ return allowedScope.filter((entry) => typeof entry === "string");
136
+ }
137
+ catch {
138
+ return [];
139
+ }
140
+ }
141
+ function escapeRegExp(value) {
142
+ return value.replace(/[\\^$+?.()|[\]{}]/g, "\\$&");
143
+ }
144
+ function globPatternToRegExp(pattern) {
145
+ let re = "^";
146
+ for (let i = 0; i < pattern.length; i++) {
147
+ const char = pattern[i];
148
+ if (char === "*") {
149
+ if (pattern[i + 1] === "*") {
150
+ if (pattern[i + 2] === "/") {
151
+ re += "(?:.*/)?";
152
+ i += 2;
153
+ }
154
+ else {
155
+ re += ".*";
156
+ i++;
157
+ }
158
+ }
159
+ else {
160
+ re += "[^/]*";
161
+ }
162
+ continue;
163
+ }
164
+ if (char === "?") {
165
+ re += "[^/]";
166
+ continue;
167
+ }
168
+ re += escapeRegExp(char);
169
+ }
170
+ re += "$";
171
+ return new RegExp(re);
172
+ }
173
+ function matchesAllowedScope(filePath, allowedScope) {
174
+ if (allowedScope.length === 0)
175
+ return false;
176
+ return allowedScope.some((pattern) => globPatternToRegExp(pattern).test(filePath));
177
+ }
178
+ function getChildCommitFiles(repoRoot, commit) {
179
+ try {
180
+ const output = (0, node_child_process_1.execFileSync)("git", ["show", "--format=", "--name-only", "--no-renames", commit], { cwd: repoRoot, encoding: "utf-8" }).trim();
181
+ if (!output)
182
+ return [];
183
+ return Array.from(new Set(output.split("\n").map((line) => line.trim()).filter(Boolean)));
184
+ }
185
+ catch {
186
+ return [];
187
+ }
188
+ }
189
+ function countLoopAbortedEvents(telemetryFile, runId) {
190
+ if (!(0, node_fs_1.existsSync)(telemetryFile))
191
+ return 0;
192
+ const content = (0, node_fs_1.readFileSync)(telemetryFile, "utf-8").trim();
193
+ if (!content)
194
+ return 0;
195
+ return content
196
+ .split("\n")
197
+ .map((line) => {
198
+ try {
199
+ return JSON.parse(line);
200
+ }
201
+ catch {
202
+ return null;
203
+ }
204
+ })
205
+ .filter((event) => !!event)
206
+ .filter((event) => event.event === "loop-aborted" && event.run_id === runId)
207
+ .length;
208
+ }
209
+ function resolveTelemetryFilePath(state, repoRoot) {
210
+ const artifactDir = state.artifact_dir ?? (0, node_path_1.join)(repoRoot, ".taskchain_artifacts", "polaris-run");
211
+ return (0, node_path_1.join)(artifactDir, "runs", state.run_id, "telemetry.jsonl");
212
+ }
213
+ function hasValidationEvidence(validation) {
214
+ if (validation === undefined || validation === null)
215
+ return false;
216
+ if (typeof validation === "boolean")
217
+ return validation;
218
+ if (typeof validation === "string") {
219
+ const n = validation.trim().toLowerCase();
220
+ return ["passed", "pass", "success", "ok"].includes(n);
221
+ }
222
+ if (typeof validation === "object" && !Array.isArray(validation)) {
223
+ const v = validation;
224
+ if (Array.isArray(v["passed"]) && v["passed"].length > 0)
225
+ return true;
226
+ if (v["passed"] === true)
227
+ return true;
228
+ if (typeof v["status"] === "string" && ["passed", "pass", "success", "ok"].includes(v["status"].toLowerCase()))
229
+ return true;
230
+ }
231
+ return false;
232
+ }
233
+ function isValidationWaiver(value) {
234
+ if (typeof value === "boolean")
235
+ return value;
236
+ if (typeof value === "string")
237
+ return value.trim().length > 0;
238
+ if (value && typeof value === "object" && !Array.isArray(value))
239
+ return Object.keys(value).length > 0;
240
+ return false;
241
+ }
242
+ function toValidationResult(rawValidation) {
243
+ return {
244
+ passed: hasValidationEvidence(rawValidation),
245
+ output: typeof rawValidation === "string"
246
+ ? rawValidation
247
+ : rawValidation != null ? JSON.stringify(rawValidation) : "",
248
+ };
249
+ }
250
+ function extractWorkNotePathsFromResult(resultFile, repoRoot) {
251
+ try {
252
+ const resolvedPath = (0, node_path_1.isAbsolute)(resultFile) ? resultFile : (0, node_path_1.resolve)(repoRoot, resultFile);
253
+ if (!(0, node_fs_1.existsSync)(resolvedPath))
254
+ return [];
255
+ const content = (0, node_fs_1.readFileSync)(resolvedPath, "utf-8");
256
+ const parsed = JSON.parse(content);
257
+ const paths = parsed["work_note_paths"];
258
+ if (Array.isArray(paths) && paths.every((p) => typeof p === "string")) {
259
+ return paths;
260
+ }
261
+ return [];
262
+ }
263
+ catch {
264
+ return [];
265
+ }
266
+ }
267
+ function bridgeEvidenceToClusterState(repoRoot, clusterId, childId, commit, rawValidation, resultFile) {
268
+ const existing = (0, store_js_1.readClusterStateSync)(clusterId, repoRoot);
269
+ if (!existing) {
270
+ throw new Error(`cluster-state.json not found for cluster ${clusterId}; cannot persist evidence for ${childId}`);
271
+ }
272
+ const updatedChildStates = existing.child_states.some((cs) => cs.id === childId)
273
+ ? existing.child_states.map((cs) => cs.id === childId ? { ...cs, status: "done", commit: commit || undefined } : cs)
274
+ : [...existing.child_states, { id: childId, status: "done", commit: commit || undefined }];
275
+ // Evict any stale commit entry for this child before conditionally re-adding
276
+ const { [childId]: _staleCommit, ...remainingCommits } = existing.commits;
277
+ const updated = {
278
+ ...existing,
279
+ state_generation: existing.state_generation + 1,
280
+ child_states: updatedChildStates,
281
+ commits: commit ? { ...remainingCommits, [childId]: commit } : remainingCommits,
282
+ result_pointers: resultFile ? { ...existing.result_pointers, [childId]: resultFile } : existing.result_pointers,
283
+ validation_results: { ...existing.validation_results, [childId]: toValidationResult(rawValidation) },
284
+ };
285
+ (0, store_js_1.writeClusterStateSync)(clusterId, updated, repoRoot);
286
+ }
287
+ function readSessionTypeFile(repoRoot) {
288
+ try {
289
+ return (0, node_fs_1.readFileSync)((0, node_path_1.join)(repoRoot, ".polaris", "session-type"), "utf-8").trim();
290
+ }
291
+ catch {
292
+ return undefined;
293
+ }
294
+ }
295
+ function getNextChildType(state, nextChild) {
296
+ if (!nextChild)
297
+ return undefined;
298
+ return state.open_children_meta?.[nextChild]?.type;
299
+ }
300
+ function isAnalyzeImplBoundary(sessionType, nextChildType) {
301
+ return sessionType === "analyze" && nextChildType === "implement";
302
+ }
303
+ function normalizeRunType(sessionType) {
304
+ return sessionType === "analyze" ? "analyze" : "implement";
305
+ }
306
+ function ledgerBranch(state) {
307
+ return state.branch ?? "unknown";
308
+ }
309
+ function ledgerLastCommit(state) {
310
+ return state.last_commit && state.last_commit.length > 0 ? state.last_commit : null;
311
+ }
312
+ function appendContinueLedgerEvents(repoRoot, state, completedChild) {
313
+ if (!completedChild)
314
+ return;
315
+ const writer = new ledger_js_1.LedgerWriter((0, node_path_1.join)(repoRoot, ledger_js_1.DEFAULT_LEDGER_PATH));
316
+ const timestamp = new Date().toISOString();
317
+ const base = {
318
+ schema_version: 1,
319
+ event_id: (0, node_crypto_1.randomUUID)(),
320
+ run_id: state.run_id,
321
+ run_type: normalizeRunType(state.session_type),
322
+ cluster_id: state.cluster_id,
323
+ branch: ledgerBranch(state),
324
+ completed_children: Array.from(new Set(state.completed_children)),
325
+ open_children: state.open_children,
326
+ next_child: state.next_open_child,
327
+ last_commit: ledgerLastCommit(state),
328
+ pr_url: null,
329
+ timestamp,
330
+ };
331
+ writer.append({
332
+ ...base,
333
+ event: "child-completed",
334
+ issue_id: completedChild,
335
+ status: state.status === "cluster-complete" ? "cluster-complete" : "running",
336
+ last_commit: ledgerLastCommit(state),
337
+ validation: { status: "complete" },
338
+ });
339
+ if (state.open_children.length === 0) {
340
+ const telemetryFile = resolveTelemetryFilePath(state, repoRoot);
341
+ writer.append({
342
+ ...base,
343
+ event_id: (0, node_crypto_1.randomUUID)(),
344
+ event: "cluster-complete",
345
+ issue_id: null,
346
+ status: "cluster-complete",
347
+ open_children: [],
348
+ next_child: null,
349
+ recovery_count: countLoopAbortedEvents(telemetryFile, state.run_id),
350
+ });
351
+ }
352
+ }
353
+ function runLoopContinue(options) {
354
+ const { stateFile, repoRoot, provider, allowAnalyzeChildren } = options;
355
+ // Step 1: Read and validate current-state.json
356
+ let rawState;
357
+ try {
358
+ rawState = (0, checkpoint_js_1.readState)(stateFile);
359
+ }
360
+ catch (err) {
361
+ const msg = err instanceof Error ? err.message : String(err);
362
+ console.error(`Error: cannot read state file ${stateFile}: ${msg}`);
363
+ process.exit(1);
364
+ }
365
+ const validationErrors = (0, checkpoint_js_1.validateState)(rawState);
366
+ if (validationErrors.length > 0) {
367
+ console.error(`current-state.json is invalid — cannot generate bootstrap packet:\n${validationErrors.join("\n")}`);
368
+ process.exit(1);
369
+ }
370
+ const state = rawState;
371
+ // ── Dispatch boundary enforcement ─────────────────────────────────────────
372
+ // continue MUST be preceded by a `polaris loop dispatch` call.
373
+ // If no dispatch was recorded (dispatch_epoch === continue_epoch),
374
+ // reject immediately and do NOT mutate any state.
375
+ const artifactDirForTelemetry = state.artifact_dir ?? (0, node_path_1.join)(repoRoot, ".taskchain_artifacts", "polaris-run");
376
+ const telemetryFileForCheck = (0, node_path_1.join)(artifactDirForTelemetry, "runs", state.run_id, "telemetry.jsonl");
377
+ try {
378
+ (0, dispatch_boundary_js_1.assertContinueRequiresDispatch)(state, telemetryFileForCheck);
379
+ }
380
+ catch (err) {
381
+ const msg = err instanceof Error ? err.message : String(err);
382
+ console.error(`Error: ${msg}`);
383
+ process.exit(1);
384
+ }
385
+ // Identify the completed child:
386
+ // - If active_child is set, use it (standard case)
387
+ // - If dispatch_epoch > continue_epoch but active_child is empty,
388
+ // resolve from dispatch_boundary.last_dispatched_child
389
+ let completedChild = state.active_child;
390
+ if (!completedChild && state.dispatch_boundary) {
391
+ const { dispatch_epoch, continue_epoch, last_dispatched_child } = state.dispatch_boundary;
392
+ if (dispatch_epoch > continue_epoch && last_dispatched_child) {
393
+ completedChild = last_dispatched_child;
394
+ }
395
+ }
396
+ const remainingOpenChildren = completedChild
397
+ ? state.open_children.filter((child) => child !== completedChild)
398
+ : state.open_children;
399
+ const nextChild = remainingOpenChildren[0] ?? null;
400
+ let completionCommit = "";
401
+ let completionResultFile = "";
402
+ let completionValidation = undefined;
403
+ if (state.dispatch_boundary && completedChild) {
404
+ const evidence = verifyCompletionEvidenceForContinue(state, completedChild, repoRoot);
405
+ if (!evidence.ok) {
406
+ console.error(`Error: ${evidence.reason}`);
407
+ process.exit(1);
408
+ }
409
+ completionCommit = evidence.commit;
410
+ completionResultFile = evidence.resultFile;
411
+ completionValidation = evidence.rawValidation;
412
+ // ── Branch custody check ──────────────────────────────────────────────────
413
+ // Reject commits that are already reachable from the base branch.
414
+ // This catches the case where a worker committed directly to main instead
415
+ // of to the delivery branch.
416
+ if (completionCommit) {
417
+ const custodyState = (0, store_js_1.readClusterStateSync)(state.cluster_id, repoRoot);
418
+ if (custodyState?.delivery_branch && custodyState?.base_branch) {
419
+ const custodyError = (0, git_custody_js_1.verifyChildCommitCustody)(repoRoot, completionCommit, custodyState.delivery_branch, custodyState.base_branch);
420
+ if (custodyError) {
421
+ console.error(`Error: branch custody violation for ${completedChild}: ${custodyError}`);
422
+ process.exit(1);
423
+ }
424
+ }
425
+ }
426
+ if (!hasValidationEvidence(completionValidation)) {
427
+ const waiver = readPacketFlag(state, completedChild, repoRoot, "validation_waiver");
428
+ if (!isValidationWaiver(waiver)) {
429
+ console.error(`Error: cannot checkpoint ${completedChild}: result file has no passing validation evidence and no validation_waiver was set in the packet`);
430
+ process.exit(1);
431
+ }
432
+ }
433
+ }
434
+ if (completedChild && completionResultFile) {
435
+ const telemetryFile = resolveTelemetryFilePath(state, repoRoot);
436
+ try {
437
+ (0, checkpoint_js_1.appendCompactReturnReceivedEvent)(telemetryFile, {
438
+ event: "compact-return-received",
439
+ run_id: state.run_id,
440
+ child_id: completedChild,
441
+ size_bytes: (0, node_fs_1.statSync)((0, node_path_1.isAbsolute)(completionResultFile) ? completionResultFile : (0, node_path_1.resolve)(repoRoot, completionResultFile)).size,
442
+ timestamp: new Date().toISOString(),
443
+ });
444
+ }
445
+ catch {
446
+ // Telemetry is best-effort; state progression must continue.
447
+ }
448
+ try {
449
+ const allowedScope = readPacketAllowedScope(state, completedChild, repoRoot);
450
+ const actualFilesTouched = completionCommit ? getChildCommitFiles(repoRoot, completionCommit) : [];
451
+ const outOfScopeFiles = actualFilesTouched.filter((file) => !matchesAllowedScope(file, allowedScope));
452
+ (0, checkpoint_js_1.appendWorkerScopeFidelityEvent)(telemetryFile, {
453
+ event: "worker-scope-fidelity",
454
+ run_id: state.run_id,
455
+ child_id: completedChild,
456
+ allowed_scope: allowedScope,
457
+ actual_files_touched: actualFilesTouched,
458
+ out_of_scope_files: outOfScopeFiles,
459
+ timestamp: new Date().toISOString(),
460
+ });
461
+ }
462
+ catch {
463
+ // Telemetry is best-effort; state progression must continue.
464
+ }
465
+ }
466
+ // Determine session type (state field takes precedence, file is secondary signal)
467
+ const sessionTypeFile = readSessionTypeFile(repoRoot);
468
+ const sessionType = state.session_type ?? sessionTypeFile;
469
+ if (sessionTypeFile && !state.session_type) {
470
+ console.warn(`Warning: session_type not in state; using .polaris/session-type file: ${sessionTypeFile}`);
471
+ }
472
+ // Update state: mark active_child as completed
473
+ const newCompletedChildren = completedChild
474
+ ? Array.from(new Set([...state.completed_children, completedChild]))
475
+ : state.completed_children;
476
+ const completedSet = new Set(newCompletedChildren);
477
+ const prunedOpenChildrenMeta = state.open_children_meta
478
+ ? Object.fromEntries(Object.entries(state.open_children_meta).filter(([id]) => !completedSet.has(id)))
479
+ : undefined;
480
+ // Record per-child result summary in loop state (belt-and-suspenders for finalize evidence)
481
+ const updatedCompletedChildrenResults = {
482
+ ...(state.completed_children_results ?? {}),
483
+ };
484
+ if (completedChild && completionResultFile) {
485
+ updatedCompletedChildrenResults[completedChild] = {
486
+ status: "done",
487
+ validation: hasValidationEvidence(completionValidation) ? "passed" : "skipped",
488
+ commit: completionCommit || null,
489
+ next_recommended_action: "continue",
490
+ };
491
+ }
492
+ const updatedState = {
493
+ ...state,
494
+ active_child: "",
495
+ completed_children: newCompletedChildren,
496
+ completed_children_results: Object.keys(updatedCompletedChildrenResults).length > 0
497
+ ? updatedCompletedChildrenResults
498
+ : state.completed_children_results,
499
+ open_children: remainingOpenChildren,
500
+ open_children_meta: prunedOpenChildrenMeta,
501
+ step_cursor: "checkpoint",
502
+ next_open_child: nextChild,
503
+ status: nextChild ? "running" : "cluster-complete",
504
+ context_budget: {
505
+ ...state.context_budget,
506
+ children_completed: newCompletedChildren.length,
507
+ },
508
+ last_commit: completionCommit || state.last_commit,
509
+ // Advance continue_epoch to match the consumed dispatch_epoch
510
+ dispatch_boundary: (0, dispatch_boundary_js_1.advanceContinueEpoch)(state.dispatch_boundary),
511
+ };
512
+ // Bridge evidence to cluster-state BEFORE committing the pruned loop state.
513
+ // Failing here leaves open_children_meta intact so the operator can retry.
514
+ if (state.dispatch_boundary && completedChild && completionResultFile) {
515
+ try {
516
+ bridgeEvidenceToClusterState(repoRoot, state.cluster_id, completedChild, completionCommit, completionValidation, completionResultFile);
517
+ }
518
+ catch (error) {
519
+ console.error(`Error: failed to persist cluster-state evidence for ${completedChild}: ${error instanceof Error ? error.message : String(error)}`);
520
+ process.exit(1);
521
+ }
522
+ }
523
+ // Step 1 (cont): Atomic write of updated current-state.json (open_children_meta pruned after bridge)
524
+ const sha = (0, checkpoint_js_1.writeStateAtomic)(stateFile, updatedState);
525
+ appendContinueLedgerEvents(repoRoot, updatedState, completedChild);
526
+ // Step 2: Append JSONL checkpoint event
527
+ const artifactDir = state.artifact_dir ?? (0, node_path_1.join)(repoRoot, ".taskchain_artifacts", "polaris-run");
528
+ const telemetryFile = (0, node_path_1.join)(artifactDir, "runs", state.run_id, "telemetry.jsonl");
529
+ (0, checkpoint_js_1.appendCheckpointEvent)(telemetryFile, {
530
+ event: "loop-checkpoint",
531
+ run_id: state.run_id,
532
+ child_id: completedChild,
533
+ next_child: nextChild,
534
+ timestamp: new Date().toISOString(),
535
+ });
536
+ // Load config early — needed for canon check and adapter selection
537
+ const config = (0, loader_js_1.loadConfig)(repoRoot);
538
+ const effectiveConfig = {
539
+ ...config,
540
+ execution: provider
541
+ ? {
542
+ ...config.execution,
543
+ rotation: [
544
+ provider,
545
+ ...(config.execution.rotation ?? []).filter((name) => name !== provider),
546
+ ],
547
+ }
548
+ : config.execution,
549
+ budget: allowAnalyzeChildren === undefined
550
+ ? config.budget
551
+ : {
552
+ ...config.budget,
553
+ allow_analyze_children: allowAnalyzeChildren,
554
+ },
555
+ };
556
+ const effectiveExecution = {
557
+ ...effectiveConfig.execution,
558
+ allow_analyze_children: effectiveConfig.budget?.allow_analyze_children,
559
+ };
560
+ // Map update runs once at session end (step 08 / polaris finalize), not per checkpoint.
561
+ // Step 3.5: Canon reconciliation check
562
+ const canonCheckEnabled = effectiveConfig.canon?.checkOnContinue !== false;
563
+ if (canonCheckEnabled && nextChild) {
564
+ const changedFiles = updatedState["changed_files"] ?? [];
565
+ const canonResult = (0, canon_check_js_1.runCanonCheck)({
566
+ repoRoot,
567
+ changedFiles,
568
+ childId: nextChild,
569
+ runId: state.run_id,
570
+ telemetryFile,
571
+ });
572
+ if (canonResult.outcome === "stale-implementation") {
573
+ const conflict = canonResult.conflicts.find((c) => c.type === "stale-implementation");
574
+ process.stderr.write([
575
+ `Canon conflict halt — cannot generate bootstrap packet.`,
576
+ `Canon file: ${conflict?.canonFile ?? "unknown"}`,
577
+ `Statement: ${conflict?.statement ?? ""}`,
578
+ `Affected file: ${conflict?.changedFile ?? ""}`,
579
+ `Detail: ${conflict?.detail ?? ""}`,
580
+ `Resolution: Update the canon file or implement the missing piece before continuing.`,
581
+ ].join("\n") + "\n");
582
+ process.exit(1);
583
+ }
584
+ }
585
+ // Step 4: Analyze→implementation boundary check
586
+ const nextChildType = getNextChildType(state, nextChild);
587
+ const boundaryTriggered = isAnalyzeImplBoundary(sessionType, nextChildType);
588
+ if (boundaryTriggered) {
589
+ (0, checkpoint_js_1.appendBoundaryEvent)(telemetryFile, {
590
+ event: "analyze-impl-boundary-enforced",
591
+ run_id: state.run_id,
592
+ stopped_before: nextChild,
593
+ reason: "analyze session cannot auto-continue into implementation",
594
+ timestamp: new Date().toISOString(),
595
+ });
596
+ }
597
+ // Step 4.5: Dispatch cognition librarian (non-blocking — failure does not halt cluster execution)
598
+ if (completedChild && completionResultFile) {
599
+ const workNotePaths = extractWorkNotePathsFromResult(completionResultFile, repoRoot);
600
+ if (workNotePaths.length > 0) {
601
+ setImmediate(async () => {
602
+ try {
603
+ const adapter = (options.adapter ?? effectiveExecution.adapter);
604
+ if (adapter) {
605
+ await (0, librarian_dispatch_js_1.dispatchCognitionLibrarian)({
606
+ runId: state.run_id,
607
+ clusterId: state.cluster_id,
608
+ workNotePaths,
609
+ repoRoot,
610
+ adapter: adapter,
611
+ provider: provider ?? effectiveConfig.execution.rotation?.[0] ?? "codex",
612
+ telemetryFile,
613
+ });
614
+ }
615
+ }
616
+ catch (err) {
617
+ // Non-blocking: log to telemetry but continue execution
618
+ try {
619
+ (0, node_fs_1.appendFileSync)(telemetryFile, JSON.stringify({
620
+ event: "cognition-librarian-dispatch-error",
621
+ run_id: state.run_id,
622
+ child_id: completedChild,
623
+ error: err instanceof Error ? err.message : String(err),
624
+ timestamp: new Date().toISOString(),
625
+ }) + "\n", "utf-8");
626
+ }
627
+ catch {
628
+ console.warn(`Warning: failed to dispatch cognition librarian for ${completedChild}: ${err instanceof Error ? err.message : String(err)}`);
629
+ }
630
+ }
631
+ });
632
+ }
633
+ }
634
+ // Steps 4-5: Generate and write bootstrap packet
635
+ const packet = (0, bootstrap_packet_js_1.buildBootstrapPacket)(updatedState, stateFile, sha, repoRoot, completedChild, (options.adapter ?? effectiveExecution.adapter), effectiveExecution);
636
+ if (boundaryTriggered) {
637
+ packet.boundary_enforcement =
638
+ "analyze-session-ended; implementation requires fresh session with explicit impl scope";
639
+ }
640
+ const bootstrapDir = (0, node_path_1.join)(repoRoot, ".polaris", "bootstrap");
641
+ const packetPath = (0, bootstrap_packet_js_1.writeBootstrapPacket)(packet, bootstrapDir);
642
+ // Step 6: Emit bootstrap packet to stdout, exit 0
643
+ console.log(JSON.stringify(packet, null, 2));
644
+ process.stderr.write(`Bootstrap packet written to: ${packetPath}\n`);
645
+ }