@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,127 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const node_fs_1 = require("node:fs");
4
+ const node_os_1 = require("node:os");
5
+ const node_path_1 = require("node:path");
6
+ const vitest_1 = require("vitest");
7
+ const ledger_js_1 = require("./ledger.js");
8
+ const tempDirs = [];
9
+ (0, vitest_1.afterEach)(() => {
10
+ for (const dir of tempDirs.splice(0)) {
11
+ (0, node_fs_1.rmSync)(dir, { recursive: true, force: true });
12
+ }
13
+ });
14
+ function makeTempDir() {
15
+ const dir = (0, node_fs_1.mkdtempSync)((0, node_path_1.join)((0, node_os_1.tmpdir)(), "polaris-ledger-"));
16
+ tempDirs.push(dir);
17
+ return dir;
18
+ }
19
+ function ledgerPath() {
20
+ return (0, node_path_1.join)(makeTempDir(), "nested", "ledger.jsonl");
21
+ }
22
+ function event(overrides = {}) {
23
+ return {
24
+ schema_version: 1,
25
+ event_id: `event-${Math.random().toString(36).slice(2)}`,
26
+ event: "run-started",
27
+ run_id: "run-1",
28
+ run_type: "implement",
29
+ cluster_id: "POL-151",
30
+ issue_id: "POL-153",
31
+ branch: "feature/pol-151",
32
+ status: "running",
33
+ completed_children: [],
34
+ open_children: ["POL-153"],
35
+ next_child: "POL-153",
36
+ last_commit: null,
37
+ pr_url: null,
38
+ timestamp: "2026-05-28T03:16:13.194Z",
39
+ ...overrides,
40
+ };
41
+ }
42
+ (0, vitest_1.describe)("LedgerWriter", () => {
43
+ (0, vitest_1.it)("defaults to the global Polaris ledger path", () => {
44
+ (0, vitest_1.expect)(ledger_js_1.DEFAULT_LEDGER_PATH).toBe(".polaris/runs/ledger.jsonl");
45
+ });
46
+ (0, vitest_1.it)("appends one JSONL line to the configured ledger file", () => {
47
+ const path = ledgerPath();
48
+ const writer = new ledger_js_1.LedgerWriter(path);
49
+ const entry = event();
50
+ writer.append(entry);
51
+ const lines = (0, node_fs_1.readFileSync)(path, "utf-8").trim().split("\n");
52
+ (0, vitest_1.expect)(lines).toHaveLength(1);
53
+ (0, vitest_1.expect)(JSON.parse(lines[0])).toEqual(entry);
54
+ });
55
+ (0, vitest_1.it)("readAll parses all ledger events", () => {
56
+ const writer = new ledger_js_1.LedgerWriter(ledgerPath());
57
+ const first = event({ event_id: "1", run_id: "run-1" });
58
+ const second = event({ event_id: "2", run_id: "run-2", cluster_id: "POL-200" });
59
+ writer.append(first);
60
+ writer.append(second);
61
+ (0, vitest_1.expect)(writer.readAll()).toEqual([first, second]);
62
+ });
63
+ (0, vitest_1.it)("queryByIssue returns events for a matching cluster_id", () => {
64
+ const writer = new ledger_js_1.LedgerWriter(ledgerPath());
65
+ const matching = event({ event_id: "1", cluster_id: "POL-151" });
66
+ const other = event({ event_id: "2", cluster_id: "POL-200" });
67
+ writer.append(matching);
68
+ writer.append(other);
69
+ (0, vitest_1.expect)(writer.queryByIssue("POL-151")).toEqual([matching]);
70
+ });
71
+ (0, vitest_1.it)("queryOpenRuns returns the latest event per run_id when status is not complete or finalized", () => {
72
+ const writer = new ledger_js_1.LedgerWriter(ledgerPath());
73
+ const staleOpen = event({ event_id: "1", run_id: "run-open", status: "running" });
74
+ const latestOpen = event({
75
+ event_id: "2",
76
+ event: "run-paused",
77
+ run_id: "run-open",
78
+ status: "paused",
79
+ pause_reason: "handoff",
80
+ });
81
+ const complete = event({
82
+ event_id: "3",
83
+ event: "run-complete",
84
+ run_id: "run-complete",
85
+ status: "complete",
86
+ open_children: [],
87
+ next_child: null,
88
+ });
89
+ const finalized = event({
90
+ event_id: "4",
91
+ event: "finalized",
92
+ run_id: "run-finalized",
93
+ status: "finalized",
94
+ finalize_result: { ok: true },
95
+ });
96
+ writer.append(staleOpen);
97
+ writer.append(latestOpen);
98
+ writer.append(complete);
99
+ writer.append(finalized);
100
+ (0, vitest_1.expect)(writer.queryOpenRuns()).toEqual([latestOpen]);
101
+ });
102
+ (0, vitest_1.it)("returns empty arrays when the ledger file does not exist", () => {
103
+ const writer = new ledger_js_1.LedgerWriter(ledgerPath());
104
+ (0, vitest_1.expect)(writer.readAll()).toEqual([]);
105
+ (0, vitest_1.expect)(writer.queryByIssue("POL-151")).toEqual([]);
106
+ (0, vitest_1.expect)(writer.queryOpenRuns()).toEqual([]);
107
+ });
108
+ (0, vitest_1.it)("keeps concurrent appends as complete JSONL lines without lost events", async () => {
109
+ const path = ledgerPath();
110
+ const writers = Array.from({ length: 25 }, () => new ledger_js_1.LedgerWriter(path));
111
+ const entries = writers.map((_, index) => event({
112
+ event_id: `event-${index}`,
113
+ run_id: `run-${index}`,
114
+ cluster_id: index % 2 === 0 ? "POL-151" : "POL-200",
115
+ }));
116
+ await Promise.all(entries.map((entry, index) => new Promise((resolve) => {
117
+ setImmediate(() => {
118
+ writers[index].append(entry);
119
+ resolve();
120
+ });
121
+ })));
122
+ const lines = (0, node_fs_1.readFileSync)(path, "utf-8").trim().split("\n");
123
+ const parsed = lines.map((line) => JSON.parse(line));
124
+ (0, vitest_1.expect)(parsed).toHaveLength(entries.length);
125
+ (0, vitest_1.expect)(new Set(parsed.map((entry) => entry.event_id))).toEqual(new Set(entries.map((entry) => entry.event_id)));
126
+ });
127
+ });
@@ -0,0 +1,348 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.resolveLifecycleProvider = resolveLifecycleProvider;
4
+ exports.dispatchLifecyclePhase = dispatchLifecyclePhase;
5
+ const node_fs_1 = require("node:fs");
6
+ const node_path_1 = require("node:path");
7
+ const node_crypto_1 = require("node:crypto");
8
+ const index_js_1 = require("../cognition/index.js");
9
+ const worker_packet_js_1 = require("./worker-packet.js");
10
+ function appendTelemetry(telemetryFile, event) {
11
+ (0, node_fs_1.mkdirSync)((0, node_path_1.dirname)(telemetryFile), { recursive: true });
12
+ (0, node_fs_1.appendFileSync)(telemetryFile, JSON.stringify(event) + "\n", "utf-8");
13
+ }
14
+ function roleForPhase(phase) {
15
+ return phase === "startup" ? "startup" : "finalize";
16
+ }
17
+ function executionRoleForPhase(phase) {
18
+ return phase === "startup" ? "startup" : "finalizer";
19
+ }
20
+ function firstConfiguredProvider(execution) {
21
+ return (execution.rotation?.[0] ??
22
+ Object.keys(execution.providers ?? {})[0] ??
23
+ "default");
24
+ }
25
+ function materializeRoleProvider(execution, roleName, roleConfig) {
26
+ const provider = roleConfig?.provider ?? firstConfiguredProvider(execution);
27
+ if (!roleConfig?.command) {
28
+ return provider;
29
+ }
30
+ // Create a new provider key to avoid mutating shared config
31
+ const newProviderKey = `${provider}#${roleName}`;
32
+ const existingConfig = execution.providers?.[provider] ?? {};
33
+ execution.providers = {
34
+ ...(execution.providers ?? {}),
35
+ [newProviderKey]: {
36
+ ...existingConfig,
37
+ command: roleConfig.command,
38
+ args: roleConfig.args,
39
+ },
40
+ };
41
+ return newProviderKey;
42
+ }
43
+ function resolveLifecycleProvider(config, phase) {
44
+ const execution = config.execution;
45
+ const roleName = executionRoleForPhase(phase);
46
+ const roles = execution.roles ?? {};
47
+ const roleConfig = roles[roleName];
48
+ const provider = materializeRoleProvider(execution, roleName, roleConfig);
49
+ return {
50
+ adapter: roleConfig?.adapter ?? execution.adapter ?? "terminal-cli",
51
+ provider,
52
+ model: roleConfig?.model,
53
+ };
54
+ }
55
+ function resultPath(options) {
56
+ if (options.resultFile) {
57
+ return options.resultFile;
58
+ }
59
+ return (0, node_path_1.join)((0, node_path_1.dirname)(options.telemetryFile), `${options.phase}-result-${(0, node_crypto_1.randomUUID)()}.json`);
60
+ }
61
+ function compilePacket(options, sealedResultFile, model) {
62
+ const base = {
63
+ runId: options.runId,
64
+ clusterId: options.clusterId,
65
+ branch: options.branch,
66
+ stateFile: options.stateFile,
67
+ telemetryFile: options.telemetryFile,
68
+ resultFile: sealedResultFile,
69
+ };
70
+ const packet = options.phase === "startup"
71
+ ? (0, worker_packet_js_1.compileStartupPacket)(base)
72
+ : (0, worker_packet_js_1.compileFinalizePacket)({
73
+ ...base,
74
+ targetBranch: options.config.finalize?.targetBranch,
75
+ });
76
+ return {
77
+ ...packet,
78
+ context: {
79
+ ...(packet.context ?? {}),
80
+ model,
81
+ },
82
+ };
83
+ }
84
+ function parseResultFile(path) {
85
+ if (!(0, node_fs_1.existsSync)(path)) {
86
+ return { ok: false, error: "missing_result", message: `Sealed lifecycle result file is missing: ${path}` };
87
+ }
88
+ let parsed;
89
+ try {
90
+ parsed = JSON.parse((0, node_fs_1.readFileSync)(path, "utf-8"));
91
+ }
92
+ catch (err) {
93
+ const msg = err instanceof Error ? err.message : String(err);
94
+ return { ok: false, error: "malformed_result", message: `Sealed lifecycle result file is malformed JSON: ${msg}` };
95
+ }
96
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
97
+ return { ok: false, error: "malformed_result", message: "Sealed lifecycle result file must contain a JSON object" };
98
+ }
99
+ return { ok: true, value: parsed };
100
+ }
101
+ function isRecord(value) {
102
+ return typeof value === "object" && value !== null && !Array.isArray(value);
103
+ }
104
+ function readString(value) {
105
+ return typeof value === "string" && value.trim().length > 0 ? value : undefined;
106
+ }
107
+ function readBoolean(value) {
108
+ return value === true;
109
+ }
110
+ function readStringArray(value) {
111
+ return Array.isArray(value)
112
+ ? value.filter((entry) => typeof entry === "string" && entry.trim().length > 0)
113
+ : [];
114
+ }
115
+ function resolveRepoRoot(options) {
116
+ if (options.repoRoot) {
117
+ return options.repoRoot;
118
+ }
119
+ let current = (0, node_path_1.dirname)(options.stateFile);
120
+ while (true) {
121
+ if ((0, node_fs_1.existsSync)((0, node_path_1.join)(current, ".git")) || (0, node_fs_1.existsSync)((0, node_path_1.join)(current, "package.json"))) {
122
+ return current;
123
+ }
124
+ const parent = (0, node_path_1.dirname)(current);
125
+ if (parent === current) {
126
+ return (0, node_path_1.dirname)(options.stateFile);
127
+ }
128
+ current = parent;
129
+ }
130
+ }
131
+ function deriveCognitionArchiveOptions(result, repoRoot) {
132
+ const candidate = isRecord(result.cognition_archive)
133
+ ? result.cognition_archive
134
+ : isRecord(result.cognition_reconcile)
135
+ ? result.cognition_reconcile
136
+ : result;
137
+ const reconcileId = readString(candidate.reconcile_id) ?? readString(candidate.reconcileId);
138
+ const runId = readString(result.run_id) ?? readString(candidate.run_id) ?? readString(candidate.runId);
139
+ const notesConsumed = readStringArray(candidate.notes_consumed
140
+ ?? candidate.notesConsumed
141
+ ?? candidate.note_paths
142
+ ?? candidate.notePaths
143
+ ?? candidate.consumed_notes);
144
+ if (!reconcileId || !runId || notesConsumed.length === 0) {
145
+ return null;
146
+ }
147
+ const status = readString(candidate.archive_status)
148
+ ?? readString(candidate.reconcile_status)
149
+ ?? readString(candidate.result)
150
+ ?? readString(candidate.status);
151
+ return {
152
+ repoRoot,
153
+ reconcileId,
154
+ runId,
155
+ notesConsumed,
156
+ polarisMdUpdated: readBoolean(candidate.polaris_md_updated ?? candidate.polarisMdUpdated),
157
+ summaryMdUpdated: readBoolean(candidate.summary_md_updated ?? candidate.summaryMdUpdated),
158
+ reconciledAt: readString(candidate.reconciled_at) ?? readString(candidate.reconciledAt),
159
+ status: candidate.rejected === true
160
+ || candidate.applied === false
161
+ || candidate.accepted === false
162
+ || status === "rejected"
163
+ ? "rejected"
164
+ : "applied",
165
+ rejectionReason: readString(candidate.reason)
166
+ ?? readString(candidate.rejection_reason)
167
+ ?? readString(candidate.error_message),
168
+ result,
169
+ };
170
+ }
171
+ function validateLifecycleResult(result, packet) {
172
+ if (result["run_id"] !== packet.run_id) {
173
+ return {
174
+ ok: false,
175
+ error: "mismatched_result",
176
+ message: `Lifecycle result run_id mismatch: expected ${packet.run_id}, got ${String(result["run_id"])}`,
177
+ };
178
+ }
179
+ const returnedRole = result["role"];
180
+ if (returnedRole !== undefined && returnedRole !== packet.worker_role) {
181
+ return {
182
+ ok: false,
183
+ error: "mismatched_result",
184
+ message: `Lifecycle result role mismatch: expected ${packet.worker_role}, got ${String(returnedRole)}`,
185
+ };
186
+ }
187
+ if (result["status"] !== "success") {
188
+ return {
189
+ ok: false,
190
+ error: "failed_result",
191
+ message: `Lifecycle result status is not success: ${String(result["status"])}`,
192
+ };
193
+ }
194
+ return { ok: true };
195
+ }
196
+ async function dispatchLifecyclePhase(options) {
197
+ const role = roleForPhase(options.phase);
198
+ const resolved = resolveLifecycleProvider(options.config, options.phase);
199
+ const sealedResultFile = resultPath(options);
200
+ const packet = compilePacket(options, sealedResultFile, resolved.model);
201
+ appendTelemetry(options.telemetryFile, {
202
+ event: "lifecycle-dispatched",
203
+ run_id: options.runId,
204
+ cluster_id: options.clusterId,
205
+ role,
206
+ phase: options.phase,
207
+ adapter: resolved.adapter,
208
+ provider: resolved.provider,
209
+ model: resolved.model ?? null,
210
+ result_file: sealedResultFile,
211
+ timestamp: new Date().toISOString(),
212
+ });
213
+ let dispatchResult;
214
+ try {
215
+ // Use the resolved adapter instead of options.adapter
216
+ const adapterToUse = options.adapter; // Note: resolved.adapter is the name string, not the adapter instance
217
+ dispatchResult = await adapterToUse.dispatch(packet, {
218
+ provider: resolved.provider,
219
+ dryRun: options.dryRun,
220
+ });
221
+ }
222
+ catch (err) {
223
+ const message = err instanceof Error ? err.message : String(err);
224
+ appendTelemetry(options.telemetryFile, {
225
+ event: "lifecycle-result-rejected",
226
+ run_id: options.runId,
227
+ role,
228
+ error: "adapter_error",
229
+ message: `Adapter threw exception: ${message}`,
230
+ timestamp: new Date().toISOString(),
231
+ });
232
+ return {
233
+ ok: false,
234
+ role,
235
+ provider: resolved.provider,
236
+ model: resolved.model,
237
+ resultFile: sealedResultFile,
238
+ error: "adapter_error",
239
+ message: `Adapter threw exception: ${message}`,
240
+ };
241
+ }
242
+ if (dispatchResult.exit_code !== 0) {
243
+ const message = dispatchResult.summary ?? `Lifecycle ${role} dispatch exited with code ${dispatchResult.exit_code}`;
244
+ appendTelemetry(options.telemetryFile, {
245
+ event: "lifecycle-result-rejected",
246
+ run_id: options.runId,
247
+ role,
248
+ error: "adapter_error",
249
+ message,
250
+ timestamp: new Date().toISOString(),
251
+ });
252
+ return {
253
+ ok: false,
254
+ role,
255
+ provider: resolved.provider,
256
+ model: resolved.model,
257
+ resultFile: sealedResultFile,
258
+ error: "adapter_error",
259
+ message,
260
+ };
261
+ }
262
+ const parsed = parseResultFile(sealedResultFile);
263
+ if (!parsed.ok) {
264
+ appendTelemetry(options.telemetryFile, {
265
+ event: "lifecycle-result-rejected",
266
+ run_id: options.runId,
267
+ role,
268
+ error: parsed.error,
269
+ message: parsed.message,
270
+ result_file: sealedResultFile,
271
+ timestamp: new Date().toISOString(),
272
+ });
273
+ return {
274
+ ok: false,
275
+ role,
276
+ provider: resolved.provider,
277
+ model: resolved.model,
278
+ resultFile: sealedResultFile,
279
+ error: parsed.error,
280
+ message: parsed.message,
281
+ };
282
+ }
283
+ const validation = validateLifecycleResult(parsed.value, packet);
284
+ if (!validation.ok) {
285
+ appendTelemetry(options.telemetryFile, {
286
+ event: "lifecycle-result-rejected",
287
+ run_id: options.runId,
288
+ role,
289
+ error: validation.error,
290
+ message: validation.message,
291
+ result_file: sealedResultFile,
292
+ timestamp: new Date().toISOString(),
293
+ });
294
+ return {
295
+ ok: false,
296
+ role,
297
+ provider: resolved.provider,
298
+ model: resolved.model,
299
+ resultFile: sealedResultFile,
300
+ error: validation.error,
301
+ message: validation.message,
302
+ };
303
+ }
304
+ try {
305
+ if (options.phase === "finalize") {
306
+ const cognitionArchiveOptions = deriveCognitionArchiveOptions(parsed.value, resolveRepoRoot(options));
307
+ if (cognitionArchiveOptions) {
308
+ (0, index_js_1.archiveCognitionNotes)(cognitionArchiveOptions);
309
+ }
310
+ }
311
+ }
312
+ catch (err) {
313
+ const message = err instanceof Error ? err.message : String(err);
314
+ appendTelemetry(options.telemetryFile, {
315
+ event: "lifecycle-result-rejected",
316
+ run_id: options.runId,
317
+ role,
318
+ error: "failed_result",
319
+ message: `Lifecycle post-validation apply failed: ${message}`,
320
+ result_file: sealedResultFile,
321
+ timestamp: new Date().toISOString(),
322
+ });
323
+ return {
324
+ ok: false,
325
+ role,
326
+ provider: resolved.provider,
327
+ model: resolved.model,
328
+ resultFile: sealedResultFile,
329
+ error: "failed_result",
330
+ message: `Lifecycle post-validation apply failed: ${message}`,
331
+ };
332
+ }
333
+ appendTelemetry(options.telemetryFile, {
334
+ event: "lifecycle-result-accepted",
335
+ run_id: options.runId,
336
+ role,
337
+ result_file: sealedResultFile,
338
+ timestamp: new Date().toISOString(),
339
+ });
340
+ return {
341
+ ok: true,
342
+ role,
343
+ provider: resolved.provider,
344
+ model: resolved.model,
345
+ resultFile: sealedResultFile,
346
+ result: parsed.value,
347
+ };
348
+ }