@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.
- package/CHANGELOG.md +19 -1
- package/README.md +21 -13
- package/assets/.agents/ACE/agent-qa/instructions.md +11 -0
- package/assets/agent-state/EVIDENCE_LOG.md +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/RUNTIME_TOOL_SPEC_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/agent-state/runtime-tool-specs.json +70 -2
- package/assets/instructions/ACE_Coder.instructions.md +13 -0
- package/assets/instructions/ACE_UI.instructions.md +11 -0
- package/assets/scripts/ace-hook-dispatch.mjs +70 -6
- package/assets/scripts/render-mcp-configs.sh +19 -5
- package/dist/ace-context.js +91 -11
- package/dist/ace-internal-tools.d.ts +3 -1
- package/dist/ace-internal-tools.js +10 -2
- package/dist/ace-server-instructions.js +3 -3
- package/dist/ace-state-resolver.js +5 -3
- package/dist/agent-runtime/role-adapters.d.ts +18 -1
- package/dist/agent-runtime/role-adapters.js +49 -5
- package/dist/astgrep-index.d.ts +57 -1
- package/dist/astgrep-index.js +140 -4
- package/dist/cli.js +232 -35
- package/dist/discovery-runtime-wrappers.d.ts +108 -0
- package/dist/discovery-runtime-wrappers.js +615 -0
- 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 +295 -0
- package/dist/helpers/drift.d.ts +13 -0
- package/dist/helpers/drift.js +45 -0
- package/dist/helpers/path-utils.d.ts +24 -0
- package/dist/helpers/path-utils.js +123 -0
- package/dist/helpers/store-resolution.d.ts +19 -0
- package/dist/helpers/store-resolution.js +305 -0
- package/dist/helpers/workspace-root.d.ts +3 -0
- package/dist/helpers/workspace-root.js +80 -0
- package/dist/helpers.d.ts +8 -125
- package/dist/helpers.js +8 -1768
- package/dist/job-scheduler.js +33 -7
- package/dist/json-sanitizer.d.ts +16 -0
- package/dist/json-sanitizer.js +26 -0
- package/dist/local-model-policy.d.ts +27 -0
- package/dist/local-model-policy.js +84 -0
- package/dist/local-model-runtime.d.ts +6 -0
- package/dist/local-model-runtime.js +33 -21
- package/dist/model-bridge.d.ts +13 -1
- package/dist/model-bridge.js +410 -23
- package/dist/orchestrator-supervisor.d.ts +56 -0
- package/dist/orchestrator-supervisor.js +179 -1
- package/dist/plan-proposal.d.ts +115 -0
- package/dist/plan-proposal.js +1073 -0
- 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 +20 -1
- package/dist/runtime-executor.js +737 -172
- package/dist/runtime-profile.d.ts +32 -0
- package/dist/runtime-profile.js +89 -13
- package/dist/runtime-tool-specs.d.ts +39 -0
- package/dist/runtime-tool-specs.js +144 -28
- package/dist/safe-edit.d.ts +7 -0
- package/dist/safe-edit.js +163 -37
- package/dist/schemas.js +48 -1
- package/dist/server.js +51 -0
- package/dist/shared.d.ts +3 -2
- package/dist/shared.js +2 -0
- 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 +2 -1
- package/dist/store/bootstrap-store.js +102 -83
- package/dist/store/cache-workspace.js +11 -5
- package/dist/store/materializers/context-snapshot-materializer.js +6 -2
- 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/repositories/vericify-repository.d.ts +1 -1
- 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.d.ts +20 -0
- package/dist/tools-agent.js +789 -25
- package/dist/tools-discovery.js +136 -1
- package/dist/tools-files.d.ts +7 -0
- package/dist/tools-files.js +1002 -11
- package/dist/tools-framework.js +105 -66
- 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/index.js +10 -1
- 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/tui/ollama.d.ts +8 -1
- package/dist/tui/ollama.js +53 -12
- package/dist/tui/openai-compatible.d.ts +13 -0
- package/dist/tui/openai-compatible.js +305 -5
- package/dist/tui/provider-discovery.d.ts +1 -0
- package/dist/tui/provider-discovery.js +35 -11
- package/dist/vericify-bridge.d.ts +6 -1
- 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
|
@@ -28,6 +28,9 @@ const ACE_CORE_FILES = [
|
|
|
28
28
|
"agent-state/SCOPE.md",
|
|
29
29
|
"agent-state/EVIDENCE_LOG.md",
|
|
30
30
|
];
|
|
31
|
+
const STORE_MAGIC = "ACEPACK1";
|
|
32
|
+
const STORE_HEADER_SIZE = 32;
|
|
33
|
+
const HOOK_CONTEXT_STORE_KEY = "state/runtime/hook_context";
|
|
31
34
|
|
|
32
35
|
const PROTECTED_PATH_FRAGMENTS = [
|
|
33
36
|
".github/hooks/",
|
|
@@ -114,9 +117,61 @@ function resolveAcePath(workspaceRoot, relativePath) {
|
|
|
114
117
|
return canonical;
|
|
115
118
|
}
|
|
116
119
|
|
|
120
|
+
function getWorkspaceStorePath(workspaceRoot) {
|
|
121
|
+
const canonical = resolve(workspaceRoot, "agent-state", "ace-state.ace");
|
|
122
|
+
if (existsSync(canonical)) return canonical;
|
|
123
|
+
return resolve(workspaceRoot, ACE_ROOT, "ace-state.ace");
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function readStoreUint64(buffer, offset) {
|
|
127
|
+
return buffer.readUInt32BE(offset) * 2 ** 32 + buffer.readUInt32BE(offset + 4);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function readStoreBlob(workspaceRoot, key) {
|
|
131
|
+
const storePath = getWorkspaceStorePath(workspaceRoot);
|
|
132
|
+
if (!existsSync(storePath)) return undefined;
|
|
133
|
+
try {
|
|
134
|
+
const file = readFileSync(storePath);
|
|
135
|
+
if (file.length < STORE_HEADER_SIZE) return undefined;
|
|
136
|
+
if (file.subarray(0, 8).toString("utf8") !== STORE_MAGIC) return undefined;
|
|
137
|
+
const indexOffset = readStoreUint64(file, 16);
|
|
138
|
+
const indexLength = readStoreUint64(file, 24);
|
|
139
|
+
const index = JSON.parse(file.subarray(indexOffset, indexOffset + indexLength).toString("utf8"));
|
|
140
|
+
const entry = index?.[key];
|
|
141
|
+
if (!entry || typeof entry.offset !== "number" || typeof entry.length !== "number") {
|
|
142
|
+
return undefined;
|
|
143
|
+
}
|
|
144
|
+
const start = entry.offset + 4;
|
|
145
|
+
const end = start + entry.length;
|
|
146
|
+
return file.subarray(start, end).toString("utf8");
|
|
147
|
+
} catch {
|
|
148
|
+
return undefined;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
117
152
|
function readIfPresent(workspaceRoot, relativePath) {
|
|
118
153
|
const absolute = resolveAcePath(workspaceRoot, relativePath);
|
|
119
|
-
if (!existsSync(absolute))
|
|
154
|
+
if (!existsSync(absolute)) {
|
|
155
|
+
const normalized = String(relativePath).replace(/\\/g, "/").replace(/^\.?\//, "");
|
|
156
|
+
const logicalPath = normalized.startsWith(`${ACE_ROOT}/`)
|
|
157
|
+
? normalized.slice(`${ACE_ROOT}/`.length)
|
|
158
|
+
: normalized;
|
|
159
|
+
const rel = logicalPath.startsWith("agent-state/") ? logicalPath.slice("agent-state/".length) : "";
|
|
160
|
+
const keys = [];
|
|
161
|
+
if (rel) {
|
|
162
|
+
keys.push(`state/artifacts/agent-state/${rel}`);
|
|
163
|
+
keys.push(`knowledge/agent-state/${rel}`);
|
|
164
|
+
if (rel === "ACE_WORKFLOW.md") {
|
|
165
|
+
keys.unshift("knowledge/runtime/ACE_WORKFLOW.md");
|
|
166
|
+
keys.push("knowledge/kernel/ACE_WORKFLOW.md");
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
for (const key of keys) {
|
|
170
|
+
const blob = readStoreBlob(workspaceRoot, key);
|
|
171
|
+
if (typeof blob === "string") return blob;
|
|
172
|
+
}
|
|
173
|
+
return undefined;
|
|
174
|
+
}
|
|
120
175
|
try {
|
|
121
176
|
return readFileSync(absolute, "utf8");
|
|
122
177
|
} catch {
|
|
@@ -203,12 +258,19 @@ function buildRoleToolHint(role) {
|
|
|
203
258
|
}
|
|
204
259
|
|
|
205
260
|
/**
|
|
206
|
-
* Try to read the store-
|
|
261
|
+
* Try to read the store-backed hook context snapshot.
|
|
207
262
|
* Returns the parsed snapshot or undefined if not present / unreadable.
|
|
208
|
-
* When present this is the single authoritative source; the dispatcher
|
|
209
|
-
* never needs to open the .ace store directly.
|
|
210
263
|
*/
|
|
211
264
|
function tryReadHookContextSnapshot(workspaceRoot) {
|
|
265
|
+
const storeRaw = readStoreBlob(workspaceRoot, HOOK_CONTEXT_STORE_KEY);
|
|
266
|
+
if (typeof storeRaw === "string") {
|
|
267
|
+
try {
|
|
268
|
+
const parsed = JSON.parse(storeRaw);
|
|
269
|
+
if (parsed?.schema_version === 1) return parsed;
|
|
270
|
+
} catch {
|
|
271
|
+
// Fall through to legacy file compatibility.
|
|
272
|
+
}
|
|
273
|
+
}
|
|
212
274
|
const snapshotPath = resolve(workspaceRoot, ACE_ROOT, "ace-hook-context.json");
|
|
213
275
|
if (!existsSync(snapshotPath)) return undefined;
|
|
214
276
|
try {
|
|
@@ -222,7 +284,7 @@ function tryReadHookContextSnapshot(workspaceRoot) {
|
|
|
222
284
|
}
|
|
223
285
|
|
|
224
286
|
function aceContext(workspaceRoot) {
|
|
225
|
-
// ── Fast path: store-
|
|
287
|
+
// ── Fast path: store-backed snapshot ────────────────────────────────────
|
|
226
288
|
const snapshot = tryReadHookContextSnapshot(workspaceRoot);
|
|
227
289
|
if (snapshot) {
|
|
228
290
|
const taskObjective = snapshot.task?.content
|
|
@@ -233,7 +295,9 @@ function aceContext(workspaceRoot) {
|
|
|
233
295
|
const scopeReminder = scopeLines.length
|
|
234
296
|
? `ACE scope reminder: ${truncate(scopeLines.slice(0, 4).join(" "), 220)}`
|
|
235
297
|
: undefined;
|
|
236
|
-
const hasAgentState =
|
|
298
|
+
const hasAgentState =
|
|
299
|
+
existsSync(resolve(workspaceRoot, ACE_ROOT, "agent-state")) ||
|
|
300
|
+
existsSync(resolve(workspaceRoot, "agent-state", "ace-state.ace"));
|
|
237
301
|
const hasSkills = existsSync(resolve(workspaceRoot, ACE_ROOT, "skills")) ||
|
|
238
302
|
existsSync(resolve(workspaceRoot, ".agents", "skills"));
|
|
239
303
|
return {
|
|
@@ -12,6 +12,9 @@ CURSOR_DIR="${ACE_ROOT}/.cursor"
|
|
|
12
12
|
VSCODE_DIR="${ACE_ROOT}/.vscode"
|
|
13
13
|
HOOK_COMMAND="node ./.agents/ACE/scripts/ace/ace-hook-dispatch.mjs"
|
|
14
14
|
HOOK_COMMAND_WINDOWS="node .\\\\.agents\\\\ACE\\\\scripts\\\\ace\\\\ace-hook-dispatch.mjs"
|
|
15
|
+
NODE_BIN_DIR="$(dirname -- "$(command -v node)")"
|
|
16
|
+
CLI_ENTRY="${WORKSPACE_ROOT}/dist/cli.js"
|
|
17
|
+
MCP_LAUNCH="export PATH=\"${NODE_BIN_DIR}:\$PATH\" && if ! command -v node >/dev/null 2>&1; then [ -s \"\$HOME/.zprofile\" ] && . \"\$HOME/.zprofile\"; [ -s \"\$HOME/.zshrc\" ] && . \"\$HOME/.zshrc\"; fi && cd \"${WORKSPACE_ROOT}\" && ACE_WORKSPACE_ROOT=\"${WORKSPACE_ROOT}\" node \"${CLI_ENTRY}\" mcp"
|
|
15
18
|
|
|
16
19
|
mkdir -p "${MCP_CONFIG_DIR}"
|
|
17
20
|
mkdir -p "${GITHUB_DIR}/hooks"
|
|
@@ -25,7 +28,18 @@ cat > "${MCP_CONFIG_DIR}/vscode.mcp.json" <<JSON
|
|
|
25
28
|
"ace-swarm": {
|
|
26
29
|
"type": "stdio",
|
|
27
30
|
"command": "/bin/zsh",
|
|
28
|
-
"args": ["-lc", "
|
|
31
|
+
"args": ["-lc", "${MCP_LAUNCH}"]
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
JSON
|
|
36
|
+
|
|
37
|
+
cat > "${WORKSPACE_ROOT}/.mcp.json" <<JSON
|
|
38
|
+
{
|
|
39
|
+
"mcpServers": {
|
|
40
|
+
"ace-swarm": {
|
|
41
|
+
"command": "/bin/zsh",
|
|
42
|
+
"args": ["-lc", "${MCP_LAUNCH}"]
|
|
29
43
|
}
|
|
30
44
|
}
|
|
31
45
|
}
|
|
@@ -36,7 +50,7 @@ cat > "${MCP_CONFIG_DIR}/cursor.mcp.json" <<JSON
|
|
|
36
50
|
"mcpServers": {
|
|
37
51
|
"ace-swarm": {
|
|
38
52
|
"command": "/bin/zsh",
|
|
39
|
-
"args": ["-lc", "
|
|
53
|
+
"args": ["-lc", "${MCP_LAUNCH}"]
|
|
40
54
|
}
|
|
41
55
|
}
|
|
42
56
|
}
|
|
@@ -47,7 +61,7 @@ cat > "${MCP_CONFIG_DIR}/claude_desktop_config.json" <<JSON
|
|
|
47
61
|
"mcpServers": {
|
|
48
62
|
"ace-swarm": {
|
|
49
63
|
"command": "/bin/zsh",
|
|
50
|
-
"args": ["-lc", "
|
|
64
|
+
"args": ["-lc", "${MCP_LAUNCH}"]
|
|
51
65
|
}
|
|
52
66
|
}
|
|
53
67
|
}
|
|
@@ -58,7 +72,7 @@ cat > "${MCP_CONFIG_DIR}/antigravity.mcp.json" <<JSON
|
|
|
58
72
|
"mcpServers": {
|
|
59
73
|
"ace-swarm": {
|
|
60
74
|
"command": "/bin/zsh",
|
|
61
|
-
"args": ["-lc", "
|
|
75
|
+
"args": ["-lc", "${MCP_LAUNCH}"]
|
|
62
76
|
}
|
|
63
77
|
}
|
|
64
78
|
}
|
|
@@ -68,7 +82,7 @@ cat > "${MCP_CONFIG_DIR}/codex.config.toml" <<TOML
|
|
|
68
82
|
# ACE instructions are scaffolded into .agents/ACE/AGENTS.md during bootstrap.
|
|
69
83
|
[mcp_servers.ace-swarm]
|
|
70
84
|
command = "/bin/zsh"
|
|
71
|
-
args = ["-lc", "
|
|
85
|
+
args = ["-lc", "${MCP_LAUNCH}"]
|
|
72
86
|
TOML
|
|
73
87
|
|
|
74
88
|
cat > "${ACE_ROOT}/CLAUDE.md" <<MD
|
package/dist/ace-context.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { buildAceContinuityPacket, buildAceRecallContext, formatAceContinuityPacketMarkdown, formatAceRecallMarkdown, normalizeAutonomyPolicy, normalizeContinuityPolicy, } from "./ace-autonomy.js";
|
|
2
2
|
import { listAceInternalToolCatalog, } from "./ace-internal-tools.js";
|
|
3
|
-
import { ALL_AGENTS, readAgentInstructions } from "./helpers.js";
|
|
3
|
+
import { ALL_AGENTS, listAvailableSkills, readAgentInstructions } from "./helpers.js";
|
|
4
4
|
import { readRuntimeProfileState, renderRuntimePrompt } from "./runtime-profile.js";
|
|
5
5
|
const ROLE_TOOL_DEFAULTS = {
|
|
6
6
|
orchestrator: [
|
|
@@ -22,9 +22,15 @@ const ROLE_TOOL_DEFAULTS = {
|
|
|
22
22
|
"emit_status_event",
|
|
23
23
|
],
|
|
24
24
|
coders: [
|
|
25
|
-
"
|
|
26
|
-
"
|
|
25
|
+
"outline_file",
|
|
26
|
+
"astgrep_query",
|
|
27
|
+
"astgrep_locate",
|
|
28
|
+
"read_file_lines",
|
|
29
|
+
"compile_structural_edit",
|
|
30
|
+
"preview_structural_edit",
|
|
31
|
+
"astgrep_rewrite",
|
|
27
32
|
"safe_edit_file",
|
|
33
|
+
"write_workspace_file",
|
|
28
34
|
"run_tests",
|
|
29
35
|
"git_diff",
|
|
30
36
|
"git_status",
|
|
@@ -91,8 +97,13 @@ export function renderAceContinuityPromptBlock(packet) {
|
|
|
91
97
|
return packet ? formatAceContinuityPacketMarkdown(packet) : "";
|
|
92
98
|
}
|
|
93
99
|
function keywordScore(task, tool) {
|
|
94
|
-
const
|
|
95
|
-
|
|
100
|
+
const name = typeof tool?.name === "string" ? tool.name : String(tool?.name ?? "");
|
|
101
|
+
const desc = typeof tool?.description === "string" ? tool.description : String(tool?.description ?? "");
|
|
102
|
+
const inputs = Array.isArray(tool?.input_keys) ? tool.input_keys.join(" ") : "";
|
|
103
|
+
const haystack = `${name} ${desc} ${inputs}`.toLowerCase();
|
|
104
|
+
if (!task)
|
|
105
|
+
return 0;
|
|
106
|
+
return String(task)
|
|
96
107
|
.toLowerCase()
|
|
97
108
|
.split(/[^a-z0-9_]+/)
|
|
98
109
|
.filter((token) => token.length > 2)
|
|
@@ -107,17 +118,26 @@ function selectToolCount(tier) {
|
|
|
107
118
|
}
|
|
108
119
|
function scopeTools(role, task, tier, explicitTools) {
|
|
109
120
|
const catalog = listAceInternalToolCatalog();
|
|
110
|
-
if (explicitTools
|
|
121
|
+
if (Array.isArray(explicitTools)) {
|
|
122
|
+
if (explicitTools.length === 0) {
|
|
123
|
+
return [];
|
|
124
|
+
}
|
|
111
125
|
const explicitSet = new Set(explicitTools);
|
|
112
126
|
return catalog.filter((tool) => explicitSet.has(tool.name));
|
|
113
127
|
}
|
|
114
|
-
const
|
|
128
|
+
const defaultTools = ROLE_TOOL_DEFAULTS[role.trim().toLowerCase()] ?? [];
|
|
129
|
+
const roleDefaults = new Set(defaultTools);
|
|
130
|
+
const rolePriority = new Map(defaultTools.map((name, index) => [name, index]));
|
|
115
131
|
const ranked = catalog
|
|
116
132
|
.map((tool) => ({
|
|
117
133
|
tool,
|
|
118
134
|
score: (roleDefaults.has(tool.name) ? 5 : 0) + keywordScore(task, tool),
|
|
119
135
|
}))
|
|
120
|
-
.sort((left, right) =>
|
|
136
|
+
.sort((left, right) => (roleDefaults.has(left.tool.name) && roleDefaults.has(right.tool.name)
|
|
137
|
+
? (rolePriority.get(left.tool.name) ?? 999) - (rolePriority.get(right.tool.name) ?? 999)
|
|
138
|
+
: right.score - left.score) ||
|
|
139
|
+
right.score - left.score ||
|
|
140
|
+
left.tool.name.localeCompare(right.tool.name))
|
|
121
141
|
.slice(0, selectToolCount(tier))
|
|
122
142
|
.map((entry) => entry.tool);
|
|
123
143
|
if (ranked.length > 0 && ranked.some((tool) => roleDefaults.has(tool.name))) {
|
|
@@ -130,7 +150,7 @@ function renderToolCatalogMarkdown(tools, tier) {
|
|
|
130
150
|
return tools
|
|
131
151
|
.map((tool) => {
|
|
132
152
|
const parts = [`- \`${tool.name}\` — ${tool.description || "ACE MCP tool"}`];
|
|
133
|
-
if (includeInputs && tool.input_keys.length > 0) {
|
|
153
|
+
if (includeInputs && Array.isArray(tool.input_keys) && tool.input_keys.length > 0) {
|
|
134
154
|
parts.push(` - input keys: ${tool.input_keys.join(", ")}`);
|
|
135
155
|
}
|
|
136
156
|
return parts.join("\n");
|
|
@@ -156,9 +176,27 @@ function buildPlanningCatalog(role, task, tier) {
|
|
|
156
176
|
.slice(0, limit)
|
|
157
177
|
.map((entry) => entry.tool);
|
|
158
178
|
}
|
|
179
|
+
function inferRelevantSkills(task) {
|
|
180
|
+
const lowered = String(task ?? "").toLowerCase();
|
|
181
|
+
const skillSignals = [
|
|
182
|
+
{ name: "state-auditor", pattern: /\b(state|drift|authority|audit)\b/ },
|
|
183
|
+
{ name: "handoff-lint", pattern: /\b(handoff|transition|payload)\b/ },
|
|
184
|
+
{ name: "schema-forge", pattern: /\b(schema|contract|interface)\b/ },
|
|
185
|
+
{ name: "release-sentry", pattern: /\b(ship|release|promotion|rollback)\b/ },
|
|
186
|
+
{ name: "risk-quant", pattern: /\b(risk|blocker|severity)\b/ },
|
|
187
|
+
{ name: "eval-harness", pattern: /\b(eval|regression|verify|validation)\b/ },
|
|
188
|
+
{ name: "incident-commander", pattern: /\b(incident|outage|blocker storm)\b/ },
|
|
189
|
+
{ name: "problem-triage", pattern: /\b(triage|classify|scope)\b/ },
|
|
190
|
+
];
|
|
191
|
+
const available = new Set(listAvailableSkills().map((skill) => skill.name));
|
|
192
|
+
return skillSignals
|
|
193
|
+
.filter((signal) => signal.pattern.test(lowered) && available.has(signal.name))
|
|
194
|
+
.map((signal) => signal.name);
|
|
195
|
+
}
|
|
159
196
|
export function buildToolPlan(options) {
|
|
160
197
|
const tier = options.tier ?? "compressed";
|
|
161
|
-
const
|
|
198
|
+
const explicitToolsProvided = Array.isArray(options.tools);
|
|
199
|
+
const catalog = explicitToolsProvided
|
|
162
200
|
? listAceInternalToolCatalog().filter((tool) => options.tools?.includes(tool.name))
|
|
163
201
|
: buildPlanningCatalog(options.role, options.task, tier);
|
|
164
202
|
const recommended = scopeTools(options.role, options.task, tier, options.tools).map((tool) => tool.name);
|
|
@@ -185,6 +223,42 @@ export function buildToolPlan(options) {
|
|
|
185
223
|
selection_limit: selectionLimit,
|
|
186
224
|
};
|
|
187
225
|
}
|
|
226
|
+
/**
|
|
227
|
+
* Per-role negative output-shape guardrails injected into the system prompt.
|
|
228
|
+
* These complement the shared "## Output Contract" block with role-specific drift constraints.
|
|
229
|
+
*
|
|
230
|
+
* - coders/builder: bridge response must be a JSON envelope; they CAN write HTML/code via tools.
|
|
231
|
+
* - vos/ui: primary output is prose; snippets are fine inline but full HTML docs are not their job.
|
|
232
|
+
*/
|
|
233
|
+
const ROLE_OUTPUT_SHAPE_GUARDRAILS = {
|
|
234
|
+
coders: [
|
|
235
|
+
"- Your bridge response MUST be a JSON envelope (status: tool, complete, etc.) — do not send raw prose as your top-level reply.",
|
|
236
|
+
"- For code mutation, default to astgrep_locate -> compile_structural_edit -> preview_structural_edit -> astgrep_rewrite(plan_id).",
|
|
237
|
+
"- Use write_workspace_file for new files, generated non-code artifacts, or explicit structural_edit_waiver cases only.",
|
|
238
|
+
"- If you bypass the structural lane for code, state the waiver reason and provide evidence_refs.",
|
|
239
|
+
"- Do NOT echo the task description or expected artifact shape as your response without executing via tool calls.",
|
|
240
|
+
"- If you are writing files, call the write tool first, then close with status:complete and evidence_refs.",
|
|
241
|
+
],
|
|
242
|
+
builder: [
|
|
243
|
+
"- Your bridge response MUST be a JSON envelope — raw prose as the top-level reply is a contract violation.",
|
|
244
|
+
"- For code mutation, default to astgrep_locate -> compile_structural_edit -> preview_structural_edit -> astgrep_rewrite(plan_id).",
|
|
245
|
+
"- Use write_workspace_file for new files, generated non-code artifacts, or explicit structural_edit_waiver cases only.",
|
|
246
|
+
"- If you bypass the structural lane for code, state the waiver reason and provide evidence_refs.",
|
|
247
|
+
"- Do NOT echo the artifact shape without executing the build step via tool calls.",
|
|
248
|
+
"- File content (code, HTML, configs) belongs inside tool calls, not in raw text output.",
|
|
249
|
+
"- If you are writing files, close with status:complete and evidence_refs after the write tool succeeds.",
|
|
250
|
+
],
|
|
251
|
+
vos: [
|
|
252
|
+
"- Your primary output is prose. Inline code snippets or JSON examples are acceptable when illustrating a point.",
|
|
253
|
+
"- Do NOT produce a full HTML document or a raw JSON structure as your main deliverable.",
|
|
254
|
+
"- You are a planning and narrative role; do not attempt to write files or persist artifacts directly.",
|
|
255
|
+
],
|
|
256
|
+
ui: [
|
|
257
|
+
"- Your primary output is prose. You may reference or sketch HTML snippets inline as examples.",
|
|
258
|
+
"- Do NOT produce a full HTML document as your response — HTML authoring is the coders role's job.",
|
|
259
|
+
"- Do not emit large raw JSON blobs as your main output; summarize or reference them instead.",
|
|
260
|
+
],
|
|
261
|
+
};
|
|
188
262
|
export function renderAceContext(options) {
|
|
189
263
|
const tier = options.tier ?? "compressed";
|
|
190
264
|
const active = readRuntimeProfileState();
|
|
@@ -211,6 +285,7 @@ export function renderAceContext(options) {
|
|
|
211
285
|
const roleInstructions = resolveRoleInstructions(options.role);
|
|
212
286
|
const toolCatalog = renderToolCatalogMarkdown(tools, tier);
|
|
213
287
|
const stateDigest = recall.task_contract.summary;
|
|
288
|
+
const relevantSkills = inferRelevantSkills(options.task);
|
|
214
289
|
const systemPrompt = [
|
|
215
290
|
runtimePrompt,
|
|
216
291
|
"",
|
|
@@ -223,17 +298,22 @@ export function renderAceContext(options) {
|
|
|
223
298
|
"## Tool Scope",
|
|
224
299
|
toolCatalog || "- No ACE tools available.",
|
|
225
300
|
"",
|
|
301
|
+
"## Relevant Skills",
|
|
302
|
+
relevantSkills.length > 0 ? `- ${relevantSkills.join(", ")}` : "- No task-specific skill hint matched.",
|
|
303
|
+
"",
|
|
226
304
|
"## Compact Guardrails",
|
|
227
305
|
"- Stop if you are about to claim tested, verified, or passed without evidence.",
|
|
228
306
|
"- If ACE state is thin or contradictory, call recall_context or validate_framework before improvising.",
|
|
229
307
|
"- For obviously multi-step work, prefer run_orchestrator over a single free-form answer.",
|
|
308
|
+
"- When you mutate workspace, use the smallest safe mutation lane: structural edit for existing code, write_workspace_file for new/generated artifacts; never assert file creation in prose alone.",
|
|
230
309
|
"- Do not declare completion while approval, retry, or blocker state remains active.",
|
|
310
|
+
...(ROLE_OUTPUT_SHAPE_GUARDRAILS[options.role.trim().toLowerCase()] ?? []),
|
|
231
311
|
"",
|
|
232
312
|
"## Output Contract",
|
|
233
313
|
'Respond in JSON only with one of these shapes:',
|
|
234
314
|
'- `{"status":"tool","thinking":"...","tool_calls":[{"tool":"name","input":{}}]}`',
|
|
235
315
|
'- `{"status":"message","thinking":"...","message":"..."}`',
|
|
236
|
-
'- `{"status":"complete","thinking":"...","summary":"..."}`',
|
|
316
|
+
'- `{"status":"complete","thinking":"...","summary":"...","evidence_refs":["agent-state/..."]}`',
|
|
237
317
|
'- `{"status":"need_input","thinking":"...","message":"..."}`',
|
|
238
318
|
].join("\n");
|
|
239
319
|
return {
|
|
@@ -4,5 +4,7 @@ export interface AceInternalToolCatalogEntry {
|
|
|
4
4
|
input_keys: string[];
|
|
5
5
|
}
|
|
6
6
|
export declare function listAceInternalToolCatalog(): AceInternalToolCatalogEntry[];
|
|
7
|
-
export declare function executeAceInternalTool(name: string, input: Record<string, unknown> | undefined, sessionId?: string
|
|
7
|
+
export declare function executeAceInternalTool(name: string, input: Record<string, unknown> | undefined, sessionId?: string, options?: {
|
|
8
|
+
workspace_path?: string;
|
|
9
|
+
}): Promise<any>;
|
|
8
10
|
//# sourceMappingURL=ace-internal-tools.d.ts.map
|
|
@@ -42,7 +42,7 @@ export function listAceInternalToolCatalog() {
|
|
|
42
42
|
}))
|
|
43
43
|
.sort((left, right) => left.name.localeCompare(right.name));
|
|
44
44
|
}
|
|
45
|
-
export async function executeAceInternalTool(name, input, sessionId) {
|
|
45
|
+
export async function executeAceInternalTool(name, input, sessionId, options = {}) {
|
|
46
46
|
const tool = getRegistry()[name];
|
|
47
47
|
if (!tool || !tool.enabled) {
|
|
48
48
|
return {
|
|
@@ -50,8 +50,16 @@ export async function executeAceInternalTool(name, input, sessionId) {
|
|
|
50
50
|
isError: true,
|
|
51
51
|
};
|
|
52
52
|
}
|
|
53
|
+
const inputWithContext = options.workspace_path && name === "write_workspace_file"
|
|
54
|
+
? {
|
|
55
|
+
...(input ?? {}),
|
|
56
|
+
workspace_path: typeof input?.workspace_path === "string" && input.workspace_path.trim()
|
|
57
|
+
? input.workspace_path
|
|
58
|
+
: options.workspace_path,
|
|
59
|
+
}
|
|
60
|
+
: input;
|
|
53
61
|
const parsedInput = tool.inputSchema
|
|
54
|
-
? tool.inputSchema.safeParse(
|
|
62
|
+
? tool.inputSchema.safeParse(inputWithContext ?? {})
|
|
55
63
|
: { success: true, data: undefined };
|
|
56
64
|
if (!parsedInput.success) {
|
|
57
65
|
const errorText = parsedInput.error.issues
|
|
@@ -229,10 +229,10 @@ export function buildHostInstructionText(host, workspaceRoot) {
|
|
|
229
229
|
"3. Prefer ACE prompts/resources (`ace-orchestrator`, `get_task_pack`, `get_skill_instructions`) over relying on this file.",
|
|
230
230
|
"",
|
|
231
231
|
"Ground truth:",
|
|
232
|
-
"- `agent-state/*` is the
|
|
233
|
-
"-
|
|
232
|
+
"- `agent-state/*` is the visible runtime state surface for this workspace.",
|
|
233
|
+
"- `agent-state/ace-state.ace` is the canonical store path; legacy nested store layouts are compatibility fallback only.",
|
|
234
234
|
"- `.agents/ACE/tasks/todo.md` is the human-facing todo surface.",
|
|
235
|
-
"-
|
|
235
|
+
"- Hook context is store-backed in `agent-state/ace-state.ace` and consumed without extra workspace projections.",
|
|
236
236
|
"",
|
|
237
237
|
`Workspace digest hint: ${buildAceDigest(workspaceRoot)}.`,
|
|
238
238
|
].join("\n");
|
|
@@ -95,9 +95,11 @@ export function resolveAceStateLayout(workspaceRoot) {
|
|
|
95
95
|
scopePath: resolveAceLogicalPath(workspaceRoot, "agent-state/SCOPE.md"),
|
|
96
96
|
evidencePath: resolveAceLogicalPath(workspaceRoot, "agent-state/EVIDENCE_LOG.md"),
|
|
97
97
|
storePath: storePresent ? storePath : undefined,
|
|
98
|
-
hookSnapshotPath:
|
|
99
|
-
?
|
|
100
|
-
:
|
|
98
|
+
hookSnapshotPath: readStoreBlobSync(workspaceRoot, "state/runtime/hook_context") != null
|
|
99
|
+
? toVirtualStorePath(storePath, "state/runtime/hook_context")
|
|
100
|
+
: existsSync(nestedAcePath(workspaceRoot, "ace-hook-context.json"))
|
|
101
|
+
? nestedAcePath(workspaceRoot, "ace-hook-context.json")
|
|
102
|
+
: undefined,
|
|
101
103
|
isAcePresent: physicalMode !== "missing" ||
|
|
102
104
|
CRITICAL_LOGICAL_PATHS.some((relativePath) => typeof readAceLogicalFile(workspaceRoot, relativePath) === "string"),
|
|
103
105
|
missingCriticalArtifacts,
|
|
@@ -21,9 +21,26 @@ export interface AdapterDecision {
|
|
|
21
21
|
domain: AdapterDomain;
|
|
22
22
|
confidence: number;
|
|
23
23
|
confidenceLevel: "low" | "medium" | "high";
|
|
24
|
+
preflight?: AcePreflightPacket;
|
|
25
|
+
}
|
|
26
|
+
export interface AcePreflightPacket {
|
|
27
|
+
required: boolean;
|
|
28
|
+
status: "passed" | "attention_required" | "blocked";
|
|
29
|
+
summary: string;
|
|
30
|
+
evidence_refs: string[];
|
|
31
|
+
model_visible_tools: ToolIntent[];
|
|
24
32
|
}
|
|
25
33
|
export declare function inferDomain(input: string): AdapterDomain;
|
|
26
34
|
export declare function parseManualHandoffCommand(input: string): HandoffIntent | undefined;
|
|
27
35
|
export declare function parseManualToolCommand(input: string): ToolIntent | undefined;
|
|
28
|
-
export declare function
|
|
36
|
+
export declare function buildAcePreflightPacket(input: {
|
|
37
|
+
role: string;
|
|
38
|
+
model_class?: "frontier" | "mid" | "small_local";
|
|
39
|
+
text: string;
|
|
40
|
+
domain: AdapterDomain;
|
|
41
|
+
preflight_required: boolean;
|
|
42
|
+
}): AcePreflightPacket;
|
|
43
|
+
export declare function planRoleExecution(roleValue: string, input: string, options?: {
|
|
44
|
+
model_class?: "frontier" | "mid" | "small_local";
|
|
45
|
+
}): AdapterDecision;
|
|
29
46
|
//# sourceMappingURL=role-adapters.d.ts.map
|
|
@@ -273,7 +273,31 @@ function buildCreateHandoffIntent(fromRole, toRole, input) {
|
|
|
273
273
|
},
|
|
274
274
|
};
|
|
275
275
|
}
|
|
276
|
-
export function
|
|
276
|
+
export function buildAcePreflightPacket(input) {
|
|
277
|
+
const routeIntent = { tool: "route_task", args: { description: input.text, domain: input.domain } };
|
|
278
|
+
const smallLocalOrchestrator = input.role === "orchestrator" && input.model_class === "small_local";
|
|
279
|
+
return {
|
|
280
|
+
required: input.preflight_required,
|
|
281
|
+
status: input.preflight_required ? "attention_required" : "passed",
|
|
282
|
+
summary: smallLocalOrchestrator
|
|
283
|
+
? "ACE-owned preflight covers recall_context, validate_framework, and get_framework_status before model dispatch."
|
|
284
|
+
: "Adapter preflight remains model-visible for this caller.",
|
|
285
|
+
evidence_refs: [
|
|
286
|
+
"agent-state/TASK.md",
|
|
287
|
+
"agent-state/STATUS.md",
|
|
288
|
+
"agent-state/QUALITY_GATES.md",
|
|
289
|
+
],
|
|
290
|
+
model_visible_tools: smallLocalOrchestrator
|
|
291
|
+
? [routeIntent]
|
|
292
|
+
: [
|
|
293
|
+
{ tool: "recall_context", args: {} },
|
|
294
|
+
{ tool: "validate_framework", args: {} },
|
|
295
|
+
{ tool: "get_framework_status", args: {} },
|
|
296
|
+
routeIntent,
|
|
297
|
+
],
|
|
298
|
+
};
|
|
299
|
+
}
|
|
300
|
+
export function planRoleExecution(roleValue, input, options = {}) {
|
|
277
301
|
const normalizedRole = canonicalizeRole(roleValue);
|
|
278
302
|
const text = input.toLowerCase();
|
|
279
303
|
const domainScore = scoreDomain(input);
|
|
@@ -316,10 +340,17 @@ export function planRoleExecution(roleValue, input) {
|
|
|
316
340
|
domainScore.confidenceLevel === "low" ||
|
|
317
341
|
contradictoryStateRequested ||
|
|
318
342
|
aceStateRequested;
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
343
|
+
const preflight = buildAcePreflightPacket({
|
|
344
|
+
role: normalizedRole,
|
|
345
|
+
model_class: options.model_class,
|
|
346
|
+
text: input,
|
|
347
|
+
domain,
|
|
348
|
+
preflight_required: preflightRequired,
|
|
349
|
+
});
|
|
350
|
+
toolCalls.push(...preflight.model_visible_tools);
|
|
351
|
+
if (options.model_class === "small_local") {
|
|
352
|
+
notes.push(preflight.summary);
|
|
353
|
+
}
|
|
323
354
|
if (preflightRequired) {
|
|
324
355
|
toolCalls.push({ tool: "execute_gates", args: {} });
|
|
325
356
|
notes.push("Orchestrator preflight required before dispatch.");
|
|
@@ -568,6 +599,19 @@ export function planRoleExecution(roleValue, input) {
|
|
|
568
599
|
domain,
|
|
569
600
|
confidence: domainScore.confidence,
|
|
570
601
|
confidenceLevel: domainScore.confidenceLevel,
|
|
602
|
+
preflight: normalizedRole === "orchestrator"
|
|
603
|
+
? buildAcePreflightPacket({
|
|
604
|
+
role: normalizedRole,
|
|
605
|
+
model_class: options.model_class,
|
|
606
|
+
text: input,
|
|
607
|
+
domain,
|
|
608
|
+
preflight_required: dispatchRequested ||
|
|
609
|
+
domainScore.ambiguous ||
|
|
610
|
+
domainScore.confidenceLevel === "low" ||
|
|
611
|
+
contradictoryStateRequested ||
|
|
612
|
+
aceStateRequested,
|
|
613
|
+
})
|
|
614
|
+
: undefined,
|
|
571
615
|
};
|
|
572
616
|
}
|
|
573
617
|
//# sourceMappingURL=role-adapters.js.map
|
package/dist/astgrep-index.d.ts
CHANGED
|
@@ -1,3 +1,57 @@
|
|
|
1
|
+
interface AstGrepMatch {
|
|
2
|
+
file?: string;
|
|
3
|
+
text?: string;
|
|
4
|
+
range?: {
|
|
5
|
+
start?: {
|
|
6
|
+
line?: number;
|
|
7
|
+
column?: number;
|
|
8
|
+
};
|
|
9
|
+
end?: {
|
|
10
|
+
line?: number;
|
|
11
|
+
column?: number;
|
|
12
|
+
};
|
|
13
|
+
};
|
|
14
|
+
metaVariables?: Record<string, unknown>;
|
|
15
|
+
kind?: string;
|
|
16
|
+
nodeKind?: string;
|
|
17
|
+
}
|
|
18
|
+
export interface AstgrepMatch {
|
|
19
|
+
file: string;
|
|
20
|
+
line: number;
|
|
21
|
+
column: number;
|
|
22
|
+
text: string;
|
|
23
|
+
context_lines?: string[];
|
|
24
|
+
}
|
|
25
|
+
export interface AstgrepLocateInput {
|
|
26
|
+
pattern: string;
|
|
27
|
+
lang: string;
|
|
28
|
+
scope?: string;
|
|
29
|
+
symbol_hint?: string;
|
|
30
|
+
max_results?: number;
|
|
31
|
+
}
|
|
32
|
+
export interface AstgrepLocatedMatch {
|
|
33
|
+
match_id: string;
|
|
34
|
+
file: string;
|
|
35
|
+
range: NonNullable<AstGrepMatch["range"]>;
|
|
36
|
+
text_preview: string;
|
|
37
|
+
matched_text: string;
|
|
38
|
+
captures?: Record<string, string>;
|
|
39
|
+
node_kind?: string;
|
|
40
|
+
file_hash: string;
|
|
41
|
+
}
|
|
42
|
+
export interface AstgrepLocateResult {
|
|
43
|
+
ok: boolean;
|
|
44
|
+
pattern: string;
|
|
45
|
+
lang: string;
|
|
46
|
+
scope: string;
|
|
47
|
+
symbol_hint?: string;
|
|
48
|
+
astgrep_command: string | null;
|
|
49
|
+
total_matches: number;
|
|
50
|
+
matches: AstgrepLocatedMatch[];
|
|
51
|
+
error?: string;
|
|
52
|
+
}
|
|
53
|
+
export declare function runAstgrepQuery(pattern: string, lang: string, roots: string[], _contextLines?: number): AstgrepMatch[];
|
|
54
|
+
export declare function locateAstgrepMatches(input: AstgrepLocateInput): AstgrepLocateResult;
|
|
1
55
|
export interface RefreshAstgrepIndexInput {
|
|
2
56
|
scope?: string;
|
|
3
57
|
append_evidence?: boolean;
|
|
@@ -20,5 +74,7 @@ export interface RefreshAstgrepIndexResult {
|
|
|
20
74
|
todo_signals: number;
|
|
21
75
|
};
|
|
22
76
|
}
|
|
23
|
-
export declare function
|
|
77
|
+
export declare function detectAstgrepCommand(): string | null;
|
|
78
|
+
export declare function refreshAstgrepIndex(input?: RefreshAstgrepIndexInput): Promise<RefreshAstgrepIndexResult>;
|
|
79
|
+
export {};
|
|
24
80
|
//# sourceMappingURL=astgrep-index.d.ts.map
|