@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.
Files changed (187) hide show
  1. package/CHANGELOG.md +52 -14
  2. package/README.md +14 -10
  3. package/assets/.agents/ACE/ACE_coders/AGENTS.md +23 -30
  4. package/assets/.agents/ACE/ACE_coders/INSTRUCTIONS.md +21 -30
  5. package/assets/.agents/skills/landing-review-watcher/SKILL.md +1 -1
  6. package/assets/.agents/skills/learn-from-work/SKILL.md +41 -0
  7. package/assets/agent-state/ACE_WORKFLOW.md +25 -2
  8. package/assets/agent-state/MODULES/schemas/ACE_RUNTIME_PROFILE.schema.json +143 -2
  9. package/assets/agent-state/MODULES/schemas/RUNTIME_EXECUTOR_SESSION_REGISTRY.schema.json +2 -2
  10. package/assets/agent-state/MODULES/schemas/SWARM_HANDOFF.schema.json +10 -0
  11. package/assets/eval-battery/battery.json +1 -1
  12. package/assets/instructions/ACE_Coder.instructions.md +9 -13
  13. package/assets/scripts/ace-hook-dispatch.mjs +16 -411
  14. package/assets/tasks/SWARM_HANDOFF.example_ui_to_coders.json +1 -2
  15. package/assets/vendor/README.md +9 -0
  16. package/assets/vendor/vericify-reader.mjs +272 -0
  17. package/assets/vendor/vericify-reader.provenance.json +10 -0
  18. package/dist/ace-autonomy.d.ts +58 -0
  19. package/dist/ace-autonomy.js +211 -6
  20. package/dist/ace-internal-tools.d.ts +1 -0
  21. package/dist/ace-internal-tools.js +3 -3
  22. package/dist/ace-server-instructions.d.ts +3 -3
  23. package/dist/ace-server-instructions.js +46 -192
  24. package/dist/cli.js +44 -6
  25. package/dist/experience-reflector.d.ts +7 -0
  26. package/dist/experience-reflector.js +39 -0
  27. package/dist/goal-engine.d.ts +64 -7
  28. package/dist/goal-engine.js +197 -41
  29. package/dist/handoff-registry.d.ts +10 -0
  30. package/dist/handoff-registry.js +59 -0
  31. package/dist/helpers/artifacts.d.ts +6 -2
  32. package/dist/helpers/artifacts.js +8 -6
  33. package/dist/helpers/bootstrap.js +13 -20
  34. package/dist/helpers/path-utils.js +2 -0
  35. package/dist/helpers/store-resolution.js +18 -3
  36. package/dist/helpers/workspace-root.d.ts +2 -0
  37. package/dist/helpers/workspace-root.js +9 -0
  38. package/dist/helpers.d.ts +1 -0
  39. package/dist/helpers.js +1 -0
  40. package/dist/hermes/bridge-protocol.d.ts +1 -1
  41. package/dist/hermes/session-manager.d.ts +17 -0
  42. package/dist/hermes/session-manager.js +67 -14
  43. package/dist/host-goal-engine.d.ts +138 -0
  44. package/dist/host-goal-engine.js +793 -0
  45. package/dist/host-goal-status.d.ts +113 -0
  46. package/dist/host-goal-status.js +175 -0
  47. package/dist/host-learning.d.ts +68 -0
  48. package/dist/host-learning.js +115 -0
  49. package/dist/host-observation.d.ts +12 -0
  50. package/dist/host-observation.js +91 -0
  51. package/dist/host-plan-revision.d.ts +14 -0
  52. package/dist/host-plan-revision.js +101 -0
  53. package/dist/host-verification-job.d.ts +12 -0
  54. package/dist/host-verification-job.js +183 -0
  55. package/dist/host-work-context.d.ts +12 -0
  56. package/dist/host-work-context.js +8 -0
  57. package/dist/job-scheduler.d.ts +58 -13
  58. package/dist/job-scheduler.js +298 -48
  59. package/dist/job-worker.d.ts +3 -1
  60. package/dist/job-worker.js +10 -3
  61. package/dist/kanban.d.ts +4 -1
  62. package/dist/kanban.js +44 -16
  63. package/dist/learned-artifacts.d.ts +64 -0
  64. package/dist/learned-artifacts.js +321 -0
  65. package/dist/learning-controls.d.ts +142 -0
  66. package/dist/learning-controls.js +135 -0
  67. package/dist/learning-input-context.d.ts +9 -0
  68. package/dist/learning-input-context.js +62 -0
  69. package/dist/learning-lifecycle.d.ts +10 -0
  70. package/dist/learning-lifecycle.js +11 -0
  71. package/dist/learning-overlays.d.ts +3 -0
  72. package/dist/learning-overlays.js +17 -0
  73. package/dist/learning-policy.d.ts +40 -0
  74. package/dist/learning-policy.js +38 -0
  75. package/dist/learning-records.d.ts +35 -0
  76. package/dist/learning-records.js +17 -0
  77. package/dist/learning-scorecard.d.ts +82 -0
  78. package/dist/learning-scorecard.js +86 -0
  79. package/dist/learning-serving.d.ts +29 -0
  80. package/dist/learning-serving.js +134 -0
  81. package/dist/linked-work.d.ts +9 -0
  82. package/dist/linked-work.js +28 -0
  83. package/dist/local-model-runtime.js +1 -1
  84. package/dist/mcp-command-progress.d.ts +16 -0
  85. package/dist/mcp-command-progress.js +70 -0
  86. package/dist/model-bridge.d.ts +14 -13
  87. package/dist/model-bridge.js +73 -41
  88. package/dist/orchestrator-supervisor.d.ts +111 -6
  89. package/dist/orchestrator-supervisor.js +67 -43
  90. package/dist/plan-proposal.js +3 -3
  91. package/dist/playbook-curator.d.ts +1 -0
  92. package/dist/playbook-curator.js +11 -9
  93. package/dist/process-identity.d.ts +8 -0
  94. package/dist/process-identity.js +38 -0
  95. package/dist/progress-command.d.ts +34 -0
  96. package/dist/progress-command.js +153 -0
  97. package/dist/prompts.js +15 -15
  98. package/dist/resources.js +2 -2
  99. package/dist/runtime-command.d.ts +8 -1
  100. package/dist/runtime-command.js +48 -7
  101. package/dist/runtime-executor.js +33 -11
  102. package/dist/runtime-profile-syntax.d.ts +6 -0
  103. package/dist/runtime-profile-syntax.js +121 -0
  104. package/dist/runtime-profile.d.ts +37 -5
  105. package/dist/runtime-profile.js +36 -129
  106. package/dist/runtime-tool-specs.js +1 -1
  107. package/dist/safe-edit.d.ts +7 -3
  108. package/dist/safe-edit.js +40 -47
  109. package/dist/schemas.js +4 -2
  110. package/dist/server.d.ts +2 -16
  111. package/dist/server.js +14 -20
  112. package/dist/shared.d.ts +2 -0
  113. package/dist/shared.js +2 -0
  114. package/dist/skill-auditor.d.ts +19 -0
  115. package/dist/skill-auditor.js +32 -2
  116. package/dist/skill-catalog.d.ts +4 -1
  117. package/dist/skill-catalog.js +6 -5
  118. package/dist/store/ace-packed-store.d.ts +5 -1
  119. package/dist/store/ace-packed-store.js +33 -1
  120. package/dist/store/bootstrap-store.js +19 -12
  121. package/dist/store/cache-workspace.d.ts +8 -0
  122. package/dist/store/cache-workspace.js +94 -27
  123. package/dist/store/importer.js +11 -20
  124. package/dist/store/knowledge-bake.d.ts +3 -1
  125. package/dist/store/knowledge-bake.js +10 -1
  126. package/dist/store/legacy-vericify-posts.d.ts +8 -0
  127. package/dist/store/legacy-vericify-posts.js +76 -0
  128. package/dist/store/materializers/hook-context-materializer.d.ts +2 -1
  129. package/dist/store/materializers/hook-context-materializer.js +6 -2
  130. package/dist/store/materializers/host-file-materializer.js +2 -2
  131. package/dist/store/materializers/projection-manager.d.ts +4 -1
  132. package/dist/store/materializers/projection-manager.js +10 -3
  133. package/dist/store/materializers/todo-syncer.d.ts +39 -20
  134. package/dist/store/materializers/todo-syncer.js +208 -110
  135. package/dist/store/materializers/vericify-projector.js +15 -26
  136. package/dist/store/repositories/goal-repository.d.ts +51 -2
  137. package/dist/store/repositories/goal-repository.js +114 -48
  138. package/dist/store/repositories/playbook-repository.d.ts +41 -3
  139. package/dist/store/repositories/playbook-repository.js +61 -5
  140. package/dist/store/repositories/todo-repository.d.ts +8 -2
  141. package/dist/store/repositories/todo-repository.js +1 -1
  142. package/dist/store/repositories/vericify-repository.d.ts +4 -0
  143. package/dist/store/repositories/vericify-repository.js +46 -0
  144. package/dist/store/skills-install.d.ts +1 -0
  145. package/dist/store/skills-install.js +20 -16
  146. package/dist/store/source-preservation.d.ts +24 -0
  147. package/dist/store/source-preservation.js +79 -0
  148. package/dist/store/store-artifacts.js +8 -1
  149. package/dist/store/test-write-boundary.d.ts +16 -0
  150. package/dist/store/test-write-boundary.js +175 -0
  151. package/dist/store/types.d.ts +5 -1
  152. package/dist/store/write-coordinator.js +16 -0
  153. package/dist/task-plan-context.d.ts +11 -0
  154. package/dist/task-plan-context.js +59 -0
  155. package/dist/todo-state.d.ts +19 -9
  156. package/dist/todo-state.js +204 -321
  157. package/dist/tools-agent.d.ts +1 -1
  158. package/dist/tools-agent.js +38 -62
  159. package/dist/tools-files.d.ts +0 -3
  160. package/dist/tools-files.js +21 -11
  161. package/dist/tools-framework.js +16 -25
  162. package/dist/tools-goal.d.ts +2 -4
  163. package/dist/tools-goal.js +119 -16
  164. package/dist/tools-handoff.d.ts +3 -2
  165. package/dist/tools-handoff.js +53 -23
  166. package/dist/tools-lifecycle.js +1 -1
  167. package/dist/tools-memory.d.ts +0 -3
  168. package/dist/tools-memory.js +51 -6
  169. package/dist/tools-scheduler.js +20 -17
  170. package/dist/tools-todo.js +160 -148
  171. package/dist/vericify-bridge.d.ts +8 -0
  172. package/dist/vericify-bridge.js +18 -0
  173. package/dist/vericify-context.d.ts +4 -0
  174. package/dist/vericify-context.js +26 -5
  175. package/dist/vericify-native.d.ts +101 -0
  176. package/dist/vericify-native.js +221 -0
  177. package/dist/verification-worker.d.ts +2 -0
  178. package/dist/verification-worker.js +31 -0
  179. package/docs/mcp-tool-reference.md +50 -10
  180. package/docs/troubleshooting.md +29 -0
  181. package/package.json +19 -6
  182. package/scripts/dev/run-tests-isolated.mjs +165 -0
  183. package/scripts/dev/run_hermes_crispr_live.mjs +1 -0
  184. package/scripts/dev/test-isolation-guard.mjs +20 -0
  185. package/scripts/dev/test-preload.mjs +153 -0
  186. package/scripts/dev/test-source-inventory.mjs +31 -0
  187. 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: number;
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;
@@ -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
- child.kill("SIGTERM");
63
+ signalGroup("SIGTERM");
42
64
  forcedKillTimer = setTimeout(() => {
43
65
  if (!finished)
44
- child.kill("SIGKILL");
66
+ signalGroup("SIGKILL");
45
67
  }, 500);
46
68
  };
47
69
  const resetStallTimer = () => {
48
70
  if (stallTimer)
49
71
  clearTimeout(stallTimer);
50
- const stallTimeoutMs = options.stall_timeout_ms;
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
- clearTimeout(timeout);
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
- clearTimeout(timeout);
134
+ if (timeout)
135
+ clearTimeout(timeout);
95
136
  finish({
96
137
  exit_code: code,
97
138
  signal,
@@ -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 { appendVericifyProcessPostSafe, deriveVericifyRunRef, isVericifyBridgeEnabled, refreshVericifyBridgeSnapshotSafe, } from "./vericify-bridge.js";
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 appendVericifyProcessPostSafe({
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
- refreshVericifyBridgeSnapshotSafe();
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
- // Liveness defaults are explicit runtime policy. The resolved model class
668
- // only informs the default budget profile when the caller has not already
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(1, input.max_turns ?? runtimeProfileSnapshot.profile.executor.max_turns ?? 6);
1437
- const turnTimeout = Math.max(1_000, input.turn_timeout_ms ?? runtimeProfileSnapshot.profile.executor.turn_timeout_ms ?? 300_000);
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?.kill("SIGTERM");
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,
@@ -0,0 +1,6 @@
1
+ export declare function parseYamlFrontMatter(raw: string): Record<string, unknown>;
2
+ export declare function extractFrontMatter(raw: string): {
3
+ front_matter: string;
4
+ body: string;
5
+ };
6
+ //# sourceMappingURL=runtime-profile-syntax.d.ts.map