@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.
- package/CHANGELOG.md +11 -1
- package/README.md +20 -13
- package/assets/.agents/skills/eval-harness/SKILL.md +14 -0
- package/assets/.agents/skills/handoff-lint/SKILL.md +14 -0
- package/assets/.agents/skills/incident-commander/SKILL.md +14 -0
- package/assets/.agents/skills/memory-curator/SKILL.md +14 -0
- package/assets/.agents/skills/release-sentry/SKILL.md +14 -0
- package/assets/.agents/skills/risk-quant/SKILL.md +14 -0
- package/assets/.agents/skills/schema-forge/SKILL.md +14 -0
- package/assets/.agents/skills/state-auditor/SKILL.md +14 -0
- package/assets/agent-state/EVIDENCE_LOG.md +1 -1
- package/assets/agent-state/MODULES/gates/gate-correctness.json +1 -1
- package/assets/agent-state/MODULES/roles/capability-framework.json +41 -0
- package/assets/agent-state/MODULES/roles/capability-git.json +33 -0
- package/assets/agent-state/MODULES/roles/capability-safety.json +37 -0
- package/assets/agent-state/MODULES/schemas/ACE_RUNTIME_PROFILE.schema.json +21 -0
- package/assets/agent-state/MODULES/schemas/RUNTIME_EXECUTOR_SESSION_REGISTRY.schema.json +43 -0
- package/assets/agent-state/MODULES/schemas/WORKSPACE_SESSION_REGISTRY.schema.json +11 -0
- package/assets/agent-state/STATUS.md +2 -2
- package/assets/scripts/ace-hook-dispatch.mjs +70 -6
- package/assets/scripts/render-mcp-configs.sh +19 -5
- package/dist/ace-context.js +22 -1
- package/dist/ace-server-instructions.js +3 -3
- package/dist/ace-state-resolver.js +5 -3
- package/dist/astgrep-index.d.ts +9 -1
- package/dist/astgrep-index.js +14 -3
- package/dist/cli.js +52 -20
- package/dist/handoff-registry.js +5 -5
- package/dist/helpers/artifacts.d.ts +19 -0
- package/dist/helpers/artifacts.js +152 -0
- package/dist/helpers/bootstrap.d.ts +24 -0
- package/dist/helpers/bootstrap.js +894 -0
- package/dist/helpers/constants.d.ts +53 -0
- package/dist/helpers/constants.js +288 -0
- package/dist/helpers/drift.d.ts +13 -0
- package/dist/helpers/drift.js +45 -0
- package/dist/helpers/path-utils.d.ts +17 -0
- package/dist/helpers/path-utils.js +104 -0
- package/dist/helpers/store-resolution.d.ts +19 -0
- package/dist/helpers/store-resolution.js +301 -0
- package/dist/helpers/workspace-root.d.ts +3 -0
- package/dist/helpers/workspace-root.js +80 -0
- package/dist/helpers.d.ts +8 -123
- package/dist/helpers.js +8 -1747
- package/dist/job-scheduler.js +3 -3
- package/dist/local-model-runtime.js +12 -1
- package/dist/model-bridge.d.ts +7 -0
- package/dist/model-bridge.js +75 -5
- package/dist/orchestrator-supervisor.d.ts +14 -0
- package/dist/orchestrator-supervisor.js +72 -1
- package/dist/run-ledger.js +3 -3
- package/dist/runtime-command.d.ts +8 -0
- package/dist/runtime-command.js +38 -6
- package/dist/runtime-executor.d.ts +14 -0
- package/dist/runtime-executor.js +669 -171
- package/dist/runtime-profile.d.ts +32 -0
- package/dist/runtime-profile.js +89 -13
- package/dist/runtime-tool-specs.d.ts +21 -0
- package/dist/runtime-tool-specs.js +78 -3
- package/dist/safe-edit.d.ts +7 -0
- package/dist/safe-edit.js +163 -37
- package/dist/schemas.js +19 -0
- package/dist/shared.d.ts +2 -2
- package/dist/status-events.js +9 -6
- package/dist/store/ace-packed-store.d.ts +3 -2
- package/dist/store/ace-packed-store.js +188 -110
- package/dist/store/bootstrap-store.d.ts +1 -1
- package/dist/store/bootstrap-store.js +94 -81
- package/dist/store/cache-workspace.d.ts +22 -0
- package/dist/store/cache-workspace.js +149 -0
- package/dist/store/materializers/context-snapshot-materializer.js +6 -7
- package/dist/store/materializers/hook-context-materializer.d.ts +6 -9
- package/dist/store/materializers/hook-context-materializer.js +11 -21
- package/dist/store/materializers/host-file-materializer.js +6 -0
- package/dist/store/materializers/projection-manager.d.ts +0 -1
- package/dist/store/materializers/projection-manager.js +5 -13
- package/dist/store/materializers/scheduler-projection-materializer.js +1 -1
- package/dist/store/materializers/vericify-projector.d.ts +7 -7
- package/dist/store/materializers/vericify-projector.js +11 -11
- package/dist/store/repositories/local-model-runtime-repository.d.ts +120 -3
- package/dist/store/repositories/local-model-runtime-repository.js +242 -6
- package/dist/store/skills-install.d.ts +4 -0
- package/dist/store/skills-install.js +21 -12
- package/dist/store/state-reader.d.ts +2 -0
- package/dist/store/state-reader.js +20 -0
- package/dist/store/store-artifacts.d.ts +7 -0
- package/dist/store/store-artifacts.js +27 -1
- package/dist/store/store-authority-audit.d.ts +18 -1
- package/dist/store/store-authority-audit.js +115 -5
- package/dist/store/store-snapshot.d.ts +3 -0
- package/dist/store/store-snapshot.js +22 -2
- package/dist/store/workspace-store-paths.d.ts +39 -0
- package/dist/store/workspace-store-paths.js +94 -0
- package/dist/store/write-coordinator.d.ts +65 -0
- package/dist/store/write-coordinator.js +386 -0
- package/dist/todo-state.js +5 -5
- package/dist/tools-agent.js +319 -34
- package/dist/tools-discovery.js +1 -1
- package/dist/tools-files.d.ts +7 -0
- package/dist/tools-files.js +299 -10
- package/dist/tools-framework.js +107 -27
- package/dist/tools-handoff.js +2 -2
- package/dist/tools-lifecycle.js +4 -4
- package/dist/tools-memory.js +6 -6
- package/dist/tools-todo.js +2 -2
- package/dist/tracker-adapters.d.ts +1 -1
- package/dist/tracker-adapters.js +13 -18
- package/dist/tracker-sync.js +5 -3
- package/dist/tui/agent-runner.js +3 -1
- package/dist/tui/chat.js +103 -7
- package/dist/tui/dashboard.d.ts +1 -0
- package/dist/tui/dashboard.js +43 -0
- package/dist/tui/layout.d.ts +20 -0
- package/dist/tui/layout.js +31 -1
- package/dist/tui/local-model-contract.d.ts +6 -2
- package/dist/tui/local-model-contract.js +16 -3
- package/dist/vericify-bridge.d.ts +5 -0
- package/dist/vericify-bridge.js +27 -3
- package/dist/workspace-manager.d.ts +30 -3
- package/dist/workspace-manager.js +257 -27
- package/package.json +1 -2
- package/dist/internal-tool-runtime.d.ts +0 -21
- package/dist/internal-tool-runtime.js +0 -136
- package/dist/store/workspace-snapshot.d.ts +0 -26
- 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
|
|
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
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
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
|
-
|
|
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
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
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
|
|
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
|
|
197
|
-
|
|
198
|
-
|
|
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
|
-
|
|
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
|
|
225
|
-
|
|
226
|
-
|
|
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, "
|
|
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
|
|
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 (
|
|
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
|
-
*
|
|
5
|
-
*
|
|
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
|
-
|
|
10
|
+
static readonly STORE_KEY = "state/runtime/hook_context";
|
|
14
11
|
private kv;
|
|
15
|
-
constructor(store: AcePackedStore
|
|
16
|
-
private
|
|
17
|
-
|
|
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
|
-
*
|
|
5
|
-
*
|
|
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
|
-
|
|
18
|
+
static STORE_KEY = "state/runtime/hook_context";
|
|
24
19
|
kv;
|
|
25
|
-
constructor(store
|
|
20
|
+
constructor(store) {
|
|
26
21
|
this.store = store;
|
|
27
|
-
this.workspaceRoot = workspaceRoot;
|
|
28
22
|
this.kv = new RuntimeKVRepository(store);
|
|
29
23
|
}
|
|
30
|
-
|
|
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
|
-
|
|
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
|
-
|
|
53
|
-
|
|
54
|
-
|
|
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.
|
|
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
|
|
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, "
|
|
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
|
-
*
|
|
8
|
-
*
|
|
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
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
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 {
|