@voybio/ace-swarm 0.2.5 → 2.4.1

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 +19 -1
  2. package/README.md +21 -13
  3. package/assets/.agents/ACE/agent-qa/instructions.md +11 -0
  4. package/assets/agent-state/EVIDENCE_LOG.md +1 -1
  5. package/assets/agent-state/MODULES/roles/capability-framework.json +41 -0
  6. package/assets/agent-state/MODULES/roles/capability-git.json +33 -0
  7. package/assets/agent-state/MODULES/roles/capability-safety.json +37 -0
  8. package/assets/agent-state/MODULES/schemas/ACE_RUNTIME_PROFILE.schema.json +21 -0
  9. package/assets/agent-state/MODULES/schemas/RUNTIME_EXECUTOR_SESSION_REGISTRY.schema.json +43 -0
  10. package/assets/agent-state/MODULES/schemas/RUNTIME_TOOL_SPEC_REGISTRY.schema.json +43 -0
  11. package/assets/agent-state/MODULES/schemas/WORKSPACE_SESSION_REGISTRY.schema.json +11 -0
  12. package/assets/agent-state/STATUS.md +2 -2
  13. package/assets/agent-state/runtime-tool-specs.json +70 -2
  14. package/assets/instructions/ACE_Coder.instructions.md +13 -0
  15. package/assets/instructions/ACE_UI.instructions.md +11 -0
  16. package/assets/scripts/ace-hook-dispatch.mjs +70 -6
  17. package/assets/scripts/render-mcp-configs.sh +19 -5
  18. package/dist/ace-context.js +91 -11
  19. package/dist/ace-internal-tools.d.ts +3 -1
  20. package/dist/ace-internal-tools.js +10 -2
  21. package/dist/ace-server-instructions.js +3 -3
  22. package/dist/ace-state-resolver.js +5 -3
  23. package/dist/agent-runtime/role-adapters.d.ts +18 -1
  24. package/dist/agent-runtime/role-adapters.js +49 -5
  25. package/dist/astgrep-index.d.ts +57 -1
  26. package/dist/astgrep-index.js +140 -4
  27. package/dist/cli.js +232 -35
  28. package/dist/discovery-runtime-wrappers.d.ts +108 -0
  29. package/dist/discovery-runtime-wrappers.js +615 -0
  30. package/dist/handoff-registry.js +5 -5
  31. package/dist/helpers/artifacts.d.ts +19 -0
  32. package/dist/helpers/artifacts.js +152 -0
  33. package/dist/helpers/bootstrap.d.ts +24 -0
  34. package/dist/helpers/bootstrap.js +894 -0
  35. package/dist/helpers/constants.d.ts +53 -0
  36. package/dist/helpers/constants.js +295 -0
  37. package/dist/helpers/drift.d.ts +13 -0
  38. package/dist/helpers/drift.js +45 -0
  39. package/dist/helpers/path-utils.d.ts +24 -0
  40. package/dist/helpers/path-utils.js +123 -0
  41. package/dist/helpers/store-resolution.d.ts +19 -0
  42. package/dist/helpers/store-resolution.js +305 -0
  43. package/dist/helpers/workspace-root.d.ts +3 -0
  44. package/dist/helpers/workspace-root.js +80 -0
  45. package/dist/helpers.d.ts +8 -125
  46. package/dist/helpers.js +8 -1768
  47. package/dist/job-scheduler.js +33 -7
  48. package/dist/json-sanitizer.d.ts +16 -0
  49. package/dist/json-sanitizer.js +26 -0
  50. package/dist/local-model-policy.d.ts +27 -0
  51. package/dist/local-model-policy.js +84 -0
  52. package/dist/local-model-runtime.d.ts +6 -0
  53. package/dist/local-model-runtime.js +33 -21
  54. package/dist/model-bridge.d.ts +13 -1
  55. package/dist/model-bridge.js +410 -23
  56. package/dist/orchestrator-supervisor.d.ts +56 -0
  57. package/dist/orchestrator-supervisor.js +179 -1
  58. package/dist/plan-proposal.d.ts +115 -0
  59. package/dist/plan-proposal.js +1073 -0
  60. package/dist/run-ledger.js +3 -3
  61. package/dist/runtime-command.d.ts +8 -0
  62. package/dist/runtime-command.js +38 -6
  63. package/dist/runtime-executor.d.ts +20 -1
  64. package/dist/runtime-executor.js +737 -172
  65. package/dist/runtime-profile.d.ts +32 -0
  66. package/dist/runtime-profile.js +89 -13
  67. package/dist/runtime-tool-specs.d.ts +39 -0
  68. package/dist/runtime-tool-specs.js +144 -28
  69. package/dist/safe-edit.d.ts +7 -0
  70. package/dist/safe-edit.js +163 -37
  71. package/dist/schemas.js +48 -1
  72. package/dist/server.js +51 -0
  73. package/dist/shared.d.ts +3 -2
  74. package/dist/shared.js +2 -0
  75. package/dist/status-events.js +9 -6
  76. package/dist/store/ace-packed-store.d.ts +3 -2
  77. package/dist/store/ace-packed-store.js +188 -110
  78. package/dist/store/bootstrap-store.d.ts +2 -1
  79. package/dist/store/bootstrap-store.js +102 -83
  80. package/dist/store/cache-workspace.js +11 -5
  81. package/dist/store/materializers/context-snapshot-materializer.js +6 -2
  82. package/dist/store/materializers/hook-context-materializer.d.ts +6 -9
  83. package/dist/store/materializers/hook-context-materializer.js +11 -21
  84. package/dist/store/materializers/host-file-materializer.js +6 -0
  85. package/dist/store/materializers/projection-manager.d.ts +0 -1
  86. package/dist/store/materializers/projection-manager.js +5 -13
  87. package/dist/store/materializers/scheduler-projection-materializer.js +1 -1
  88. package/dist/store/materializers/vericify-projector.d.ts +7 -7
  89. package/dist/store/materializers/vericify-projector.js +11 -11
  90. package/dist/store/repositories/local-model-runtime-repository.d.ts +120 -3
  91. package/dist/store/repositories/local-model-runtime-repository.js +242 -6
  92. package/dist/store/repositories/vericify-repository.d.ts +1 -1
  93. package/dist/store/skills-install.d.ts +4 -0
  94. package/dist/store/skills-install.js +21 -12
  95. package/dist/store/state-reader.d.ts +2 -0
  96. package/dist/store/state-reader.js +20 -0
  97. package/dist/store/store-artifacts.d.ts +7 -0
  98. package/dist/store/store-artifacts.js +27 -1
  99. package/dist/store/store-authority-audit.d.ts +18 -1
  100. package/dist/store/store-authority-audit.js +115 -5
  101. package/dist/store/store-snapshot.d.ts +3 -0
  102. package/dist/store/store-snapshot.js +22 -2
  103. package/dist/store/workspace-store-paths.d.ts +39 -0
  104. package/dist/store/workspace-store-paths.js +94 -0
  105. package/dist/store/write-coordinator.d.ts +65 -0
  106. package/dist/store/write-coordinator.js +386 -0
  107. package/dist/todo-state.js +5 -5
  108. package/dist/tools-agent.d.ts +20 -0
  109. package/dist/tools-agent.js +789 -25
  110. package/dist/tools-discovery.js +136 -1
  111. package/dist/tools-files.d.ts +7 -0
  112. package/dist/tools-files.js +1002 -11
  113. package/dist/tools-framework.js +105 -66
  114. package/dist/tools-handoff.js +2 -2
  115. package/dist/tools-lifecycle.js +4 -4
  116. package/dist/tools-memory.js +6 -6
  117. package/dist/tools-todo.js +2 -2
  118. package/dist/tracker-adapters.d.ts +1 -1
  119. package/dist/tracker-adapters.js +13 -18
  120. package/dist/tracker-sync.js +5 -3
  121. package/dist/tui/agent-runner.js +3 -1
  122. package/dist/tui/chat.js +103 -7
  123. package/dist/tui/dashboard.d.ts +1 -0
  124. package/dist/tui/dashboard.js +43 -0
  125. package/dist/tui/index.js +10 -1
  126. package/dist/tui/layout.d.ts +20 -0
  127. package/dist/tui/layout.js +31 -1
  128. package/dist/tui/local-model-contract.d.ts +6 -2
  129. package/dist/tui/local-model-contract.js +16 -3
  130. package/dist/tui/ollama.d.ts +8 -1
  131. package/dist/tui/ollama.js +53 -12
  132. package/dist/tui/openai-compatible.d.ts +13 -0
  133. package/dist/tui/openai-compatible.js +305 -5
  134. package/dist/tui/provider-discovery.d.ts +1 -0
  135. package/dist/tui/provider-discovery.js +35 -11
  136. package/dist/vericify-bridge.d.ts +6 -1
  137. package/dist/vericify-bridge.js +27 -3
  138. package/dist/workspace-manager.d.ts +30 -3
  139. package/dist/workspace-manager.js +257 -27
  140. package/package.json +1 -2
  141. package/dist/internal-tool-runtime.d.ts +0 -21
  142. package/dist/internal-tool-runtime.js +0 -136
  143. package/dist/store/workspace-snapshot.d.ts +0 -26
  144. package/dist/store/workspace-snapshot.js +0 -107
@@ -5,7 +5,7 @@
5
5
  *
6
6
  * Replaces the old copyTree()-based bootstrap with:
7
7
  * 1. Create minimal directories
8
- * 2. Initialize AcePackedStore at .agents/ACE/ace-state.ace
8
+ * 2. Initialize AcePackedStore at agent-state/ace-state.ace
9
9
  * 3. Bake core knowledge (agents, modules, kernel)
10
10
  * 4. Write topology records
11
11
  * 5. Write initial runtime state seeds
@@ -26,6 +26,8 @@ import { HostFileMaterializer } from "./materializers/host-file-materializer.js"
26
26
  import { ProjectionManager } from "./materializers/projection-manager.js";
27
27
  import { TodoSyncer } from "./materializers/todo-syncer.js";
28
28
  import { OPERATIONAL_ARTIFACT_REL_PATHS, operationalArtifactKey, } from "./store-artifacts.js";
29
+ import { ensureCanonicalWorkspaceStore } from "./workspace-store-paths.js";
30
+ import { withStoreWriteCoordinator } from "./write-coordinator.js";
29
31
  import { STORE_VERSION } from "./types.js";
30
32
  import { buildProviderDoctorCommands, defaultModelForProvider, normalizeLocalBaseUrl, normalizeProvider, } from "../tui/provider-discovery.js";
31
33
  const __dirname = dirname(fileURLToPath(import.meta.url));
@@ -41,13 +43,19 @@ async function applyLlmRuntimeConfig(store, opts) {
41
43
  if (!opts.llm)
42
44
  return;
43
45
  const provider = normalizeProvider(opts.llm) ?? opts.llm;
44
- const configuredModel = opts.model ?? defaultModelForProvider(provider);
46
+ const configuredModel = opts.model?.trim() ||
47
+ (provider === "ollama" ? defaultModelForProvider(provider) : undefined);
45
48
  const configuredBaseUrl = normalizeLocalBaseUrl(opts.baseUrl ?? opts.ollamaUrl);
46
49
  const profilePayload = {
47
50
  provider,
48
- model: configuredModel,
49
51
  generated_at: new Date().toISOString(),
50
52
  };
53
+ if (configuredModel) {
54
+ profilePayload.model = configuredModel;
55
+ }
56
+ if (opts.launcherCommand) {
57
+ profilePayload.launch_command = opts.launcherCommand;
58
+ }
51
59
  if (configuredBaseUrl) {
52
60
  profilePayload.base_url = configuredBaseUrl;
53
61
  if (provider === "ollama") {
@@ -91,12 +99,7 @@ async function materializeStoreSurfaces(store, workspaceRoot, opts) {
91
99
  await store.commit();
92
100
  const projections = new ProjectionManager(store, workspaceRoot);
93
101
  await projections.projectAfterCommit(["hook_context", "todo_state", "scheduler", "context_snapshots"]);
94
- materialized.push(join(workspaceRoot, ".agents", "ACE", "ace-hook-context.json"));
95
102
  materialized.push(join(workspaceRoot, ".agents", "ACE", "tasks", "todo.md"));
96
- materialized.push(join(workspaceRoot, ".agents", "ACE", "agent-state", "job-queue.json"));
97
- materialized.push(join(workspaceRoot, ".agents", "ACE", "agent-state", "job-locks.json"));
98
- materialized.push(join(workspaceRoot, ".agents", "ACE", "agent-state", "scheduler-lease.json"));
99
- materialized.push(join(workspaceRoot, ".agents", "ACE", "agent-state", "context-snapshots", "index.json"));
100
103
  return [...new Set(materialized)];
101
104
  }
102
105
  // Artifacts that receive live timestamp substitution on first seed.
@@ -116,88 +119,101 @@ async function seedOperationalArtifacts(store) {
116
119
  }
117
120
  export async function bootstrapStoreWorkspace(opts) {
118
121
  const { workspaceRoot, force = false } = opts;
119
- const warnings = [];
120
- const materialized = [];
121
- const storePath = join(workspaceRoot, ".agents", "ACE", "ace-state.ace");
122
- if (existsSync(storePath) && !force) {
123
- if (!(opts.includeMcpConfig ?? false) && !(opts.includeClientConfigBundle ?? false) && !opts.llm) {
124
- warnings.push(`Store already exists at ${storePath}. Use --force to reinitialize, or run 'ace migrate' to import existing state.`);
122
+ const resolved = await ensureCanonicalWorkspaceStore(workspaceRoot, {
123
+ operationLabel: "bootstrapStoreWorkspace",
124
+ });
125
+ const storePath = resolved.storePath;
126
+ return withStoreWriteCoordinator(storePath, async () => {
127
+ const warnings = [...resolved.warnings];
128
+ const materialized = [];
129
+ if (resolved.mode === "dual_store_conflict" && !force) {
130
+ warnings.push("Both canonical and legacy stores exist and differ. Resolve with 'ace repair' before reinitializing.");
125
131
  return { storePath, agents: 0, modules: { gates: 0, roles: 0, schemas: 0 }, materialized, warnings };
126
132
  }
127
- const existingStore = await openStore(storePath);
133
+ if (existsSync(storePath) && !force) {
134
+ if (!(opts.includeMcpConfig ?? false) && !(opts.includeClientConfigBundle ?? false) && !opts.llm) {
135
+ warnings.push(`Store already exists at ${storePath}. Use --force to reinitialize, or run 'ace migrate' to import existing state.`);
136
+ return { storePath, agents: 0, modules: { gates: 0, roles: 0, schemas: 0 }, materialized, warnings };
137
+ }
138
+ const existingStore = await openStore(storePath);
139
+ try {
140
+ await seedOperationalArtifacts(existingStore);
141
+ materialized.push(...(await materializeStoreSurfaces(existingStore, workspaceRoot, opts)));
142
+ const agents = (await existingStore.listAgents()).length;
143
+ warnings.push(`Reused existing store at ${storePath} and refreshed host materializations.`);
144
+ return { storePath, agents, modules: { gates: 0, roles: 0, schemas: 0 }, materialized, warnings };
145
+ }
146
+ finally {
147
+ await existingStore.close();
148
+ }
149
+ }
150
+ for (const dir of [
151
+ join(workspaceRoot, "agent-state"),
152
+ join(workspaceRoot, ".agents", "ACE"),
153
+ join(workspaceRoot, ".agents", "ACE", "tasks"),
154
+ ]) {
155
+ mkdirSync(dir, { recursive: true });
156
+ }
157
+ const store = await openStore(storePath);
128
158
  try {
129
- await seedOperationalArtifacts(existingStore);
130
- materialized.push(...(await materializeStoreSurfaces(existingStore, workspaceRoot, opts)));
131
- const agents = (await existingStore.listAgents()).length;
132
- warnings.push(`Reused existing store at ${storePath} and refreshed host materializations.`);
133
- return { storePath, agents, modules: { gates: 0, roles: 0, schemas: 0 }, materialized, warnings };
159
+ await store.setJSON("meta/schema_version", STORE_VERSION);
160
+ await store.setJSON("meta/created_at", Date.now());
161
+ await store.setJSON("meta/project_name", opts.projectName ?? "ACE Workspace");
162
+ await store.setJSON("meta/host_materialization", {
163
+ include_mcp_config: opts.includeMcpConfig ?? false,
164
+ include_client_config_bundle: opts.includeClientConfigBundle ?? false,
165
+ });
166
+ const assetsRoot = getAssetsRoot();
167
+ const knowledge = await bakeAllCoreKnowledge(store, assetsRoot);
168
+ await bakeTopology(store, assetsRoot);
169
+ await store.setJSON("state/handoffs/__index", []);
170
+ await store.setJSON("state/todo/index", []);
171
+ await store.setJSON("state/ledger/seq", 0);
172
+ await store.setJSON("state/scheduler/queue", []);
173
+ await store.setJSON("state/scheduler/locks", []);
174
+ await store.setJSON("state/scheduler/lease", null);
175
+ await store.setJSON("state/memory/context_snapshots/index.json", { snapshots: [] });
176
+ await store.setJSON("state/runtime/sessions/index", []);
177
+ await store.setJSON("state/discovery/index", []);
178
+ await store.setJSON("state/vericify/posts/index", []);
179
+ await applyLlmRuntimeConfig(store, opts);
180
+ await seedOperationalArtifacts(store);
181
+ await buildCatalog(store);
182
+ await store.commit();
183
+ await store.compact();
184
+ materialized.push(...(await materializeStoreSurfaces(store, workspaceRoot, opts)));
185
+ const agents = (await store.listAgents()).length;
186
+ return {
187
+ storePath,
188
+ agents,
189
+ modules: knowledge.modules,
190
+ materialized,
191
+ warnings,
192
+ };
134
193
  }
135
194
  finally {
136
- await existingStore.close();
195
+ await store.close();
137
196
  }
138
- }
139
- // 1. Create minimal directories under .agents/ACE/ (canonical ACE namespace)
140
- for (const dir of [
141
- join(workspaceRoot, ".agents", "ACE"),
142
- join(workspaceRoot, ".agents", "ACE", "tasks"),
143
- ]) {
144
- mkdirSync(dir, { recursive: true });
145
- }
146
- // 2. Initialize store
147
- const store = await openStore(storePath);
148
- try {
149
- // 3. Write meta
150
- await store.setJSON("meta/schema_version", STORE_VERSION);
151
- await store.setJSON("meta/created_at", Date.now());
152
- await store.setJSON("meta/project_name", opts.projectName ?? "ACE Workspace");
153
- await store.setJSON("meta/host_materialization", {
154
- include_mcp_config: opts.includeMcpConfig ?? false,
155
- include_client_config_bundle: opts.includeClientConfigBundle ?? false,
156
- });
157
- // 4. Bake core knowledge
158
- const assetsRoot = getAssetsRoot();
159
- const knowledge = await bakeAllCoreKnowledge(store, assetsRoot);
160
- // 5. Write topology
161
- await bakeTopology(store, assetsRoot);
162
- // 6. Write initial empty runtime seeds
163
- await store.setJSON("state/handoffs/__index", []);
164
- await store.setJSON("state/todo/index", []);
165
- await store.setJSON("state/ledger/seq", 0);
166
- await store.setJSON("state/scheduler/queue", []);
167
- await store.setJSON("state/scheduler/locks", []);
168
- await store.setJSON("state/scheduler/lease", null);
169
- await store.setJSON("state/memory/context_snapshots/index.json", { snapshots: [] });
170
- await store.setJSON("state/runtime/sessions/index", []);
171
- await store.setJSON("state/discovery/index", []);
172
- await store.setJSON("state/vericify/posts/index", []);
173
- await applyLlmRuntimeConfig(store, opts);
174
- await seedOperationalArtifacts(store);
175
- // 7. Build catalog
176
- await buildCatalog(store);
177
- // 8. Commit + compact
178
- await store.commit();
179
- await store.compact();
180
- materialized.push(...(await materializeStoreSurfaces(store, workspaceRoot, opts)));
181
- const agents = (await store.listAgents()).length;
182
- return {
183
- storePath,
184
- agents,
185
- modules: knowledge.modules,
186
- materialized,
187
- warnings,
188
- };
189
- }
190
- finally {
191
- await store.close();
192
- }
197
+ }, { operation_label: "bootstrapStoreWorkspace" });
193
198
  }
194
199
  // ── ace repair ────────────────────────────────────────────────────────────────
195
200
  export async function repairWorkspace(workspaceRoot) {
196
- const storePath = join(workspaceRoot, ".agents", "ACE", "ace-state.ace");
197
- if (!existsSync(storePath)) {
198
- return [`No store found at ${storePath}. Run 'ace init' first.`];
201
+ const resolved = await ensureCanonicalWorkspaceStore(workspaceRoot, {
202
+ operationLabel: "repairWorkspace",
203
+ });
204
+ if (resolved.mode === "missing") {
205
+ return [
206
+ `No store found at ${resolved.canonicalPath} or ${resolved.legacyPath}. Run 'ace init' first.`,
207
+ ];
199
208
  }
200
- const warnings = [];
209
+ if (resolved.mode === "dual_store_conflict") {
210
+ return [
211
+ ...resolved.warnings,
212
+ "Resolve dual ACE stores before repair can safely materialize host files.",
213
+ ];
214
+ }
215
+ const { storePath } = resolved;
216
+ const warnings = [...resolved.warnings];
201
217
  const store = await openStore(storePath);
202
218
  try {
203
219
  const hostPolicy = (await store.getJSON("meta/host_materialization")) ?? {};
@@ -221,10 +237,13 @@ export async function repairWorkspace(workspaceRoot) {
221
237
  }
222
238
  // ── ace compact ───────────────────────────────────────────────────────────────
223
239
  export async function compactWorkspace(workspaceRoot) {
224
- const storePath = join(workspaceRoot, ".agents", "ACE", "ace-state.ace");
225
- if (!existsSync(storePath)) {
226
- throw new Error(`No store found at ${storePath}. Run 'ace init' first.`);
240
+ const resolved = await ensureCanonicalWorkspaceStore(workspaceRoot, {
241
+ operationLabel: "compactWorkspace",
242
+ });
243
+ if (resolved.mode === "missing") {
244
+ throw new Error(`No store found at ${resolved.canonicalPath} or ${resolved.legacyPath}. Run 'ace init' first.`);
227
245
  }
246
+ const { storePath } = resolved;
228
247
  const { statSync } = await import("fs");
229
248
  const before = statSync(storePath).size;
230
249
  const store = await openStore(storePath);
@@ -2,7 +2,8 @@ import { existsSync, readdirSync, readFileSync, rmSync } 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 { writeStoreBlobsSync } from "./store-artifacts.js";
5
+ import { getWorkspaceStorePath } from "./store-snapshot.js";
6
+ import { writeStoreBlobsQueued } from "./store-artifacts.js";
6
7
  const SCAN_ROOTS_REL = [
7
8
  "agent-state",
8
9
  ".agents/ACE/agent-state",
@@ -48,10 +49,15 @@ function isTextBuffer(input) {
48
49
  function selectScanRoots(workspaceRoot) {
49
50
  return SCAN_ROOTS_REL.map((relPath) => join(workspaceRoot, relPath)).filter((abs) => existsSync(abs));
50
51
  }
52
+ function isCacheableAcePath(path) {
53
+ return path === "agent-state"
54
+ || path.startsWith("agent-state/")
55
+ || path.startsWith(`${ACE_ROOT_REL}/`);
56
+ }
51
57
  export async function cacheWorkspaceArtifacts(workspaceRoot, options = {}) {
52
58
  const dryRun = options.dryRun ?? false;
53
59
  const clean = options.clean ?? true;
54
- const storePath = join(workspaceRoot, ".agents", "ACE", "ace-state.ace");
60
+ const storePath = getWorkspaceStorePath(workspaceRoot);
55
61
  if (!existsSync(storePath)) {
56
62
  throw new Error(`No store found at ${storePath}. Run 'ace init' first.`);
57
63
  }
@@ -66,7 +72,7 @@ export async function cacheWorkspaceArtifacts(workspaceRoot, options = {}) {
66
72
  scanned += 1;
67
73
  const relPath = normalizeRelPath(relative(workspaceRoot, absPath));
68
74
  const canonicalPath = mapAceWorkspaceRelativePath(relPath);
69
- if (!canonicalPath.startsWith(`${ACE_ROOT_REL}/`)) {
75
+ if (!isCacheableAcePath(canonicalPath)) {
70
76
  skipped += 1;
71
77
  continue;
72
78
  }
@@ -105,10 +111,10 @@ export async function cacheWorkspaceArtifacts(workspaceRoot, options = {}) {
105
111
  }
106
112
  const uniqueForWrite = [...dedupByKey.values()];
107
113
  if (!dryRun && uniqueForWrite.length > 0) {
108
- writeStoreBlobsSync(workspaceRoot, uniqueForWrite.map((candidate) => ({
114
+ await writeStoreBlobsQueued(workspaceRoot, uniqueForWrite.map((candidate) => ({
109
115
  key: candidate.key,
110
116
  content: candidate.content,
111
- })));
117
+ })), { operation_label: "cacheWorkspace" });
112
118
  }
113
119
  let removed = 0;
114
120
  if (!dryRun && clean && candidates.length > 0) {
@@ -19,13 +19,14 @@ export class ContextSnapshotMaterializer {
19
19
  this.repo = new ContextSnapshotRepository(store);
20
20
  }
21
21
  directoryPath() {
22
- return join(this.workspaceRoot, ".agents", "ACE", "agent-state", "context-snapshots");
22
+ return join(this.workspaceRoot, "agent-state", "context-snapshots");
23
23
  }
24
24
  async materializeAll() {
25
25
  const dir = this.directoryPath();
26
26
  if (!existsSync(dir))
27
27
  mkdirSync(dir, { recursive: true });
28
28
  const snapshots = await this.repo.listSnapshots();
29
+ const expectedFiles = new Set(["index.json", ...snapshots.map(({ file }) => file)]);
29
30
  writeText(join(dir, "index.json"), `${JSON.stringify({
30
31
  snapshots: snapshots.map(({ name, file, timestamp, summary }) => ({
31
32
  name,
@@ -34,10 +35,13 @@ export class ContextSnapshotMaterializer {
34
35
  summary,
35
36
  })),
36
37
  }, null, 2)}\n`);
38
+ for (const { file, record } of snapshots) {
39
+ writeText(join(dir, file), `${JSON.stringify(record, null, 2)}\n`);
40
+ }
37
41
  for (const file of readdirSync(dir)) {
38
42
  if (!file.endsWith(".json"))
39
43
  continue;
40
- if (file === "index.json")
44
+ if (expectedFiles.has(file))
41
45
  continue;
42
46
  rmSync(join(dir, file), { force: true });
43
47
  }
@@ -1,20 +1,17 @@
1
1
  /**
2
2
  * HookContextMaterializer
3
3
  *
4
- * Writes .agents/ACE/ace-hook-context.json from store state.
5
- * Called at every session start, prompt submit, and tool gating change.
6
- *
7
- * The hook dispatcher (ace-hook-dispatch.mjs) reads ONLY this file.
8
- * It never touches the .ace store directly.
4
+ * Stages the compact hook snapshot into ace-state.ace so hook clients can
5
+ * read a single runtime payload without extra workspace projections.
9
6
  */
10
7
  import { AcePackedStore } from "../ace-packed-store.js";
11
8
  export declare class HookContextMaterializer {
12
9
  private store;
13
- private workspaceRoot;
10
+ static readonly STORE_KEY = "state/runtime/hook_context";
14
11
  private kv;
15
- constructor(store: AcePackedStore, workspaceRoot: string);
16
- private contextPath;
17
- materialize(): Promise<void>;
12
+ constructor(store: AcePackedStore);
13
+ private buildSnapshot;
14
+ stageStoreProjection(): Promise<void>;
18
15
  private _readContent;
19
16
  private _readKernelWorkflow;
20
17
  private _getEnabledAgents;
@@ -1,14 +1,9 @@
1
1
  /**
2
2
  * HookContextMaterializer
3
3
  *
4
- * Writes .agents/ACE/ace-hook-context.json from store state.
5
- * Called at every session start, prompt submit, and tool gating change.
6
- *
7
- * The hook dispatcher (ace-hook-dispatch.mjs) reads ONLY this file.
8
- * It never touches the .ace store directly.
4
+ * Stages the compact hook snapshot into ace-state.ace so hook clients can
5
+ * read a single runtime payload without extra workspace projections.
9
6
  */
10
- import { writeFileSync, mkdirSync, existsSync } from "fs";
11
- import { join, dirname } from "path";
12
7
  import { RuntimeKVRepository } from "../repositories/runtime-kv-repository.js";
13
8
  function fnv1a(s) {
14
9
  let h = 2166136261;
@@ -20,17 +15,13 @@ function fnv1a(s) {
20
15
  }
21
16
  export class HookContextMaterializer {
22
17
  store;
23
- workspaceRoot;
18
+ static STORE_KEY = "state/runtime/hook_context";
24
19
  kv;
25
- constructor(store, workspaceRoot) {
20
+ constructor(store) {
26
21
  this.store = store;
27
- this.workspaceRoot = workspaceRoot;
28
22
  this.kv = new RuntimeKVRepository(store);
29
23
  }
30
- contextPath() {
31
- return join(this.workspaceRoot, ".agents", "ACE", "ace-hook-context.json");
32
- }
33
- async materialize() {
24
+ async buildSnapshot() {
34
25
  const task = await this._readContent("task");
35
26
  const status = await this._readContent("status");
36
27
  const scope = await this._readContent("scope");
@@ -38,7 +29,7 @@ export class HookContextMaterializer {
38
29
  const workflow = await this._readKernelWorkflow();
39
30
  const enabledAgents = await this._getEnabledAgents();
40
31
  const gatedTools = await this._buildGateMap();
41
- const snapshot = {
32
+ return {
42
33
  schema_version: 1,
43
34
  generated_at: new Date().toISOString(),
44
35
  task: { content: task, hash: fnv1a(task) },
@@ -49,11 +40,9 @@ export class HookContextMaterializer {
49
40
  active_agents: enabledAgents,
50
41
  gated_tools: gatedTools,
51
42
  };
52
- const contextPath = this.contextPath();
53
- const dir = dirname(contextPath);
54
- if (!existsSync(dir))
55
- mkdirSync(dir, { recursive: true });
56
- writeFileSync(contextPath, JSON.stringify(snapshot, null, 2), "utf8");
43
+ }
44
+ async stageStoreProjection() {
45
+ await this.store.setJSON(HookContextMaterializer.STORE_KEY, await this.buildSnapshot());
57
46
  }
58
47
  async _readContent(kind) {
59
48
  // Try KV first (runtime overrides), then store blobs, then empty
@@ -94,7 +83,8 @@ export class HookContextMaterializer {
94
83
  /** Update a runtime content field (task, status, scope, etc.) */
95
84
  async setContent(kind, content) {
96
85
  await this.kv.setString(`context/${kind}`, content);
97
- await this.materialize();
86
+ await this.stageStoreProjection();
87
+ await this.store.commit();
98
88
  }
99
89
  }
100
90
  //# sourceMappingURL=hook-context-materializer.js.map
@@ -198,6 +198,7 @@ export class HostFileMaterializer {
198
198
  const fileNames = {
199
199
  codex: "codex.config.toml",
200
200
  vscode: "vscode.mcp.json",
201
+ copilot: ".mcp.json",
201
202
  claude: "claude_desktop_config.json",
202
203
  cursor: "cursor.mcp.json",
203
204
  antigravity: "antigravity.mcp.json",
@@ -272,6 +273,11 @@ export class HostFileMaterializer {
272
273
  }
273
274
  if (includeMcpConfig) {
274
275
  paths.push(await this.materializeEntry(this.buildVsCodeMcpEntry()));
276
+ paths.push(await this.materializeEntry({
277
+ absPath: this.root(".mcp.json"),
278
+ keyParts: [".mcp.json"],
279
+ fallbackContent: getMcpServerConfigSnippet("copilot"),
280
+ }));
275
281
  }
276
282
  if (includeClientConfigBundle) {
277
283
  for (const entry of this.buildInstructionShimEntries()) {
@@ -6,7 +6,6 @@ export declare class ProjectionManager {
6
6
  private vericify;
7
7
  private todoSyncer;
8
8
  private hookContext;
9
- private contextSnapshots;
10
9
  private scheduler;
11
10
  constructor(store: AcePackedStore, workspaceRoot: string);
12
11
  projectAfterCommit(targets: readonly RuntimeProjectionTarget[]): Promise<void>;
@@ -1,4 +1,3 @@
1
- import { ContextSnapshotMaterializer } from "./context-snapshot-materializer.js";
2
1
  import { HookContextMaterializer } from "./hook-context-materializer.js";
3
2
  import { SchedulerProjectionMaterializer } from "./scheduler-projection-materializer.js";
4
3
  import { TodoSyncer } from "./todo-syncer.js";
@@ -9,15 +8,13 @@ export class ProjectionManager {
9
8
  vericify;
10
9
  todoSyncer;
11
10
  hookContext;
12
- contextSnapshots;
13
11
  scheduler;
14
12
  constructor(store, workspaceRoot) {
15
13
  this.store = store;
16
14
  this.workspaceRoot = workspaceRoot;
17
15
  this.vericify = new VericifyProjector(store, workspaceRoot);
18
16
  this.todoSyncer = new TodoSyncer(store, workspaceRoot);
19
- this.hookContext = new HookContextMaterializer(store, workspaceRoot);
20
- this.contextSnapshots = new ContextSnapshotMaterializer(store, workspaceRoot);
17
+ this.hookContext = new HookContextMaterializer(store);
21
18
  this.scheduler = new SchedulerProjectionMaterializer(store, workspaceRoot);
22
19
  }
23
20
  async projectAfterCommit(targets) {
@@ -45,6 +42,10 @@ export class ProjectionManager {
45
42
  await this.vericify.projectVericifyPosts();
46
43
  stagedStoreWrites = true;
47
44
  }
45
+ else if (target === "hook_context") {
46
+ await this.hookContext.stageStoreProjection();
47
+ stagedStoreWrites = true;
48
+ }
48
49
  else if (target === "scheduler") {
49
50
  renderedScheduler = await this.scheduler.render();
50
51
  await this.scheduler.stageStoreProjections(renderedScheduler);
@@ -58,15 +59,6 @@ export class ProjectionManager {
58
59
  if (target === "todo_state") {
59
60
  await this.todoSyncer.writeToFile();
60
61
  }
61
- else if (target === "hook_context") {
62
- await this.hookContext.materialize();
63
- }
64
- else if (target === "context_snapshots") {
65
- await this.contextSnapshots.materializeAll();
66
- }
67
- else if (target === "scheduler") {
68
- await this.scheduler.materializeFiles(renderedScheduler);
69
- }
70
62
  }
71
63
  }
72
64
  }
@@ -20,7 +20,7 @@ export class SchedulerProjectionMaterializer {
20
20
  this.repo = new SchedulerRepository(store);
21
21
  }
22
22
  filePath(file) {
23
- return join(this.workspaceRoot, ".agents", "ACE", "agent-state", file);
23
+ return join(this.workspaceRoot, "agent-state", file);
24
24
  }
25
25
  async render() {
26
26
  const queue = await this.repo.readQueue();
@@ -4,15 +4,15 @@
4
4
  * Writes 5 Vericify-facing files from store state on every relevant mutation.
5
5
  * These are MIRRORS only — the store is source of truth.
6
6
  *
7
- * All files live under .agents/ACE/ (the canonical ACE namespace as defined
8
- * by ACE_ROOT_REL in helpers.ts and remapped via ACE_MANAGED_PREFIXES).
7
+ * Runtime-facing state projections now live under top-level agent-state/.
8
+ * Host/task scaffolding remains under .agents/ACE/ where required.
9
9
  *
10
10
  * Files projected:
11
- * .agents/ACE/agent-state/handoff-registry.json
12
- * .agents/ACE/agent-state/todo-state.json ← schema: { version, updated_at, order[], nodes{} }
13
- * .agents/ACE/agent-state/run-ledger.json ← schema: { version, updated_at, entries[] }
14
- * .agents/ACE/agent-state/STATUS_EVENTS.ndjson ← schema: StatusEventRecord per line
15
- * .agents/ACE/agent-state/vericify/process-posts.json
11
+ * agent-state/handoff-registry.json
12
+ * agent-state/todo-state.json ← schema: { version, updated_at, order[], nodes{} }
13
+ * agent-state/run-ledger.json ← schema: { version, updated_at, entries[] }
14
+ * agent-state/STATUS_EVENTS.ndjson ← schema: StatusEventRecord per line
15
+ * agent-state/vericify/process-posts.json
16
16
  */
17
17
  import { AcePackedStore } from "../ace-packed-store.js";
18
18
  export declare class VericifyProjector {
@@ -4,15 +4,15 @@
4
4
  * Writes 5 Vericify-facing files from store state on every relevant mutation.
5
5
  * These are MIRRORS only — the store is source of truth.
6
6
  *
7
- * All files live under .agents/ACE/ (the canonical ACE namespace as defined
8
- * by ACE_ROOT_REL in helpers.ts and remapped via ACE_MANAGED_PREFIXES).
7
+ * Runtime-facing state projections now live under top-level agent-state/.
8
+ * Host/task scaffolding remains under .agents/ACE/ where required.
9
9
  *
10
10
  * Files projected:
11
- * .agents/ACE/agent-state/handoff-registry.json
12
- * .agents/ACE/agent-state/todo-state.json ← schema: { version, updated_at, order[], nodes{} }
13
- * .agents/ACE/agent-state/run-ledger.json ← schema: { version, updated_at, entries[] }
14
- * .agents/ACE/agent-state/STATUS_EVENTS.ndjson ← schema: StatusEventRecord per line
15
- * .agents/ACE/agent-state/vericify/process-posts.json
11
+ * agent-state/handoff-registry.json
12
+ * agent-state/todo-state.json ← schema: { version, updated_at, order[], nodes{} }
13
+ * agent-state/run-ledger.json ← schema: { version, updated_at, entries[] }
14
+ * agent-state/STATUS_EVENTS.ndjson ← schema: StatusEventRecord per line
15
+ * agent-state/vericify/process-posts.json
16
16
  */
17
17
  import { createHash, randomUUID } from "crypto";
18
18
  import { HandoffRepository } from "../repositories/handoff-repository.js";
@@ -21,9 +21,9 @@ import { LedgerRepository } from "../repositories/ledger-repository.js";
21
21
  import { TrackerRepository } from "../repositories/tracker-repository.js";
22
22
  import { VericifyRepository } from "../repositories/vericify-repository.js";
23
23
  import { operationalArtifactKey } from "../store-artifacts.js";
24
- // Canonical ACE state root mirrors helpers.ts ACE_ROOT_REL + ACE_MANAGED_PREFIXES remapping
25
- const ACE_ROOT = ".agents/ACE";
26
- const ACE_STATE_ROOT = `${ACE_ROOT}/agent-state`;
24
+ // Runtime-facing state now lives in top-level agent-state/.
25
+ const ACE_STATE_ROOT = "agent-state";
26
+ const ACE_TASKS_ROOT = ".agents/ACE/tasks";
27
27
  const CHECKSUMS_KEY = "host/materializations/checksums";
28
28
  function sha256(content) {
29
29
  return createHash("sha256").update(content, "utf8").digest("hex");
@@ -101,7 +101,7 @@ export class VericifyProjector {
101
101
  const content = JSON.stringify({
102
102
  version: 1,
103
103
  updated_at: new Date().toISOString(),
104
- source_todo_path: `${ACE_ROOT}/tasks/todo.md`,
104
+ source_todo_path: `${ACE_TASKS_ROOT}/todo.md`,
105
105
  order,
106
106
  nodes,
107
107
  }, null, 2);