@voybio/ace-swarm 0.2.4 → 2.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (125) hide show
  1. package/CHANGELOG.md +11 -1
  2. package/README.md +20 -13
  3. package/assets/.agents/skills/eval-harness/SKILL.md +14 -0
  4. package/assets/.agents/skills/handoff-lint/SKILL.md +14 -0
  5. package/assets/.agents/skills/incident-commander/SKILL.md +14 -0
  6. package/assets/.agents/skills/memory-curator/SKILL.md +14 -0
  7. package/assets/.agents/skills/release-sentry/SKILL.md +14 -0
  8. package/assets/.agents/skills/risk-quant/SKILL.md +14 -0
  9. package/assets/.agents/skills/schema-forge/SKILL.md +14 -0
  10. package/assets/.agents/skills/state-auditor/SKILL.md +14 -0
  11. package/assets/agent-state/EVIDENCE_LOG.md +1 -1
  12. package/assets/agent-state/MODULES/gates/gate-correctness.json +1 -1
  13. package/assets/agent-state/MODULES/roles/capability-framework.json +41 -0
  14. package/assets/agent-state/MODULES/roles/capability-git.json +33 -0
  15. package/assets/agent-state/MODULES/roles/capability-safety.json +37 -0
  16. package/assets/agent-state/MODULES/schemas/ACE_RUNTIME_PROFILE.schema.json +21 -0
  17. package/assets/agent-state/MODULES/schemas/RUNTIME_EXECUTOR_SESSION_REGISTRY.schema.json +43 -0
  18. package/assets/agent-state/MODULES/schemas/WORKSPACE_SESSION_REGISTRY.schema.json +11 -0
  19. package/assets/agent-state/STATUS.md +2 -2
  20. package/assets/scripts/ace-hook-dispatch.mjs +70 -6
  21. package/assets/scripts/render-mcp-configs.sh +19 -5
  22. package/dist/ace-context.js +22 -1
  23. package/dist/ace-server-instructions.js +3 -3
  24. package/dist/ace-state-resolver.js +5 -3
  25. package/dist/astgrep-index.d.ts +9 -1
  26. package/dist/astgrep-index.js +14 -3
  27. package/dist/cli.js +52 -20
  28. package/dist/handoff-registry.js +5 -5
  29. package/dist/helpers/artifacts.d.ts +19 -0
  30. package/dist/helpers/artifacts.js +152 -0
  31. package/dist/helpers/bootstrap.d.ts +24 -0
  32. package/dist/helpers/bootstrap.js +894 -0
  33. package/dist/helpers/constants.d.ts +53 -0
  34. package/dist/helpers/constants.js +288 -0
  35. package/dist/helpers/drift.d.ts +13 -0
  36. package/dist/helpers/drift.js +45 -0
  37. package/dist/helpers/path-utils.d.ts +17 -0
  38. package/dist/helpers/path-utils.js +104 -0
  39. package/dist/helpers/store-resolution.d.ts +19 -0
  40. package/dist/helpers/store-resolution.js +301 -0
  41. package/dist/helpers/workspace-root.d.ts +3 -0
  42. package/dist/helpers/workspace-root.js +80 -0
  43. package/dist/helpers.d.ts +8 -123
  44. package/dist/helpers.js +8 -1747
  45. package/dist/job-scheduler.js +3 -3
  46. package/dist/local-model-runtime.js +12 -1
  47. package/dist/model-bridge.d.ts +7 -0
  48. package/dist/model-bridge.js +75 -5
  49. package/dist/orchestrator-supervisor.d.ts +14 -0
  50. package/dist/orchestrator-supervisor.js +72 -1
  51. package/dist/run-ledger.js +3 -3
  52. package/dist/runtime-command.d.ts +8 -0
  53. package/dist/runtime-command.js +38 -6
  54. package/dist/runtime-executor.d.ts +14 -0
  55. package/dist/runtime-executor.js +669 -171
  56. package/dist/runtime-profile.d.ts +32 -0
  57. package/dist/runtime-profile.js +89 -13
  58. package/dist/runtime-tool-specs.d.ts +21 -0
  59. package/dist/runtime-tool-specs.js +78 -3
  60. package/dist/safe-edit.d.ts +7 -0
  61. package/dist/safe-edit.js +163 -37
  62. package/dist/schemas.js +19 -0
  63. package/dist/shared.d.ts +2 -2
  64. package/dist/status-events.js +9 -6
  65. package/dist/store/ace-packed-store.d.ts +3 -2
  66. package/dist/store/ace-packed-store.js +188 -110
  67. package/dist/store/bootstrap-store.d.ts +1 -1
  68. package/dist/store/bootstrap-store.js +94 -81
  69. package/dist/store/cache-workspace.d.ts +22 -0
  70. package/dist/store/cache-workspace.js +149 -0
  71. package/dist/store/materializers/context-snapshot-materializer.js +6 -7
  72. package/dist/store/materializers/hook-context-materializer.d.ts +6 -9
  73. package/dist/store/materializers/hook-context-materializer.js +11 -21
  74. package/dist/store/materializers/host-file-materializer.js +6 -0
  75. package/dist/store/materializers/projection-manager.d.ts +0 -1
  76. package/dist/store/materializers/projection-manager.js +5 -13
  77. package/dist/store/materializers/scheduler-projection-materializer.js +1 -1
  78. package/dist/store/materializers/vericify-projector.d.ts +7 -7
  79. package/dist/store/materializers/vericify-projector.js +11 -11
  80. package/dist/store/repositories/local-model-runtime-repository.d.ts +120 -3
  81. package/dist/store/repositories/local-model-runtime-repository.js +242 -6
  82. package/dist/store/skills-install.d.ts +4 -0
  83. package/dist/store/skills-install.js +21 -12
  84. package/dist/store/state-reader.d.ts +2 -0
  85. package/dist/store/state-reader.js +20 -0
  86. package/dist/store/store-artifacts.d.ts +7 -0
  87. package/dist/store/store-artifacts.js +27 -1
  88. package/dist/store/store-authority-audit.d.ts +18 -1
  89. package/dist/store/store-authority-audit.js +115 -5
  90. package/dist/store/store-snapshot.d.ts +3 -0
  91. package/dist/store/store-snapshot.js +22 -2
  92. package/dist/store/workspace-store-paths.d.ts +39 -0
  93. package/dist/store/workspace-store-paths.js +94 -0
  94. package/dist/store/write-coordinator.d.ts +65 -0
  95. package/dist/store/write-coordinator.js +386 -0
  96. package/dist/todo-state.js +5 -5
  97. package/dist/tools-agent.js +319 -34
  98. package/dist/tools-discovery.js +1 -1
  99. package/dist/tools-files.d.ts +7 -0
  100. package/dist/tools-files.js +299 -10
  101. package/dist/tools-framework.js +107 -27
  102. package/dist/tools-handoff.js +2 -2
  103. package/dist/tools-lifecycle.js +4 -4
  104. package/dist/tools-memory.js +6 -6
  105. package/dist/tools-todo.js +2 -2
  106. package/dist/tracker-adapters.d.ts +1 -1
  107. package/dist/tracker-adapters.js +13 -18
  108. package/dist/tracker-sync.js +5 -3
  109. package/dist/tui/agent-runner.js +3 -1
  110. package/dist/tui/chat.js +103 -7
  111. package/dist/tui/dashboard.d.ts +1 -0
  112. package/dist/tui/dashboard.js +43 -0
  113. package/dist/tui/layout.d.ts +20 -0
  114. package/dist/tui/layout.js +31 -1
  115. package/dist/tui/local-model-contract.d.ts +6 -2
  116. package/dist/tui/local-model-contract.js +16 -3
  117. package/dist/vericify-bridge.d.ts +5 -0
  118. package/dist/vericify-bridge.js +27 -3
  119. package/dist/workspace-manager.d.ts +30 -3
  120. package/dist/workspace-manager.js +257 -27
  121. package/package.json +1 -2
  122. package/dist/internal-tool-runtime.d.ts +0 -21
  123. package/dist/internal-tool-runtime.js +0 -136
  124. package/dist/store/workspace-snapshot.d.ts +0 -26
  125. 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));
@@ -91,12 +93,7 @@ async function materializeStoreSurfaces(store, workspaceRoot, opts) {
91
93
  await store.commit();
92
94
  const projections = new ProjectionManager(store, workspaceRoot);
93
95
  await projections.projectAfterCommit(["hook_context", "todo_state", "scheduler", "context_snapshots"]);
94
- materialized.push(join(workspaceRoot, ".agents", "ACE", "ace-hook-context.json"));
95
96
  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
97
  return [...new Set(materialized)];
101
98
  }
102
99
  // Artifacts that receive live timestamp substitution on first seed.
@@ -116,88 +113,101 @@ async function seedOperationalArtifacts(store) {
116
113
  }
117
114
  export async function bootstrapStoreWorkspace(opts) {
118
115
  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.`);
116
+ const resolved = await ensureCanonicalWorkspaceStore(workspaceRoot, {
117
+ operationLabel: "bootstrapStoreWorkspace",
118
+ });
119
+ const storePath = resolved.storePath;
120
+ return withStoreWriteCoordinator(storePath, async () => {
121
+ const warnings = [...resolved.warnings];
122
+ const materialized = [];
123
+ if (resolved.mode === "dual_store_conflict" && !force) {
124
+ warnings.push("Both canonical and legacy stores exist and differ. Resolve with 'ace repair' before reinitializing.");
125
125
  return { storePath, agents: 0, modules: { gates: 0, roles: 0, schemas: 0 }, materialized, warnings };
126
126
  }
127
- const existingStore = await openStore(storePath);
127
+ if (existsSync(storePath) && !force) {
128
+ if (!(opts.includeMcpConfig ?? false) && !(opts.includeClientConfigBundle ?? false) && !opts.llm) {
129
+ warnings.push(`Store already exists at ${storePath}. Use --force to reinitialize, or run 'ace migrate' to import existing state.`);
130
+ return { storePath, agents: 0, modules: { gates: 0, roles: 0, schemas: 0 }, materialized, warnings };
131
+ }
132
+ const existingStore = await openStore(storePath);
133
+ try {
134
+ await seedOperationalArtifacts(existingStore);
135
+ materialized.push(...(await materializeStoreSurfaces(existingStore, workspaceRoot, opts)));
136
+ const agents = (await existingStore.listAgents()).length;
137
+ warnings.push(`Reused existing store at ${storePath} and refreshed host materializations.`);
138
+ return { storePath, agents, modules: { gates: 0, roles: 0, schemas: 0 }, materialized, warnings };
139
+ }
140
+ finally {
141
+ await existingStore.close();
142
+ }
143
+ }
144
+ for (const dir of [
145
+ join(workspaceRoot, "agent-state"),
146
+ join(workspaceRoot, ".agents", "ACE"),
147
+ join(workspaceRoot, ".agents", "ACE", "tasks"),
148
+ ]) {
149
+ mkdirSync(dir, { recursive: true });
150
+ }
151
+ const store = await openStore(storePath);
128
152
  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 };
153
+ await store.setJSON("meta/schema_version", STORE_VERSION);
154
+ await store.setJSON("meta/created_at", Date.now());
155
+ await store.setJSON("meta/project_name", opts.projectName ?? "ACE Workspace");
156
+ await store.setJSON("meta/host_materialization", {
157
+ include_mcp_config: opts.includeMcpConfig ?? false,
158
+ include_client_config_bundle: opts.includeClientConfigBundle ?? false,
159
+ });
160
+ const assetsRoot = getAssetsRoot();
161
+ const knowledge = await bakeAllCoreKnowledge(store, assetsRoot);
162
+ await bakeTopology(store, assetsRoot);
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
+ await buildCatalog(store);
176
+ await store.commit();
177
+ await store.compact();
178
+ materialized.push(...(await materializeStoreSurfaces(store, workspaceRoot, opts)));
179
+ const agents = (await store.listAgents()).length;
180
+ return {
181
+ storePath,
182
+ agents,
183
+ modules: knowledge.modules,
184
+ materialized,
185
+ warnings,
186
+ };
134
187
  }
135
188
  finally {
136
- await existingStore.close();
189
+ await store.close();
137
190
  }
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
- }
191
+ }, { operation_label: "bootstrapStoreWorkspace" });
193
192
  }
194
193
  // ── ace repair ────────────────────────────────────────────────────────────────
195
194
  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.`];
195
+ const resolved = await ensureCanonicalWorkspaceStore(workspaceRoot, {
196
+ operationLabel: "repairWorkspace",
197
+ });
198
+ if (resolved.mode === "missing") {
199
+ return [
200
+ `No store found at ${resolved.canonicalPath} or ${resolved.legacyPath}. Run 'ace init' first.`,
201
+ ];
199
202
  }
200
- const warnings = [];
203
+ if (resolved.mode === "dual_store_conflict") {
204
+ return [
205
+ ...resolved.warnings,
206
+ "Resolve dual ACE stores before repair can safely materialize host files.",
207
+ ];
208
+ }
209
+ const { storePath } = resolved;
210
+ const warnings = [...resolved.warnings];
201
211
  const store = await openStore(storePath);
202
212
  try {
203
213
  const hostPolicy = (await store.getJSON("meta/host_materialization")) ?? {};
@@ -221,10 +231,13 @@ export async function repairWorkspace(workspaceRoot) {
221
231
  }
222
232
  // ── ace compact ───────────────────────────────────────────────────────────────
223
233
  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.`);
234
+ const resolved = await ensureCanonicalWorkspaceStore(workspaceRoot, {
235
+ operationLabel: "compactWorkspace",
236
+ });
237
+ if (resolved.mode === "missing") {
238
+ throw new Error(`No store found at ${resolved.canonicalPath} or ${resolved.legacyPath}. Run 'ace init' first.`);
227
239
  }
240
+ const { storePath } = resolved;
228
241
  const { statSync } = await import("fs");
229
242
  const before = statSync(storePath).size;
230
243
  const store = await openStore(storePath);
@@ -0,0 +1,22 @@
1
+ export interface CacheWorkspaceOptions {
2
+ dryRun?: boolean;
3
+ clean?: boolean;
4
+ }
5
+ export interface CacheWorkspaceResult {
6
+ storePath: string;
7
+ dry_run: boolean;
8
+ clean: boolean;
9
+ scanned_files: number;
10
+ cached_files: number;
11
+ removed_files: number;
12
+ kept_projected_files: number;
13
+ skipped_files: number;
14
+ warnings: string[];
15
+ cached: Array<{
16
+ path: string;
17
+ key: string;
18
+ bytes: number;
19
+ }>;
20
+ }
21
+ export declare function cacheWorkspaceArtifacts(workspaceRoot: string, options?: CacheWorkspaceOptions): Promise<CacheWorkspaceResult>;
22
+ //# sourceMappingURL=cache-workspace.d.ts.map
@@ -0,0 +1,149 @@
1
+ import { existsSync, readdirSync, readFileSync, rmSync } from "node:fs";
2
+ import { dirname, isAbsolute, join, relative } from "node:path";
3
+ import { ACE_ROOT_REL, isProjectedAceWorkspacePath, mapAceWorkspaceRelativePath, resolveStoreFallbackKeysForPath, } from "../helpers.js";
4
+ import { normalizeRelPath } from "../shared.js";
5
+ import { getWorkspaceStorePath } from "./store-snapshot.js";
6
+ import { writeStoreBlobsQueued } from "./store-artifacts.js";
7
+ const SCAN_ROOTS_REL = [
8
+ "agent-state",
9
+ ".agents/ACE/agent-state",
10
+ ".agents/ACE/tasks",
11
+ ".agents/ACE/skills",
12
+ ];
13
+ function isInside(base, target) {
14
+ const rel = relative(base, target);
15
+ return rel === "" || (!rel.startsWith("..") && !isAbsolute(rel));
16
+ }
17
+ function collectFiles(root) {
18
+ const out = [];
19
+ if (!existsSync(root))
20
+ return out;
21
+ const walk = (dir) => {
22
+ for (const entry of readdirSync(dir, { withFileTypes: true })) {
23
+ const abs = join(dir, entry.name);
24
+ if (entry.isDirectory()) {
25
+ walk(abs);
26
+ continue;
27
+ }
28
+ if (entry.isFile()) {
29
+ out.push(abs);
30
+ }
31
+ }
32
+ };
33
+ walk(root);
34
+ return out;
35
+ }
36
+ function pruneEmptyParents(path, stopAt) {
37
+ let cursor = dirname(path);
38
+ while (isInside(stopAt, cursor) && cursor !== stopAt && existsSync(cursor)) {
39
+ const entries = readdirSync(cursor);
40
+ if (entries.length > 0)
41
+ break;
42
+ rmSync(cursor, { recursive: true, force: true });
43
+ cursor = dirname(cursor);
44
+ }
45
+ }
46
+ function isTextBuffer(input) {
47
+ return !input.includes(0);
48
+ }
49
+ function selectScanRoots(workspaceRoot) {
50
+ return SCAN_ROOTS_REL.map((relPath) => join(workspaceRoot, relPath)).filter((abs) => existsSync(abs));
51
+ }
52
+ function isCacheableAcePath(path) {
53
+ return path === "agent-state"
54
+ || path.startsWith("agent-state/")
55
+ || path.startsWith(`${ACE_ROOT_REL}/`);
56
+ }
57
+ export async function cacheWorkspaceArtifacts(workspaceRoot, options = {}) {
58
+ const dryRun = options.dryRun ?? false;
59
+ const clean = options.clean ?? true;
60
+ const storePath = getWorkspaceStorePath(workspaceRoot);
61
+ if (!existsSync(storePath)) {
62
+ throw new Error(`No store found at ${storePath}. Run 'ace init' first.`);
63
+ }
64
+ const warnings = [];
65
+ const scanRoots = selectScanRoots(workspaceRoot);
66
+ const candidates = [];
67
+ let scanned = 0;
68
+ let keptProjected = 0;
69
+ let skipped = 0;
70
+ for (const scanRoot of scanRoots) {
71
+ for (const absPath of collectFiles(scanRoot)) {
72
+ scanned += 1;
73
+ const relPath = normalizeRelPath(relative(workspaceRoot, absPath));
74
+ const canonicalPath = mapAceWorkspaceRelativePath(relPath);
75
+ if (!isCacheableAcePath(canonicalPath)) {
76
+ skipped += 1;
77
+ continue;
78
+ }
79
+ if (canonicalPath === `${ACE_ROOT_REL}/ace-state.ace`) {
80
+ skipped += 1;
81
+ continue;
82
+ }
83
+ if (isProjectedAceWorkspacePath(canonicalPath)) {
84
+ keptProjected += 1;
85
+ continue;
86
+ }
87
+ const raw = readFileSync(absPath);
88
+ if (!isTextBuffer(raw)) {
89
+ skipped += 1;
90
+ warnings.push(`Skipped non-text artifact: ${canonicalPath}`);
91
+ continue;
92
+ }
93
+ const fallbackKeys = resolveStoreFallbackKeysForPath(canonicalPath);
94
+ if (fallbackKeys.length === 0) {
95
+ skipped += 1;
96
+ warnings.push(`No store fallback key for ${canonicalPath}`);
97
+ continue;
98
+ }
99
+ candidates.push({
100
+ absPath,
101
+ canonicalPath,
102
+ key: fallbackKeys[0],
103
+ content: raw.toString("utf-8"),
104
+ bytes: raw.byteLength,
105
+ });
106
+ }
107
+ }
108
+ const dedupByKey = new Map();
109
+ for (const candidate of candidates) {
110
+ dedupByKey.set(candidate.key, candidate);
111
+ }
112
+ const uniqueForWrite = [...dedupByKey.values()];
113
+ if (!dryRun && uniqueForWrite.length > 0) {
114
+ await writeStoreBlobsQueued(workspaceRoot, uniqueForWrite.map((candidate) => ({
115
+ key: candidate.key,
116
+ content: candidate.content,
117
+ })), { operation_label: "cacheWorkspace" });
118
+ }
119
+ let removed = 0;
120
+ if (!dryRun && clean && candidates.length > 0) {
121
+ const removedPaths = new Set();
122
+ for (const candidate of candidates) {
123
+ if (removedPaths.has(candidate.absPath))
124
+ continue;
125
+ rmSync(candidate.absPath, { force: true });
126
+ removedPaths.add(candidate.absPath);
127
+ removed += 1;
128
+ const pruneRoot = scanRoots.find((root) => isInside(root, candidate.absPath)) ?? workspaceRoot;
129
+ pruneEmptyParents(candidate.absPath, pruneRoot);
130
+ }
131
+ }
132
+ return {
133
+ storePath,
134
+ dry_run: dryRun,
135
+ clean,
136
+ scanned_files: scanned,
137
+ cached_files: candidates.length,
138
+ removed_files: removed,
139
+ kept_projected_files: keptProjected,
140
+ skipped_files: skipped,
141
+ warnings,
142
+ cached: candidates.map((candidate) => ({
143
+ path: candidate.canonicalPath,
144
+ key: candidate.key,
145
+ bytes: candidate.bytes,
146
+ })),
147
+ };
148
+ }
149
+ //# sourceMappingURL=cache-workspace.js.map
@@ -19,18 +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 retained = new Set(["index.json"]);
30
- for (const snapshot of snapshots) {
31
- retained.add(snapshot.file);
32
- writeText(join(dir, snapshot.file), `${JSON.stringify(snapshot.record, null, 2)}\n`);
33
- }
29
+ const expectedFiles = new Set(["index.json", ...snapshots.map(({ file }) => file)]);
34
30
  writeText(join(dir, "index.json"), `${JSON.stringify({
35
31
  snapshots: snapshots.map(({ name, file, timestamp, summary }) => ({
36
32
  name,
@@ -39,10 +35,13 @@ export class ContextSnapshotMaterializer {
39
35
  summary,
40
36
  })),
41
37
  }, null, 2)}\n`);
38
+ for (const { file, record } of snapshots) {
39
+ writeText(join(dir, file), `${JSON.stringify(record, null, 2)}\n`);
40
+ }
42
41
  for (const file of readdirSync(dir)) {
43
42
  if (!file.endsWith(".json"))
44
43
  continue;
45
- if (retained.has(file))
44
+ if (expectedFiles.has(file))
46
45
  continue;
47
46
  rmSync(join(dir, file), { force: true });
48
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 {