@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,74 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.executeDryRun = executeDryRun;
4
+ const node_crypto_1 = require("node:crypto");
5
+ const state_js_1 = require("../state.js");
6
+ const fingerprint_js_1 = require("../verification/fingerprint.js");
7
+ const child_selector_js_1 = require("../scheduling/child-selector.js");
8
+ const logger_js_1 = require("../audit/logger.js");
9
+ async function executeDryRun(request) {
10
+ const state = await (0, state_js_1.loadState)(request.artifact_dir);
11
+ if (state === null) {
12
+ return {
13
+ ok: false,
14
+ rejection: {
15
+ reason: "run_not_found",
16
+ detail: `No state found in .taskchain_artifacts/${request.artifact_dir}`,
17
+ },
18
+ };
19
+ }
20
+ if (state.status !== "running") {
21
+ return {
22
+ ok: false,
23
+ rejection: { reason: "run_not_continuable", expected: "running", actual: state.status },
24
+ };
25
+ }
26
+ const activeChild = state.active_child ?? "";
27
+ if (activeChild !== "") {
28
+ return {
29
+ ok: false,
30
+ rejection: { reason: "concurrent_execution", detail: `active_child is set: ${activeChild}` },
31
+ };
32
+ }
33
+ if (state.step_cursor !== request.expected_step_cursor) {
34
+ return {
35
+ ok: false,
36
+ rejection: {
37
+ reason: "step_cursor_mismatch",
38
+ expected: request.expected_step_cursor,
39
+ actual: state.step_cursor ?? undefined,
40
+ },
41
+ };
42
+ }
43
+ const nextChild = (0, child_selector_js_1.selectNextChild)(state);
44
+ if (nextChild === null) {
45
+ return { ok: false, rejection: { reason: "no_open_children" } };
46
+ }
47
+ // Nonce ties this fingerprint to a single approval issuance — prevents replay
48
+ const nonce = (0, node_crypto_1.randomUUID)();
49
+ const fingerprint = (0, fingerprint_js_1.computeStateFingerprint)({ state, approvalNonce: nonce });
50
+ await (0, logger_js_1.appendAuditEvent)(request.artifact_dir, {
51
+ event_type: "dry_run_executed",
52
+ run_id: state.run_id,
53
+ step_cursor: state.step_cursor ?? "",
54
+ operator: "mcp",
55
+ operation: "loop_continue_dry_run",
56
+ child_id: nextChild,
57
+ result: "preview",
58
+ });
59
+ return {
60
+ ok: true,
61
+ preview: {
62
+ next_child: nextChild,
63
+ fingerprint,
64
+ approval_template: {
65
+ run_id: state.run_id,
66
+ expected_step_cursor: state.step_cursor ?? "",
67
+ fingerprint,
68
+ runtime_generation: state.runtime_generation ?? 0,
69
+ nonce,
70
+ requested_action: "loop_continue",
71
+ },
72
+ },
73
+ };
74
+ }
@@ -0,0 +1,106 @@
1
+ "use strict";
2
+ /**
3
+ * execution-window.ts — Execution window support for Alice/Delegator
4
+ *
5
+ * Alice/Delegator compatibility principles:
6
+ *
7
+ * 1. Approval tokens must be provider-agnostic (no Alice-specific fields).
8
+ * ExecutionWindow carries only generic orchestration fields; Alice is one
9
+ * possible issuer, not the assumed issuer.
10
+ *
11
+ * 2. Dry-run contract must remain stable — Alice implements against it without
12
+ * version coupling. The shape of ExecutionWindow and WindowValidationResult
13
+ * must not change in a breaking way without a schema_version bump in the
14
+ * broader protocol.
15
+ *
16
+ * 3. Fingerprint must be deterministic — Alice can re-run the dry-run for the
17
+ * same state and obtain the same fingerprint. This is guaranteed by
18
+ * computeStateFingerprint in src/runtime/verification/fingerprint.ts.
19
+ *
20
+ * 4. Confirmations must be idempotent at protocol level — validateWindow is
21
+ * pure and side-effect-free; calling it multiple times for the same inputs
22
+ * yields the same result. Callers are responsible for persisting
23
+ * decremented windows exactly once.
24
+ */
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ exports.validateWindow = validateWindow;
27
+ exports.decrementWindow = decrementWindow;
28
+ /**
29
+ * Validates an ExecutionWindow against the current runtime state and
30
+ * fingerprint. All checks must pass for the result to be `{ ok: true }`.
31
+ *
32
+ * Checks performed (in order):
33
+ * 1. run_id_mismatch — window.run_id must equal state.run_id
34
+ * 2. window_not_yet_valid — valid_from must be in the past or now
35
+ * 3. window_expired — valid_until must be strictly in the future
36
+ * 4. window_exhausted — max_continuations must be > 0
37
+ * 5. state_fingerprint_drifted — currentFingerprint must exactly match
38
+ * window.state_fingerprint_at_issue
39
+ *
40
+ * Note: allowed_child_types is validated against the proposed continuation's
41
+ * child type once that information is threaded through to this call site.
42
+ * The field is intentionally included in ExecutionWindow now so that the
43
+ * protocol shape is stable when that check is wired in. Until then, a
44
+ * non-empty allowed_child_types list is accepted without failing — see
45
+ * the inline comment near the check location.
46
+ */
47
+ function validateWindow(state, window, currentFingerprint) {
48
+ // 1. run_id must match
49
+ if (window.run_id !== state.run_id) {
50
+ return {
51
+ ok: false,
52
+ reason: "run_id_mismatch",
53
+ detail: `window.run_id=${window.run_id} state.run_id=${state.run_id}`,
54
+ };
55
+ }
56
+ const now = new Date();
57
+ // 2. Window must have started
58
+ if (new Date(window.valid_from) > now) {
59
+ return {
60
+ ok: false,
61
+ reason: "window_not_yet_valid",
62
+ detail: `valid_from=${window.valid_from} now=${now.toISOString()}`,
63
+ };
64
+ }
65
+ // 3. Window must not have expired
66
+ if (new Date(window.valid_until) <= now) {
67
+ return {
68
+ ok: false,
69
+ reason: "window_expired",
70
+ detail: `valid_until=${window.valid_until} now=${now.toISOString()}`,
71
+ };
72
+ }
73
+ // 4. Continuations remaining
74
+ if (window.max_continuations <= 0) {
75
+ return {
76
+ ok: false,
77
+ reason: "window_exhausted",
78
+ detail: `max_continuations=${window.max_continuations}`,
79
+ };
80
+ }
81
+ // 5. Fingerprint must match exactly — no tolerance
82
+ if (currentFingerprint !== window.state_fingerprint_at_issue) {
83
+ return {
84
+ ok: false,
85
+ reason: "state_fingerprint_drifted",
86
+ detail: `expected=${window.state_fingerprint_at_issue} got=${currentFingerprint}`,
87
+ };
88
+ }
89
+ // allowed_child_types check deferred — child type not yet threaded through at call site.
90
+ // If allowed_child_types is non-empty, we skip the check rather than fail, because the
91
+ // child-type information is not yet available here. This preserves protocol shape for
92
+ // future wiring without blocking windows that specify allowed_child_types today.
93
+ return { ok: true };
94
+ }
95
+ /**
96
+ * Returns a new ExecutionWindow with max_continuations decremented by 1.
97
+ *
98
+ * Does NOT mutate the input window. The caller is responsible for persisting
99
+ * the returned window exactly once to ensure idempotency at the protocol level.
100
+ */
101
+ function decrementWindow(window) {
102
+ return {
103
+ ...window,
104
+ max_continuations: window.max_continuations - 1,
105
+ };
106
+ }
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.selectNextChild = selectNextChild;
4
+ /**
5
+ * Select the next child to execute.
6
+ *
7
+ * TODO: TEMPORARY — lexical sort of issue IDs is a placeholder only.
8
+ * Real scheduling must come from runtime orchestration policy (priority,
9
+ * dependencies, cycle assignment, etc.). Do not treat this ordering as
10
+ * authoritative. Replace with a SchedulingService in a future cluster.
11
+ */
12
+ function selectNextChild(state) {
13
+ if (state.open_children.length === 0)
14
+ return null;
15
+ return [...state.open_children].sort()[0] ?? null;
16
+ }
@@ -0,0 +1,43 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.getArtifactsDir = getArtifactsDir;
7
+ exports.getArtifactDir = getArtifactDir;
8
+ exports.getStateFilePath = getStateFilePath;
9
+ exports.loadState = loadState;
10
+ exports.writeState = writeState;
11
+ exports.listArtifactDirs = listArtifactDirs;
12
+ const promises_1 = require("node:fs/promises");
13
+ const node_path_1 = __importDefault(require("node:path"));
14
+ function getArtifactsDir() {
15
+ return node_path_1.default.join(process.cwd(), ".taskchain_artifacts");
16
+ }
17
+ function getArtifactDir(artifactDir) {
18
+ return node_path_1.default.join(getArtifactsDir(), artifactDir);
19
+ }
20
+ function getStateFilePath(artifactDir) {
21
+ return node_path_1.default.join(getArtifactDir(artifactDir), "current-state.json");
22
+ }
23
+ async function loadState(artifactDir) {
24
+ try {
25
+ const raw = await (0, promises_1.readFile)(getStateFilePath(artifactDir), "utf-8");
26
+ return JSON.parse(raw);
27
+ }
28
+ catch {
29
+ return null;
30
+ }
31
+ }
32
+ async function writeState(artifactDir, state) {
33
+ await (0, promises_1.writeFile)(getStateFilePath(artifactDir), JSON.stringify(state, null, 2) + "\n", "utf-8");
34
+ }
35
+ async function listArtifactDirs() {
36
+ try {
37
+ const entries = await (0, promises_1.readdir)(getArtifactsDir(), { withFileTypes: true });
38
+ return entries.filter((e) => e.isDirectory()).map((e) => e.name);
39
+ }
40
+ catch {
41
+ return [];
42
+ }
43
+ }
@@ -0,0 +1,46 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getOverallStatus = getOverallStatus;
4
+ exports.getLoopStatus = getLoopStatus;
5
+ exports.getCurrentState = getCurrentState;
6
+ const state_js_1 = require("./state.js");
7
+ async function getOverallStatus() {
8
+ const dirs = await (0, state_js_1.listArtifactDirs)();
9
+ const runs = await Promise.all(dirs.map(async (dir) => {
10
+ const state = await (0, state_js_1.loadState)(dir);
11
+ return state
12
+ ? {
13
+ artifact_dir: dir,
14
+ run_id: state.run_id,
15
+ status: state.status,
16
+ step_cursor: state.step_cursor,
17
+ cluster_id: state.cluster_id,
18
+ open_children_count: state.open_children.length,
19
+ completed_children_count: state.completed_children.length,
20
+ }
21
+ : { artifact_dir: dir, status: "unreadable" };
22
+ }));
23
+ return { runs };
24
+ }
25
+ async function getLoopStatus(artifactDir) {
26
+ const state = await (0, state_js_1.loadState)(artifactDir);
27
+ if (!state)
28
+ return null;
29
+ return {
30
+ artifact_dir: artifactDir,
31
+ run_id: state.run_id,
32
+ cluster_id: state.cluster_id,
33
+ status: state.status,
34
+ step_cursor: state.step_cursor,
35
+ active_child: state.active_child,
36
+ open_children: state.open_children,
37
+ completed_children: state.completed_children,
38
+ context_budget: state.context_budget,
39
+ runtime_generation: state.runtime_generation,
40
+ orchestration_mode: state.orchestration_mode,
41
+ continuation_epoch: state.continuation_epoch,
42
+ };
43
+ }
44
+ async function getCurrentState(artifactDir) {
45
+ return (0, state_js_1.loadState)(artifactDir);
46
+ }
@@ -0,0 +1,80 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.validateEnvelope = validateEnvelope;
4
+ const fingerprint_js_1 = require("./fingerprint.js");
5
+ const child_selector_js_1 = require("../scheduling/child-selector.js");
6
+ function validateEnvelope(state, envelope) {
7
+ if (envelope.requested_action !== "loop_continue") {
8
+ return {
9
+ ok: false,
10
+ failure: {
11
+ check: "requested_action",
12
+ reason: "unsupported_action",
13
+ expected: "loop_continue",
14
+ actual: envelope.requested_action,
15
+ },
16
+ };
17
+ }
18
+ if (state.status !== "running") {
19
+ return {
20
+ ok: false,
21
+ failure: { check: "status", reason: "run_not_continuable", actual: state.status },
22
+ };
23
+ }
24
+ const activeChild = state.active_child ?? "";
25
+ if (activeChild !== "") {
26
+ return {
27
+ ok: false,
28
+ failure: { check: "active_child", reason: "concurrent_execution", actual: activeChild },
29
+ };
30
+ }
31
+ if (state.run_id !== envelope.run_id) {
32
+ return {
33
+ ok: false,
34
+ failure: {
35
+ check: "run_id",
36
+ reason: "run_id_mismatch",
37
+ expected: envelope.run_id,
38
+ actual: state.run_id,
39
+ },
40
+ };
41
+ }
42
+ if (state.step_cursor !== envelope.expected_step_cursor) {
43
+ return {
44
+ ok: false,
45
+ failure: {
46
+ check: "step_cursor",
47
+ reason: "step_cursor_mismatch",
48
+ expected: envelope.expected_step_cursor,
49
+ actual: state.step_cursor,
50
+ },
51
+ };
52
+ }
53
+ const stateGeneration = state.runtime_generation ?? 0;
54
+ if (stateGeneration !== envelope.runtime_generation) {
55
+ return {
56
+ ok: false,
57
+ failure: {
58
+ check: "runtime_generation",
59
+ reason: "runtime_generation_mismatch",
60
+ expected: String(envelope.runtime_generation),
61
+ actual: String(stateGeneration),
62
+ },
63
+ };
64
+ }
65
+ const currentFingerprint = (0, fingerprint_js_1.computeStateFingerprint)({ state, approvalNonce: envelope.nonce });
66
+ if (currentFingerprint !== envelope.fingerprint) {
67
+ return {
68
+ ok: false,
69
+ failure: { check: "fingerprint", reason: "state_mutated_since_approval" },
70
+ };
71
+ }
72
+ const nextChild = (0, child_selector_js_1.selectNextChild)(state);
73
+ if (nextChild === null) {
74
+ return { ok: false, failure: { check: "next_child", reason: "no_open_children" } };
75
+ }
76
+ if (new Date(envelope.expires_at) <= new Date()) {
77
+ return { ok: false, failure: { check: "expires_at", reason: "approval_expired" } };
78
+ }
79
+ return { ok: true, next_child: nextChild };
80
+ }
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.computeStateFingerprint = computeStateFingerprint;
4
+ const node_crypto_1 = require("node:crypto");
5
+ /**
6
+ * Compute a replay-resistant state fingerprint.
7
+ *
8
+ * Scope includes all fields that must not change between dry-run issuance and
9
+ * confirmed continuation. The approval_nonce (when present) ties the fingerprint
10
+ * to a specific approval issuance, preventing pre-computation and replay attacks.
11
+ */
12
+ function computeStateFingerprint({ state, approvalNonce }) {
13
+ const canonical = JSON.stringify({
14
+ schema_version: state.schema_version,
15
+ runtime_generation: state.runtime_generation ?? 0,
16
+ run_id: state.run_id,
17
+ step_cursor: state.step_cursor,
18
+ active_child: state.active_child ?? null,
19
+ status: state.status,
20
+ orchestration_mode: state.orchestration_mode ?? "bootstrap",
21
+ continuation_epoch: state.continuation_epoch ?? 0,
22
+ open_children: [...state.open_children].sort(),
23
+ approval_nonce: approvalNonce ?? null,
24
+ });
25
+ return (0, node_crypto_1.createHash)("sha256").update(canonical).digest("hex");
26
+ }
@@ -0,0 +1,105 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const vitest_1 = require("vitest");
4
+ const index_js_1 = require("./index.js");
5
+ vitest_1.vi.mock("../config/loader.js", () => ({
6
+ loadConfig: () => ({
7
+ skill_packet: {
8
+ analysis_confidence_threshold: 85,
9
+ auto_deep_analysis: false,
10
+ allow_cross_provider_delegation: false,
11
+ },
12
+ }),
13
+ }));
14
+ function configureForTest(program, output) {
15
+ program.exitOverride();
16
+ program.configureOutput({
17
+ writeOut: (value) => {
18
+ output.stdout += value;
19
+ },
20
+ writeErr: (value) => {
21
+ output.stderr += value;
22
+ },
23
+ });
24
+ for (const command of program.commands) {
25
+ configureForTest(command, output);
26
+ }
27
+ }
28
+ async function runSkillCommand(argv) {
29
+ const output = { stdout: "", stderr: "" };
30
+ let exitCode = 0;
31
+ const stdoutSpy = vitest_1.vi.spyOn(process.stdout, "write").mockImplementation((chunk) => {
32
+ output.stdout += String(chunk);
33
+ return true;
34
+ });
35
+ const stderrSpy = vitest_1.vi.spyOn(process.stderr, "write").mockImplementation((chunk) => {
36
+ output.stderr += String(chunk);
37
+ return true;
38
+ });
39
+ const exitSpy = vitest_1.vi.spyOn(process, "exit").mockImplementation((code) => {
40
+ exitCode = typeof code === "number" ? code : 0;
41
+ throw new Error(`process.exit(${code})`);
42
+ });
43
+ const command = (0, index_js_1.createSkillCommand)({ repoRoot: "/repo" });
44
+ configureForTest(command, output);
45
+ try {
46
+ await command.parseAsync(["node", "polaris-skill", ...argv], { from: "node" });
47
+ }
48
+ catch (error) {
49
+ if (error instanceof Error && "exitCode" in error) {
50
+ exitCode = Number(error.exitCode);
51
+ }
52
+ else if (error instanceof Error && error.message.startsWith("process.exit(")) {
53
+ // swallow process.exit mock throws
54
+ }
55
+ else {
56
+ throw error;
57
+ }
58
+ }
59
+ finally {
60
+ stdoutSpy.mockRestore();
61
+ stderrSpy.mockRestore();
62
+ exitSpy.mockRestore();
63
+ }
64
+ return { ...output, exitCode };
65
+ }
66
+ (0, vitest_1.describe)("polaris skill packet CLI", () => {
67
+ (0, vitest_1.it)("prints skill help when no subcommand is given", async () => {
68
+ const result = await runSkillCommand(["--help"]);
69
+ (0, vitest_1.expect)(result.stdout).toContain("skill packet");
70
+ });
71
+ vitest_1.it.each(["analyze", "run", "ingest", "promote"])("generates a valid JSON packet for %s", async (skill) => {
72
+ const result = await runSkillCommand(["packet", skill]);
73
+ const packet = JSON.parse(result.stdout);
74
+ (0, vitest_1.expect)(packet.skill_name).toBe(skill);
75
+ (0, vitest_1.expect)(typeof packet.packet_id).toBe("string");
76
+ (0, vitest_1.expect)(typeof packet.active_role).toBe("string");
77
+ (0, vitest_1.expect)(typeof packet.role_summary).toBe("string");
78
+ (0, vitest_1.expect)(Array.isArray(packet.authority_boundaries)).toBe(true);
79
+ (0, vitest_1.expect)(Array.isArray(packet.prohibited_actions)).toBe(true);
80
+ (0, vitest_1.expect)(Array.isArray(packet.allowed_outputs)).toBe(true);
81
+ (0, vitest_1.expect)(Array.isArray(packet.deliverables)).toBe(true);
82
+ (0, vitest_1.expect)(Array.isArray(packet.stop_conditions)).toBe(true);
83
+ (0, vitest_1.expect)(typeof packet.generated_at).toBe("string");
84
+ });
85
+ (0, vitest_1.it)("writes error and exits for unknown skill", async () => {
86
+ const result = await runSkillCommand(["packet", "unknown-skill"]);
87
+ (0, vitest_1.expect)(result.stderr).toContain("Unknown skill");
88
+ (0, vitest_1.expect)(result.stderr).toContain("analyze");
89
+ (0, vitest_1.expect)(result.exitCode).toBe(1);
90
+ });
91
+ (0, vitest_1.it)("analyze packet includes confidence_policy", async () => {
92
+ const result = await runSkillCommand(["packet", "analyze"]);
93
+ const packet = JSON.parse(result.stdout);
94
+ const policy = packet.confidence_policy;
95
+ (0, vitest_1.expect)(policy).toBeDefined();
96
+ (0, vitest_1.expect)(policy.threshold).toBe(85);
97
+ (0, vitest_1.expect)(policy.auto_deep_analysis).toBe(false);
98
+ (0, vitest_1.expect)(policy.on_below_threshold).toBe("ask_user");
99
+ });
100
+ (0, vitest_1.it)("run packet does not include confidence_policy", async () => {
101
+ const result = await runSkillCommand(["packet", "run"]);
102
+ const packet = JSON.parse(result.stdout);
103
+ (0, vitest_1.expect)(packet.confidence_policy).toBeUndefined();
104
+ });
105
+ });