@voybio/ace-swarm 2.4.9 → 2.4.10

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 (185) hide show
  1. package/CHANGELOG.md +52 -14
  2. package/README.md +14 -10
  3. package/assets/.agents/ACE/ACE_coders/AGENTS.md +23 -30
  4. package/assets/.agents/ACE/ACE_coders/INSTRUCTIONS.md +21 -30
  5. package/assets/.agents/skills/landing-review-watcher/SKILL.md +1 -1
  6. package/assets/.agents/skills/learn-from-work/SKILL.md +41 -0
  7. package/assets/agent-state/ACE_WORKFLOW.md +25 -2
  8. package/assets/agent-state/MODULES/schemas/ACE_RUNTIME_PROFILE.schema.json +143 -2
  9. package/assets/agent-state/MODULES/schemas/RUNTIME_EXECUTOR_SESSION_REGISTRY.schema.json +2 -2
  10. package/assets/agent-state/MODULES/schemas/SWARM_HANDOFF.schema.json +10 -0
  11. package/assets/eval-battery/battery.json +1 -1
  12. package/assets/instructions/ACE_Coder.instructions.md +9 -13
  13. package/assets/scripts/ace-hook-dispatch.mjs +16 -411
  14. package/assets/tasks/SWARM_HANDOFF.example_ui_to_coders.json +1 -2
  15. package/assets/vendor/README.md +9 -0
  16. package/assets/vendor/vericify-reader.mjs +272 -0
  17. package/assets/vendor/vericify-reader.provenance.json +10 -0
  18. package/dist/ace-autonomy.d.ts +58 -0
  19. package/dist/ace-autonomy.js +211 -6
  20. package/dist/ace-internal-tools.d.ts +1 -0
  21. package/dist/ace-internal-tools.js +3 -3
  22. package/dist/ace-server-instructions.d.ts +3 -3
  23. package/dist/ace-server-instructions.js +46 -192
  24. package/dist/cli.js +44 -6
  25. package/dist/experience-reflector.d.ts +7 -0
  26. package/dist/experience-reflector.js +39 -0
  27. package/dist/goal-engine.d.ts +64 -7
  28. package/dist/goal-engine.js +197 -41
  29. package/dist/handoff-registry.d.ts +10 -0
  30. package/dist/handoff-registry.js +59 -0
  31. package/dist/helpers/artifacts.d.ts +6 -2
  32. package/dist/helpers/artifacts.js +8 -6
  33. package/dist/helpers/bootstrap.js +13 -20
  34. package/dist/helpers/path-utils.js +2 -0
  35. package/dist/helpers/store-resolution.js +18 -3
  36. package/dist/helpers/workspace-root.d.ts +2 -0
  37. package/dist/helpers/workspace-root.js +9 -0
  38. package/dist/helpers.d.ts +1 -0
  39. package/dist/helpers.js +1 -0
  40. package/dist/hermes/bridge-protocol.d.ts +1 -1
  41. package/dist/hermes/session-manager.d.ts +17 -0
  42. package/dist/hermes/session-manager.js +67 -14
  43. package/dist/host-goal-engine.d.ts +138 -0
  44. package/dist/host-goal-engine.js +793 -0
  45. package/dist/host-goal-status.d.ts +113 -0
  46. package/dist/host-goal-status.js +175 -0
  47. package/dist/host-learning.d.ts +68 -0
  48. package/dist/host-learning.js +115 -0
  49. package/dist/host-observation.d.ts +12 -0
  50. package/dist/host-observation.js +91 -0
  51. package/dist/host-plan-revision.d.ts +14 -0
  52. package/dist/host-plan-revision.js +101 -0
  53. package/dist/host-verification-job.d.ts +12 -0
  54. package/dist/host-verification-job.js +183 -0
  55. package/dist/host-work-context.d.ts +12 -0
  56. package/dist/host-work-context.js +8 -0
  57. package/dist/job-scheduler.d.ts +48 -14
  58. package/dist/job-scheduler.js +169 -23
  59. package/dist/job-worker.d.ts +3 -1
  60. package/dist/job-worker.js +10 -3
  61. package/dist/kanban.d.ts +4 -1
  62. package/dist/kanban.js +44 -16
  63. package/dist/learned-artifacts.d.ts +64 -0
  64. package/dist/learned-artifacts.js +321 -0
  65. package/dist/learning-controls.d.ts +142 -0
  66. package/dist/learning-controls.js +135 -0
  67. package/dist/learning-input-context.d.ts +9 -0
  68. package/dist/learning-input-context.js +62 -0
  69. package/dist/learning-lifecycle.d.ts +10 -0
  70. package/dist/learning-lifecycle.js +11 -0
  71. package/dist/learning-overlays.d.ts +3 -0
  72. package/dist/learning-overlays.js +17 -0
  73. package/dist/learning-policy.d.ts +40 -0
  74. package/dist/learning-policy.js +38 -0
  75. package/dist/learning-records.d.ts +35 -0
  76. package/dist/learning-records.js +17 -0
  77. package/dist/learning-scorecard.d.ts +82 -0
  78. package/dist/learning-scorecard.js +86 -0
  79. package/dist/learning-serving.d.ts +29 -0
  80. package/dist/learning-serving.js +134 -0
  81. package/dist/linked-work.d.ts +9 -0
  82. package/dist/linked-work.js +28 -0
  83. package/dist/local-model-runtime.js +1 -1
  84. package/dist/mcp-command-progress.d.ts +16 -0
  85. package/dist/mcp-command-progress.js +70 -0
  86. package/dist/model-bridge.d.ts +14 -13
  87. package/dist/model-bridge.js +73 -41
  88. package/dist/orchestrator-supervisor.d.ts +108 -6
  89. package/dist/orchestrator-supervisor.js +4 -32
  90. package/dist/plan-proposal.js +3 -3
  91. package/dist/playbook-curator.d.ts +1 -0
  92. package/dist/playbook-curator.js +11 -9
  93. package/dist/process-identity.d.ts +8 -0
  94. package/dist/process-identity.js +38 -0
  95. package/dist/progress-command.d.ts +34 -0
  96. package/dist/progress-command.js +153 -0
  97. package/dist/prompts.js +15 -15
  98. package/dist/resources.js +2 -2
  99. package/dist/runtime-command.d.ts +8 -1
  100. package/dist/runtime-command.js +48 -7
  101. package/dist/runtime-executor.js +33 -11
  102. package/dist/runtime-profile-syntax.d.ts +6 -0
  103. package/dist/runtime-profile-syntax.js +121 -0
  104. package/dist/runtime-profile.d.ts +37 -5
  105. package/dist/runtime-profile.js +36 -129
  106. package/dist/runtime-tool-specs.js +1 -1
  107. package/dist/safe-edit.d.ts +7 -3
  108. package/dist/safe-edit.js +40 -47
  109. package/dist/schemas.js +4 -2
  110. package/dist/server.d.ts +2 -16
  111. package/dist/server.js +14 -20
  112. package/dist/shared.d.ts +2 -0
  113. package/dist/shared.js +2 -0
  114. package/dist/skill-auditor.d.ts +19 -0
  115. package/dist/skill-auditor.js +32 -2
  116. package/dist/skill-catalog.d.ts +4 -1
  117. package/dist/skill-catalog.js +6 -5
  118. package/dist/store/ace-packed-store.d.ts +5 -1
  119. package/dist/store/ace-packed-store.js +33 -1
  120. package/dist/store/bootstrap-store.js +19 -12
  121. package/dist/store/cache-workspace.d.ts +8 -0
  122. package/dist/store/cache-workspace.js +94 -27
  123. package/dist/store/importer.js +11 -20
  124. package/dist/store/knowledge-bake.d.ts +3 -1
  125. package/dist/store/knowledge-bake.js +10 -1
  126. package/dist/store/legacy-vericify-posts.d.ts +8 -0
  127. package/dist/store/legacy-vericify-posts.js +76 -0
  128. package/dist/store/materializers/hook-context-materializer.d.ts +2 -1
  129. package/dist/store/materializers/hook-context-materializer.js +6 -2
  130. package/dist/store/materializers/host-file-materializer.js +2 -2
  131. package/dist/store/materializers/projection-manager.d.ts +4 -1
  132. package/dist/store/materializers/projection-manager.js +10 -3
  133. package/dist/store/materializers/todo-syncer.d.ts +39 -20
  134. package/dist/store/materializers/todo-syncer.js +208 -110
  135. package/dist/store/materializers/vericify-projector.js +15 -26
  136. package/dist/store/repositories/goal-repository.d.ts +51 -2
  137. package/dist/store/repositories/goal-repository.js +114 -48
  138. package/dist/store/repositories/playbook-repository.d.ts +41 -3
  139. package/dist/store/repositories/playbook-repository.js +61 -5
  140. package/dist/store/repositories/todo-repository.d.ts +8 -2
  141. package/dist/store/repositories/todo-repository.js +1 -1
  142. package/dist/store/repositories/vericify-repository.d.ts +4 -0
  143. package/dist/store/repositories/vericify-repository.js +46 -0
  144. package/dist/store/skills-install.d.ts +1 -0
  145. package/dist/store/skills-install.js +20 -16
  146. package/dist/store/source-preservation.d.ts +24 -0
  147. package/dist/store/source-preservation.js +79 -0
  148. package/dist/store/store-artifacts.js +8 -1
  149. package/dist/store/test-write-boundary.d.ts +16 -0
  150. package/dist/store/test-write-boundary.js +175 -0
  151. package/dist/store/types.d.ts +5 -1
  152. package/dist/store/write-coordinator.js +16 -0
  153. package/dist/task-plan-context.d.ts +11 -0
  154. package/dist/task-plan-context.js +59 -0
  155. package/dist/todo-state.d.ts +19 -9
  156. package/dist/todo-state.js +204 -321
  157. package/dist/tools-agent.d.ts +1 -1
  158. package/dist/tools-agent.js +38 -62
  159. package/dist/tools-files.d.ts +0 -3
  160. package/dist/tools-files.js +21 -11
  161. package/dist/tools-framework.js +16 -25
  162. package/dist/tools-goal.d.ts +2 -4
  163. package/dist/tools-goal.js +119 -16
  164. package/dist/tools-handoff.js +28 -4
  165. package/dist/tools-lifecycle.js +1 -1
  166. package/dist/tools-memory.d.ts +0 -3
  167. package/dist/tools-memory.js +51 -6
  168. package/dist/tools-scheduler.js +19 -17
  169. package/dist/tools-todo.js +160 -148
  170. package/dist/vericify-bridge.d.ts +8 -0
  171. package/dist/vericify-bridge.js +18 -0
  172. package/dist/vericify-context.d.ts +4 -0
  173. package/dist/vericify-context.js +26 -5
  174. package/dist/vericify-native.d.ts +101 -0
  175. package/dist/vericify-native.js +221 -0
  176. package/dist/verification-worker.d.ts +2 -0
  177. package/dist/verification-worker.js +31 -0
  178. package/docs/mcp-tool-reference.md +44 -9
  179. package/package.json +19 -6
  180. package/scripts/dev/run-tests-isolated.mjs +165 -0
  181. package/scripts/dev/run_hermes_crispr_live.mjs +1 -0
  182. package/scripts/dev/test-isolation-guard.mjs +20 -0
  183. package/scripts/dev/test-preload.mjs +153 -0
  184. package/scripts/dev/test-source-inventory.mjs +31 -0
  185. package/docs/development.md +0 -46
@@ -99,7 +99,7 @@ async function materializeStoreSurfaces(store, workspaceRoot, opts) {
99
99
  await todoSyncer.initStarter();
100
100
  await store.commit();
101
101
  const projections = new ProjectionManager(store, workspaceRoot);
102
- await projections.projectAfterCommit(["hook_context", "todo_state", "scheduler", "context_snapshots"]);
102
+ await projections.projectAfterCommit(["vericify_posts", "hook_context", "todo_state", "scheduler", "context_snapshots"]);
103
103
  materialized.push(join(workspaceRoot, ".agents", "ACE", "tasks", "todo.md"));
104
104
  return [...new Set(materialized)];
105
105
  }
@@ -113,6 +113,8 @@ const GATE_CONTRACT_OPERATIONAL_ARTIFACT_RELS = [
113
113
  async function seedOperationalArtifacts(store) {
114
114
  const bootstrapTs = new Date().toISOString();
115
115
  for (const relPath of OPERATIONAL_ARTIFACT_REL_PATHS) {
116
+ if (await store.getBlob(operationalArtifactKey(relPath)) !== undefined)
117
+ continue;
116
118
  const knowledgeKey = `knowledge/agent-state/${relPath.replace(/^agent-state\//, "")}`;
117
119
  let content = relPath.endsWith("-archive.ndjson")
118
120
  ? ""
@@ -156,6 +158,7 @@ export async function bootstrapStoreWorkspace(opts) {
156
158
  try {
157
159
  await migrateExistingStoreGateContract(existingStore, workspaceRoot, assetsRoot, warnings);
158
160
  if (!(opts.includeMcpConfig ?? false) && !(opts.includeClientConfigBundle ?? false) && !opts.llm) {
161
+ await existingStore.commit();
159
162
  const agents = (await existingStore.listAgents()).length;
160
163
  warnings.push(`Reused existing store at ${storePath}. Refreshed package gate contract state.`);
161
164
  return { storePath, agents, modules: { gates: 0, roles: 0, schemas: 0 }, materialized, warnings };
@@ -166,7 +169,7 @@ export async function bootstrapStoreWorkspace(opts) {
166
169
  return { storePath, agents, modules: { gates: 0, roles: 0, schemas: 0 }, materialized, warnings };
167
170
  }
168
171
  finally {
169
- await existingStore.close();
172
+ await existingStore.close({ commit: false });
170
173
  }
171
174
  }
172
175
  for (const dir of [
@@ -197,7 +200,9 @@ export async function bootstrapStoreWorkspace(opts) {
197
200
  await store.setJSON("state/memory/context_snapshots/index.json", { snapshots: [] });
198
201
  await store.setJSON("state/runtime/sessions/index", []);
199
202
  await store.setJSON("state/discovery/index", []);
200
- await store.setJSON("state/vericify/posts/index", []);
203
+ if (await store.getBlob("state/vericify/posts/index") === undefined) {
204
+ await store.setJSON("state/vericify/posts/index", []);
205
+ }
201
206
  await applyLlmRuntimeConfig(store, opts);
202
207
  await seedOperationalArtifacts(store);
203
208
  await buildCatalog(store);
@@ -214,7 +219,7 @@ export async function bootstrapStoreWorkspace(opts) {
214
219
  };
215
220
  }
216
221
  finally {
217
- await store.close();
222
+ await store.close({ commit: false });
218
223
  }
219
224
  }, { operation_label: "bootstrapStoreWorkspace" });
220
225
  }
@@ -303,7 +308,7 @@ export async function repairWorkspace(workspaceRoot) {
303
308
  warnings.push(`repair error: ${e.message}`);
304
309
  }
305
310
  finally {
306
- await store.close();
311
+ await store.close({ commit: false });
307
312
  }
308
313
  return warnings;
309
314
  }
@@ -318,13 +323,15 @@ export async function compactWorkspace(workspaceRoot, options = {}) {
318
323
  const { storePath } = resolved;
319
324
  const { statSync } = await import("fs");
320
325
  const before = statSync(storePath).size;
321
- const store = await openStore(storePath);
322
- try {
323
- await store.compact();
324
- }
325
- finally {
326
- await store.close();
327
- }
326
+ await withStoreWriteCoordinator(storePath, async () => {
327
+ const store = await openStore(storePath);
328
+ try {
329
+ await store.compact();
330
+ }
331
+ finally {
332
+ await store.close({ commit: false });
333
+ }
334
+ }, { operation_label: "compactWorkspace" });
328
335
  const after = statSync(storePath).size;
329
336
  const sweep = options.sweep === false
330
337
  ? undefined
@@ -25,6 +25,14 @@ export interface CacheWorkspaceResult {
25
25
  key: string;
26
26
  bytes: number;
27
27
  }>;
28
+ verified_sources: Array<{
29
+ path: string;
30
+ sha256: string;
31
+ source_key: string;
32
+ target_key: string;
33
+ receipt_key: string;
34
+ removed: boolean;
35
+ }>;
28
36
  }
29
37
  export declare function cacheWorkspaceArtifacts(workspaceRoot: string, options?: CacheWorkspaceOptions): Promise<CacheWorkspaceResult>;
30
38
  //# sourceMappingURL=cache-workspace.d.ts.map
@@ -1,9 +1,11 @@
1
- import { existsSync, readdirSync, readFileSync, rmSync, statSync } from "node:fs";
1
+ import { existsSync, readdirSync, rmSync, statSync } from "node:fs";
2
2
  import { dirname, isAbsolute, join, relative } from "node:path";
3
3
  import { ACE_ROOT_REL, isProjectedAceWorkspacePath, mapAceWorkspaceRelativePath, resolveStoreFallbackKeysForPath, } from "../helpers.js";
4
4
  import { normalizeRelPath } from "../shared.js";
5
- import { getWorkspaceStorePath } from "./store-snapshot.js";
6
- import { writeStoreBlobsQueued } from "./store-artifacts.js";
5
+ import { getWorkspaceStorePath, readStoreBlobByPathSync, readStoreJsonByPathSync } from "./store-snapshot.js";
6
+ import { openStore } from "./ace-packed-store.js";
7
+ import { withStoreWriteCoordinator } from "./write-coordinator.js";
8
+ import { captureWorkspaceSource, preservedSourceKey, sourceUnchanged, stagePreservedSource, verifyPreservedSource } from "./source-preservation.js";
7
9
  const SCAN_ROOTS_REL = [
8
10
  "agent-state",
9
11
  ".agents/ACE/agent-state",
@@ -146,8 +148,17 @@ export async function cacheWorkspaceArtifacts(workspaceRoot, options = {}) {
146
148
  keptProjected += 1;
147
149
  continue;
148
150
  }
149
- const raw = readFileSync(absPath);
150
- if (!isTextBuffer(raw)) {
151
+ let source;
152
+ try {
153
+ source = captureWorkspaceSource(workspaceRoot, absPath);
154
+ }
155
+ catch (error) {
156
+ skipped += 1;
157
+ warnings.push(`Kept unstable source ${relPath}: ${error.message}`);
158
+ continue;
159
+ }
160
+ const raw = Buffer.from(source.content_base64, "base64");
161
+ if (!isTextBuffer(raw) || !Buffer.from(raw.toString("utf8"), "utf8").equals(raw)) {
151
162
  skipped += 1;
152
163
  warnings.push(`Skipped non-text artifact: ${canonicalPath}`);
153
164
  continue;
@@ -164,32 +175,87 @@ export async function cacheWorkspaceArtifacts(workspaceRoot, options = {}) {
164
175
  key: fallbackKeys[0],
165
176
  content: raw.toString("utf-8"),
166
177
  bytes: raw.byteLength,
178
+ source,
167
179
  });
168
180
  }
169
181
  }
170
- const dedupByKey = new Map();
182
+ const byKey = new Map();
171
183
  for (const candidate of candidates) {
172
- dedupByKey.set(candidate.key, candidate);
173
- }
174
- const uniqueForWrite = [...dedupByKey.values()];
175
- if (!dryRun && uniqueForWrite.length > 0) {
176
- await writeStoreBlobsQueued(workspaceRoot, uniqueForWrite.map((candidate) => ({
177
- key: candidate.key,
178
- content: candidate.content,
179
- })), { operation_label: "cacheWorkspace" });
184
+ const group = byKey.get(candidate.key) ?? [];
185
+ group.push(candidate);
186
+ byKey.set(candidate.key, group);
180
187
  }
181
188
  let removed = 0;
182
- if (!dryRun && clean && candidates.length > 0) {
183
- const removedPaths = new Set();
184
- for (const candidate of candidates) {
185
- if (removedPaths.has(candidate.absPath))
186
- continue;
187
- rmSync(candidate.absPath, { force: true });
188
- removedPaths.add(candidate.absPath);
189
- removed += 1;
190
- const pruneRoot = scanRoots.find((root) => isInside(root, candidate.absPath)) ?? workspaceRoot;
191
- pruneEmptyParents(candidate.absPath, pruneRoot);
192
- }
189
+ const cached = [];
190
+ const verifiedSources = [];
191
+ if (!dryRun && candidates.length > 0) {
192
+ await withStoreWriteCoordinator(storePath, async () => {
193
+ const store = await openStore(storePath);
194
+ try {
195
+ for (const group of byKey.values()) {
196
+ if (new Set(group.map((candidate) => candidate.source.sha256)).size > 1) {
197
+ warnings.push(`Fallback-key collision at ${group[0].key}; kept all sources: ${group.map((c) => c.source.source_path).join(", ")}`);
198
+ continue;
199
+ }
200
+ for (const candidate of group) {
201
+ if (!sourceUnchanged(workspaceRoot, candidate.absPath, candidate.source)) {
202
+ warnings.push(`Source changed since scan; kept ${candidate.source.source_path}`);
203
+ continue;
204
+ }
205
+ await stagePreservedSource(store, candidate.source);
206
+ const existing = await store.getBlob(candidate.key);
207
+ if (existing !== undefined && existing !== candidate.content) {
208
+ warnings.push(`Canonical content conflict at ${candidate.key}; kept ${candidate.source.source_path}`);
209
+ continue;
210
+ }
211
+ if (existing === undefined)
212
+ await store.setBlob(candidate.key, candidate.content);
213
+ cached.push(candidate);
214
+ }
215
+ }
216
+ await store.commit();
217
+ // Independent committed-file readback precedes the durable receipt.
218
+ for (const candidate of cached) {
219
+ verifyPreservedSource(storePath, candidate.source);
220
+ if (readStoreBlobByPathSync(storePath, candidate.key) !== candidate.content) {
221
+ throw new Error(`Canonical readback failed: ${candidate.source.source_path}`);
222
+ }
223
+ const sourceKey = preservedSourceKey(candidate.source);
224
+ const receiptKey = sourceKey.replace("/sources/", "/receipts/");
225
+ await store.setJSON(receiptKey, {
226
+ source_key: sourceKey, target_key: candidate.key,
227
+ sha256: candidate.source.sha256, identity: candidate.source.identity,
228
+ verified_at: new Date().toISOString(),
229
+ });
230
+ verifiedSources.push({ path: candidate.source.source_path, sha256: candidate.source.sha256, source_key: sourceKey, target_key: candidate.key, receipt_key: receiptKey, removed: false });
231
+ }
232
+ await store.commit();
233
+ // No awaits between the final source identity check and unlink.
234
+ for (let i = 0; i < cached.length; i++) {
235
+ const candidate = cached[i];
236
+ const receipt = verifiedSources[i];
237
+ const committedReceipt = readStoreJsonByPathSync(storePath, receipt.receipt_key);
238
+ verifyPreservedSource(storePath, candidate.source);
239
+ if (committedReceipt?.sha256 !== receipt.sha256 || committedReceipt.target_key !== candidate.key || readStoreBlobByPathSync(storePath, candidate.key) !== candidate.content) {
240
+ throw new Error(`Migration receipt readback failed: ${candidate.source.source_path}`);
241
+ }
242
+ if (!clean)
243
+ continue;
244
+ if (!sourceUnchanged(workspaceRoot, candidate.absPath, candidate.source)) {
245
+ warnings.push(`Source changed before removal; kept ${candidate.source.source_path}`);
246
+ continue;
247
+ }
248
+ rmSync(candidate.absPath);
249
+ receipt.removed = true;
250
+ removed += 1;
251
+ const pruneRoot = scanRoots.find((root) => isInside(root, candidate.absPath)) ?? workspaceRoot;
252
+ pruneEmptyParents(candidate.absPath, pruneRoot);
253
+ }
254
+ }
255
+ finally {
256
+ await store.close({ commit: false });
257
+ }
258
+ }, { operation_label: "cacheWorkspace" });
193
259
  }
194
260
  const removedSemanticCache = gcSemanticCache
195
261
  ? removeSemanticCache(workspaceRoot, minAgeMs, dryRun)
@@ -199,13 +265,14 @@ export async function cacheWorkspaceArtifacts(workspaceRoot, options = {}) {
199
265
  dry_run: dryRun,
200
266
  clean,
201
267
  scanned_files: scanned,
202
- cached_files: candidates.length,
268
+ cached_files: dryRun ? candidates.length : cached.length,
203
269
  removed_files: removed,
204
270
  removed_semantic_cache_files: removedSemanticCache,
205
271
  kept_projected_files: keptProjected,
206
272
  skipped_files: skipped,
207
273
  warnings,
208
- cached: candidates.map((candidate) => ({
274
+ verified_sources: verifiedSources,
275
+ cached: (dryRun ? candidates : cached).map((candidate) => ({
209
276
  path: candidate.canonicalPath,
210
277
  key: candidate.key,
211
278
  bytes: candidate.bytes,
@@ -14,7 +14,8 @@ import { HandoffRepository } from "./repositories/handoff-repository.js";
14
14
  import { TodoRepository } from "./repositories/todo-repository.js";
15
15
  import { LedgerRepository } from "./repositories/ledger-repository.js";
16
16
  import { TrackerRepository } from "./repositories/tracker-repository.js";
17
- import { VericifyRepository } from "./repositories/vericify-repository.js";
17
+ import { preserveLegacyVericifyPosts } from "./legacy-vericify-posts.js";
18
+ import { withStoreWriteCoordinator } from "./write-coordinator.js";
18
19
  function readJSON(path) {
19
20
  if (!existsSync(path))
20
21
  return undefined;
@@ -36,6 +37,11 @@ function readText(path) {
36
37
  }
37
38
  }
38
39
  export async function importFromFileWorkspace(workspaceRoot, storePath) {
40
+ return withStoreWriteCoordinator(storePath, () => importFileWorkspaceLocked(workspaceRoot, storePath), {
41
+ operation_label: "importFromFileWorkspace",
42
+ });
43
+ }
44
+ async function importFileWorkspaceLocked(workspaceRoot, storePath) {
39
45
  const result = {
40
46
  handoffs: 0,
41
47
  todos: 0,
@@ -50,7 +56,6 @@ export async function importFromFileWorkspace(workspaceRoot, storePath) {
50
56
  const todoRepo = new TodoRepository(store);
51
57
  const ledgerRepo = new LedgerRepository(store);
52
58
  const trackerRepo = new TrackerRepository(store);
53
- const vericifyRepo = new VericifyRepository(store);
54
59
  await ledgerRepo.init();
55
60
  // ── Handoffs ──────────────────────────────────────────────────────────
56
61
  const handoffReg = readJSON(join(workspaceRoot, "agent-state", "handoff-registry.json"));
@@ -129,28 +134,14 @@ export async function importFromFileWorkspace(workspaceRoot, storePath) {
129
134
  }
130
135
  }
131
136
  // ── Vericify Posts ────────────────────────────────────────────────────
132
- const postsFile = readJSON(join(workspaceRoot, "agent-state", "vericify", "process-posts.json"));
133
- if (postsFile?.posts) {
134
- for (const post of postsFile.posts) {
135
- try {
136
- await vericifyRepo.appendPost({
137
- run_id: String(post.run_id ?? "migrated"),
138
- agent_id: String(post.agent_id ?? "unknown"),
139
- kind: post.kind ?? "completion",
140
- summary: String(post.summary ?? ""),
141
- });
142
- result.vericify_posts++;
143
- }
144
- catch (e) {
145
- result.warnings.push(`vericify post: ${e.message}`);
146
- }
147
- }
148
- }
137
+ const legacy = await preserveLegacyVericifyPosts(store, workspaceRoot, storePath);
138
+ result.vericify_posts = legacy.imported;
139
+ result.warnings.push(...legacy.warnings);
149
140
  await store.commit();
150
141
  await store.compact();
151
142
  }
152
143
  finally {
153
- await store.close();
144
+ await store.close({ commit: false });
154
145
  }
155
146
  return result;
156
147
  }
@@ -31,7 +31,9 @@ export declare function bakeTaskArtifacts(store: AcePackedStore, assetsRoot: str
31
31
  tasks: number;
32
32
  runtime: number;
33
33
  }>;
34
- export declare function bakeSkillPack(store: AcePackedStore, assetsRoot: string, skillName: string): Promise<number>;
34
+ export declare function bakeSkillPack(store: AcePackedStore, assetsRoot: string, skillName: string, options?: {
35
+ onSkip?: (key: string) => void;
36
+ }): Promise<number>;
35
37
  export declare function listAvailableSkills(assetsRoot: string): Promise<string[]>;
36
38
  export declare function bakeAllCoreKnowledge(store: AcePackedStore, assetsRoot: string): Promise<{
37
39
  agents: {
@@ -292,17 +292,26 @@ export async function bakeTaskArtifacts(store, assetsRoot) {
292
292
  return { state, tasks, runtime };
293
293
  }
294
294
  // ── Skills ───────────────────────────────────────────────────────────────────
295
- export async function bakeSkillPack(store, assetsRoot, skillName) {
295
+ export async function bakeSkillPack(store, assetsRoot, skillName, options = {}) {
296
296
  const skillDir = join(assetsRoot, ".agents", "skills", skillName);
297
297
  if (!existsSync(skillDir)) {
298
298
  throw new Error(`[knowledge-bake] skill pack not found: ${skillName} at ${skillDir}`);
299
299
  }
300
300
  let fileCount = 0;
301
+ const prefix = `knowledge/skills/${skillName}/`;
302
+ const owners = new Map((await store.getEntries({ keyPrefix: prefix })).map((entry) => [entry.key, entry.content_source]));
301
303
  for (const filePath of walkDir(skillDir)) {
302
304
  const ext = extname(filePath);
303
305
  if (!MARKDOWN_EXTS.has(ext))
304
306
  continue;
305
307
  const relPath = relative(skillDir, filePath);
308
+ const key = `${prefix}${relPath.replaceAll("\\", "/")}`;
309
+ const existing = await store.getBlob(key);
310
+ if (key.startsWith("knowledge/skills/learned/") || (existing !== undefined && owners.get(key) !== ContentSource.Package)) {
311
+ options.onSkip?.(key);
312
+ console.log(`[knowledge-bake] skipped user-owned file: ${key}`);
313
+ continue;
314
+ }
306
315
  const content = readText(filePath);
307
316
  await store.setSkillContent(skillName, relPath, content, ContentSource.Package);
308
317
  fileCount++;
@@ -0,0 +1,8 @@
1
+ import type { AcePackedStore } from "./ace-packed-store.js";
2
+ /** Caller owns the store coordinator. No projection or unlink is performed here. */
3
+ export declare function preserveLegacyVericifyPosts(store: AcePackedStore, root: string, storePath?: string): Promise<{
4
+ imported: number;
5
+ canProject: boolean;
6
+ warnings: string[];
7
+ }>;
8
+ //# sourceMappingURL=legacy-vericify-posts.d.ts.map
@@ -0,0 +1,76 @@
1
+ import { existsSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { operationalArtifactKey } from "./store-artifacts.js";
4
+ import { VericifyRepository, projectVericifyPost } from "./repositories/vericify-repository.js";
5
+ import { captureWorkspaceSource, sourceFromBytes, stagePreservedSource, verifyPreservedSource } from "./source-preservation.js";
6
+ import { getWorkspaceStorePath, readStoreJsonByPathSync } from "./store-snapshot.js";
7
+ import { isDeepStrictEqual } from "node:util";
8
+ const REL = "agent-state/vericify/process-posts.json";
9
+ /** Caller owns the store coordinator. No projection or unlink is performed here. */
10
+ export async function preserveLegacyVericifyPosts(store, root, storePath = getWorkspaceStorePath(root)) {
11
+ const warnings = [];
12
+ const sources = [];
13
+ const loose = join(root, REL);
14
+ let canProject = true;
15
+ if (existsSync(loose)) {
16
+ try {
17
+ sources.push(captureWorkspaceSource(root, loose));
18
+ }
19
+ catch (error) {
20
+ warnings.push(`Kept legacy posts: ${error.message}`);
21
+ canProject = false;
22
+ }
23
+ }
24
+ const packed = await store.getBlob(operationalArtifactKey(REL));
25
+ const checksums = await store.getJSON("host/materializations/checksums");
26
+ const repo = new VericifyRepository(store);
27
+ if (packed?.trim()) {
28
+ const source = sourceFromBytes(`${REL}#prior-store-value`, Buffer.from(packed));
29
+ let represented = false;
30
+ if (checksums?.["vericify/process-posts.json"]?.hash === source.sha256) {
31
+ try {
32
+ const prior = JSON.parse(packed);
33
+ const records = new Map((await repo.list()).map((p) => [p.id, JSON.parse(JSON.stringify(projectVericifyPost(p)))]));
34
+ represented = Array.isArray(prior.posts) && prior.posts.every((p) => isDeepStrictEqual(records.get(String(p.process_post_id ?? p.id)), p));
35
+ }
36
+ catch { /* Unverified content is preserved below, never projected over. */ }
37
+ }
38
+ if (!represented && !sources.some((s) => s.sha256 === source.sha256))
39
+ sources.push(source);
40
+ }
41
+ const expected = new Map();
42
+ let imported = 0;
43
+ for (const source of sources) {
44
+ await stagePreservedSource(store, source);
45
+ try {
46
+ const parsed = JSON.parse(Buffer.from(source.content_base64, "base64").toString("utf8"));
47
+ if (!parsed || !Array.isArray(parsed.posts))
48
+ throw new Error("Expected a posts array");
49
+ for (const post of parsed.posts) {
50
+ if (!post || typeof post !== "object" || Array.isArray(post))
51
+ throw new Error("Invalid historical post");
52
+ const record = await repo.importPost(post);
53
+ expected.set(record.id, post);
54
+ imported += 1;
55
+ }
56
+ }
57
+ catch (error) {
58
+ canProject = false;
59
+ warnings.push(`Legacy post projection retained: ${error.message}`);
60
+ }
61
+ }
62
+ if (sources.length > 0) {
63
+ await store.commit();
64
+ for (const source of sources)
65
+ verifyPreservedSource(storePath, source);
66
+ const index = readStoreJsonByPathSync(storePath, "state/vericify/posts/index") ?? [];
67
+ for (const [id, original] of expected) {
68
+ const actual = readStoreJsonByPathSync(storePath, `state/vericify/posts/${id}`);
69
+ const retained = actual && (actual.legacy_record ?? JSON.parse(JSON.stringify(projectVericifyPost(actual))));
70
+ if (!index.includes(id) || !isDeepStrictEqual(retained, original))
71
+ throw new Error(`Historical post readback failed: ${id}`);
72
+ }
73
+ }
74
+ return { imported, canProject, warnings };
75
+ }
76
+ //# sourceMappingURL=legacy-vericify-posts.js.map
@@ -7,9 +7,10 @@
7
7
  import { AcePackedStore } from "../ace-packed-store.js";
8
8
  export declare class HookContextMaterializer {
9
9
  private store;
10
+ private workspaceRoot;
10
11
  static readonly STORE_KEY = "state/runtime/hook_context";
11
12
  private kv;
12
- constructor(store: AcePackedStore);
13
+ constructor(store: AcePackedStore, workspaceRoot: string);
13
14
  private buildSnapshot;
14
15
  stageStoreProjection(): Promise<void>;
15
16
  private _readContent;
@@ -4,6 +4,7 @@
4
4
  * Stages the compact hook snapshot into ace-state.ace so hook clients can
5
5
  * read a single runtime payload without extra workspace projections.
6
6
  */
7
+ import { resolveCurrentWork, formatCurrentWork } from "../../ace-autonomy.js";
7
8
  import { RuntimeKVRepository } from "../repositories/runtime-kv-repository.js";
8
9
  function fnv1a(s) {
9
10
  let h = 2166136261;
@@ -15,10 +16,12 @@ function fnv1a(s) {
15
16
  }
16
17
  export class HookContextMaterializer {
17
18
  store;
19
+ workspaceRoot;
18
20
  static STORE_KEY = "state/runtime/hook_context";
19
21
  kv;
20
- constructor(store) {
22
+ constructor(store, workspaceRoot) {
21
23
  this.store = store;
24
+ this.workspaceRoot = workspaceRoot;
22
25
  this.kv = new RuntimeKVRepository(store);
23
26
  }
24
27
  async buildSnapshot() {
@@ -32,6 +35,7 @@ export class HookContextMaterializer {
32
35
  return {
33
36
  schema_version: 1,
34
37
  generated_at: new Date().toISOString(),
38
+ current_work: formatCurrentWork(resolveCurrentWork({ workspaceRoot: this.workspaceRoot }), "block"),
35
39
  task: { content: task, hash: fnv1a(task) },
36
40
  status: { content: status, hash: fnv1a(status) },
37
41
  scope: { content: scope, hash: fnv1a(scope) },
@@ -59,7 +63,7 @@ export class HookContextMaterializer {
59
63
  evidence_log: "knowledge/agent-state/EVIDENCE_LOG.md",
60
64
  };
61
65
  const fallbackKey = fallback[kind];
62
- return fallbackKey ? (await this.store.getBlob(fallbackKey)) ?? "" : "";
66
+ return fallbackKey ? (await this.store.getBlob(fallbackKey.replace("knowledge/", "state/artifacts/"))) ?? (await this.store.getBlob(fallbackKey)) ?? "" : "";
63
67
  }
64
68
  async _readKernelWorkflow() {
65
69
  return ((await this.store.getBlob("knowledge/runtime/ACE_WORKFLOW.md")) ??
@@ -8,7 +8,7 @@
8
8
  */
9
9
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
10
10
  import { dirname, join, resolve } from "node:path";
11
- import { fileURLToPath } from "node:url";
11
+ import { fileURLToPath, pathToFileURL } from "node:url";
12
12
  import { buildHostInstructionText } from "../../ace-server-instructions.js";
13
13
  import { ALL_MCP_CLIENTS, getAllMcpServerConfigSnippets, getMcpClientInstallHint, getMcpServerConfigSnippet, } from "../../helpers.js";
14
14
  const __dirname = dirname(fileURLToPath(import.meta.url));
@@ -186,7 +186,7 @@ export class HostFileMaterializer {
186
186
  return {
187
187
  absPath: this.ace("scripts", "ace", scriptName),
188
188
  keyParts: [".agents", "ACE", "scripts", "ace", scriptName],
189
- fallbackContent: readFileSync(src, "utf8"),
189
+ fallbackContent: readFileSync(src, "utf8").replace("__ACE_AUTONOMY_MODULE_URL__", pathToFileURL(resolve(__dirname, "..", "..", "ace-autonomy.js")).href),
190
190
  };
191
191
  });
192
192
  }
@@ -1,4 +1,5 @@
1
1
  import { AcePackedStore } from "../ace-packed-store.js";
2
+ import { type TodoProjectionResult } from "./todo-syncer.js";
2
3
  export type RuntimeProjectionTarget = "context_snapshots" | "handoffs" | "ledger" | "scheduler" | "status_events" | "todo_state" | "vericify_posts" | "hook_context";
3
4
  /**
4
5
  * Awaitable handle for the detached lifecycle sweep. CLI entry points and
@@ -15,6 +16,8 @@ export declare class ProjectionManager {
15
16
  private scheduler;
16
17
  private static lifecycleSweepActive;
17
18
  constructor(store: AcePackedStore, workspaceRoot: string);
18
- projectAfterCommit(targets: readonly RuntimeProjectionTarget[]): Promise<void>;
19
+ projectAfterCommit(targets: readonly RuntimeProjectionTarget[]): Promise<{
20
+ todo?: TodoProjectionResult;
21
+ }>;
19
22
  }
20
23
  //# sourceMappingURL=projection-manager.d.ts.map
@@ -27,10 +27,11 @@ export class ProjectionManager {
27
27
  this.workspaceRoot = workspaceRoot;
28
28
  this.vericify = new VericifyProjector(store, workspaceRoot);
29
29
  this.todoSyncer = new TodoSyncer(store, workspaceRoot);
30
- this.hookContext = new HookContextMaterializer(store);
30
+ this.hookContext = new HookContextMaterializer(store, workspaceRoot);
31
31
  this.scheduler = new SchedulerProjectionMaterializer(store, workspaceRoot);
32
32
  }
33
33
  async projectAfterCommit(targets) {
34
+ const result = {};
34
35
  const uniqueTargets = [...new Set(targets)];
35
36
  let stagedStoreWrites = false;
36
37
  let renderedScheduler;
@@ -81,7 +82,11 @@ export class ProjectionManager {
81
82
  // REPORT_STORE_WIRING_MITIGATIONS_2026-07-09.md F1). The detached promise
82
83
  // is exposed via waitForPendingLifecycleSweep() for CLI/test flows.
83
84
  pendingLifecycleSweep = cacheWorkspaceArtifacts(workspaceRoot, {
84
- clean: true,
85
+ // Automatic discovery must not ingest over live state or remove an
86
+ // unverified loose source. Explicit cache/compact uses verified migration.
87
+ dryRun: true,
88
+ clean: false,
89
+ gcSemanticCache: false,
85
90
  minAgeMs: 5 * 60 * 1000,
86
91
  })
87
92
  .then(() => undefined)
@@ -94,9 +99,11 @@ export class ProjectionManager {
94
99
  }
95
100
  for (const target of uniqueTargets) {
96
101
  if (target === "todo_state") {
97
- await this.todoSyncer.writeToFile();
102
+ result.todo = await this.todoSyncer.writeToFile();
103
+ await this.store.commit();
98
104
  }
99
105
  }
106
+ return result;
100
107
  }
101
108
  }
102
109
  //# sourceMappingURL=projection-manager.js.map
@@ -1,30 +1,49 @@
1
- /**
2
- * TodoSyncer
3
- *
4
- * Bidirectional sync between tasks/todo.md (human-editable) and the store.
5
- *
6
- * - On write: store → tasks/todo.md (ACE writes todo state from store)
7
- * - On read: tasks/todo.md → store (if externally modified by mtime + hash)
8
- *
9
- * tasks/todo.md format:
10
- * - [ ] Todo item title (id: todo-001)
11
- * - [x] Completed item (id: todo-002)
12
- * - [~] In progress (id: todo-003)
13
- * - [!] Blocked (id: todo-004)
14
- */
15
1
  import { AcePackedStore } from "../ace-packed-store.js";
2
+ import { type TodoNode } from "../repositories/todo-repository.js";
3
+ export declare const STATUS_ICONS: Record<TodoNode["status"], string>;
4
+ export declare const ICON_STATUS: Record<string, TodoNode["status"]>;
5
+ export interface TodoImportResult {
6
+ changed: boolean;
7
+ import_warnings: string[];
8
+ }
9
+ export interface TodoProjectionResult {
10
+ written: boolean;
11
+ import_warnings: string[];
12
+ }
13
+ interface ParsedTodo {
14
+ raw_line: string;
15
+ id?: string;
16
+ title: string;
17
+ status: TodoNode["status"];
18
+ section?: string;
19
+ source_line: number;
20
+ depends_on?: string[];
21
+ priority?: TodoNode["priority"];
22
+ assigned_to?: string;
23
+ notes?: string;
24
+ }
25
+ export declare function parseTodoMd(content: string): {
26
+ items: ParsedTodo[];
27
+ import_warnings: string[];
28
+ };
29
+ export declare function renderTodoMd(todos: TodoNode[]): string;
16
30
  export declare class TodoSyncer {
17
31
  private store;
18
32
  private workspaceRoot;
19
33
  private repo;
20
- private lastHash;
34
+ private submittedStamp?;
21
35
  private todoMdPath;
22
36
  constructor(store: AcePackedStore, workspaceRoot: string);
23
- /** Write store todo state → tasks/todo.md */
24
- writeToFile(): Promise<void>;
25
- /** Check if tasks/todo.md was modified externally, and if so ingest changes */
26
- syncFromFile(): Promise<boolean>;
27
- /** Initialize todo.md with starter content if it doesn't exist */
37
+ private stamp;
38
+ private setStamp;
39
+ /** Stage a non-destructive native import. The caller owns commit/discard and the coordinator. */
40
+ syncFromFile(content?: string, force?: boolean, observeNative?: boolean): Promise<TodoImportResult>;
41
+ /** Supplied content is an observation only after its file publication succeeds. */
42
+ acknowledgeSubmittedFile(content: string): Promise<void>;
43
+ projectionIsCurrent(): Promise<boolean>;
44
+ /** Do not overwrite unimported edits or malformed source text. */
45
+ writeToFile(): Promise<TodoProjectionResult>;
28
46
  initStarter(): Promise<void>;
29
47
  }
48
+ export {};
30
49
  //# sourceMappingURL=todo-syncer.d.ts.map