@voybio/ace-swarm 2.4.3 → 2.4.6

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 (144) hide show
  1. package/CHANGELOG.md +78 -0
  2. package/README.md +72 -532
  3. package/assets/agent-state/INTERFACE_REGISTRY.md +2 -2
  4. package/assets/agent-state/MODULES/gates/gate-autonomy.json +4 -2
  5. package/assets/agent-state/MODULES/gates/gate-completeness.json +4 -2
  6. package/assets/agent-state/MODULES/gates/gate-operability.json +4 -2
  7. package/assets/agent-state/MODULES/gates/gate-security.json +3 -1
  8. package/assets/agent-state/MODULES/registry.json +1 -4
  9. package/assets/agent-state/MODULES/roles/capability-build.json +1 -2
  10. package/assets/agent-state/MODULES/roles/capability-eval.json +1 -1
  11. package/assets/agent-state/MODULES/roles/capability-qa.json +1 -2
  12. package/assets/agent-state/QUALITY_GATES.md +25 -9
  13. package/assets/agent-state/TEAL_CONFIG.md +2 -11
  14. package/assets/eval-battery/battery.json +85 -0
  15. package/assets/eval-battery/fixtures/edit-target.js +3 -0
  16. package/assets/scripts/render-mcp-configs.sh +12 -0
  17. package/dist/ace-context.d.ts +18 -0
  18. package/dist/ace-context.js +161 -16
  19. package/dist/ace-server-instructions.js +36 -9
  20. package/dist/astgrep-index.d.ts +7 -1
  21. package/dist/astgrep-index.js +66 -39
  22. package/dist/bridge-trace.d.ts +17 -0
  23. package/dist/bridge-trace.js +23 -0
  24. package/dist/cli.d.ts +9 -1
  25. package/dist/cli.js +619 -10
  26. package/dist/discovery-runtime-wrappers.d.ts +16 -1
  27. package/dist/discovery-runtime-wrappers.js +65 -9
  28. package/dist/eval-harness.d.ts +110 -0
  29. package/dist/eval-harness.js +254 -0
  30. package/dist/experience-reflector.d.ts +13 -0
  31. package/dist/experience-reflector.js +62 -0
  32. package/dist/gate-contract.d.ts +63 -0
  33. package/dist/gate-contract.js +178 -0
  34. package/dist/goal-engine.d.ts +155 -0
  35. package/dist/goal-engine.js +795 -0
  36. package/dist/helpers/store-resolution.js +40 -39
  37. package/dist/hermes/session-manager.d.ts +10 -0
  38. package/dist/hermes/session-manager.js +130 -27
  39. package/dist/job-scheduler.d.ts +58 -0
  40. package/dist/job-scheduler.js +202 -2
  41. package/dist/job-worker.d.ts +87 -0
  42. package/dist/job-worker.js +182 -0
  43. package/dist/local-model-policy.d.ts +8 -2
  44. package/dist/local-model-policy.js +31 -17
  45. package/dist/local-model-runtime.d.ts +6 -0
  46. package/dist/local-model-runtime.js +130 -2
  47. package/dist/measured-classing.d.ts +66 -0
  48. package/dist/measured-classing.js +165 -0
  49. package/dist/model-bridge.d.ts +45 -0
  50. package/dist/model-bridge.js +502 -44
  51. package/dist/orchestrator-supervisor.js +1 -1
  52. package/dist/plan-proposal.d.ts +7 -0
  53. package/dist/plan-proposal.js +74 -4
  54. package/dist/playbook-adaptation.d.ts +37 -0
  55. package/dist/playbook-adaptation.js +159 -0
  56. package/dist/playbook-curator.d.ts +16 -0
  57. package/dist/playbook-curator.js +106 -0
  58. package/dist/playbook-llm-reflector.d.ts +26 -0
  59. package/dist/playbook-llm-reflector.js +157 -0
  60. package/dist/public-surface.d.ts +2 -0
  61. package/dist/public-surface.js +26 -14
  62. package/dist/runtime-executor.js +45 -2
  63. package/dist/runtime-tool-specs.d.ts +8 -1
  64. package/dist/runtime-tool-specs.js +19 -1
  65. package/dist/safe-edit.d.ts +20 -0
  66. package/dist/safe-edit.js +355 -78
  67. package/dist/schemas.js +16 -15
  68. package/dist/server.d.ts +11 -2
  69. package/dist/server.js +55 -5
  70. package/dist/shared.d.ts +12 -0
  71. package/dist/shared.js +13 -1
  72. package/dist/source-mutation-coordinator.d.ts +54 -0
  73. package/dist/source-mutation-coordinator.js +259 -0
  74. package/dist/status-events.d.ts +4 -1
  75. package/dist/status-events.js +41 -6
  76. package/dist/store/ace-packed-store.d.ts +28 -9
  77. package/dist/store/ace-packed-store.js +324 -57
  78. package/dist/store/bgzf.d.ts +4 -0
  79. package/dist/store/bgzf.js +94 -0
  80. package/dist/store/bootstrap-store.d.ts +4 -1
  81. package/dist/store/bootstrap-store.js +87 -9
  82. package/dist/store/cache-workspace.d.ts +8 -0
  83. package/dist/store/cache-workspace.js +67 -1
  84. package/dist/store/crc32.d.ts +2 -0
  85. package/dist/store/crc32.js +16 -0
  86. package/dist/store/fsck.d.ts +16 -0
  87. package/dist/store/fsck.js +240 -0
  88. package/dist/store/gate-contract-migration.d.ts +10 -0
  89. package/dist/store/gate-contract-migration.js +413 -0
  90. package/dist/store/materializers/context-snapshot-materializer.d.ts +1 -0
  91. package/dist/store/materializers/context-snapshot-materializer.js +4 -1
  92. package/dist/store/materializers/projection-manager.d.ts +7 -0
  93. package/dist/store/materializers/projection-manager.js +37 -0
  94. package/dist/store/materializers/scheduler-projection-materializer.js +10 -3
  95. package/dist/store/repositories/goal-repository.d.ts +112 -0
  96. package/dist/store/repositories/goal-repository.js +157 -0
  97. package/dist/store/repositories/playbook-repository.d.ts +107 -0
  98. package/dist/store/repositories/playbook-repository.js +314 -0
  99. package/dist/store/store-artifacts.js +44 -2
  100. package/dist/store/store-authority-audit.js +1 -0
  101. package/dist/store/store-cli.d.ts +30 -0
  102. package/dist/store/store-cli.js +242 -0
  103. package/dist/store/store-snapshot.d.ts +12 -0
  104. package/dist/store/store-snapshot.js +74 -11
  105. package/dist/store/types.d.ts +1 -0
  106. package/dist/store/write-coordinator.d.ts +7 -0
  107. package/dist/store/write-coordinator.js +11 -0
  108. package/dist/todo-state.d.ts +21 -0
  109. package/dist/todo-state.js +150 -53
  110. package/dist/tools-agent.js +86 -22
  111. package/dist/tools-discovery.js +5 -3
  112. package/dist/tools-files.js +107 -23
  113. package/dist/tools-framework.js +146 -40
  114. package/dist/tools-goal.d.ts +11 -0
  115. package/dist/tools-goal.js +108 -0
  116. package/dist/tools-handoff.js +7 -11
  117. package/dist/tools-lifecycle.js +2 -0
  118. package/dist/tools-scheduler.js +44 -1
  119. package/dist/tools-skills.js +3 -2
  120. package/dist/tools-todo.js +64 -3
  121. package/dist/tools.js +2 -0
  122. package/dist/tui/chat.js +4 -0
  123. package/dist/tui/index.js +4 -1
  124. package/dist/tui/ollama.d.ts +2 -0
  125. package/dist/tui/openai-compatible.d.ts +14 -0
  126. package/dist/tui/openai-compatible.js +15 -2
  127. package/dist/tui/provider-discovery.d.ts +1 -0
  128. package/dist/tui/provider-discovery.js +2 -2
  129. package/docs/cli-reference.md +125 -0
  130. package/docs/development.md +46 -0
  131. package/docs/evaluation-safety.md +27 -0
  132. package/docs/experience-playbook.md +35 -0
  133. package/docs/hermes.md +129 -0
  134. package/docs/library-api.md +31 -0
  135. package/docs/mcp-tool-reference.md +290 -0
  136. package/docs/provider-security.md +85 -0
  137. package/docs/state-model.md +113 -0
  138. package/docs/troubleshooting.md +95 -0
  139. package/docs/tui-operator-guide.md +75 -0
  140. package/package.json +5 -1
  141. package/scripts/dev/run_hermes_crispr_live.mjs +212 -0
  142. package/assets/agent-state/MODULES/gates/gate-correctness.json +0 -7
  143. package/assets/agent-state/MODULES/gates/gate-evaluation.json +0 -7
  144. package/assets/agent-state/MODULES/gates/gate-typescript-public-surface.json +0 -7
@@ -0,0 +1,413 @@
1
+ import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ export const PACKAGE_GATE_CONTRACT_VERSION = 2;
4
+ export const PACKAGE_GATE_CONTRACT_VERSION_KEY = "meta/package_gate_contract_version";
5
+ const LEGACY_GATE_MIGRATIONS = [
6
+ {
7
+ fileName: "gate-autonomy.json",
8
+ legacyContent: JSON.stringify({
9
+ id: "gate-autonomy",
10
+ type: "artifact_scan",
11
+ invariant: "Every execution cycle records objective, strategy, evidence, and next state",
12
+ command: "",
13
+ evidence_requirement: "STATUS + EVIDENCE_LOG + HANDOFF pointers",
14
+ }, null, 2),
15
+ currentAssetRelativePath: "agent-state/MODULES/gates/gate-autonomy.json",
16
+ },
17
+ {
18
+ fileName: "gate-completeness.json",
19
+ legacyContent: JSON.stringify({
20
+ id: "gate-completeness",
21
+ type: "artifact_scan",
22
+ invariant: "All required artifacts exist and are non-empty",
23
+ command: "",
24
+ evidence_requirement: "File presence and section completeness evidence",
25
+ }, null, 2),
26
+ currentAssetRelativePath: "agent-state/MODULES/gates/gate-completeness.json",
27
+ },
28
+ {
29
+ fileName: "gate-operability.json",
30
+ legacyContent: JSON.stringify({
31
+ id: "gate-operability",
32
+ type: "artifact_scan",
33
+ invariant: "Runbooks, ownership, and incident routing are defined for release",
34
+ command: "",
35
+ evidence_requirement: "COMMUNICATION_CHANNELS.md + observability/release artifacts",
36
+ }, null, 2),
37
+ currentAssetRelativePath: "agent-state/MODULES/gates/gate-operability.json",
38
+ },
39
+ {
40
+ fileName: "gate-security.json",
41
+ legacyContent: JSON.stringify({
42
+ id: "gate-security",
43
+ type: "manual_review",
44
+ invariant: "No unmitigated high-severity security or policy risks",
45
+ command: "",
46
+ evidence_requirement: "SECURITY_REPORT.md with explicit mitigations or accepted residual risk",
47
+ }, null, 2),
48
+ currentAssetRelativePath: "agent-state/MODULES/gates/gate-security.json",
49
+ },
50
+ {
51
+ fileName: "gate-correctness.json",
52
+ legacyContent: JSON.stringify({
53
+ id: "gate-correctness",
54
+ type: "executable",
55
+ invariant: "All required tests pass",
56
+ command: "if [ -f ace-mcp-server/package.json ]; then cd ace-mcp-server && npm test --silent; elif [ -f package.json ]; then npm test --silent; else echo 'package.json not found for gate-correctness' && exit 1; fi",
57
+ evidence_requirement: "Command output snippet with exit code 0",
58
+ }, null, 2),
59
+ remove: true,
60
+ },
61
+ {
62
+ fileName: "gate-evaluation.json",
63
+ legacyContent: JSON.stringify({
64
+ id: "gate-evaluation",
65
+ type: "executable",
66
+ invariant: "Core autonomy benchmark suites meet defined pass thresholds",
67
+ command: "bash scripts/ace/eval-harness.sh",
68
+ evidence_requirement: "EVAL_REPORT.md + command output",
69
+ }, null, 2),
70
+ remove: true,
71
+ },
72
+ {
73
+ fileName: "gate-typescript-public-surface.json",
74
+ legacyContent: JSON.stringify({
75
+ id: "gate-typescript-public-surface",
76
+ type: "executable",
77
+ invariant: "Exported MCP tools, resources, prompts, and public status events stay registered, described, schema-backed where required, and covered by the audit gate",
78
+ command: "node --input-type=module -e \"import('./dist/public-surface.js').then(async (m) => { const result = await m.auditPublicSurface({ write_artifact: false }); if (!result.ok) { console.error(result.failures.join('\\n')); process.exit(1); } console.log(JSON.stringify(result.summary)); })\"",
79
+ evidence_requirement: "PUBLIC_SURFACE_REPORT.md + passing public-surface audit",
80
+ }, null, 2),
81
+ remove: true,
82
+ },
83
+ ];
84
+ const LEGACY_STATIC_ASSET_MIGRATIONS = [
85
+ {
86
+ key: "knowledge/agent-state/TEAL_CONFIG.md",
87
+ legacyContent: `# TEAL_CONFIG.md
88
+
89
+ \`\`\`yaml
90
+ teal_version: "1.1"
91
+ timestamp: "2026-03-03T20:45:00Z"
92
+
93
+ modules:
94
+ skeptic:
95
+ version: "1.0.0"
96
+ interface: "QUALITY_GATES.md"
97
+ sidecar: true
98
+
99
+ ops:
100
+ version: "1.0.0"
101
+ outputs: ["STATUS.md", "HANDOFF.json"]
102
+
103
+ astgrep:
104
+ version: "1.0.0"
105
+ inputs: ["TASK.md", "SCOPE.md", "AST_GREP_COMMANDS.md"]
106
+ outputs: ["AST_GREP_INDEX.md", "AST_GREP_INDEX.json"]
107
+
108
+ research:
109
+ version: "1.0.0"
110
+ inputs: ["TASK.md"]
111
+ outputs: ["EVIDENCE_LOG.md"]
112
+
113
+ spec:
114
+ version: "1.0.0"
115
+ depends_on: ["research", "skeptic"]
116
+ outputs: ["SPEC_CONTRACT.json", "INTERFACE_REGISTRY.md"]
117
+
118
+ build:
119
+ version: "1.0.0"
120
+ depends_on: ["spec"]
121
+ parallelizable: true
122
+
123
+ qa:
124
+ version: "1.0.0"
125
+ depends_on: ["build"]
126
+ gates: ["gate-completeness", "gate-correctness", "gate-autonomy"]
127
+
128
+ docs:
129
+ version: "1.0.0"
130
+ depends_on: ["build", "qa"]
131
+
132
+ memory:
133
+ version: "1.0.0"
134
+ sidecar: true
135
+ depends_on: ["ops"]
136
+ outputs: ["MEMORY_INDEX.md"]
137
+
138
+ security:
139
+ version: "1.0.0"
140
+ sidecar: true
141
+ depends_on: ["skeptic", "spec", "build"]
142
+ gates: ["gate-security"]
143
+
144
+ observability:
145
+ version: "1.0.0"
146
+ sidecar: true
147
+ depends_on: ["ops", "qa"]
148
+ outputs: ["OBSERVABILITY_REPORT.md"]
149
+
150
+ eval:
151
+ version: "1.0.0"
152
+ depends_on: ["qa"]
153
+ gates: ["gate-evaluation"]
154
+
155
+ release:
156
+ version: "1.0.0"
157
+ depends_on: ["security", "observability", "eval"]
158
+ gates: ["gate-operability"]
159
+
160
+ pipelines:
161
+ standard:
162
+ - astgrep -> research -> spec -> build -> qa -> docs
163
+ - skeptic (sidecar)
164
+
165
+ high_certainty:
166
+ - astgrep -> spec -> build -> qa
167
+ - security (sidecar)
168
+ - eval -> release
169
+
170
+ high_ambiguity:
171
+ - astgrep -> research -> spec -> build
172
+ - skeptic (continuous)
173
+ - memory (continuous)
174
+ - ops (orchestration)
175
+
176
+ production_promotion:
177
+ - qa -> security -> eval -> observability -> release
178
+
179
+ gates:
180
+ gate-completeness:
181
+ module: qa
182
+ inputs: ["SPEC_CONTRACT.json", "artifact_set"]
183
+
184
+ gate-correctness:
185
+ module: qa
186
+ inputs: ["test_results", "EVIDENCE_LOG.md"]
187
+
188
+ gate-autonomy:
189
+ module: skeptic
190
+ inputs: ["STATUS.md", "HANDOFF.json", "EVIDENCE_LOG.md"]
191
+
192
+ gate-security:
193
+ module: security
194
+ inputs: ["RISKS.md", "SECURITY_REPORT.md"]
195
+
196
+ gate-evaluation:
197
+ module: eval
198
+ inputs: ["EVAL_REPORT.md"]
199
+
200
+ gate-operability:
201
+ module: release
202
+ inputs: ["OBSERVABILITY_REPORT.md", "RELEASE_DECISION.md"]
203
+ \`\`\`
204
+ `,
205
+ currentAssetRelativePath: "agent-state/TEAL_CONFIG.md",
206
+ },
207
+ {
208
+ key: "knowledge/agent-state/MODULES/registry.json",
209
+ legacyContent: JSON.stringify({
210
+ roles: [
211
+ "capability-astgrep",
212
+ "capability-skeptic",
213
+ "capability-ops",
214
+ "capability-research",
215
+ "capability-spec",
216
+ "capability-build",
217
+ "capability-qa",
218
+ "capability-docs",
219
+ "capability-memory",
220
+ "capability-security",
221
+ "capability-observability",
222
+ "capability-eval",
223
+ "capability-release",
224
+ "capability-safety",
225
+ "capability-framework",
226
+ "capability-git",
227
+ ],
228
+ gates: [
229
+ "gate-completeness",
230
+ "gate-correctness",
231
+ "gate-autonomy",
232
+ "gate-security",
233
+ "gate-operability",
234
+ "gate-evaluation",
235
+ "gate-typescript-public-surface",
236
+ ],
237
+ schemas: [
238
+ "STATUS_EVENT.schema.json",
239
+ "HANDOFF.schema.json",
240
+ "ARTIFACT_MANIFEST.schema.json",
241
+ "ACE_RUNTIME_PROFILE.schema.json",
242
+ "WORKSPACE_SESSION_REGISTRY.schema.json",
243
+ "RUNTIME_TOOL_SPEC_REGISTRY.schema.json",
244
+ "RUNTIME_EXECUTOR_SESSION_REGISTRY.schema.json",
245
+ "TRACKER_SNAPSHOT.schema.json",
246
+ "VERICIFY_BRIDGE_SNAPSHOT.schema.json",
247
+ "VERICIFY_PROCESS_POST_LOG.schema.json",
248
+ ],
249
+ }, null, 2),
250
+ currentAssetRelativePath: "agent-state/MODULES/registry.json",
251
+ },
252
+ {
253
+ key: "knowledge/agent-state/QUALITY_GATES.md",
254
+ legacyContent: `# QUALITY GATES
255
+
256
+ ## gate-completeness
257
+
258
+ - Invariant: required artifacts exist and are non-empty.
259
+ - Pass condition: all required files are present with required sections.
260
+ - Fail condition: any missing required artifact or empty required section.
261
+ - Evidence: file list + section checks in \`EVIDENCE_LOG.md\`.
262
+
263
+ ## gate-correctness
264
+
265
+ - Invariant: behavior satisfies spec acceptance criteria.
266
+ - Pass condition: mapped tests pass and no unresolved critical failures.
267
+ - Fail condition: failing mapped test, unresolved regression, or invalid provenance.
268
+ - Evidence: test output and verification report pointers.
269
+ `,
270
+ currentAssetRelativePath: "agent-state/QUALITY_GATES.md",
271
+ },
272
+ {
273
+ key: "knowledge/agent-state/INTERFACE_REGISTRY.md",
274
+ legacyContent: `# INTERFACE_REGISTRY
275
+
276
+ ## Runtime Executor Session Contract
277
+
278
+ - \`runtime-executor-sessions.json\` is the authoritative session registry for unattended runtime executor workspaces.
279
+ - It must validate against \`MODULES/schemas/RUNTIME_EXECUTOR_SESSION_REGISTRY.schema.json\`.
280
+ - Every session entry must expose \`session_id\`, \`workspace_path\`, \`root_path\`, \`status\`, \`source\`, timestamps, optional hook details, and any \`metadata\` required for routing/debugging.
281
+
282
+ ## Runtime Tool Spec Contract
283
+
284
+ - \`runtime-tool-specs.json\` is the authoritative registry for external runtime tool declarations.
285
+ - It must validate against \`MODULES/schemas/RUNTIME_TOOL_SPEC_REGISTRY.schema.json\`.
286
+ - Each tool entry must include deterministic command metadata and explicitly declare environment inputs under \`env_keys\`.
287
+
288
+ ## Workspace Session Registry Contract
289
+
290
+ - \`runtime-workspaces.json\` is the authoritative registry for active ACE workspace sessions.
291
+ - It must validate against \`MODULES/schemas/WORKSPACE_SESSION_REGISTRY.schema.json\`.
292
+ - Entries may optionally include hook health summaries and per-hook status under \`hooks\`.
293
+
294
+ ## Tracker Snapshot Contract
295
+
296
+ - \`tracker-snapshot.json\` is the normalized cache of task/comment data mirrored from provider trackers.
297
+ - It must validate against \`MODULES/schemas/TRACKER_SNAPSHOT.schema.json\`.
298
+ - Scheduler and future executor consumers must use normalized item/comment fields only; provider-specific detail belongs under \`metadata\`.
299
+
300
+ ## Vericify Sidecar Contract
301
+
302
+ - \`vericify/ace-bridge.json\` is an optional sidecar bridge snapshot for Vericify-style read-model consumers.
303
+ - It must validate against \`MODULES/schemas/VERICIFY_BRIDGE_SNAPSHOT.schema.json\`.
304
+ - \`vericify/process-posts.json\` is an optional structured process-post log and must validate against \`MODULES/schemas/VERICIFY_PROCESS_POST_LOG.schema.json\`.
305
+ - Vericify remains optional; ACE must not require the Vericify package to read or write these artifacts.
306
+
307
+ ## Public Surface Gate
308
+
309
+ - \`audit_public_surface\` is the canonical TypeScript public-surface gate for MCP tools, resources, prompts, and registered event names.
310
+ - \`PUBLIC_SURFACE_REPORT.md\` is the durable audit artifact written by that gate.
311
+ - \`MODULES/gates/gate-typescript-public-surface.json\` is the executable gate manifest for CI or operator use.
312
+
313
+ ## Provenance Contract
314
+
315
+ - \`ARTIFACT_MANIFEST.json\` is mandatory and must be schema-valid.
316
+ - Each artifact entry must include \`artifact_id\`, \`artifact_path\`, \`producer_module\`, \`spec_version\`, \`req_ids\`, \`checksum\`, \`confidence_level\`, \`evidence_ref\`, and \`timestamp\`.
317
+ - \`PROVENANCE_LOG.md\` must mirror manifest entries with append-only evidence-linked records.
318
+
319
+ ## Versioning Rules
320
+
321
+ - additive changes: \`minor\`
322
+ - breaking changes: \`major\`
323
+ - bugfix/clarification: \`patch\`
324
+
325
+ ## Compatibility Requirement
326
+
327
+ Producer and consumer compatibility must be documented before release.
328
+ `,
329
+ currentAssetRelativePath: "agent-state/INTERFACE_REGISTRY.md",
330
+ },
331
+ ];
332
+ function normalizeForExactMatch(content) {
333
+ return content.replace(/\r\n/g, "\n").trimEnd();
334
+ }
335
+ function matchesLegacyPackageContent(content, legacyContent) {
336
+ return normalizeForExactMatch(content) === normalizeForExactMatch(legacyContent);
337
+ }
338
+ function matchesCurrentPackageContent(content, currentContent) {
339
+ return normalizeForExactMatch(content) === normalizeForExactMatch(currentContent);
340
+ }
341
+ function readAsset(assetsRoot, relativePath) {
342
+ return readFileSync(join(assetsRoot, relativePath), "utf-8");
343
+ }
344
+ export async function recordPackageGateContractVersion(store) {
345
+ await store.setJSON(PACKAGE_GATE_CONTRACT_VERSION_KEY, PACKAGE_GATE_CONTRACT_VERSION);
346
+ }
347
+ export async function migratePackageGateContract(store, workspaceRoot, assetsRoot) {
348
+ const messages = [];
349
+ let changed = false;
350
+ for (const entry of LEGACY_GATE_MIGRATIONS) {
351
+ const key = `knowledge/gates/${entry.fileName}`;
352
+ const currentContent = entry.currentAssetRelativePath
353
+ ? readAsset(assetsRoot, entry.currentAssetRelativePath)
354
+ : undefined;
355
+ const existing = await store.getBlob(key);
356
+ if (typeof existing === "string") {
357
+ if (matchesLegacyPackageContent(existing, entry.legacyContent)) {
358
+ if (entry.remove) {
359
+ await store.delete(key);
360
+ messages.push(`Removed legacy package gate ${key}.`);
361
+ }
362
+ else if (currentContent) {
363
+ await store.setBlob(key, currentContent);
364
+ messages.push(`Updated legacy package gate ${key}.`);
365
+ }
366
+ changed = true;
367
+ }
368
+ else if (!currentContent || !matchesCurrentPackageContent(existing, currentContent)) {
369
+ messages.push(`Skipped customized gate ${key}; content differs from known package seed.`);
370
+ }
371
+ }
372
+ const projectionPath = join(workspaceRoot, "agent-state", "MODULES", "gates", entry.fileName);
373
+ if (existsSync(projectionPath)) {
374
+ const projectionContent = readFileSync(projectionPath, "utf-8");
375
+ if (matchesLegacyPackageContent(projectionContent, entry.legacyContent)) {
376
+ if (entry.remove) {
377
+ rmSync(projectionPath, { force: true });
378
+ messages.push(`Removed legacy gate projection ${projectionPath}.`);
379
+ }
380
+ else if (currentContent) {
381
+ mkdirSync(join(workspaceRoot, "agent-state", "MODULES", "gates"), { recursive: true });
382
+ writeFileSync(projectionPath, currentContent, "utf-8");
383
+ messages.push(`Updated legacy gate projection ${projectionPath}.`);
384
+ }
385
+ changed = true;
386
+ }
387
+ else if (!currentContent || !matchesCurrentPackageContent(projectionContent, currentContent)) {
388
+ messages.push(`Skipped customized gate projection ${projectionPath}; content differs from known package seed.`);
389
+ }
390
+ }
391
+ }
392
+ for (const entry of LEGACY_STATIC_ASSET_MIGRATIONS) {
393
+ const currentContent = readAsset(assetsRoot, entry.currentAssetRelativePath);
394
+ const existing = await store.getBlob(entry.key);
395
+ if (typeof existing !== "string")
396
+ continue;
397
+ if (matchesLegacyPackageContent(existing, entry.legacyContent)) {
398
+ await store.setBlob(entry.key, currentContent);
399
+ messages.push(`Updated legacy package asset ${entry.key}.`);
400
+ changed = true;
401
+ }
402
+ else if (!matchesCurrentPackageContent(existing, currentContent)) {
403
+ messages.push(`Skipped customized asset ${entry.key}; content differs from known package seed.`);
404
+ }
405
+ }
406
+ const recordedVersion = await store.getJSON(PACKAGE_GATE_CONTRACT_VERSION_KEY);
407
+ if (recordedVersion !== PACKAGE_GATE_CONTRACT_VERSION) {
408
+ await recordPackageGateContractVersion(store);
409
+ changed = true;
410
+ }
411
+ return { changed, messages };
412
+ }
413
+ //# sourceMappingURL=gate-contract-migration.js.map
@@ -6,5 +6,6 @@ export declare class ContextSnapshotMaterializer {
6
6
  constructor(store: AcePackedStore, workspaceRoot: string);
7
7
  private directoryPath;
8
8
  materializeAll(): Promise<void>;
9
+ materializeAllForExport(outputDir: string): Promise<void>;
9
10
  }
10
11
  //# sourceMappingURL=context-snapshot-materializer.d.ts.map
@@ -22,7 +22,10 @@ export class ContextSnapshotMaterializer {
22
22
  return join(this.workspaceRoot, "agent-state", "context-snapshots");
23
23
  }
24
24
  async materializeAll() {
25
- const dir = this.directoryPath();
25
+ throw new Error("Context snapshots are store-only by default. Use `ace read agent-state/context-snapshots/<name>.json --out <file>` to export a copy.");
26
+ }
27
+ async materializeAllForExport(outputDir) {
28
+ const dir = outputDir;
26
29
  if (!existsSync(dir))
27
30
  mkdirSync(dir, { recursive: true });
28
31
  const snapshots = await this.repo.listSnapshots();
@@ -1,5 +1,11 @@
1
1
  import { AcePackedStore } from "../ace-packed-store.js";
2
2
  export type RuntimeProjectionTarget = "context_snapshots" | "handoffs" | "ledger" | "scheduler" | "status_events" | "todo_state" | "vericify_posts" | "hook_context";
3
+ /**
4
+ * Awaitable handle for the detached lifecycle sweep. CLI entry points and
5
+ * tests MUST await this before process exit / assertions; the MCP server may
6
+ * ignore it (long-lived process, sweep completes in background).
7
+ */
8
+ export declare function waitForPendingLifecycleSweep(): Promise<void>;
3
9
  export declare class ProjectionManager {
4
10
  private store;
5
11
  private workspaceRoot;
@@ -7,6 +13,7 @@ export declare class ProjectionManager {
7
13
  private todoSyncer;
8
14
  private hookContext;
9
15
  private scheduler;
16
+ private static lifecycleSweepActive;
10
17
  constructor(store: AcePackedStore, workspaceRoot: string);
11
18
  projectAfterCommit(targets: readonly RuntimeProjectionTarget[]): Promise<void>;
12
19
  }
@@ -2,6 +2,18 @@ import { HookContextMaterializer } from "./hook-context-materializer.js";
2
2
  import { SchedulerProjectionMaterializer } from "./scheduler-projection-materializer.js";
3
3
  import { TodoSyncer } from "./todo-syncer.js";
4
4
  import { VericifyProjector } from "./vericify-projector.js";
5
+ import { cacheWorkspaceArtifacts } from "../cache-workspace.js";
6
+ let pendingLifecycleSweep;
7
+ let lastLifecycleSweepStartedAt = 0;
8
+ const LIFECYCLE_SWEEP_MIN_INTERVAL_MS = 60_000;
9
+ /**
10
+ * Awaitable handle for the detached lifecycle sweep. CLI entry points and
11
+ * tests MUST await this before process exit / assertions; the MCP server may
12
+ * ignore it (long-lived process, sweep completes in background).
13
+ */
14
+ export function waitForPendingLifecycleSweep() {
15
+ return pendingLifecycleSweep ?? Promise.resolve();
16
+ }
5
17
  export class ProjectionManager {
6
18
  store;
7
19
  workspaceRoot;
@@ -9,6 +21,7 @@ export class ProjectionManager {
9
21
  todoSyncer;
10
22
  hookContext;
11
23
  scheduler;
24
+ static lifecycleSweepActive = false;
12
25
  constructor(store, workspaceRoot) {
13
26
  this.store = store;
14
27
  this.workspaceRoot = workspaceRoot;
@@ -55,6 +68,30 @@ export class ProjectionManager {
55
68
  if (stagedStoreWrites) {
56
69
  await this.store.commit();
57
70
  }
71
+ if (stagedStoreWrites &&
72
+ !ProjectionManager.lifecycleSweepActive &&
73
+ Date.now() - lastLifecycleSweepStartedAt >= LIFECYCLE_SWEEP_MIN_INTERVAL_MS) {
74
+ ProjectionManager.lifecycleSweepActive = true;
75
+ lastLifecycleSweepStartedAt = Date.now();
76
+ const workspaceRoot = this.workspaceRoot;
77
+ // Deliberately NOT awaited: projectAfterCommit runs inside
78
+ // withStoreWriteCoordinator in most callers, and the sweep's own
79
+ // writeStoreBlobsQueued must enqueue BEHIND the current operation in the
80
+ // non-reentrant write queue. Awaiting here deadlocks (see
81
+ // REPORT_STORE_WIRING_MITIGATIONS_2026-07-09.md F1). The detached promise
82
+ // is exposed via waitForPendingLifecycleSweep() for CLI/test flows.
83
+ pendingLifecycleSweep = cacheWorkspaceArtifacts(workspaceRoot, {
84
+ clean: true,
85
+ minAgeMs: 5 * 60 * 1000,
86
+ })
87
+ .then(() => undefined)
88
+ .catch((error) => {
89
+ console.error(`ACE lifecycle sweep-lite skipped: ${error instanceof Error ? error.message : String(error)}`);
90
+ })
91
+ .finally(() => {
92
+ ProjectionManager.lifecycleSweepActive = false;
93
+ });
94
+ }
58
95
  for (const target of uniqueTargets) {
59
96
  if (target === "todo_state") {
60
97
  await this.todoSyncer.writeToFile();
@@ -2,6 +2,7 @@ import { existsSync, mkdirSync, renameSync, writeFileSync } from "node:fs";
2
2
  import { dirname, join } from "node:path";
3
3
  import { operationalArtifactKey } from "../store-artifacts.js";
4
4
  import { SchedulerRepository } from "../repositories/scheduler-repository.js";
5
+ import { isProjectedAceWorkspacePath } from "../../helpers/path-utils.js";
5
6
  function writeText(path, content) {
6
7
  const dir = dirname(path);
7
8
  if (!existsSync(dir))
@@ -40,9 +41,15 @@ export class SchedulerProjectionMaterializer {
40
41
  }
41
42
  async materializeFiles(rendered) {
42
43
  const content = rendered ?? (await this.render());
43
- writeText(this.filePath("job-queue.json"), content.queue);
44
- writeText(this.filePath("job-locks.json"), content.locks);
45
- writeText(this.filePath("scheduler-lease.json"), content.lease);
44
+ if (isProjectedAceWorkspacePath("agent-state/job-queue.json")) {
45
+ writeText(this.filePath("job-queue.json"), content.queue);
46
+ }
47
+ if (isProjectedAceWorkspacePath("agent-state/job-locks.json")) {
48
+ writeText(this.filePath("job-locks.json"), content.locks);
49
+ }
50
+ if (isProjectedAceWorkspacePath("agent-state/scheduler-lease.json")) {
51
+ writeText(this.filePath("scheduler-lease.json"), content.lease);
52
+ }
46
53
  }
47
54
  }
48
55
  //# sourceMappingURL=scheduler-projection-materializer.js.map
@@ -0,0 +1,112 @@
1
+ /**
2
+ * GoalRepository — durable storage for the ACE Goal Engine (WS-F).
3
+ *
4
+ * Persists one {@link GoalRecord} plus its active {@link TaskPlan} per goal, and
5
+ * a lightweight index for listing. Storage is plain JSON under
6
+ * `<workspaceRoot>/agent-state/goals/`, written atomically (temp + rename) so a
7
+ * crash mid-write never leaves a torn record — the property WS-F's resume path
8
+ * depends on. The repository is intentionally root-parameterized (rather than
9
+ * bound to the packed store) so the Goal Engine and its tests can drive it
10
+ * hermetically against a temp workspace.
11
+ *
12
+ * Layout:
13
+ * agent-state/goals/index.json { version, updated_at, goals: [...] }
14
+ * agent-state/goals/<goal_id>.json GoalRecord
15
+ * agent-state/goals/<goal_id>.plan.json TaskPlan (rewritten every transition)
16
+ */
17
+ import type { TaskPlan } from "../../orchestrator-supervisor.js";
18
+ export type GoalStatus = "draft" | "planning" | "executing" | "verifying" | "blocked" | "done" | "failed" | "stopped";
19
+ export type GoalEscalationKind = "approval_required" | "run_complete" | "run_error" | "gate_failed" | "budget_blocked" | "blocker";
20
+ export interface GoalBudgets {
21
+ max_wall_clock_ms: number;
22
+ max_ticks: number;
23
+ max_replans: number;
24
+ max_step_retries: number;
25
+ }
26
+ export interface SuccessContract {
27
+ /** Union of step-level and goal-level required artifacts. */
28
+ expected_artifacts: Array<{
29
+ path: string;
30
+ required?: boolean;
31
+ }>;
32
+ required_evidence_refs: string[];
33
+ verification_commands: string[];
34
+ /**
35
+ * TODO(WS-F): wire gate_ids to execute_gates. Always `[]` today and never
36
+ * read, so it is deliberately excluded from `enforceableObligationCount`.
37
+ */
38
+ gate_ids: string[];
39
+ /**
40
+ * Success criteria that could not be compiled to a machine-checkable form.
41
+ * Never silently dropped (L3): the engine routes these to a terminal qa
42
+ * review step so a human/qa role adjudicates them.
43
+ */
44
+ uncompilable_criteria: string[];
45
+ }
46
+ export interface GoalEscalation {
47
+ at: string;
48
+ kind: GoalEscalationKind;
49
+ reason_code: string;
50
+ summary: string;
51
+ }
52
+ export interface GoalRecord {
53
+ goal_id: string;
54
+ objective: string;
55
+ status: GoalStatus;
56
+ plan_id?: string;
57
+ success_contract: SuccessContract;
58
+ budgets: GoalBudgets;
59
+ created_at: string;
60
+ updated_at: string;
61
+ started_at?: string;
62
+ tick_count: number;
63
+ replan_count: number;
64
+ last_heartbeat_at?: string;
65
+ stop_requested: boolean;
66
+ escalations: GoalEscalation[];
67
+ result_summary?: string;
68
+ reason_code?: string;
69
+ current_step_id?: string;
70
+ }
71
+ export interface GoalIndexEntry {
72
+ goal_id: string;
73
+ status: GoalStatus;
74
+ objective: string;
75
+ updated_at: string;
76
+ }
77
+ export interface GoalIndexFile {
78
+ version: 1;
79
+ updated_at: string;
80
+ goals: GoalIndexEntry[];
81
+ }
82
+ export declare function newGoalId(): string;
83
+ export declare class GoalRepository {
84
+ private readonly workspaceRoot;
85
+ private readonly dir;
86
+ constructor(workspaceRoot: string);
87
+ private ensureDir;
88
+ private goalPath;
89
+ private planPath;
90
+ private indexPath;
91
+ private writeAtomic;
92
+ private readJson;
93
+ readIndex(): GoalIndexFile;
94
+ private upsertIndex;
95
+ /** Persist a goal record and refresh the index in one call. */
96
+ saveGoal(goal: GoalRecord): GoalRecord;
97
+ getGoal(goalId: string): GoalRecord | undefined;
98
+ savePlan(goalId: string, plan: TaskPlan): void;
99
+ getPlan(goalId: string): TaskPlan | undefined;
100
+ listGoals(filter?: {
101
+ status?: GoalStatus;
102
+ }): GoalIndexEntry[];
103
+ /** Delete a goal, its plan, and its index entry. Returns true if present. */
104
+ deleteGoal(goalId: string): boolean;
105
+ /**
106
+ * Rebuild the index from the on-disk goal files. Cheap self-heal used at
107
+ * startup so a hand-deleted or partially-written index never hides live goals.
108
+ */
109
+ rebuildIndex(): GoalIndexFile;
110
+ }
111
+ export declare function defaultGoalBudgets(): GoalBudgets;
112
+ //# sourceMappingURL=goal-repository.d.ts.map