@voybio/ace-swarm 2.4.8 → 2.4.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +52 -14
- package/README.md +14 -10
- package/assets/.agents/ACE/ACE_coders/AGENTS.md +23 -30
- package/assets/.agents/ACE/ACE_coders/INSTRUCTIONS.md +21 -30
- package/assets/.agents/skills/landing-review-watcher/SKILL.md +1 -1
- package/assets/.agents/skills/learn-from-work/SKILL.md +41 -0
- package/assets/agent-state/ACE_WORKFLOW.md +25 -2
- package/assets/agent-state/MODULES/schemas/ACE_RUNTIME_PROFILE.schema.json +143 -2
- package/assets/agent-state/MODULES/schemas/RUNTIME_EXECUTOR_SESSION_REGISTRY.schema.json +2 -2
- package/assets/agent-state/MODULES/schemas/SWARM_HANDOFF.schema.json +10 -0
- package/assets/eval-battery/battery.json +1 -1
- package/assets/instructions/ACE_Coder.instructions.md +9 -13
- package/assets/scripts/ace-hook-dispatch.mjs +16 -411
- package/assets/tasks/SWARM_HANDOFF.example_ui_to_coders.json +1 -2
- package/assets/vendor/README.md +9 -0
- package/assets/vendor/vericify-reader.mjs +272 -0
- package/assets/vendor/vericify-reader.provenance.json +10 -0
- package/dist/ace-autonomy.d.ts +58 -0
- package/dist/ace-autonomy.js +211 -6
- package/dist/ace-internal-tools.d.ts +1 -0
- package/dist/ace-internal-tools.js +3 -3
- package/dist/ace-server-instructions.d.ts +3 -3
- package/dist/ace-server-instructions.js +46 -192
- package/dist/cli.js +44 -6
- package/dist/experience-reflector.d.ts +7 -0
- package/dist/experience-reflector.js +39 -0
- package/dist/goal-engine.d.ts +64 -7
- package/dist/goal-engine.js +197 -41
- package/dist/handoff-registry.d.ts +10 -0
- package/dist/handoff-registry.js +59 -0
- package/dist/helpers/artifacts.d.ts +6 -2
- package/dist/helpers/artifacts.js +8 -6
- package/dist/helpers/bootstrap.js +13 -20
- package/dist/helpers/path-utils.js +2 -0
- package/dist/helpers/store-resolution.js +18 -3
- package/dist/helpers/workspace-root.d.ts +2 -0
- package/dist/helpers/workspace-root.js +9 -0
- package/dist/helpers.d.ts +1 -0
- package/dist/helpers.js +1 -0
- package/dist/hermes/bridge-protocol.d.ts +1 -1
- package/dist/hermes/session-manager.d.ts +17 -0
- package/dist/hermes/session-manager.js +67 -14
- package/dist/host-goal-engine.d.ts +138 -0
- package/dist/host-goal-engine.js +793 -0
- package/dist/host-goal-status.d.ts +113 -0
- package/dist/host-goal-status.js +175 -0
- package/dist/host-learning.d.ts +68 -0
- package/dist/host-learning.js +115 -0
- package/dist/host-observation.d.ts +12 -0
- package/dist/host-observation.js +91 -0
- package/dist/host-plan-revision.d.ts +14 -0
- package/dist/host-plan-revision.js +101 -0
- package/dist/host-verification-job.d.ts +12 -0
- package/dist/host-verification-job.js +183 -0
- package/dist/host-work-context.d.ts +12 -0
- package/dist/host-work-context.js +8 -0
- package/dist/job-scheduler.d.ts +58 -13
- package/dist/job-scheduler.js +298 -48
- package/dist/job-worker.d.ts +3 -1
- package/dist/job-worker.js +10 -3
- package/dist/kanban.d.ts +4 -1
- package/dist/kanban.js +44 -16
- package/dist/learned-artifacts.d.ts +64 -0
- package/dist/learned-artifacts.js +321 -0
- package/dist/learning-controls.d.ts +142 -0
- package/dist/learning-controls.js +135 -0
- package/dist/learning-input-context.d.ts +9 -0
- package/dist/learning-input-context.js +62 -0
- package/dist/learning-lifecycle.d.ts +10 -0
- package/dist/learning-lifecycle.js +11 -0
- package/dist/learning-overlays.d.ts +3 -0
- package/dist/learning-overlays.js +17 -0
- package/dist/learning-policy.d.ts +40 -0
- package/dist/learning-policy.js +38 -0
- package/dist/learning-records.d.ts +35 -0
- package/dist/learning-records.js +17 -0
- package/dist/learning-scorecard.d.ts +82 -0
- package/dist/learning-scorecard.js +86 -0
- package/dist/learning-serving.d.ts +29 -0
- package/dist/learning-serving.js +134 -0
- package/dist/linked-work.d.ts +9 -0
- package/dist/linked-work.js +28 -0
- package/dist/local-model-runtime.js +1 -1
- package/dist/mcp-command-progress.d.ts +16 -0
- package/dist/mcp-command-progress.js +70 -0
- package/dist/model-bridge.d.ts +14 -13
- package/dist/model-bridge.js +73 -41
- package/dist/orchestrator-supervisor.d.ts +111 -6
- package/dist/orchestrator-supervisor.js +67 -43
- package/dist/plan-proposal.js +3 -3
- package/dist/playbook-curator.d.ts +1 -0
- package/dist/playbook-curator.js +11 -9
- package/dist/process-identity.d.ts +8 -0
- package/dist/process-identity.js +38 -0
- package/dist/progress-command.d.ts +34 -0
- package/dist/progress-command.js +153 -0
- package/dist/prompts.js +15 -15
- package/dist/resources.js +2 -2
- package/dist/runtime-command.d.ts +8 -1
- package/dist/runtime-command.js +48 -7
- package/dist/runtime-executor.js +33 -11
- package/dist/runtime-profile-syntax.d.ts +6 -0
- package/dist/runtime-profile-syntax.js +121 -0
- package/dist/runtime-profile.d.ts +37 -5
- package/dist/runtime-profile.js +36 -129
- package/dist/runtime-tool-specs.js +1 -1
- package/dist/safe-edit.d.ts +7 -3
- package/dist/safe-edit.js +40 -47
- package/dist/schemas.js +4 -2
- package/dist/server.d.ts +2 -16
- package/dist/server.js +14 -20
- package/dist/shared.d.ts +2 -0
- package/dist/shared.js +2 -0
- package/dist/skill-auditor.d.ts +19 -0
- package/dist/skill-auditor.js +32 -2
- package/dist/skill-catalog.d.ts +4 -1
- package/dist/skill-catalog.js +6 -5
- package/dist/store/ace-packed-store.d.ts +5 -1
- package/dist/store/ace-packed-store.js +33 -1
- package/dist/store/bootstrap-store.js +19 -12
- package/dist/store/cache-workspace.d.ts +8 -0
- package/dist/store/cache-workspace.js +94 -27
- package/dist/store/importer.js +11 -20
- package/dist/store/knowledge-bake.d.ts +3 -1
- package/dist/store/knowledge-bake.js +10 -1
- package/dist/store/legacy-vericify-posts.d.ts +8 -0
- package/dist/store/legacy-vericify-posts.js +76 -0
- package/dist/store/materializers/hook-context-materializer.d.ts +2 -1
- package/dist/store/materializers/hook-context-materializer.js +6 -2
- package/dist/store/materializers/host-file-materializer.js +2 -2
- package/dist/store/materializers/projection-manager.d.ts +4 -1
- package/dist/store/materializers/projection-manager.js +10 -3
- package/dist/store/materializers/todo-syncer.d.ts +39 -20
- package/dist/store/materializers/todo-syncer.js +208 -110
- package/dist/store/materializers/vericify-projector.js +15 -26
- package/dist/store/repositories/goal-repository.d.ts +51 -2
- package/dist/store/repositories/goal-repository.js +114 -48
- package/dist/store/repositories/playbook-repository.d.ts +41 -3
- package/dist/store/repositories/playbook-repository.js +61 -5
- package/dist/store/repositories/todo-repository.d.ts +8 -2
- package/dist/store/repositories/todo-repository.js +1 -1
- package/dist/store/repositories/vericify-repository.d.ts +4 -0
- package/dist/store/repositories/vericify-repository.js +46 -0
- package/dist/store/skills-install.d.ts +1 -0
- package/dist/store/skills-install.js +20 -16
- package/dist/store/source-preservation.d.ts +24 -0
- package/dist/store/source-preservation.js +79 -0
- package/dist/store/store-artifacts.js +8 -1
- package/dist/store/test-write-boundary.d.ts +16 -0
- package/dist/store/test-write-boundary.js +175 -0
- package/dist/store/types.d.ts +5 -1
- package/dist/store/write-coordinator.js +16 -0
- package/dist/task-plan-context.d.ts +11 -0
- package/dist/task-plan-context.js +59 -0
- package/dist/todo-state.d.ts +19 -9
- package/dist/todo-state.js +204 -321
- package/dist/tools-agent.d.ts +1 -1
- package/dist/tools-agent.js +38 -62
- package/dist/tools-files.d.ts +0 -3
- package/dist/tools-files.js +21 -11
- package/dist/tools-framework.js +16 -25
- package/dist/tools-goal.d.ts +2 -4
- package/dist/tools-goal.js +119 -16
- package/dist/tools-handoff.d.ts +3 -2
- package/dist/tools-handoff.js +53 -23
- package/dist/tools-lifecycle.js +1 -1
- package/dist/tools-memory.d.ts +0 -3
- package/dist/tools-memory.js +51 -6
- package/dist/tools-scheduler.js +20 -17
- package/dist/tools-todo.js +160 -148
- package/dist/vericify-bridge.d.ts +8 -0
- package/dist/vericify-bridge.js +18 -0
- package/dist/vericify-context.d.ts +4 -0
- package/dist/vericify-context.js +26 -5
- package/dist/vericify-native.d.ts +101 -0
- package/dist/vericify-native.js +221 -0
- package/dist/verification-worker.d.ts +2 -0
- package/dist/verification-worker.js +31 -0
- package/docs/mcp-tool-reference.md +50 -10
- package/docs/troubleshooting.md +29 -0
- package/package.json +19 -6
- package/scripts/dev/run-tests-isolated.mjs +165 -0
- package/scripts/dev/run_hermes_crispr_live.mjs +1 -0
- package/scripts/dev/test-isolation-guard.mjs +20 -0
- package/scripts/dev/test-preload.mjs +153 -0
- package/scripts/dev/test-source-inventory.mjs +31 -0
- package/docs/development.md +0 -46
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/** OS identity, not just a PID: do not signal a reused or unverifiable process. */
|
|
2
|
+
import { execFileSync } from 'node:child_process';
|
|
3
|
+
import { hostname } from 'node:os';
|
|
4
|
+
export function readProcessIdentity(pid) {
|
|
5
|
+
if (!Number.isSafeInteger(pid) || pid <= 1)
|
|
6
|
+
return undefined;
|
|
7
|
+
try {
|
|
8
|
+
const row = execFileSync('ps', ['-p', String(pid), '-o', 'lstart=', '-o', 'stat='], { encoding: 'utf8', timeout: 2000 }).trim();
|
|
9
|
+
const match = row.match(/^(.+?)\s+(\S+)$/);
|
|
10
|
+
if (!match || /^[ZX]/.test(match[2]))
|
|
11
|
+
return undefined;
|
|
12
|
+
return { pid, started_at: match[1].trim().replace(/\s+/g, ' '), hostname: hostname() };
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
return undefined;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
export function probeProcess(identity) {
|
|
19
|
+
if (identity.hostname !== hostname())
|
|
20
|
+
return 'unknown';
|
|
21
|
+
const observed = readProcessIdentity(identity.pid);
|
|
22
|
+
if (observed)
|
|
23
|
+
return observed.started_at === identity.started_at ? 'alive' : 'dead';
|
|
24
|
+
try {
|
|
25
|
+
const stat = execFileSync('ps', ['-p', String(identity.pid), '-o', 'stat='], { encoding: 'utf8', timeout: 2000 }).trim();
|
|
26
|
+
if (/^[ZX]/.test(stat))
|
|
27
|
+
return 'dead';
|
|
28
|
+
}
|
|
29
|
+
catch { /* Permission and transient OS errors are not proof of death. */ }
|
|
30
|
+
try {
|
|
31
|
+
process.kill(identity.pid, 0);
|
|
32
|
+
return 'unknown';
|
|
33
|
+
}
|
|
34
|
+
catch (error) {
|
|
35
|
+
return error.code === 'ESRCH' ? 'dead' : 'unknown';
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=process-identity.js.map
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { type ProcessIdentity } from './process-identity.js';
|
|
2
|
+
export interface CommandPolicy {
|
|
3
|
+
stall_min?: number;
|
|
4
|
+
kill_min?: number;
|
|
5
|
+
deadline_min?: number;
|
|
6
|
+
}
|
|
7
|
+
export interface CommandProgress {
|
|
8
|
+
pid?: number;
|
|
9
|
+
started_at: string;
|
|
10
|
+
last_output_at?: string;
|
|
11
|
+
last_progress_at: string;
|
|
12
|
+
elapsed_ms: number;
|
|
13
|
+
silence_ms: number;
|
|
14
|
+
output_tail: string;
|
|
15
|
+
status: 'running' | 'suspected_stall' | 'terminating' | 'done' | 'failed';
|
|
16
|
+
reason_code?: string;
|
|
17
|
+
}
|
|
18
|
+
export interface CommandOptions extends CommandPolicy {
|
|
19
|
+
signal?: AbortSignal;
|
|
20
|
+
log_path?: string;
|
|
21
|
+
poll_interval_ms?: number;
|
|
22
|
+
onProgress?: (progress: CommandProgress) => void | Promise<void>;
|
|
23
|
+
onSpawn?: (identity: ProcessIdentity) => void | Promise<void>;
|
|
24
|
+
}
|
|
25
|
+
export interface CommandResult {
|
|
26
|
+
ok: boolean;
|
|
27
|
+
output: string;
|
|
28
|
+
exit_code: number | null;
|
|
29
|
+
duration_ms: number;
|
|
30
|
+
reason_code?: string;
|
|
31
|
+
}
|
|
32
|
+
export declare function resolveCommandPolicy(options?: CommandPolicy): Required<Omit<CommandPolicy, 'deadline_min'>> & Pick<CommandPolicy, 'deadline_min'>;
|
|
33
|
+
export declare function runProgressCommand(command: string, root: string, options?: CommandOptions): Promise<CommandResult>;
|
|
34
|
+
//# sourceMappingURL=progress-command.d.ts.map
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
/** One process-group command runner shared by verification, tests and staged checks. */
|
|
2
|
+
import { spawn } from 'node:child_process';
|
|
3
|
+
import { appendFileSync, mkdirSync } from 'node:fs';
|
|
4
|
+
import { dirname } from 'node:path';
|
|
5
|
+
import { readProcessIdentity } from './process-identity.js';
|
|
6
|
+
export function resolveCommandPolicy(options = {}) {
|
|
7
|
+
const stall = options.stall_min ?? 10;
|
|
8
|
+
const kill = stall === 0 ? 0 : options.kill_min ?? Math.max(60, stall);
|
|
9
|
+
for (const [key, value] of Object.entries({ stall_min: stall, kill_min: kill, deadline_min: options.deadline_min })) {
|
|
10
|
+
if (value !== undefined && (!Number.isFinite(value) || value < 0 || (key === 'deadline_min' && value === 0)))
|
|
11
|
+
throw new Error(`${key} must be finite and ${key === 'deadline_min' ? 'positive' : 'nonnegative'}.`);
|
|
12
|
+
}
|
|
13
|
+
if (stall > 0 && kill > 0 && kill < stall)
|
|
14
|
+
throw new Error('The kill silence window must not precede the stall warning.');
|
|
15
|
+
return { stall_min: stall, kill_min: kill, ...(options.deadline_min !== undefined ? { deadline_min: options.deadline_min } : {}) };
|
|
16
|
+
}
|
|
17
|
+
export async function runProgressCommand(command, root, options = {}) {
|
|
18
|
+
const policy = resolveCommandPolicy(options);
|
|
19
|
+
if (options.signal?.aborted)
|
|
20
|
+
return { ok: false, output: '', exit_code: null, duration_ms: 0, reason_code: 'command_canceled' };
|
|
21
|
+
const started = Date.now();
|
|
22
|
+
let lastOutput = started;
|
|
23
|
+
let outputAt;
|
|
24
|
+
let output = '';
|
|
25
|
+
let stopping;
|
|
26
|
+
let closed = false;
|
|
27
|
+
let force;
|
|
28
|
+
if (options.log_path)
|
|
29
|
+
mkdirSync(dirname(options.log_path), { recursive: true });
|
|
30
|
+
// Register process ownership before releasing the command. If the runner
|
|
31
|
+
// dies during registration, EOF exits the waiting shell without side effects.
|
|
32
|
+
const child = spawn('sh', ['-c', 'IFS= read -r ace_start || exit 125; exec sh -c "$1"', 'ace-command', command], { cwd: root, detached: process.platform !== 'win32', stdio: ['pipe', 'pipe', 'pipe'] });
|
|
33
|
+
const notify = (final) => {
|
|
34
|
+
const now = Date.now(), silence = now - lastOutput;
|
|
35
|
+
const value = { pid: child.pid, started_at: new Date(started).toISOString(), last_output_at: outputAt,
|
|
36
|
+
last_progress_at: new Date(lastOutput).toISOString(), elapsed_ms: now - started, silence_ms: silence, output_tail: output.slice(-2000),
|
|
37
|
+
status: final ?? (stopping ? 'terminating' : policy.stall_min > 0 && silence >= policy.stall_min * 60000 ? 'suspected_stall' : 'running'),
|
|
38
|
+
...(stopping ? { reason_code: stopping } : {}) };
|
|
39
|
+
try {
|
|
40
|
+
Promise.resolve(options.onProgress?.(value)).catch(() => { });
|
|
41
|
+
}
|
|
42
|
+
catch { /* Observer failure cannot kill work. */ }
|
|
43
|
+
};
|
|
44
|
+
const signalGroup = (signal) => {
|
|
45
|
+
if (!child.pid)
|
|
46
|
+
return;
|
|
47
|
+
try {
|
|
48
|
+
if (process.platform === 'win32')
|
|
49
|
+
child.kill(signal);
|
|
50
|
+
else
|
|
51
|
+
process.kill(-child.pid, signal);
|
|
52
|
+
}
|
|
53
|
+
catch (error) {
|
|
54
|
+
if (error.code !== 'ESRCH')
|
|
55
|
+
output = `${output}\nUnable to signal process group: ${String(error)}`.slice(-64000);
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
const stop = (reason) => {
|
|
59
|
+
if (closed || stopping)
|
|
60
|
+
return;
|
|
61
|
+
stopping = reason;
|
|
62
|
+
signalGroup('SIGTERM');
|
|
63
|
+
notify();
|
|
64
|
+
force = setTimeout(() => signalGroup('SIGKILL'), 1000);
|
|
65
|
+
};
|
|
66
|
+
const abort = () => stop('command_canceled');
|
|
67
|
+
options.signal?.addEventListener('abort', abort, { once: true });
|
|
68
|
+
const capture = (chunk) => {
|
|
69
|
+
const value = chunk.toString();
|
|
70
|
+
output = (output + value).slice(-64000);
|
|
71
|
+
lastOutput = Date.now();
|
|
72
|
+
outputAt = new Date(lastOutput).toISOString();
|
|
73
|
+
if (options.log_path) {
|
|
74
|
+
try {
|
|
75
|
+
appendFileSync(options.log_path, value);
|
|
76
|
+
}
|
|
77
|
+
catch (error) {
|
|
78
|
+
stop('command_log_failed');
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
notify();
|
|
82
|
+
};
|
|
83
|
+
child.stdout.on('data', capture);
|
|
84
|
+
child.stderr.on('data', capture);
|
|
85
|
+
child.once('spawn', async () => {
|
|
86
|
+
const identity = child.pid && readProcessIdentity(child.pid);
|
|
87
|
+
try {
|
|
88
|
+
if (options.onSpawn && !identity)
|
|
89
|
+
throw new Error('Command process identity unavailable.');
|
|
90
|
+
if (identity)
|
|
91
|
+
await options.onSpawn?.(identity);
|
|
92
|
+
child.stdin.end(closed || stopping ? '' : 'run\n');
|
|
93
|
+
}
|
|
94
|
+
catch (error) {
|
|
95
|
+
output = `${output}\n${String(error)}`.trim();
|
|
96
|
+
stop('command_ownership_failed');
|
|
97
|
+
child.stdin.end();
|
|
98
|
+
}
|
|
99
|
+
notify();
|
|
100
|
+
if (options.signal?.aborted)
|
|
101
|
+
abort();
|
|
102
|
+
});
|
|
103
|
+
child.stdin.on('error', () => { });
|
|
104
|
+
const timer = setInterval(() => {
|
|
105
|
+
const now = Date.now();
|
|
106
|
+
if (policy.deadline_min !== undefined && now - started >= policy.deadline_min * 60000)
|
|
107
|
+
stop('command_deadline_exceeded');
|
|
108
|
+
else if (policy.kill_min > 0 && now - lastOutput >= policy.kill_min * 60000)
|
|
109
|
+
stop('command_stalled');
|
|
110
|
+
else
|
|
111
|
+
notify();
|
|
112
|
+
}, options.poll_interval_ms ?? 1000);
|
|
113
|
+
let deadlineTimer;
|
|
114
|
+
const armDeadline = () => {
|
|
115
|
+
if (policy.deadline_min === undefined || closed)
|
|
116
|
+
return;
|
|
117
|
+
const remaining = policy.deadline_min * 60000 - (Date.now() - started);
|
|
118
|
+
if (remaining <= 0) {
|
|
119
|
+
stop('command_deadline_exceeded');
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
// Node clamps overflowing timers to 1ms. Long explicit deadlines must not
|
|
123
|
+
// accidentally become immediate cancellations.
|
|
124
|
+
deadlineTimer = setTimeout(armDeadline, Math.min(remaining, 2147483647));
|
|
125
|
+
};
|
|
126
|
+
armDeadline();
|
|
127
|
+
return await new Promise(resolve => {
|
|
128
|
+
const finish = (code, error) => {
|
|
129
|
+
if (closed)
|
|
130
|
+
return;
|
|
131
|
+
closed = true;
|
|
132
|
+
clearInterval(timer);
|
|
133
|
+
if (force)
|
|
134
|
+
clearTimeout(force);
|
|
135
|
+
if (deadlineTimer)
|
|
136
|
+
clearTimeout(deadlineTimer);
|
|
137
|
+
options.signal?.removeEventListener('abort', abort);
|
|
138
|
+
if (error)
|
|
139
|
+
output = `${output}\n${error.message}`.trim();
|
|
140
|
+
// Descendants may have ignored TERM and closed inherited output. Ensure
|
|
141
|
+
// cancellation cleans the entire original group before reporting terminal.
|
|
142
|
+
if (stopping)
|
|
143
|
+
signalGroup('SIGKILL');
|
|
144
|
+
const ok = !stopping && !error && code === 0;
|
|
145
|
+
notify(ok ? 'done' : 'failed');
|
|
146
|
+
resolve({ ok, output, exit_code: code, duration_ms: Date.now() - started,
|
|
147
|
+
...(stopping ? { reason_code: stopping } : error ? { reason_code: 'command_spawn_failed' } : {}) });
|
|
148
|
+
};
|
|
149
|
+
child.once('error', error => finish(null, error));
|
|
150
|
+
child.once('close', code => finish(code));
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
//# sourceMappingURL=progress-command.js.map
|
package/dist/prompts.js
CHANGED
|
@@ -89,7 +89,7 @@ function renderRuntimeRecallSections(input) {
|
|
|
89
89
|
export function registerPrompts(server) {
|
|
90
90
|
// ── Token-budget mode ─────────────────────────────────────────────
|
|
91
91
|
const BRIEF_SCHEMA = z
|
|
92
|
-
.boolean()
|
|
92
|
+
.union([z.boolean(), z.enum(['true', 'false']).transform(value => value === 'true')])
|
|
93
93
|
.optional()
|
|
94
94
|
.describe("Token-budget mode: true = role instructions only (no kernel/task-packs). Default: false (full context).");
|
|
95
95
|
// ── 1. Per-agent activation prompts ─────────────────────────────────
|
|
@@ -171,7 +171,7 @@ export function registerPrompts(server) {
|
|
|
171
171
|
"You are now operating as ACE-Orchestrator.",
|
|
172
172
|
"",
|
|
173
173
|
"## Orchestrator Instructions",
|
|
174
|
-
readAgentInstructions("orchestrator"),
|
|
174
|
+
readAgentInstructions("orchestrator", { includeLearned: true }),
|
|
175
175
|
"",
|
|
176
176
|
...(brief ? ["## ACE Preflight", formatAceRecallMarkdown(buildAceRecallContext())] : [formatRecallSlices(task)]),
|
|
177
177
|
...(brief
|
|
@@ -214,7 +214,7 @@ export function registerPrompts(server) {
|
|
|
214
214
|
"You are now operating as ACE-VOS.",
|
|
215
215
|
"",
|
|
216
216
|
"## VOS Instructions",
|
|
217
|
-
readAgentInstructions("vos"),
|
|
217
|
+
readAgentInstructions("vos", { includeLearned: true }),
|
|
218
218
|
...(brief
|
|
219
219
|
? []
|
|
220
220
|
: [
|
|
@@ -249,7 +249,7 @@ export function registerPrompts(server) {
|
|
|
249
249
|
"You are now operating as ACE-UI.",
|
|
250
250
|
"",
|
|
251
251
|
"## UI Instructions",
|
|
252
|
-
readAgentInstructions("ui"),
|
|
252
|
+
readAgentInstructions("ui", { includeLearned: true }),
|
|
253
253
|
...(brief
|
|
254
254
|
? []
|
|
255
255
|
: [
|
|
@@ -284,7 +284,7 @@ export function registerPrompts(server) {
|
|
|
284
284
|
"You are now operating as ACE-Coders.",
|
|
285
285
|
"",
|
|
286
286
|
"## Coders Instructions",
|
|
287
|
-
readAgentInstructions("coders"),
|
|
287
|
+
readAgentInstructions("coders", { includeLearned: true }),
|
|
288
288
|
...(brief
|
|
289
289
|
? []
|
|
290
290
|
: [
|
|
@@ -316,10 +316,10 @@ export function registerPrompts(server) {
|
|
|
316
316
|
"You are now operating as ACE-ASTGrep.",
|
|
317
317
|
"",
|
|
318
318
|
"## ASTGrep Agent Instructions",
|
|
319
|
-
readAgentInstructions("astgrep"),
|
|
319
|
+
readAgentInstructions("astgrep", { includeLearned: true }),
|
|
320
320
|
"",
|
|
321
321
|
"## AST-grep Command Pack",
|
|
322
|
-
readSkillInstructions("astgrep-index"),
|
|
322
|
+
readSkillInstructions("astgrep-index", { includeLearned: true }),
|
|
323
323
|
"",
|
|
324
324
|
task
|
|
325
325
|
? `## Current Task\n${task}`
|
|
@@ -341,7 +341,7 @@ export function registerPrompts(server) {
|
|
|
341
341
|
"You are now operating as ACE-Memory.",
|
|
342
342
|
"",
|
|
343
343
|
"## Memory Agent Instructions",
|
|
344
|
-
readAgentInstructions("memory"),
|
|
344
|
+
readAgentInstructions("memory", { includeLearned: true }),
|
|
345
345
|
"",
|
|
346
346
|
"## Shared Kernel",
|
|
347
347
|
readKernelArtifact("directive_kernel"),
|
|
@@ -366,7 +366,7 @@ export function registerPrompts(server) {
|
|
|
366
366
|
"You are now operating as ACE-Security.",
|
|
367
367
|
"",
|
|
368
368
|
"## Security Agent Instructions",
|
|
369
|
-
readAgentInstructions("security"),
|
|
369
|
+
readAgentInstructions("security", { includeLearned: true }),
|
|
370
370
|
"",
|
|
371
371
|
"## Shared Kernel",
|
|
372
372
|
readKernelArtifact("directive_kernel"),
|
|
@@ -391,7 +391,7 @@ export function registerPrompts(server) {
|
|
|
391
391
|
"You are now operating as ACE-Observability.",
|
|
392
392
|
"",
|
|
393
393
|
"## Observability Agent Instructions",
|
|
394
|
-
readAgentInstructions("observability"),
|
|
394
|
+
readAgentInstructions("observability", { includeLearned: true }),
|
|
395
395
|
"",
|
|
396
396
|
"## Shared Kernel",
|
|
397
397
|
readKernelArtifact("directive_kernel"),
|
|
@@ -416,7 +416,7 @@ export function registerPrompts(server) {
|
|
|
416
416
|
"You are now operating as ACE-Eval.",
|
|
417
417
|
"",
|
|
418
418
|
"## Eval Agent Instructions",
|
|
419
|
-
readAgentInstructions("eval"),
|
|
419
|
+
readAgentInstructions("eval", { includeLearned: true }),
|
|
420
420
|
"",
|
|
421
421
|
"## Shared Kernel",
|
|
422
422
|
readKernelArtifact("directive_kernel"),
|
|
@@ -441,7 +441,7 @@ export function registerPrompts(server) {
|
|
|
441
441
|
"You are now operating as ACE-Release.",
|
|
442
442
|
"",
|
|
443
443
|
"## Release Agent Instructions",
|
|
444
|
-
readAgentInstructions("release"),
|
|
444
|
+
readAgentInstructions("release", { includeLearned: true }),
|
|
445
445
|
"",
|
|
446
446
|
"## Shared Kernel",
|
|
447
447
|
readKernelArtifact("directive_kernel"),
|
|
@@ -563,7 +563,7 @@ export function registerPrompts(server) {
|
|
|
563
563
|
text: [
|
|
564
564
|
`# ACE Skill Activation: ${skill}`,
|
|
565
565
|
"",
|
|
566
|
-
readSkillInstructions(skill),
|
|
566
|
+
readSkillInstructions(skill, { includeLearned: true }),
|
|
567
567
|
"",
|
|
568
568
|
task ? `## Task\n${task}` : "## Task\nApply this skill to the current workspace objective.",
|
|
569
569
|
].join("\n"),
|
|
@@ -580,7 +580,7 @@ export function registerPrompts(server) {
|
|
|
580
580
|
text: [
|
|
581
581
|
"# CodeMunch Activation",
|
|
582
582
|
"",
|
|
583
|
-
readSkillInstructions("codemunch"),
|
|
583
|
+
readSkillInstructions("codemunch", { includeLearned: true }),
|
|
584
584
|
"",
|
|
585
585
|
task
|
|
586
586
|
? `## Objective\n${task}`
|
|
@@ -599,7 +599,7 @@ export function registerPrompts(server) {
|
|
|
599
599
|
text: [
|
|
600
600
|
"# CodeSnipe Activation",
|
|
601
601
|
"",
|
|
602
|
-
readSkillInstructions("codesnipe"),
|
|
602
|
+
readSkillInstructions("codesnipe", { includeLearned: true }),
|
|
603
603
|
"",
|
|
604
604
|
task
|
|
605
605
|
? `## Objective\n${task}`
|
package/dist/resources.js
CHANGED
|
@@ -26,7 +26,7 @@ export function registerResources(server) {
|
|
|
26
26
|
contents: [
|
|
27
27
|
{
|
|
28
28
|
uri: `ace://agents/${role}/instructions`,
|
|
29
|
-
text: readAgentInstructions(role),
|
|
29
|
+
text: readAgentInstructions(role, { includeLearned: true }),
|
|
30
30
|
mimeType: "text/markdown",
|
|
31
31
|
},
|
|
32
32
|
],
|
|
@@ -154,7 +154,7 @@ export function registerResources(server) {
|
|
|
154
154
|
contents: [
|
|
155
155
|
{
|
|
156
156
|
uri: uri.href,
|
|
157
|
-
text: readSkillInstructions(name),
|
|
157
|
+
text: readSkillInstructions(name, { includeLearned: true }),
|
|
158
158
|
mimeType: "text/markdown",
|
|
159
159
|
},
|
|
160
160
|
],
|
|
@@ -16,8 +16,15 @@ export interface ShellCommandProgressEvent {
|
|
|
16
16
|
export interface RunShellCommandOptions {
|
|
17
17
|
cwd: string;
|
|
18
18
|
env?: NodeJS.ProcessEnv;
|
|
19
|
-
timeout_ms
|
|
19
|
+
timeout_ms?: number;
|
|
20
|
+
/** Final silence threshold; 0 disables stall detection. */
|
|
20
21
|
stall_timeout_ms?: number;
|
|
22
|
+
stall_warning_ms?: number;
|
|
23
|
+
on_stall?: (event: {
|
|
24
|
+
at: number;
|
|
25
|
+
last_progress_at: number;
|
|
26
|
+
silence_ms: number;
|
|
27
|
+
}) => void;
|
|
21
28
|
max_output_bytes?: number;
|
|
22
29
|
on_spawn?: (child: ChildProcess) => void;
|
|
23
30
|
on_progress?: (event: ShellCommandProgressEvent) => void;
|
package/dist/runtime-command.js
CHANGED
|
@@ -9,6 +9,12 @@ function appendChunk(buffer, chunk, maxBytes) {
|
|
|
9
9
|
return clipped.subarray(0, maxBytes).toString("utf8");
|
|
10
10
|
}
|
|
11
11
|
export async function runShellCommand(command, options) {
|
|
12
|
+
for (const [name, value] of Object.entries({ timeout_ms: options.timeout_ms, stall_timeout_ms: options.stall_timeout_ms, stall_warning_ms: options.stall_warning_ms })) {
|
|
13
|
+
if (value !== undefined && (!Number.isFinite(value) || value < 0))
|
|
14
|
+
throw new Error(`${name} must be finite and nonnegative; 0 disables the limit.`);
|
|
15
|
+
}
|
|
16
|
+
if (options.stall_timeout_ms && options.stall_warning_ms && options.stall_warning_ms > options.stall_timeout_ms)
|
|
17
|
+
throw new Error("The stall warning must not follow the final silence limit.");
|
|
12
18
|
const startedAt = Date.now();
|
|
13
19
|
const maxOutputBytes = Math.max(4 * 1024, options.max_output_bytes ?? 256 * 1024);
|
|
14
20
|
return new Promise((resolve, reject) => {
|
|
@@ -19,6 +25,7 @@ export async function runShellCommand(command, options) {
|
|
|
19
25
|
let finished = false;
|
|
20
26
|
let lastProgressAt = startedAt;
|
|
21
27
|
let stallTimer;
|
|
28
|
+
let warningTimer;
|
|
22
29
|
let forcedKillTimer;
|
|
23
30
|
let child;
|
|
24
31
|
try {
|
|
@@ -26,6 +33,7 @@ export async function runShellCommand(command, options) {
|
|
|
26
33
|
cwd: options.cwd,
|
|
27
34
|
env: options.env,
|
|
28
35
|
stdio: ["ignore", "pipe", "pipe"],
|
|
36
|
+
detached: process.platform !== "win32",
|
|
29
37
|
});
|
|
30
38
|
}
|
|
31
39
|
catch (error) {
|
|
@@ -33,23 +41,48 @@ export async function runShellCommand(command, options) {
|
|
|
33
41
|
return;
|
|
34
42
|
}
|
|
35
43
|
options.on_spawn?.(child);
|
|
44
|
+
const signalGroup = (signal) => {
|
|
45
|
+
if (!child.pid)
|
|
46
|
+
return;
|
|
47
|
+
try {
|
|
48
|
+
if (process.platform === "win32")
|
|
49
|
+
child.kill(signal);
|
|
50
|
+
else
|
|
51
|
+
process.kill(-child.pid, signal);
|
|
52
|
+
}
|
|
53
|
+
catch (error) {
|
|
54
|
+
if (error.code !== "ESRCH")
|
|
55
|
+
stderr = appendChunk(stderr, String(error), maxOutputBytes);
|
|
56
|
+
}
|
|
57
|
+
};
|
|
36
58
|
const requestTimeout = (reason) => {
|
|
37
59
|
if (finished || timedOut)
|
|
38
60
|
return;
|
|
39
61
|
timedOut = true;
|
|
40
62
|
timeoutReason = reason;
|
|
41
|
-
|
|
63
|
+
signalGroup("SIGTERM");
|
|
42
64
|
forcedKillTimer = setTimeout(() => {
|
|
43
65
|
if (!finished)
|
|
44
|
-
|
|
66
|
+
signalGroup("SIGKILL");
|
|
45
67
|
}, 500);
|
|
46
68
|
};
|
|
47
69
|
const resetStallTimer = () => {
|
|
48
70
|
if (stallTimer)
|
|
49
71
|
clearTimeout(stallTimer);
|
|
50
|
-
|
|
72
|
+
if (warningTimer)
|
|
73
|
+
clearTimeout(warningTimer);
|
|
74
|
+
const stallTimeoutMs = options.stall_timeout_ms ?? 60 * 60_000;
|
|
51
75
|
if (!stallTimeoutMs || stallTimeoutMs <= 0)
|
|
52
76
|
return;
|
|
77
|
+
const warningMs = options.stall_warning_ms ?? Math.min(10 * 60_000, stallTimeoutMs);
|
|
78
|
+
if (warningMs > 0)
|
|
79
|
+
warningTimer = setTimeout(() => {
|
|
80
|
+
const at = Date.now();
|
|
81
|
+
try {
|
|
82
|
+
options.on_stall?.({ at, last_progress_at: lastProgressAt, silence_ms: at - lastProgressAt });
|
|
83
|
+
}
|
|
84
|
+
catch { /* Warning observers do not own execution. */ }
|
|
85
|
+
}, warningMs);
|
|
53
86
|
stallTimer = setTimeout(() => requestTimeout("stall"), stallTimeoutMs + STALL_TIMEOUT_SCHEDULER_GRACE_MS);
|
|
54
87
|
};
|
|
55
88
|
const recordProgress = (source) => {
|
|
@@ -65,11 +98,15 @@ export async function runShellCommand(command, options) {
|
|
|
65
98
|
clearTimeout(stallTimer);
|
|
66
99
|
if (forcedKillTimer)
|
|
67
100
|
clearTimeout(forcedKillTimer);
|
|
101
|
+
if (warningTimer)
|
|
102
|
+
clearTimeout(warningTimer);
|
|
103
|
+
if (timedOut)
|
|
104
|
+
signalGroup("SIGKILL");
|
|
68
105
|
resolve(result);
|
|
69
106
|
};
|
|
70
|
-
const timeout = setTimeout(() => {
|
|
107
|
+
const timeout = options.timeout_ms && options.timeout_ms > 0 ? setTimeout(() => {
|
|
71
108
|
requestTimeout("turn_budget");
|
|
72
|
-
}, options.timeout_ms);
|
|
109
|
+
}, options.timeout_ms) : undefined;
|
|
73
110
|
recordProgress("spawn");
|
|
74
111
|
child.stdout?.setEncoding("utf8");
|
|
75
112
|
child.stdout?.on("data", (chunk) => {
|
|
@@ -82,16 +119,20 @@ export async function runShellCommand(command, options) {
|
|
|
82
119
|
recordProgress("stderr");
|
|
83
120
|
});
|
|
84
121
|
child.on("error", (error) => {
|
|
85
|
-
|
|
122
|
+
if (timeout)
|
|
123
|
+
clearTimeout(timeout);
|
|
86
124
|
if (stallTimer)
|
|
87
125
|
clearTimeout(stallTimer);
|
|
88
126
|
if (forcedKillTimer)
|
|
89
127
|
clearTimeout(forcedKillTimer);
|
|
128
|
+
if (warningTimer)
|
|
129
|
+
clearTimeout(warningTimer);
|
|
90
130
|
if (!finished)
|
|
91
131
|
reject(error);
|
|
92
132
|
});
|
|
93
133
|
child.on("close", (code, signal) => {
|
|
94
|
-
|
|
134
|
+
if (timeout)
|
|
135
|
+
clearTimeout(timeout);
|
|
95
136
|
finish({
|
|
96
137
|
exit_code: code,
|
|
97
138
|
signal,
|
package/dist/runtime-executor.js
CHANGED
|
@@ -12,7 +12,7 @@ import { renderAceContinuityPromptBlock, renderAceRecallPromptBlock, renderAceSn
|
|
|
12
12
|
import { executeRuntimeTool, buildFilteredToolCatalog, SMALL_LOCAL_PRIORITY_TOOL_NAMES, } from "./runtime-tool-specs.js";
|
|
13
13
|
import { validateRuntimeExecutorSessionRegistryPayload, } from "./schemas.js";
|
|
14
14
|
import { appendStatusEventSafe } from "./status-events.js";
|
|
15
|
-
import {
|
|
15
|
+
import { appendAutomaticVericifyProcessPostSafe, deriveVericifyRunRef, isVericifyBridgeEnabled, refreshVericifyBridgeSnapshotSafe, } from "./vericify-bridge.js";
|
|
16
16
|
import { createWorkspaceSessionAsync, removeWorkspaceSession, runWorkspaceSessionHook, } from "./workspace-manager.js";
|
|
17
17
|
import { buildAceContinuityPacket, buildAceRecallContext, normalizeAutonomyPolicy, normalizeContinuityPolicy, } from "./ace-autonomy.js";
|
|
18
18
|
import { openStore } from "./store/ace-packed-store.js";
|
|
@@ -358,7 +358,7 @@ async function emitVericifyProcessPostForSession(session, kind, summary, toolRef
|
|
|
358
358
|
if (!isVericifyBridgeEnabled())
|
|
359
359
|
return;
|
|
360
360
|
const refs = deriveVericifyRunRef(session);
|
|
361
|
-
await
|
|
361
|
+
const posted = await appendAutomaticVericifyProcessPostSafe({
|
|
362
362
|
run_id: refs.run_id,
|
|
363
363
|
branch_id: refs.branch_id,
|
|
364
364
|
lane_id: refs.lane_id,
|
|
@@ -368,7 +368,8 @@ async function emitVericifyProcessPostForSession(session, kind, summary, toolRef
|
|
|
368
368
|
tool_refs: toolRefs,
|
|
369
369
|
evidence_refs: evidenceRefs,
|
|
370
370
|
}).catch(() => undefined);
|
|
371
|
-
|
|
371
|
+
if (posted && !posted.skipped)
|
|
372
|
+
refreshVericifyBridgeSnapshotSafe();
|
|
372
373
|
}
|
|
373
374
|
async function touchRuntimeProgress(sessionId, _reason, at = Date.now()) {
|
|
374
375
|
if (!storeExistsSync(workspaceRoot()))
|
|
@@ -664,12 +665,12 @@ async function runSessionLoop(sessionId, context, autoCleanup, runtimeProfileSna
|
|
|
664
665
|
let consecutiveStallRestarts = runtimeStatus?.stall_restart_count ?? 0;
|
|
665
666
|
let isStallRestart = false;
|
|
666
667
|
let stallRestartContext = "";
|
|
667
|
-
//
|
|
668
|
-
//
|
|
669
|
-
// supplied a workspace/session budget or status-seeded runtime budget.
|
|
668
|
+
// Overall deadlines come only from explicit profile/session policy.
|
|
669
|
+
// Default liveness checks measure silence, separately warning and killing.
|
|
670
670
|
const livenessDefaults = getLivenessDefaults(effectiveModelClass);
|
|
671
671
|
const effectiveTurnBudgetMs = runtimeStatus?.turn_budget_ms ?? registryStart.turn_timeout_ms ?? livenessDefaults.turn_budget_ms;
|
|
672
|
-
const effectiveStallWindowMs = runtimeStatus?.stall_window_ms ?? livenessDefaults.stall_window_ms;
|
|
672
|
+
const effectiveStallWindowMs = runtimeStatus?.stall_window_ms ?? runtimeProfileSnapshot.profile.executor.stall_window_ms ?? livenessDefaults.stall_window_ms;
|
|
673
|
+
const effectiveStallWarningMs = runtimeProfileSnapshot.profile.executor.stall_warning_ms ?? Math.min(livenessDefaults.stall_warning_ms, effectiveStallWindowMs);
|
|
673
674
|
const maxStallRestarts = livenessDefaults.max_stall_restarts;
|
|
674
675
|
const initialBackoffMs = livenessDefaults.initial_backoff_ms;
|
|
675
676
|
const maxRetryBackoffMs = livenessDefaults.max_retry_backoff_ms;
|
|
@@ -698,7 +699,7 @@ async function runSessionLoop(sessionId, context, autoCleanup, runtimeProfileSna
|
|
|
698
699
|
const flushProgress = async () => {
|
|
699
700
|
await pumpProgressWrite().catch(() => undefined);
|
|
700
701
|
};
|
|
701
|
-
for (let turnNumber = 1; turnNumber <= registryStart.max_turns; turnNumber += 1) {
|
|
702
|
+
for (let turnNumber = 1; (registryStart.max_turns === 0 || turnNumber <= registryStart.max_turns); turnNumber += 1) {
|
|
702
703
|
if (active?.stop_requested) {
|
|
703
704
|
const stopped = await finalizeSession(sessionId, "stopped", `Unattended session ${sessionId} stopped by request.`);
|
|
704
705
|
if (stopped) {
|
|
@@ -910,6 +911,10 @@ async function runSessionLoop(sessionId, context, autoCleanup, runtimeProfileSna
|
|
|
910
911
|
},
|
|
911
912
|
timeout_ms: effectiveTurnBudgetMs,
|
|
912
913
|
stall_timeout_ms: effectiveStallWindowMs,
|
|
914
|
+
stall_warning_ms: effectiveStallWarningMs,
|
|
915
|
+
on_stall: (event) => {
|
|
916
|
+
void emitExecutorEvent("RUNTIME_EXECUTOR_SUSPECTED_STALL", "in_progress", `Turn ${turnNumber} has no output for ${event.silence_ms}ms; work remains running until the configured final silence threshold.`, { session_id: sessionId, turn_number: turnNumber, last_progress_at: event.last_progress_at, stall_window_ms: effectiveStallWindowMs }).catch(() => undefined);
|
|
917
|
+
},
|
|
913
918
|
on_spawn: (child) => {
|
|
914
919
|
if (active)
|
|
915
920
|
active.child = child;
|
|
@@ -1433,8 +1438,8 @@ export async function startUnattendedSession(input) {
|
|
|
1433
1438
|
});
|
|
1434
1439
|
}
|
|
1435
1440
|
const workspaceSession = workspace.session;
|
|
1436
|
-
const maxTurns = Math.max(
|
|
1437
|
-
const turnTimeout = Math.max(
|
|
1441
|
+
const maxTurns = Math.max(0, input.max_turns ?? runtimeProfileSnapshot.profile.executor.max_turns ?? 0);
|
|
1442
|
+
const turnTimeout = Math.max(0, input.turn_timeout_ms ?? runtimeProfileSnapshot.profile.executor.turn_timeout_ms ?? 0);
|
|
1438
1443
|
const now = new Date().toISOString();
|
|
1439
1444
|
const sessionRecord = {
|
|
1440
1445
|
session_id: sessionId,
|
|
@@ -1581,7 +1586,24 @@ export async function stopUnattendedSession(sessionId) {
|
|
|
1581
1586
|
};
|
|
1582
1587
|
}
|
|
1583
1588
|
active.stop_requested = true;
|
|
1584
|
-
active.child
|
|
1589
|
+
const child = active.child;
|
|
1590
|
+
if (child?.pid) {
|
|
1591
|
+
const killGroup = (signal) => {
|
|
1592
|
+
try {
|
|
1593
|
+
if (process.platform === "win32")
|
|
1594
|
+
child.kill(signal);
|
|
1595
|
+
else
|
|
1596
|
+
process.kill(-child.pid, signal);
|
|
1597
|
+
}
|
|
1598
|
+
catch (error) {
|
|
1599
|
+
if (error.code !== "ESRCH")
|
|
1600
|
+
throw error;
|
|
1601
|
+
}
|
|
1602
|
+
};
|
|
1603
|
+
killGroup("SIGTERM");
|
|
1604
|
+
const force = setTimeout(() => killGroup("SIGKILL"), 500);
|
|
1605
|
+
force.unref?.();
|
|
1606
|
+
}
|
|
1585
1607
|
const waited = await waitForUnattendedSession(sessionId, 15_000);
|
|
1586
1608
|
return {
|
|
1587
1609
|
ok: waited.ok,
|