@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,216 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.isPlaceholderCommit = isPlaceholderCommit;
4
+ exports.backfillClusterStateEvidence = backfillClusterStateEvidence;
5
+ const node_fs_1 = require("node:fs");
6
+ const node_path_1 = require("node:path");
7
+ const checkpoint_js_1 = require("./checkpoint.js");
8
+ const store_js_1 = require("../cluster-state/store.js");
9
+ // Matches abbreviated/full hex SHAs (>=7 chars), case-insensitive — rejects placeholder strings.
10
+ const HEX_SHA_RE = /^[0-9a-f]{7,}$/i;
11
+ function isPlaceholderCommit(commit) {
12
+ if (typeof commit !== "string" || commit.trim().length === 0)
13
+ return true;
14
+ return !HEX_SHA_RE.test(commit.trim());
15
+ }
16
+ function readJsonFile(filePath) {
17
+ if (!(0, node_fs_1.existsSync)(filePath))
18
+ return undefined;
19
+ try {
20
+ return JSON.parse((0, node_fs_1.readFileSync)(filePath, "utf-8"));
21
+ }
22
+ catch {
23
+ return undefined;
24
+ }
25
+ }
26
+ // Scan a directory for the first (sorted) file whose name starts with `<childId>-` or equals `<childId>.json`.
27
+ function findFileByChildPrefix(dir, childId) {
28
+ if (!(0, node_fs_1.existsSync)(dir))
29
+ return undefined;
30
+ for (const name of (0, node_fs_1.readdirSync)(dir).sort()) {
31
+ if (name === `${childId}.json` || name.startsWith(`${childId}-`)) {
32
+ return (0, node_path_1.join)(dir, name);
33
+ }
34
+ }
35
+ return undefined;
36
+ }
37
+ function resolveStatePath(repoRoot, filePath) {
38
+ if (typeof filePath !== "string" || filePath.trim().length === 0)
39
+ return undefined;
40
+ const trimmed = filePath.trim();
41
+ return (0, node_path_1.isAbsolute)(trimmed) ? trimmed : (0, node_path_1.resolve)(repoRoot, trimmed);
42
+ }
43
+ function hasPassingValidation(value) {
44
+ if (typeof value === "string") {
45
+ const n = value.trim().toLowerCase();
46
+ return n === "passed" || n === "pass" || n === "success" || n === "ok";
47
+ }
48
+ if (typeof value === "boolean")
49
+ return value;
50
+ if (!value || typeof value !== "object" || Array.isArray(value))
51
+ return false;
52
+ const rec = value;
53
+ const passed = rec["passed"];
54
+ if (passed === true)
55
+ return true;
56
+ if (Array.isArray(passed) && passed.length > 0)
57
+ return true;
58
+ if (typeof passed === "number" && passed > 0)
59
+ return true;
60
+ for (const key of ["status", "summary", "validation"]) {
61
+ const v = rec[key];
62
+ if (typeof v === "string" && ["passed", "pass", "success", "ok"].includes(v.trim().toLowerCase())) {
63
+ return true;
64
+ }
65
+ }
66
+ return false;
67
+ }
68
+ function hasValidationWaiver(packet) {
69
+ if (!packet || typeof packet !== "object" || Array.isArray(packet))
70
+ return false;
71
+ const pkt = packet;
72
+ const isTruthy = (v) => {
73
+ if (typeof v === "string")
74
+ return v.trim().length > 0;
75
+ if (typeof v === "boolean")
76
+ return v;
77
+ if (v && typeof v === "object" && !Array.isArray(v))
78
+ return Object.keys(v).length > 0;
79
+ return false;
80
+ };
81
+ if (isTruthy(pkt["validation_waiver"]))
82
+ return true;
83
+ const instr = pkt["instructions"];
84
+ if (instr && typeof instr === "object" && !Array.isArray(instr)) {
85
+ if (isTruthy(instr["validation_waiver"]))
86
+ return true;
87
+ }
88
+ return false;
89
+ }
90
+ function backfillClusterStateEvidence(options) {
91
+ const { repoRoot, stateFile, dryRun = false } = options;
92
+ const state = (0, checkpoint_js_1.readState)(stateFile);
93
+ const clusterId = state.cluster_id;
94
+ const resultsDir = (0, node_path_1.join)(repoRoot, ".polaris", "clusters", clusterId, "results");
95
+ const packetsDir = (0, node_path_1.join)(repoRoot, ".polaris", "clusters", clusterId, "packets");
96
+ const backfilled = [];
97
+ const skipped = [];
98
+ for (const childId of state.completed_children) {
99
+ // Resolve result file — mirrors continue.ts priority:
100
+ // 1. result_file on child meta (explicit override, e.g. --result-file flag)
101
+ // 2. dispatch_record.expected_result_path
102
+ // 3. directory scan by child ID prefix (fallback for older state)
103
+ let resultFilePath;
104
+ const childMeta = state.open_children_meta?.[childId];
105
+ const dispatchRecord = childMeta?.dispatch_record;
106
+ for (const candidate of [childMeta?.result_file, dispatchRecord?.expected_result_path]) {
107
+ const abs = resolveStatePath(repoRoot, candidate);
108
+ if (abs && (0, node_fs_1.existsSync)(abs)) {
109
+ resultFilePath = abs;
110
+ break;
111
+ }
112
+ }
113
+ if (!resultFilePath) {
114
+ resultFilePath = findFileByChildPrefix(resultsDir, childId);
115
+ }
116
+ if (!resultFilePath) {
117
+ skipped.push({ childId, reason: "no result file found" });
118
+ continue;
119
+ }
120
+ const result = readJsonFile(resultFilePath);
121
+ if (!result || typeof result !== "object" || Array.isArray(result)) {
122
+ skipped.push({ childId, reason: "result file unreadable or not a JSON object" });
123
+ continue;
124
+ }
125
+ // Guard: result file must belong to this child (prevents mis-routing from prefix scan or wrong pointer).
126
+ const resultChildId = result["child_id"] ?? result["childId"] ?? result["id"];
127
+ if (resultChildId !== undefined && resultChildId !== childId) {
128
+ skipped.push({
129
+ childId,
130
+ reason: `result file belongs to ${String(resultChildId)}, not ${childId}`,
131
+ });
132
+ continue;
133
+ }
134
+ // Guard: result must indicate completion.
135
+ if (result["status"] !== undefined && result["status"] !== "done") {
136
+ skipped.push({
137
+ childId,
138
+ reason: `result status is not done: ${String(result["status"])}`,
139
+ });
140
+ continue;
141
+ }
142
+ // Reject placeholder commits.
143
+ const rawCommit = result["commit"] ?? result["commit_hash"];
144
+ if (isPlaceholderCommit(rawCommit)) {
145
+ skipped.push({ childId, reason: `placeholder or missing commit: ${String(rawCommit ?? "(none)")}` });
146
+ continue;
147
+ }
148
+ const commit = rawCommit.trim();
149
+ // Validate — or check for waiver.
150
+ let packetFilePath;
151
+ if (dispatchRecord?.packet_path) {
152
+ const abs = (0, node_path_1.resolve)(repoRoot, dispatchRecord.packet_path);
153
+ if ((0, node_fs_1.existsSync)(abs))
154
+ packetFilePath = abs;
155
+ }
156
+ if (!packetFilePath) {
157
+ packetFilePath = findFileByChildPrefix(packetsDir, childId);
158
+ }
159
+ const packet = packetFilePath ? readJsonFile(packetFilePath) : undefined;
160
+ const validationPassed = hasPassingValidation(result["validation"]);
161
+ if (!validationPassed && !hasValidationWaiver(packet)) {
162
+ skipped.push({ childId, reason: "validation not passed and no validation_waiver on packet" });
163
+ continue;
164
+ }
165
+ backfilled.push({
166
+ childId,
167
+ resultFile: (0, node_path_1.relative)(repoRoot, resultFilePath),
168
+ packetFile: packetFilePath ? (0, node_path_1.relative)(repoRoot, packetFilePath) : undefined,
169
+ commit,
170
+ validationPassed,
171
+ });
172
+ }
173
+ if (!dryRun && backfilled.length > 0) {
174
+ applyBackfillToClusterState({ clusterId, repoRoot, backfilled });
175
+ }
176
+ return { clusterId, backfilled, skipped };
177
+ }
178
+ function applyBackfillToClusterState(params) {
179
+ const { clusterId, repoRoot, backfilled } = params;
180
+ const existing = (0, store_js_1.readClusterStateSync)(clusterId, repoRoot);
181
+ if (!existing) {
182
+ throw new Error(`cluster-state.json not found for ${clusterId} — cannot apply backfill`);
183
+ }
184
+ const updated = {
185
+ ...existing,
186
+ state_generation: existing.state_generation + 1,
187
+ commits: { ...existing.commits },
188
+ result_pointers: { ...existing.result_pointers },
189
+ packet_pointers: { ...existing.packet_pointers },
190
+ validation_results: { ...existing.validation_results },
191
+ claim_metadata: { ...existing.claim_metadata },
192
+ child_states: existing.child_states.map((cs) => ({ ...cs })),
193
+ };
194
+ for (const entry of backfilled) {
195
+ updated.commits[entry.childId] = entry.commit;
196
+ updated.result_pointers[entry.childId] = entry.resultFile;
197
+ if (entry.packetFile) {
198
+ updated.packet_pointers[entry.childId] = entry.packetFile;
199
+ }
200
+ const validationResult = {
201
+ passed: entry.validationPassed,
202
+ output: `backfilled from ${entry.resultFile}`,
203
+ };
204
+ updated.validation_results[entry.childId] = validationResult;
205
+ delete updated.claim_metadata[entry.childId];
206
+ const childState = updated.child_states.find((cs) => cs.id === entry.childId);
207
+ if (childState) {
208
+ childState.status = "done";
209
+ childState.commit = entry.commit;
210
+ }
211
+ else {
212
+ updated.child_states.push({ id: entry.childId, status: "done", commit: entry.commit });
213
+ }
214
+ }
215
+ (0, store_js_1.writeClusterStateSync)(clusterId, updated, repoRoot);
216
+ }
@@ -0,0 +1,141 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.selectExecutionAdapter = selectExecutionAdapter;
4
+ exports.buildCompactBootstrapState = buildCompactBootstrapState;
5
+ exports.buildExecutionAdapterContract = buildExecutionAdapterContract;
6
+ const node_path_1 = require("node:path");
7
+ const FALLBACK_ORDER = [
8
+ "agent-subtask",
9
+ "terminal-cli",
10
+ "ci",
11
+ "ssh",
12
+ "remote-worker",
13
+ "cross-agent",
14
+ ];
15
+ function fromConfigured(mode) {
16
+ switch (mode) {
17
+ case "agent-subtask":
18
+ return {
19
+ mode,
20
+ autoDispatch: true,
21
+ providerCoupling: "native-same-agent",
22
+ priority: 1,
23
+ warnings: [],
24
+ reason: "native same-agent subtask adapter configured",
25
+ };
26
+ case "terminal-cli":
27
+ return {
28
+ mode,
29
+ autoDispatch: false,
30
+ providerCoupling: "shell-process",
31
+ priority: 2,
32
+ warnings: [],
33
+ reason: "terminal CLI worker adapter configured",
34
+ };
35
+ case "ci":
36
+ return {
37
+ mode,
38
+ autoDispatch: false,
39
+ providerCoupling: "remote-worker",
40
+ priority: 3,
41
+ warnings: [],
42
+ reason: "CI worker adapter configured",
43
+ };
44
+ case "ssh":
45
+ case "remote-worker":
46
+ return {
47
+ mode,
48
+ autoDispatch: false,
49
+ providerCoupling: "remote-worker",
50
+ priority: 3,
51
+ warnings: [],
52
+ reason: "remote worker adapter configured",
53
+ };
54
+ case "cross-agent":
55
+ return {
56
+ mode,
57
+ autoDispatch: true,
58
+ providerCoupling: "explicit-cross-agent",
59
+ priority: 4,
60
+ warnings: [],
61
+ reason: "cross-agent fallback explicitly configured",
62
+ };
63
+ default:
64
+ throw new Error(`Unknown ExecutionAdapterMode: ${String(mode)}`);
65
+ }
66
+ }
67
+ function selectExecutionAdapter(input) {
68
+ const requested = input.explicitAdapter ?? input.configuredAdapter;
69
+ const warnings = [];
70
+ if (requested === "cross-agent" && !input.crossAgentConfigured && !input.tokenBudgetLow) {
71
+ warnings.push("cross-agent fallback requires explicit configuration or low-token emergency");
72
+ return {
73
+ ...fromConfigured("terminal-cli"),
74
+ warnings,
75
+ reason: "cross-agent fallback denied; terminal CLI requires explicit external worker handoff",
76
+ };
77
+ }
78
+ if (requested) {
79
+ return fromConfigured(requested);
80
+ }
81
+ if (input.insideAgentSession && input.nativeSubtaskAvailable) {
82
+ return {
83
+ mode: "agent-subtask",
84
+ autoDispatch: true,
85
+ providerCoupling: "native-same-agent",
86
+ priority: 1,
87
+ warnings,
88
+ reason: "native same-agent subtask dispatch is available",
89
+ };
90
+ }
91
+ if (input.insideAgentSession && !input.nativeSubtaskAvailable) {
92
+ warnings.push("native subtask dispatch unavailable; parent must not shell out to nested agent CLI by default");
93
+ return {
94
+ ...fromConfigured("terminal-cli"),
95
+ autoDispatch: false,
96
+ warnings,
97
+ reason: "fallback requires external terminal worker or explicit adapter configuration",
98
+ };
99
+ }
100
+ return fromConfigured("terminal-cli");
101
+ }
102
+ function buildCompactBootstrapState(input) {
103
+ // Normalize paths to repo-relative for portability
104
+ const repoRoot = process.cwd();
105
+ const relStateFile = input.stateFile.startsWith("/") ? (0, node_path_1.relative)(repoRoot, input.stateFile) : input.stateFile;
106
+ const relTelemetryFile = input.telemetryFile.startsWith("/") ? (0, node_path_1.relative)(repoRoot, input.telemetryFile) : input.telemetryFile;
107
+ const result = {
108
+ run_id: input.runId,
109
+ cluster_id: input.clusterId,
110
+ child_id: input.childId,
111
+ state_file: relStateFile,
112
+ telemetry_file: relTelemetryFile,
113
+ current_state_sha: input.currentStateSha,
114
+ branch: input.branch,
115
+ compact_mode: input.compactMode ?? "standard",
116
+ return_summary_contract: [
117
+ "child_id",
118
+ "status",
119
+ "commit_hash",
120
+ "validation_summary",
121
+ "next_action",
122
+ ],
123
+ };
124
+ if (input.allowAnalyzeChildren !== undefined) {
125
+ result.allow_analyze_children = input.allowAnalyzeChildren;
126
+ }
127
+ return result;
128
+ }
129
+ function buildExecutionAdapterContract(selection, compactBootstrapState) {
130
+ return {
131
+ ...selection,
132
+ compact_bootstrap_state: compactBootstrapState,
133
+ dispatch_contract: {
134
+ one_child_per_worker: true,
135
+ parent_receives_compact_summary_only: true,
136
+ child_transcript_retained_by_worker: true,
137
+ updates_current_state_and_telemetry: true,
138
+ },
139
+ fallback_order: FALLBACK_ORDER,
140
+ };
141
+ }
@@ -0,0 +1,66 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const vitest_1 = require("vitest");
4
+ const execution_adapter_js_1 = require("./execution-adapter.js");
5
+ (0, vitest_1.describe)("selectExecutionAdapter", () => {
6
+ (0, vitest_1.it)("prefers native same-agent subtask dispatch inside interactive agent sessions", () => {
7
+ const selected = (0, execution_adapter_js_1.selectExecutionAdapter)({
8
+ insideAgentSession: true,
9
+ nativeSubtaskAvailable: true,
10
+ });
11
+ (0, vitest_1.expect)(selected.mode).toBe("agent-subtask");
12
+ (0, vitest_1.expect)(selected.autoDispatch).toBe(true);
13
+ (0, vitest_1.expect)(selected.providerCoupling).toBe("native-same-agent");
14
+ });
15
+ (0, vitest_1.it)("does not cross-call another agent unless explicitly configured", () => {
16
+ const selected = (0, execution_adapter_js_1.selectExecutionAdapter)({
17
+ insideAgentSession: true,
18
+ nativeSubtaskAvailable: false,
19
+ configuredAdapter: "cross-agent",
20
+ crossAgentConfigured: false,
21
+ tokenBudgetLow: false,
22
+ });
23
+ (0, vitest_1.expect)(selected.mode).toBe("terminal-cli");
24
+ (0, vitest_1.expect)(selected.autoDispatch).toBe(false);
25
+ (0, vitest_1.expect)(selected.warnings).toContain("cross-agent fallback requires explicit configuration or low-token emergency");
26
+ });
27
+ (0, vitest_1.it)("allows explicit cross-agent fallback when configured", () => {
28
+ const selected = (0, execution_adapter_js_1.selectExecutionAdapter)({
29
+ insideAgentSession: true,
30
+ nativeSubtaskAvailable: false,
31
+ configuredAdapter: "cross-agent",
32
+ crossAgentConfigured: true,
33
+ });
34
+ (0, vitest_1.expect)(selected.mode).toBe("cross-agent");
35
+ (0, vitest_1.expect)(selected.autoDispatch).toBe(true);
36
+ });
37
+ });
38
+ (0, vitest_1.describe)("buildCompactBootstrapState", () => {
39
+ (0, vitest_1.it)("contains only compact handoff fields", () => {
40
+ const compact = (0, execution_adapter_js_1.buildCompactBootstrapState)({
41
+ runId: "run-001",
42
+ clusterId: "POL-42",
43
+ childId: "POL-49",
44
+ stateFile: ".taskchain_artifacts/polaris-run/current-state.json",
45
+ telemetryFile: ".taskchain_artifacts/polaris-run/runs/run-001/telemetry.jsonl",
46
+ currentStateSha: "abc123",
47
+ branch: "feature/pol-42",
48
+ });
49
+ (0, vitest_1.expect)(compact).toEqual({
50
+ run_id: "run-001",
51
+ cluster_id: "POL-42",
52
+ child_id: "POL-49",
53
+ state_file: ".taskchain_artifacts/polaris-run/current-state.json",
54
+ telemetry_file: ".taskchain_artifacts/polaris-run/runs/run-001/telemetry.jsonl",
55
+ current_state_sha: "abc123",
56
+ branch: "feature/pol-42",
57
+ return_summary_contract: [
58
+ "child_id",
59
+ "status",
60
+ "commit_hash",
61
+ "validation_summary",
62
+ "next_action",
63
+ ],
64
+ });
65
+ });
66
+ });
@@ -0,0 +1,169 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.formatFinalizeEvidenceFailures = formatFinalizeEvidenceFailures;
4
+ exports.verifyCompletedChildFinalizeEvidence = verifyCompletedChildFinalizeEvidence;
5
+ exports.assertFinalizeEvidenceOrThrow = assertFinalizeEvidenceOrThrow;
6
+ const node_child_process_1 = require("node:child_process");
7
+ const node_fs_1 = require("node:fs");
8
+ const node_path_1 = require("node:path");
9
+ const checkpoint_js_1 = require("./checkpoint.js");
10
+ const artifact_policy_js_1 = require("../finalize/artifact-policy.js");
11
+ function readJsonFile(path) {
12
+ if (!(0, node_fs_1.existsSync)(path))
13
+ return undefined;
14
+ try {
15
+ return JSON.parse((0, node_fs_1.readFileSync)(path, "utf-8"));
16
+ }
17
+ catch {
18
+ return undefined;
19
+ }
20
+ }
21
+ function resolvePath(repoRoot, pathLike) {
22
+ if (typeof pathLike !== "string" || pathLike.trim().length === 0)
23
+ return undefined;
24
+ return (0, node_path_1.isAbsolute)(pathLike) ? pathLike : (0, node_path_1.resolve)(repoRoot, pathLike);
25
+ }
26
+ function pickCommitHash(...candidates) {
27
+ for (const candidate of candidates) {
28
+ if (typeof candidate !== "string")
29
+ continue;
30
+ const commit = candidate.trim();
31
+ if (commit.length > 0)
32
+ return commit;
33
+ }
34
+ return undefined;
35
+ }
36
+ function packetFlag(packet, key) {
37
+ if (!packet || typeof packet !== "object" || Array.isArray(packet))
38
+ return undefined;
39
+ const pkt = packet;
40
+ const fromRoot = pkt[key];
41
+ if (fromRoot !== undefined)
42
+ return fromRoot;
43
+ const instructions = pkt.instructions;
44
+ if (!instructions || typeof instructions !== "object" || Array.isArray(instructions))
45
+ return undefined;
46
+ return instructions[key];
47
+ }
48
+ function hasValidationWaiver(value) {
49
+ if (typeof value === "string")
50
+ return value.trim().length > 0;
51
+ if (typeof value === "boolean")
52
+ return value;
53
+ if (value && typeof value === "object" && !Array.isArray(value))
54
+ return Object.keys(value).length > 0;
55
+ return false;
56
+ }
57
+ function isArtifactOnlyAllowed(value) {
58
+ if (typeof value === "boolean")
59
+ return value;
60
+ if (typeof value === "string")
61
+ return value.trim().toLowerCase() === "true";
62
+ return false;
63
+ }
64
+ function hasPassingValidation(value) {
65
+ if (typeof value === "string") {
66
+ const normalized = value.trim().toLowerCase();
67
+ return normalized === "passed" || normalized === "pass" || normalized === "success" || normalized === "ok";
68
+ }
69
+ if (typeof value === "boolean")
70
+ return value;
71
+ if (!value || typeof value !== "object" || Array.isArray(value))
72
+ return false;
73
+ const record = value;
74
+ const status = record["status"];
75
+ if (typeof status === "string" && ["passed", "pass", "success", "ok"].includes(status.trim().toLowerCase())) {
76
+ return true;
77
+ }
78
+ const summary = record["summary"];
79
+ if (typeof summary === "string" && ["passed", "pass", "success", "ok"].includes(summary.trim().toLowerCase())) {
80
+ return true;
81
+ }
82
+ const validation = record["validation"];
83
+ if (typeof validation === "string" && ["passed", "pass", "success", "ok"].includes(validation.trim().toLowerCase())) {
84
+ return true;
85
+ }
86
+ const passed = record["passed"];
87
+ if (passed === true)
88
+ return true;
89
+ if (Array.isArray(passed))
90
+ return passed.length > 0;
91
+ if (typeof passed === "number")
92
+ return passed > 0;
93
+ return false;
94
+ }
95
+ function getCommitFiles(repoRoot, commitHash) {
96
+ try {
97
+ const output = (0, node_child_process_1.execFileSync)("git", ["show", "--pretty=format:", "--name-only", commitHash], { cwd: repoRoot, encoding: "utf-8" });
98
+ return output.split("\n").map((line) => line.trim()).filter(Boolean);
99
+ }
100
+ catch {
101
+ return null;
102
+ }
103
+ }
104
+ function listFailingChildren(failures) {
105
+ const lines = failures.map((failure) => `- ${failure.childId}: ${failure.reasons.join("; ")}`);
106
+ return [
107
+ "finalize aborted: completed children missing implementation evidence:",
108
+ ...lines,
109
+ ].join("\n");
110
+ }
111
+ function formatFinalizeEvidenceFailures(failures) {
112
+ return listFailingChildren(failures);
113
+ }
114
+ function verifyCompletedChildFinalizeEvidence(repoRoot, stateFile) {
115
+ const state = (0, checkpoint_js_1.readState)(stateFile);
116
+ const clusterStatePath = (0, node_path_1.resolve)(repoRoot, ".polaris", "clusters", state.cluster_id, "cluster-state.json");
117
+ const clusterState = (readJsonFile(clusterStatePath) ?? {});
118
+ const failures = [];
119
+ for (const childId of state.completed_children) {
120
+ const reasons = [];
121
+ const childMeta = state.open_children_meta?.[childId];
122
+ const dispatchRecord = childMeta?.dispatch_record;
123
+ const packetPath = resolvePath(repoRoot, dispatchRecord?.packet_path ?? clusterState.packet_pointers?.[childId]);
124
+ const resultPath = resolvePath(repoRoot, dispatchRecord?.expected_result_path ?? childMeta?.result_file ?? clusterState.result_pointers?.[childId]);
125
+ const packet = packetPath ? readJsonFile(packetPath) : undefined;
126
+ const result = (resultPath ? readJsonFile(resultPath) : undefined);
127
+ const stateResult = state.completed_children_results?.[childId];
128
+ const commitHash = pickCommitHash(clusterState.commits?.[childId], stateResult?.commit, result?.commit, result?.commit_hash);
129
+ if (!commitHash) {
130
+ reasons.push("no commit hash recorded in cluster state or result evidence");
131
+ }
132
+ else {
133
+ const commitFiles = getCommitFiles(repoRoot, commitHash);
134
+ if (commitFiles === null) {
135
+ reasons.push(`commit ${commitHash} not found in git history`);
136
+ }
137
+ else if (commitFiles.length === 0) {
138
+ reasons.push(`commit ${commitHash} contains no file changes`);
139
+ }
140
+ else {
141
+ const nonArtifactFiles = commitFiles.filter((file) => (0, artifact_policy_js_1.classifyArtifactPath)(file, state.cluster_id) === "non-artifact");
142
+ const artifactOnlyAllowed = isArtifactOnlyAllowed(packetFlag(packet, "artifact_only"));
143
+ if (nonArtifactFiles.length === 0 && !artifactOnlyAllowed) {
144
+ reasons.push(`commit ${commitHash} changes only artifacts and packet is missing artifact_only: true`);
145
+ }
146
+ }
147
+ }
148
+ const validationWaiver = packetFlag(packet, "validation_waiver");
149
+ const validationPassed = hasPassingValidation(result?.validation)
150
+ || hasPassingValidation(stateResult?.validation)
151
+ || hasPassingValidation(clusterState.validation_results?.[childId]);
152
+ if (!validationPassed && !hasValidationWaiver(validationWaiver)) {
153
+ reasons.push("validation evidence missing or not passed and no validation_waiver was provided");
154
+ }
155
+ if (reasons.length > 0) {
156
+ failures.push({ childId, reasons });
157
+ }
158
+ }
159
+ return {
160
+ ok: failures.length === 0,
161
+ failures,
162
+ };
163
+ }
164
+ function assertFinalizeEvidenceOrThrow(repoRoot, stateFile) {
165
+ const report = verifyCompletedChildFinalizeEvidence(repoRoot, stateFile);
166
+ if (!report.ok) {
167
+ throw new Error(formatFinalizeEvidenceFailures(report.failures));
168
+ }
169
+ }