@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,145 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ const vitest_1 = require("vitest");
40
+ const fs_1 = require("fs");
41
+ const path = __importStar(require("path"));
42
+ const store_1 = require("./store");
43
+ const local_graph_1 = require("../tracker/local-graph");
44
+ const test_clusters_json_1 = __importDefault(require("./fixtures/test-clusters.json"));
45
+ vitest_1.vi.mock('fs', () => ({
46
+ promises: {
47
+ readFile: vitest_1.vi.fn(),
48
+ writeFile: vitest_1.vi.fn(),
49
+ rename: vitest_1.vi.fn(),
50
+ },
51
+ }));
52
+ vitest_1.vi.mock('../tracker/local-graph');
53
+ const MOCK_CLUSTER_ID = 'POL-TEST-1';
54
+ (0, vitest_1.describe)('Cluster State Store', () => {
55
+ (0, vitest_1.beforeEach)(() => {
56
+ vitest_1.vi.resetAllMocks();
57
+ });
58
+ (0, vitest_1.describe)('readClusterState', () => {
59
+ (0, vitest_1.it)('should read and parse the cluster state file', async () => {
60
+ const mockState = {
61
+ schema_version: '1.0',
62
+ cluster_id: MOCK_CLUSTER_ID,
63
+ state_generation: 1,
64
+ child_states: [],
65
+ claim_metadata: {},
66
+ packet_pointers: {},
67
+ result_pointers: {},
68
+ validation_results: {},
69
+ commits: {},
70
+ blockers: [],
71
+ };
72
+ fs_1.promises.readFile.mockResolvedValue(JSON.stringify(mockState));
73
+ const state = await (0, store_1.readClusterState)(MOCK_CLUSTER_ID);
74
+ (0, vitest_1.expect)(state).toEqual(mockState);
75
+ (0, vitest_1.expect)(fs_1.promises.readFile).toHaveBeenCalledWith(vitest_1.expect.stringContaining('cluster-state.json'), 'utf-8');
76
+ });
77
+ (0, vitest_1.it)('should return null if the file does not exist', async () => {
78
+ const error = new Error('ENOENT: no such file or directory');
79
+ error.code = 'ENOENT';
80
+ fs_1.promises.readFile.mockRejectedValue(error);
81
+ const state = await (0, store_1.readClusterState)(MOCK_CLUSTER_ID);
82
+ (0, vitest_1.expect)(state).toBeNull();
83
+ });
84
+ (0, vitest_1.it)('should re-throw other errors', async () => {
85
+ const error = new Error('Read error');
86
+ fs_1.promises.readFile.mockRejectedValue(error);
87
+ await (0, vitest_1.expect)((0, store_1.readClusterState)(MOCK_CLUSTER_ID)).rejects.toThrow('Read error');
88
+ });
89
+ });
90
+ (0, vitest_1.describe)('writeClusterState', () => {
91
+ (0, vitest_1.it)('should write the cluster state atomically', async () => {
92
+ const newState = {
93
+ schema_version: '1.0',
94
+ cluster_id: MOCK_CLUSTER_ID,
95
+ state_generation: 2,
96
+ child_states: [],
97
+ claim_metadata: {},
98
+ packet_pointers: {},
99
+ result_pointers: {},
100
+ validation_results: {},
101
+ commits: {},
102
+ blockers: [],
103
+ };
104
+ // Mock existing state as null
105
+ fs_1.promises.readFile.mockResolvedValueOnce(null);
106
+ await (0, store_1.writeClusterState)(MOCK_CLUSTER_ID, newState);
107
+ const filePath = path.join(process.cwd(), '.polaris', 'clusters', MOCK_CLUSTER_ID, 'cluster-state.json');
108
+ (0, vitest_1.expect)(fs_1.promises.writeFile).toHaveBeenCalledWith(filePath + '.tmp', JSON.stringify(newState, null, 2));
109
+ (0, vitest_1.expect)(fs_1.promises.rename).toHaveBeenCalledWith(filePath + '.tmp', filePath);
110
+ });
111
+ (0, vitest_1.it)('should throw an error for a stale state generation', async () => {
112
+ const existingState = {
113
+ schema_version: '1.0',
114
+ cluster_id: MOCK_CLUSTER_ID,
115
+ state_generation: 2,
116
+ child_states: [],
117
+ claim_metadata: {},
118
+ packet_pointers: {},
119
+ result_pointers: {},
120
+ validation_results: {},
121
+ commits: {},
122
+ blockers: [],
123
+ };
124
+ const newState = { ...existingState, state_generation: 2 };
125
+ fs_1.promises.readFile.mockResolvedValue(JSON.stringify(existingState));
126
+ await (0, vitest_1.expect)((0, store_1.writeClusterState)(MOCK_CLUSTER_ID, newState)).rejects.toThrow('Stale state: state_generation is not greater than current state.');
127
+ });
128
+ });
129
+ (0, vitest_1.describe)('initializeClusterState', () => {
130
+ (0, vitest_1.it)('should initialize state from a LocalGraph', async () => {
131
+ const mockGraph = local_graph_1.LocalGraph.fromGraph(test_clusters_json_1.default);
132
+ vitest_1.vi.spyOn(local_graph_1.LocalGraph, 'load').mockResolvedValue(mockGraph);
133
+ // Mock writeClusterState to avoid its internal logic for this test
134
+ const writeSpy = vitest_1.vi.spyOn(fs_1.promises, 'writeFile');
135
+ const initialState = await (0, store_1.initializeClusterState)(MOCK_CLUSTER_ID);
136
+ (0, vitest_1.expect)(local_graph_1.LocalGraph.load).toHaveBeenCalledWith(MOCK_CLUSTER_ID);
137
+ (0, vitest_1.expect)(initialState.cluster_id).toBe(MOCK_CLUSTER_ID);
138
+ (0, vitest_1.expect)(initialState.state_generation).toBe(1);
139
+ (0, vitest_1.expect)(initialState.child_states).toHaveLength(2);
140
+ (0, vitest_1.expect)(initialState.child_states[0]).toEqual({ id: 'CHILD-1', status: 'open' });
141
+ (0, vitest_1.expect)(initialState.child_states[1]).toEqual({ id: 'CHILD-2', status: 'open' });
142
+ (0, vitest_1.expect)(writeSpy).toHaveBeenCalled();
143
+ });
144
+ });
145
+ });
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,158 @@
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.archiveCognitionNotes = archiveCognitionNotes;
7
+ const node_fs_1 = require("node:fs");
8
+ const node_path_1 = __importDefault(require("node:path"));
9
+ const PENDING_PREFIX = ".polaris/cognition/pending/";
10
+ const ARCHIVE_PREFIX = ".polaris/cognition/archive/";
11
+ function normalizeRelativePath(filePath) {
12
+ return node_path_1.default.posix.normalize(filePath.replace(/\\/g, "/")).replace(/^\.\//, "");
13
+ }
14
+ function resolvePendingNotePath(repoRoot, notePath) {
15
+ const rawRelativePath = node_path_1.default.isAbsolute(notePath)
16
+ ? node_path_1.default.relative(repoRoot, notePath)
17
+ : notePath;
18
+ let normalized = normalizeRelativePath(rawRelativePath);
19
+ // Remove leading slashes
20
+ normalized = normalized.replace(/^\/+/, "");
21
+ // Use path.posix.normalize to collapse ".." and "."
22
+ normalized = node_path_1.default.posix.normalize(normalized);
23
+ // Validate: reject paths that escape the repository or are absolute
24
+ if (normalized.startsWith("../") || normalized.includes("/../") || normalized.startsWith("/")) {
25
+ throw new Error(`Invalid note path: path traversal or absolute path detected: ${notePath}`);
26
+ }
27
+ const pendingRelativePath = normalized.startsWith(PENDING_PREFIX)
28
+ ? normalized
29
+ : `${PENDING_PREFIX}${normalized}`;
30
+ const noteRelativePath = pendingRelativePath.slice(PENDING_PREFIX.length);
31
+ const folderName = node_path_1.default.posix.dirname(noteRelativePath);
32
+ const folder = folderName === "." ? "" : folderName;
33
+ const noteName = node_path_1.default.posix.basename(noteRelativePath);
34
+ const archiveRelativePath = `${ARCHIVE_PREFIX}${noteRelativePath}`;
35
+ return {
36
+ pendingRelativePath,
37
+ archiveRelativePath,
38
+ folder,
39
+ noteName,
40
+ };
41
+ }
42
+ function readIndex(indexPath) {
43
+ if (!(0, node_fs_1.existsSync)(indexPath)) {
44
+ return { entries: [] };
45
+ }
46
+ try {
47
+ const parsed = JSON.parse((0, node_fs_1.readFileSync)(indexPath, "utf-8"));
48
+ if (Array.isArray(parsed.entries)) {
49
+ return { entries: parsed.entries };
50
+ }
51
+ }
52
+ catch {
53
+ // Fall through to reset malformed index files.
54
+ }
55
+ return { entries: [] };
56
+ }
57
+ function writeIndex(indexPath, entry) {
58
+ const index = readIndex(indexPath);
59
+ index.entries.push(entry);
60
+ (0, node_fs_1.mkdirSync)(node_path_1.default.dirname(indexPath), { recursive: true });
61
+ (0, node_fs_1.writeFileSync)(indexPath, JSON.stringify(index, null, 2) + "\n", "utf-8");
62
+ }
63
+ function buildArchivedResultPayload(options) {
64
+ return options.result ?? {
65
+ reconcile_id: options.reconcileId,
66
+ run_id: options.runId,
67
+ reconciled_at: options.reconciledAt ?? new Date().toISOString(),
68
+ notes_consumed: options.notesConsumed,
69
+ polaris_md_updated: options.polarisMdUpdated,
70
+ summary_md_updated: options.summaryMdUpdated,
71
+ status: options.status ?? "applied",
72
+ };
73
+ }
74
+ function archiveCognitionNotes(options) {
75
+ const archivedNotes = [];
76
+ const missingNotes = [];
77
+ const updatedIndexFiles = [];
78
+ const resultFiles = [];
79
+ const timestamp = options.reconciledAt ?? new Date().toISOString();
80
+ const groupedNotes = new Map();
81
+ const resolvedNotes = options.notesConsumed.map((notePath) => resolvePendingNotePath(options.repoRoot, notePath));
82
+ for (const note of resolvedNotes) {
83
+ const targetGroup = groupedNotes.get(note.folder) ?? [];
84
+ groupedNotes.set(note.folder, targetGroup);
85
+ const pendingAbsolutePath = node_path_1.default.join(options.repoRoot, note.pendingRelativePath);
86
+ const archiveAbsolutePath = node_path_1.default.join(options.repoRoot, note.archiveRelativePath);
87
+ (0, node_fs_1.mkdirSync)(node_path_1.default.dirname(archiveAbsolutePath), { recursive: true });
88
+ if (options.status === "rejected") {
89
+ targetGroup.push(note.noteName);
90
+ continue;
91
+ }
92
+ if ((0, node_fs_1.existsSync)(pendingAbsolutePath)) {
93
+ (0, node_fs_1.renameSync)(pendingAbsolutePath, archiveAbsolutePath);
94
+ archivedNotes.push(note.archiveRelativePath);
95
+ targetGroup.push(note.noteName);
96
+ continue;
97
+ }
98
+ if ((0, node_fs_1.existsSync)(archiveAbsolutePath)) {
99
+ archivedNotes.push(note.archiveRelativePath);
100
+ targetGroup.push(note.noteName);
101
+ continue;
102
+ }
103
+ missingNotes.push(note.pendingRelativePath);
104
+ }
105
+ if (options.status === "rejected") {
106
+ for (const [folder, notesConsumed] of groupedNotes.entries()) {
107
+ if (notesConsumed.length === 0) {
108
+ continue;
109
+ }
110
+ const indexRelativePath = `${PENDING_PREFIX}${folder ? `${folder}/` : ""}cognition-index.json`;
111
+ writeIndex(node_path_1.default.join(options.repoRoot, indexRelativePath), {
112
+ event: "cognition-librarian-patch-rejected",
113
+ reconcile_id: options.reconcileId,
114
+ run_id: options.runId,
115
+ rejected_at: timestamp,
116
+ notes_consumed: notesConsumed,
117
+ polaris_md_updated: options.polarisMdUpdated,
118
+ summary_md_updated: options.summaryMdUpdated,
119
+ reason: options.rejectionReason,
120
+ });
121
+ updatedIndexFiles.push(indexRelativePath);
122
+ }
123
+ return {
124
+ archivedNotes,
125
+ missingNotes,
126
+ updatedIndexFiles,
127
+ resultFiles,
128
+ };
129
+ }
130
+ const archivedResultPayload = buildArchivedResultPayload(options);
131
+ for (const [folder, notesConsumed] of groupedNotes.entries()) {
132
+ if (notesConsumed.length === 0) {
133
+ continue;
134
+ }
135
+ const archiveFolderRelativePath = `${ARCHIVE_PREFIX}${folder ? `${folder}/` : ""}`;
136
+ const archiveFolderPath = node_path_1.default.join(options.repoRoot, archiveFolderRelativePath);
137
+ (0, node_fs_1.mkdirSync)(archiveFolderPath, { recursive: true });
138
+ const resultRelativePath = `${archiveFolderRelativePath}.reconcile-${options.reconcileId}.json`;
139
+ (0, node_fs_1.writeFileSync)(node_path_1.default.join(options.repoRoot, resultRelativePath), JSON.stringify(archivedResultPayload, null, 2) + "\n", "utf-8");
140
+ resultFiles.push(resultRelativePath);
141
+ const indexRelativePath = `${archiveFolderRelativePath}cognition-index.json`;
142
+ writeIndex(node_path_1.default.join(options.repoRoot, indexRelativePath), {
143
+ reconcile_id: options.reconcileId,
144
+ run_id: options.runId,
145
+ reconciled_at: timestamp,
146
+ notes_consumed: notesConsumed,
147
+ polaris_md_updated: options.polarisMdUpdated,
148
+ summary_md_updated: options.summaryMdUpdated,
149
+ });
150
+ updatedIndexFiles.push(indexRelativePath);
151
+ }
152
+ return {
153
+ archivedNotes,
154
+ missingNotes,
155
+ updatedIndexFiles,
156
+ resultFiles,
157
+ };
158
+ }
@@ -0,0 +1,161 @@
1
+ "use strict";
2
+ /**
3
+ * Types and schema validator for the closeout-librarian role.
4
+ *
5
+ * The Closeout Librarian runs exactly once per completed cluster, after all
6
+ * children are done and before PR creation. It reconciles cluster work into
7
+ * project cognition (POLARIS.md, SUMMARY.md), ingests documentation, validates
8
+ * links, and commits all documentation changes as a single librarian commit.
9
+ *
10
+ * The Librarian may NOT modify implementation code, runtime state, dispatch
11
+ * workers, or create PRs.
12
+ *
13
+ * Spec: smartdocs/specs/active/closeout-librarian-spec.md
14
+ */
15
+ Object.defineProperty(exports, "__esModule", { value: true });
16
+ exports.validateCloseoutLibrarianPacket = validateCloseoutLibrarianPacket;
17
+ exports.validateCloseoutLibrarianResult = validateCloseoutLibrarianResult;
18
+ exports.checkLibrarianResultGate = checkLibrarianResultGate;
19
+ /**
20
+ * Validate a CloseoutLibrarianPacket. Returns an array of error strings; empty means valid.
21
+ *
22
+ * Performs lightweight top-level checks only: object presence, required field types,
23
+ * enum values, and array presence. Does NOT validate nested element schemas (e.g.,
24
+ * individual child_summaries entries), string formats (e.g., ISO dates), or cross-field
25
+ * consistency. Further semantic validation is performed by the Foreman via
26
+ * checkLibrarianResultGate and other runtime-spec result checks before finalize.
27
+ */
28
+ function validateCloseoutLibrarianPacket(value) {
29
+ const errors = [];
30
+ if (typeof value !== "object" || value === null) {
31
+ return ["CloseoutLibrarianPacket must be a JSON object"];
32
+ }
33
+ const p = value;
34
+ if (p["role"] !== "closeout-librarian") {
35
+ errors.push('role must be "closeout-librarian"');
36
+ }
37
+ if (p["schema_version"] !== "1.0") {
38
+ errors.push('schema_version must be "1.0"');
39
+ }
40
+ if (typeof p["run_id"] !== "string" || !p["run_id"]) {
41
+ errors.push("missing or empty run_id");
42
+ }
43
+ if (typeof p["dispatch_id"] !== "string" || !p["dispatch_id"]) {
44
+ errors.push("missing or empty dispatch_id");
45
+ }
46
+ if (typeof p["cluster_id"] !== "string" || !p["cluster_id"]) {
47
+ errors.push("missing or empty cluster_id");
48
+ }
49
+ if (!Array.isArray(p["completed_children"]) || p["completed_children"].length === 0) {
50
+ errors.push("completed_children must be a non-empty array");
51
+ }
52
+ if (!Array.isArray(p["child_summaries"])) {
53
+ errors.push("child_summaries must be an array");
54
+ }
55
+ if (!Array.isArray(p["affected_folders"])) {
56
+ errors.push("affected_folders must be an array");
57
+ }
58
+ if (!Array.isArray(p["polaris_md_paths"])) {
59
+ errors.push("polaris_md_paths must be an array");
60
+ }
61
+ if (typeof p["result_path"] !== "string" || !p["result_path"]) {
62
+ errors.push("missing or empty result_path");
63
+ }
64
+ if (!Array.isArray(p["prohibited_write_paths"])) {
65
+ errors.push("prohibited_write_paths must be an array");
66
+ }
67
+ if (!Array.isArray(p["allowed_write_paths"])) {
68
+ errors.push("allowed_write_paths must be an array");
69
+ }
70
+ return errors;
71
+ }
72
+ /**
73
+ * Validate a CloseoutLibrarianResult. Returns an array of error strings; empty means valid.
74
+ *
75
+ * Performs lightweight top-level checks only: object presence, required field types,
76
+ * enum values, and array presence. Does NOT validate nested element schemas, string
77
+ * formats (e.g., reconciled_at ISO date), or cross-field consistency (e.g., whether
78
+ * commit_sha matches files_committed). Further semantic validation is performed by the
79
+ * Foreman via checkLibrarianResultGate and other runtime-spec result checks before finalize.
80
+ */
81
+ function validateCloseoutLibrarianResult(value) {
82
+ const errors = [];
83
+ if (typeof value !== "object" || value === null) {
84
+ return ["CloseoutLibrarianResult must be a JSON object"];
85
+ }
86
+ const r = value;
87
+ if (r["role"] !== "closeout-librarian") {
88
+ errors.push('role must be "closeout-librarian"');
89
+ }
90
+ if (r["schema_version"] !== "1.0") {
91
+ errors.push('schema_version must be "1.0"');
92
+ }
93
+ if (typeof r["run_id"] !== "string" || !r["run_id"]) {
94
+ errors.push("missing or empty run_id");
95
+ }
96
+ if (typeof r["dispatch_id"] !== "string" || !r["dispatch_id"]) {
97
+ errors.push("missing or empty dispatch_id");
98
+ }
99
+ if (typeof r["cluster_id"] !== "string" || !r["cluster_id"]) {
100
+ errors.push("missing or empty cluster_id");
101
+ }
102
+ const validStatuses = ["success", "partial", "blocked", "failure"];
103
+ if (!validStatuses.includes(r["status"])) {
104
+ errors.push(`status must be one of: ${validStatuses.join(", ")}`);
105
+ }
106
+ if (r["commit_sha"] !== null && typeof r["commit_sha"] !== "string") {
107
+ errors.push("commit_sha must be a string or null");
108
+ }
109
+ if (!Array.isArray(r["files_committed"])) {
110
+ errors.push("files_committed must be an array");
111
+ }
112
+ if (!Array.isArray(r["polaris_md_updates"])) {
113
+ errors.push("polaris_md_updates must be an array");
114
+ }
115
+ if (!Array.isArray(r["summary_md_updates"])) {
116
+ errors.push("summary_md_updates must be an array");
117
+ }
118
+ if (!Array.isArray(r["docs_ingested"])) {
119
+ errors.push("docs_ingested must be an array");
120
+ }
121
+ if (!Array.isArray(r["docs_archived"])) {
122
+ errors.push("docs_archived must be an array");
123
+ }
124
+ if (!Array.isArray(r["yaml_updates"])) {
125
+ errors.push("yaml_updates must be an array");
126
+ }
127
+ if (!Array.isArray(r["cognition_archived"])) {
128
+ errors.push("cognition_archived must be an array");
129
+ }
130
+ if (typeof r["link_validation"] !== "object" || r["link_validation"] === null) {
131
+ errors.push("link_validation must be an object");
132
+ }
133
+ if (!Array.isArray(r["blockers"])) {
134
+ errors.push("blockers must be an array");
135
+ }
136
+ if (typeof r["reconciled_at"] !== "string") {
137
+ errors.push("reconciled_at must be a string");
138
+ }
139
+ if (typeof r["evidence_summary"] !== "string") {
140
+ errors.push("evidence_summary must be a string");
141
+ }
142
+ return errors;
143
+ }
144
+ /**
145
+ * Determine whether a CloseoutLibrarianResult allows the Foreman to proceed to finalize.
146
+ * Returns null if finalize may proceed; returns a blocker description string if not.
147
+ */
148
+ function checkLibrarianResultGate(result) {
149
+ if (result.status === "success" || result.status === "partial") {
150
+ return null;
151
+ }
152
+ if (result.status === "blocked") {
153
+ const blocking = result.blockers.filter((b) => b.resolution_required);
154
+ if (blocking.length === 0) {
155
+ throw new Error("Invalid result: status 'blocked' but no resolution_required blockers");
156
+ }
157
+ const desc = blocking.map((b) => b.description).join("; ");
158
+ return `Closeout Librarian blocked: ${desc}`;
159
+ }
160
+ return `Closeout Librarian failed: ${result.evidence_summary}`;
161
+ }