@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
@@ -1,27 +1,17 @@
1
- import { existsSync, readFileSync } from "node:fs";
1
+ import { existsSync } from "node:fs";
2
2
  import { resolve } from "node:path";
3
- import { readAceLogicalFile, resolveAceLogicalPath, resolveAceStateLayout, } from "./ace-state-resolver.js";
3
+ import { formatCurrentWork, resolveCurrentWork } from "./ace-autonomy.js";
4
+ import { withWorkspaceRoot } from "./helpers/workspace-root.js";
5
+ import { readAceLogicalFile, } from "./ace-state-resolver.js";
6
+ import { getHostBinding } from './host-work-context.js';
4
7
  const ACE_ROOT_REL = ".agents/ACE";
5
- const CORE_FILES = [
6
- "agent-state/TASK.md",
7
- "agent-state/STATUS.md",
8
- "agent-state/SCOPE.md",
9
- "agent-state/EVIDENCE_LOG.md",
10
- ];
11
- const STATE_DIRS = [
12
- "agent-state",
13
- "global-state",
14
- "venture-state",
15
- "brand-state",
16
- "engineering-state",
17
- ];
18
8
  const BOOTSTRAP_TOOLS = new Set([
19
9
  "bootstrap_state",
20
10
  "recall_context",
21
11
  "build_continuity_packet",
22
12
  ]);
23
13
  // Named set — new refresh_* tools must be added here explicitly.
24
- // These tools rewrite snapshot files but don't need EVIDENCE_LOG reconciliation guidance.
14
+ // Refreshes invalidate the current-work digest too.
25
15
  const REFRESH_TOOLS = new Set([
26
16
  "refresh_astgrep_index",
27
17
  "refresh_tracker_snapshot",
@@ -30,6 +20,7 @@ const REFRESH_TOOLS = new Set([
30
20
  // Named set — tools that mutate state but do not match any MUTATION_PREFIXES entry.
31
21
  // New mutation tools with non-standard prefixes must be added here explicitly.
32
22
  const NAMED_MUTATION_TOOLS = new Set([
23
+ 'next_step',
33
24
  "rewrite_targets",
34
25
  "apply_patch",
35
26
  "astgrep_rewrite",
@@ -64,18 +55,8 @@ const MUTATION_PREFIXES = [
64
55
  "update_",
65
56
  "write_",
66
57
  ];
67
- const DIGEST_CACHE_TTL_MS = 60_000;
58
+ const DIGEST_CACHE_TTL_MS = 2_000;
68
59
  const digestCache = new Map();
69
- function readIfPresent(filePath) {
70
- if (!existsSync(filePath))
71
- return undefined;
72
- try {
73
- return readFileSync(filePath, "utf-8");
74
- }
75
- catch {
76
- return undefined;
77
- }
78
- }
79
60
  function nonEmptyLines(input) {
80
61
  return input
81
62
  .split(/\r?\n/)
@@ -90,34 +71,6 @@ function truncate(input, max = 140) {
90
71
  return input;
91
72
  return `${input.slice(0, Math.max(0, max - 1)).trimEnd()}…`;
92
73
  }
93
- function resolveWorkspacePath(workspaceRoot, relativePath) {
94
- if (relativePath === "agent-state") {
95
- const layout = resolveAceStateLayout(workspaceRoot);
96
- if (layout.physicalMode === "top_level") {
97
- return resolve(workspaceRoot, "agent-state");
98
- }
99
- return resolve(workspaceRoot, ACE_ROOT_REL, "agent-state");
100
- }
101
- if (relativePath.startsWith("agent-state/")) {
102
- return (resolveAceLogicalPath(workspaceRoot, relativePath) ??
103
- resolve(workspaceRoot, ACE_ROOT_REL, relativePath));
104
- }
105
- const canonicalRel = relativePath.startsWith(`${ACE_ROOT_REL}/`)
106
- ? relativePath
107
- : `agent-state|global-state|venture-state|brand-state|engineering-state`
108
- .split("|")
109
- .some((prefix) => relativePath === prefix || relativePath.startsWith(`${prefix}/`))
110
- ? `${ACE_ROOT_REL}/${relativePath}`
111
- : relativePath;
112
- const canonicalPath = resolve(workspaceRoot, canonicalRel);
113
- if (canonicalRel !== relativePath) {
114
- const legacyPath = resolve(workspaceRoot, relativePath);
115
- if (!existsSync(canonicalPath) && existsSync(legacyPath)) {
116
- return legacyPath;
117
- }
118
- }
119
- return canonicalPath;
120
- }
121
74
  function displayWorkspacePath(workspaceRoot, relativePath) {
122
75
  if (relativePath === "agent-state" || relativePath.startsWith("agent-state/")) {
123
76
  return relativePath;
@@ -138,64 +91,8 @@ function displayWorkspacePath(workspaceRoot, relativePath) {
138
91
  }
139
92
  return canonicalRel;
140
93
  }
141
- function listExistingCoreFiles(workspaceRoot) {
142
- return CORE_FILES.filter((relativePath) => Boolean(resolveAceLogicalPath(workspaceRoot, relativePath)))
143
- .map((relativePath) => displayWorkspacePath(workspaceRoot, relativePath));
144
- }
145
- function listExistingStateDirs(workspaceRoot) {
146
- return STATE_DIRS.filter((relativePath) => existsSync(resolveWorkspacePath(workspaceRoot, relativePath)))
147
- .map((relativePath) => displayWorkspacePath(workspaceRoot, relativePath));
148
- }
149
- function extractObjective(taskRaw) {
150
- if (!taskRaw)
151
- return undefined;
152
- const match = taskRaw.match(/## Objective\s+([\s\S]*?)(?:\n## |\n# |$)/);
153
- if (match?.[1]) {
154
- return truncate(oneLine(match[1]));
155
- }
156
- const bodyLine = nonEmptyLines(taskRaw).find((line) => !line.startsWith("#"));
157
- if (bodyLine) {
158
- return truncate(oneLine(bodyLine));
159
- }
160
- const heading = taskRaw.match(/^#\s+(.+)$/m)?.[1];
161
- return heading ? truncate(oneLine(heading)) : undefined;
162
- }
163
- function extractStatusValue(statusRaw, label) {
164
- if (!statusRaw)
165
- return undefined;
166
- const pattern = new RegExp(`^- ${label}:\\s*(.+)$`, "m");
167
- const match = statusRaw.match(pattern);
168
- return match?.[1] ? truncate(oneLine(match[1])) : undefined;
169
- }
170
- function extractAutonomyHint(workspaceRoot) {
171
- const workflowRaw = readAceLogicalFile(workspaceRoot, "agent-state/ACE_WORKFLOW.md");
172
- if (!workflowRaw)
173
- return undefined;
174
- const hints = [];
175
- if (/^\s*orchestrator_preflight:\s*true\s*$/m.test(workflowRaw)) {
176
- hints.push("orchestrator preflight");
177
- }
178
- if (/^\s*recall_context:\s*true\s*$/m.test(workflowRaw)) {
179
- hints.push("context recall");
180
- }
181
- const reviewMode = workflowRaw.match(/^\s*review_mode:\s*["']?([A-Za-z0-9_-]+)["']?\s*$/m)?.[1];
182
- if (reviewMode) {
183
- hints.push(`review mode ${reviewMode}`);
184
- }
185
- return hints.length > 0 ? hints.join(", ") : undefined;
186
- }
187
94
  export function buildAceDigest(workspaceRoot) {
188
- const taskRaw = readAceLogicalFile(workspaceRoot, "agent-state/TASK.md");
189
- const statusRaw = readAceLogicalFile(workspaceRoot, "agent-state/STATUS.md");
190
- const objective = extractObjective(taskRaw);
191
- const phase = extractStatusValue(statusRaw, "Current phase");
192
- const blockers = extractStatusValue(statusRaw, "Blockers");
193
- const parts = [
194
- objective ? `task=${objective}` : undefined,
195
- phase ? `phase=${phase}` : undefined,
196
- blockers ? `blockers=${blockers}` : undefined,
197
- ].filter((value) => Boolean(value));
198
- return parts.length > 0 ? parts.join(" | ") : "ACE state detected; load recall_context for task and status.";
95
+ return formatCurrentWork(resolveCurrentWork({ workspaceRoot }), "line");
199
96
  }
200
97
  function buildAceDigestCached(workspaceRoot) {
201
98
  const now = Date.now();
@@ -207,87 +104,34 @@ function buildAceDigestCached(workspaceRoot) {
207
104
  return value;
208
105
  }
209
106
  export function buildServerInstructions(workspaceRoot) {
210
- const coreFiles = listExistingCoreFiles(workspaceRoot);
211
- const stateDirs = listExistingStateDirs(workspaceRoot);
212
- const digest = buildAceDigest(workspaceRoot);
213
- const autonomyHint = extractAutonomyHint(workspaceRoot);
214
- const lines = [
215
- "You are operating in an ACE-governed workspace.",
216
- coreFiles.length > 0
217
- ? `Ground truth for task/status/scope/evidence is store-backed under ${coreFiles.join(", ")} (canonical store: ${ACE_ROOT_REL}/agent-state/ace-state.ace).`
218
- : `Ground truth is store-backed under ${ACE_ROOT_REL}/agent-state/* artifacts (canonical store: ${ACE_ROOT_REL}/agent-state/ace-state.ace), not chat history.`,
219
- "`ace compact` and the automatic lifecycle sweep intentionally remove loose agent-state/* files from disk after folding them into the store — this is expected, not data loss, and applies to every swept artifact (kanban, run-ledger, handoffs, playbook, tracker snapshots, etc.), not only TASK/STATUS/SCOPE/EVIDENCE_LOG. If a path is not on disk, call list_workspace on its directory to see the full store-backed listing (or `ace ls` from the CLI), then read it back with read_workspace_file (or `ace read <path>`); never recreate swept files.",
220
- stateDirs.length > 0
221
- ? `Durable artifacts belong under ${stateDirs.map((entry) => `${entry}/`).join(", ")} and are persisted into the store; the loose copies are sweep inputs, not the source of truth.`
222
- : undefined,
223
- "Before significant work, call recall_context to load current task, scope, and status.",
224
- "Use route_task and get_agent_instructions for role guidance; do not self-assign by guesswork.",
225
- "After meaningful edits or state changes, call execute_gates and persist evidence/handoffs in ACE artifacts.",
226
- "For delegated or long-running work, use create_handoff / ack_handoff and append_vericify_process_post instead of ad-hoc status notes.",
227
- "For self-paced, evidence-gated multi-step objectives beyond this session, use start_goal / get_goal_status / resume_goal / stop_goal (or `ace goal` from the CLI).",
228
- "Prefer the matching MCP tool over ad-hoc shell/chat tracking: git_status / git_diff / git_log / git_commit for git; enqueue_job / dispatch_jobs / heartbeat_job / get_lock_table for background jobs; snapshot_state / semantic_diff / drift_report / rewrite_targets for change intelligence.",
229
- "skill_catalog_summary / skill_audit / problem_triage surface packaged skills; get_todo / update_todo / get_run_ledger is the human-facing todo surface; scan_workspace_delta / web_research_packet / codemunch_snapshot / codemunch_index cover workspace-wide search and indexing.",
230
- `Current ACE digest: ${digest}.`,
231
- autonomyHint ? `Runtime autonomy signals: ${autonomyHint}.` : undefined,
232
- ];
233
- return lines.filter((line) => Boolean(line)).join("\n");
234
- }
235
- export function buildHostInstructionText(host, workspaceRoot) {
236
- const hostLabel = {
237
- claude: "Claude Code",
238
- copilot: "GitHub Copilot",
239
- cursor: "Cursor",
240
- codex: "Codex",
241
- }[host];
242
107
  return [
243
- `# ACE Bootstrap For ${hostLabel}`,
244
- "",
245
- "This is a thin ACE bootstrap stub.",
246
- "Full instructions, skills, task packs, and runtime state live in ACE artifacts and should be accessed through the ACE MCP server.",
247
- "",
248
- "Session start protocol:",
249
- "1. Call `recall_context` to load task, scope, and status through the ACE MCP server.",
250
- "2. Call `route_task` and `get_agent_instructions` before choosing a role.",
251
- "3. Prefer ACE prompts/resources (`ace-orchestrator`, `get_task_pack`, `get_skill_instructions`) over relying on this file.",
252
- "4. Read/write task state through MCP tools (`recall_context`, `read_workspace_file`, `write_workspace_file`, lifecycle append tools); do not create files under `agent-state/` directly.",
253
- "5. For self-paced, evidence-gated multi-step objectives beyond this session, use `start_goal` / `get_goal_status` / `resume_goal` / `stop_goal` (or `ace goal` from the CLI).",
254
- "6. Also prefer the matching MCP domain over ad-hoc equivalents for git, background jobs/scheduler, change intelligence, discovery/indexing, skills, and todo — see docs/mcp-tool-reference.md for the full per-domain tool catalog.",
108
+ "You are working in an ACE workspace. ACE keeps the durable state of the work so you can spend your turns doing it.",
255
109
  "",
256
- "Ground truth:",
257
- "- ACE MCP tools are the authoritative interface for task state and lifecycle updates.",
258
- "- `agent-state/ace-state.ace` is the canonical store path; visible `agent-state/*` files are compatibility projections or sweep inputs.",
259
- "- `ace compact` and the automatic lifecycle sweep intentionally remove loose `agent-state/*` files from disk after folding them into the store — this is expected, not data loss, for any swept artifact. Do NOT recreate them; if a path isn't on disk, call `list_workspace` on its directory (or `ace ls`) to see the full store-backed listing, then retrieve it via `ace read <path>` or the `read_workspace_file` / `recall_context` MCP tools.",
260
- "- `.agents/ACE/tasks/todo.md` is the human-facing todo surface.",
261
- "- Hook context is store-backed in `agent-state/ace-state.ace` and consumed without extra workspace projections.",
110
+ formatCurrentWork(resolveCurrentWork({ workspaceRoot }), "block"),
262
111
  "",
263
- `Workspace digest hint: ${buildAceDigest(workspaceRoot)}.`,
112
+ "Goal work: next_step → do the work with your own tools → complete_step (updates linked work and returns the next step). Create a host-authored plan with start_goal executor:host.",
113
+ "Verification runs in the background. A pending receipt is not goal completion: use get_goal_status view:compact; retain live work. Goals have no default time or step ceiling. Budget increases require operator approval; operator_proposal is not authorization. Never approve your own increase. stop_goal pauses work; resume_goal preserves accepted attempts.",
114
+ "Standalone tasks: update_todo to start or finish; create_handoff to delegate to another agent.",
115
+ "After a restart or compaction: recall_context returns the current work.",
116
+ "State lives in agent-state/ace-state.ace. For a missing file, inspect list_workspace/read_workspace_file; report failed readback as missing history. Claim preservation only with verified readback.",
117
+ "Other ACE tools are optional; see docs/mcp-tool-reference.md.",
264
118
  ].join("\n");
265
119
  }
120
+ export function buildHostInstructionText(host, workspaceRoot) {
121
+ const hostLabel = { claude: "Claude Code", copilot: "GitHub Copilot", cursor: "Cursor", codex: "Codex" }[host];
122
+ return `# ACE Bootstrap For ${hostLabel}\n\n${buildServerInstructions(workspaceRoot)}\n`;
123
+ }
266
124
  export function buildBootstrapNudge(workspaceRoot) {
267
- const coreFiles = listExistingCoreFiles(workspaceRoot);
268
- return [
269
- "ACE bootstrap hint: call `recall_context` before significant work so task and scope come from file-backed state.",
270
- `ACE digest: ${buildAceDigestCached(workspaceRoot)}.`,
271
- coreFiles.length > 0 ? `Current core files: ${coreFiles.join(", ")}.` : undefined,
272
- ]
273
- .filter((value) => Boolean(value))
274
- .join(" ");
125
+ return buildAceDigestCached(workspaceRoot);
275
126
  }
276
- export function buildBootstrapGuidance(workspaceRoot, toolName) {
277
- return `ACE context loaded via \`${toolName}\`. Current digest: ${buildAceDigestCached(workspaceRoot)}.`;
127
+ export function buildBootstrapGuidance(workspaceRoot, _toolName) {
128
+ return buildAceDigest(workspaceRoot);
278
129
  }
279
- export function buildMutationGuidance(workspaceRoot, toolName) {
280
- const evidencePath = displayWorkspacePath(workspaceRoot, "agent-state/EVIDENCE_LOG.md");
281
- return [
282
- `ACE digest after \`${toolName}\`: ${buildAceDigestCached(workspaceRoot)}.`,
283
- `If this changed code or state, reconcile \`${evidencePath}\`, run \`execute_gates\` when appropriate, and use structured handoffs/process posts for delegated follow-up.`,
284
- ].join(" ");
130
+ export function buildMutationGuidance(workspaceRoot, _toolName) {
131
+ return buildAceDigest(workspaceRoot);
285
132
  }
286
- export function buildRefreshGuidance(workspaceRoot, toolName) {
287
- return [
288
- `ACE snapshot refresh completed via \`${toolName}\`.`,
289
- `Current digest: ${buildAceDigestCached(workspaceRoot)}.`,
290
- ].join(" ");
133
+ export function buildRefreshGuidance(workspaceRoot, _toolName) {
134
+ return buildAceDigest(workspaceRoot);
291
135
  }
292
136
  function isBootstrapTool(toolName) {
293
137
  return BOOTSTRAP_TOOLS.has(toolName);
@@ -329,7 +173,21 @@ export function installAceToolGovernance(server, workspaceRoot) {
329
173
  const wrapToolCallback = (toolName, callback) => async (...args) => {
330
174
  const extra = args.at(-1);
331
175
  const sessionId = typeof extra?.sessionId === "string" ? extra.sessionId : undefined;
332
- const rawResult = await callback(...args);
176
+ const activeStep = withWorkspaceRoot(workspaceRoot, () => getHostBinding(sessionId));
177
+ if (activeStep && !['next_step', 'complete_step', 'start_goal'].includes(toolName)) {
178
+ const { recordHostContact } = await import('./host-goal-engine.js');
179
+ await withWorkspaceRoot(workspaceRoot, () => recordHostContact(activeStep)).catch(error => console.error(`ACE contact pending: ${String(error)}`));
180
+ }
181
+ const rawResult = await withWorkspaceRoot(workspaceRoot, () => callback(...args));
182
+ if (['run_tests', 'execute_gates', 'safe_edit_file', 'apply_patch'].includes(toolName)) {
183
+ const { recordHostToolEvidence } = await import('./host-goal-engine.js');
184
+ await withWorkspaceRoot(workspaceRoot, () => recordHostToolEvidence(toolName, rawResult, activeStep)).catch(error => console.error(`ACE step evidence pending: ${error instanceof Error ? error.message : String(error)}`));
185
+ }
186
+ if (isMutationTool(toolName) || isRefreshTool(toolName) || isBootstrapTool(toolName))
187
+ digestCache.delete(workspaceRoot);
188
+ // These responses already contain current work. Replays must remain byte-for-byte stable.
189
+ if (['next_step', 'complete_step'].includes(toolName) || (toolName === 'start_goal' && args[0]?.executor === 'host'))
190
+ return rawResult;
333
191
  const failed = Boolean(rawResult && typeof rawResult === "object" && rawResult.isError);
334
192
  if (sessionId && !failed && isBootstrapTool(toolName)) {
335
193
  bootstrappedSessions.add(sessionId);
@@ -345,7 +203,7 @@ export function installAceToolGovernance(server, workspaceRoot) {
345
203
  next = appendTextContent(next, buildBootstrapNudge(workspaceRoot));
346
204
  }
347
205
  }
348
- if (isBootstrapTool(toolName)) {
206
+ if (isBootstrapTool(toolName) && !failed) {
349
207
  next = appendTextContent(next, buildBootstrapGuidance(workspaceRoot, toolName));
350
208
  }
351
209
  else if (isRefreshTool(toolName)) {
@@ -353,7 +211,7 @@ export function installAceToolGovernance(server, workspaceRoot) {
353
211
  }
354
212
  else if (isMutationTool(toolName)) {
355
213
  const mutationKey = sessionId ?? "__global__";
356
- const currentDigest = buildAceDigestCached(workspaceRoot);
214
+ const currentDigest = buildAceDigest(workspaceRoot);
357
215
  const state = mutationGuidanceState.get(mutationKey) ?? { count: 0 };
358
216
  state.count += 1;
359
217
  const shouldAppend = state.lastDigest === undefined || state.lastDigest !== currentDigest || state.count % 10 === 0;
@@ -382,11 +240,7 @@ export function installAceToolGovernance(server, workspaceRoot) {
382
240
  };
383
241
  }
384
242
  export function buildHookAdditionalContext(workspaceRoot) {
385
- const parts = [
386
- buildServerInstructions(workspaceRoot),
387
- `State digest: ${buildAceDigest(workspaceRoot)}.`,
388
- ];
389
- return parts.join("\n");
243
+ return formatCurrentWork(resolveCurrentWork({ workspaceRoot }), "block");
390
244
  }
391
245
  export function buildScopeReminder(workspaceRoot) {
392
246
  const scopeRaw = readAceLogicalFile(workspaceRoot, "agent-state/SCOPE.md");
package/dist/cli.js CHANGED
@@ -37,6 +37,7 @@ Usage:
37
37
  ace turnkey [options] Project minimal workspace bootstrap stubs from the ACE store
38
38
  ace doctor [options] Validate ACE runtime + MCP readiness
39
39
  ace goal <sub> [options] Drive a self-paced, evidence-gated goal loop
40
+ ace learn <sub> [args] List, show, approve, retire, export or report learned artifacts
40
41
  ace playbook <sub> [args] Inspect and curate the experience playbook (experimental)
41
42
  ace eval [--adapt] [options] Run the eval harness / playbook adaptation cycle (experimental)
42
43
  ace compact [--no-sweep] Compact the store and sweep loose generated artifacts
@@ -57,7 +58,8 @@ Options for goal:
57
58
  [--max-ticks N] [--goal-id <id>] [--plan-only] [--detach]
58
59
  status [<goal_id>] List goals, or show one goal's plan and escalations
59
60
  run <goal_id> Drive an already-executing goal to a terminal state
60
- resume <goal_id> Revive a planning/blocked/stopped goal, then drive it
61
+ resume <goal_id> [--budget-hours N] [--max-replans N]
62
+ Raise explicit allowances if authorized, then resume
61
63
  stop <goal_id> Request a cooperative stop (honoured between steps)
62
64
 
63
65
  A goal only reaches \`done\` when its success contract is satisfied: every
@@ -1019,7 +1021,6 @@ async function runDoctor(args) {
1019
1021
  if (provider === "ollama" && !hasModel && repairOllama) {
1020
1022
  const repair = await runShellCommand(`ollama pull ${model}`, {
1021
1023
  cwd: WORKSPACE_ROOT,
1022
- timeout_ms: 10 * 60_000,
1023
1024
  });
1024
1025
  await appendRunLedgerEntrySafe({
1025
1026
  tool: "doctor",
@@ -1429,7 +1430,7 @@ async function runGoalCliInner(args) {
1429
1430
  console.error(`Usage: ace goal ${sub} <goal_id>`);
1430
1431
  process.exit(1);
1431
1432
  }
1432
- const run = sub === "resume" ? await engine.resumeGoal(goalId) : await engine.runGoal(goalId);
1433
+ const run = sub === "resume" ? await engine.resumeGoal(goalId, {}, { budget_hours: readNumberFlag(args, "--budget-hours"), max_replans: readNumberFlag(args, "--max-replans") }) : await engine.runGoal(goalId);
1433
1434
  console.log(`Goal ${run.goal.goal_id}: ${run.goal.status}${run.goal.reason_code ? ` (${run.goal.reason_code})` : ""}`);
1434
1435
  return;
1435
1436
  }
@@ -1439,7 +1440,7 @@ async function runGoalCliInner(args) {
1439
1440
  console.error("Usage: ace goal stop <goal_id>");
1440
1441
  process.exit(1);
1441
1442
  }
1442
- const goal = engine.stopGoal(goalId);
1443
+ const goal = await engine.stopGoal(goalId);
1443
1444
  console.log(`Goal ${goal.goal_id}: stop requested (status ${goal.status}).`);
1444
1445
  return;
1445
1446
  }
@@ -1703,8 +1704,10 @@ async function main() {
1703
1704
  if (result.sweep) {
1704
1705
  console.log(`Sweep: folded ${result.sweep.cached_files} artifact(s) into the store, freed ${result.sweep.removed_files} loose file(s) from disk, semantic GC removed ${result.sweep.removed_semantic_cache_files}`);
1705
1706
  if (result.sweep.removed_files > 0) {
1706
- console.log(" Swept files are stored, not lost — read them back with `ace read <path>` (e.g. `ace read agent-state/TASK.md`). Do not recreate them.");
1707
+ console.log(` Verified source readbacks: ${result.sweep.verified_sources.filter((source) => source.removed).length}. Receipts and exact source bytes are retained under state/migrations/.`);
1707
1708
  }
1709
+ for (const warning of result.sweep.warnings)
1710
+ console.warn(` ! ${warning}`);
1708
1711
  }
1709
1712
  return;
1710
1713
  }
@@ -1747,7 +1750,7 @@ async function main() {
1747
1750
  console.log(`Cached files: ${result.cached_files}`);
1748
1751
  console.log(`Kept projected files: ${result.kept_projected_files}`);
1749
1752
  console.log(`Skipped files: ${result.skipped_files}`);
1750
- console.log(`Removed files: ${result.removed_files} (folded into the store, not lost — read back with \`ace read <path>\`; do not recreate)`);
1753
+ console.log(`Removed files: ${result.removed_files}; verified source readbacks: ${result.verified_sources.filter((source) => source.removed).length}`);
1751
1754
  console.log(`Semantic cache GC removed files: ${result.removed_semantic_cache_files}`);
1752
1755
  console.log(`Staging GC removed entries: ${stagingGc.removed_entries}`);
1753
1756
  if (result.warnings.length > 0) {
@@ -1775,6 +1778,41 @@ async function main() {
1775
1778
  await runEvalCli(args.slice(1));
1776
1779
  return;
1777
1780
  }
1781
+ if (command === 'learn') {
1782
+ const rest = args.slice(1);
1783
+ try {
1784
+ const { listLearning, showLearning, approveLearning, retireLearning, exportLearning, learningReport } = await import('./learning-controls.js');
1785
+ const sub = rest[0] ?? 'list';
1786
+ let result;
1787
+ if (sub === 'list')
1788
+ result = listLearning(WORKSPACE_ROOT);
1789
+ else if (sub === 'show') {
1790
+ result = showLearning(WORKSPACE_ROOT, rest[1]);
1791
+ if (!result)
1792
+ throw Error('Learning item not found: ' + rest[1]);
1793
+ }
1794
+ else if (sub === 'approve') {
1795
+ await approveLearning(WORKSPACE_ROOT, rest[1]);
1796
+ result = { approved: rest[1] };
1797
+ }
1798
+ else if (sub === 'retire') {
1799
+ await retireLearning(WORKSPACE_ROOT, rest[1], readFlagValue(rest, '--reason') ?? '');
1800
+ result = { retired: rest[1] };
1801
+ }
1802
+ else if (sub === 'export')
1803
+ result = await exportLearning(WORKSPACE_ROOT, readFlagValue(rest, '--to') ?? 'docs/learned');
1804
+ else if (sub === 'report')
1805
+ result = learningReport(WORKSPACE_ROOT);
1806
+ else
1807
+ throw Error('Usage: ace learn list|show <id>|approve <id>|retire <id> --reason <text>|export --to docs/learned|report');
1808
+ console.log(JSON.stringify(result, null, 2));
1809
+ }
1810
+ catch (error) {
1811
+ console.error(String(error));
1812
+ process.exitCode = 1;
1813
+ }
1814
+ return;
1815
+ }
1778
1816
  if (command === "playbook") {
1779
1817
  await runPlaybookCli(args.slice(1));
1780
1818
  return;
@@ -10,4 +10,11 @@ export interface ReflectDeterministicInput {
10
10
  maxOpsPerRun?: number;
11
11
  }
12
12
  export declare function reflectDeterministic(input: ReflectDeterministicInput): PlaybookDeltaOp[];
13
+ import type { TaskStep, ObservedRun } from './orchestrator-supervisor.js';
14
+ import type { GoalRecord } from './store/repositories/goal-repository.js';
15
+ export declare function normalizedFailureLines(text: string): string[];
16
+ export declare function failureSignature(text: string): string | undefined;
17
+ export declare function exactRedGreen(runs: ObservedRun[]): Array<[ObservedRun, ObservedRun]>;
18
+ export declare function learningTaskText(step: TaskStep): string;
19
+ export declare function reflectFromStepOutcome(step: TaskStep, goal: Pick<GoalRecord, 'goal_id'>): PlaybookDeltaOp[];
13
20
  //# sourceMappingURL=experience-reflector.d.ts.map
@@ -59,4 +59,43 @@ export function reflectDeterministic(input) {
59
59
  }
60
60
  return ops.slice(0, input.maxOpsPerRun ?? 3);
61
61
  }
62
+ // Attached hosts use their existing plan attempts, never local bridge traces.
63
+ import { createHash } from 'node:crypto';
64
+ export function normalizedFailureLines(text) {
65
+ return text.split(/\r?\n/).filter(line => /(error|fail|assert|exception|not ok|✗|denied|timeout)/i.test(line)).map(line => line
66
+ .replace(/\b\d{4}-\d\d-\d\d[T ][\d:.]+Z?\b/g, '<time>')
67
+ .replace(/(?:[A-Za-z]:[\\/]|\/)[^\s'"`:)]+(?::\d+(?::\d+)?)?/g, '<path>')
68
+ .replace(/:\d+(?::\d+)?/g, ':<line>')
69
+ .replace(/\b[0-9a-f]{8,}\b/gi, '<id>')
70
+ .replace(/"[^"\n]*"|'[^'\n]*'|`[^`\n]*`/g, '<value>')
71
+ .replace(/\s+/g, ' ').trim()).filter(Boolean);
72
+ }
73
+ export function failureSignature(text) {
74
+ const lines = normalizedFailureLines(text).slice(0, 3);
75
+ return lines.length ? createHash('sha256').update(lines.join('\n')).digest('hex').slice(0, 12) : undefined;
76
+ }
77
+ export function exactRedGreen(runs) {
78
+ return runs.flatMap((run, index) => {
79
+ if (run.attribution !== 'Linked' || run.outcome !== 'failed' || run.exit_code === null || run.exit_code === 0)
80
+ return [];
81
+ const pass = runs.slice(index + 1).find(next => next.attribution === 'Linked' && next.command === run.command && next.cwd === run.cwd && next.outcome === 'ok' && next.exit_code === 0 && next.at >= run.at);
82
+ return pass ? [[run, pass]] : [];
83
+ });
84
+ }
85
+ export function learningTaskText(step) {
86
+ const owned = step.attempts_log?.flatMap(a => a.checks ?? []);
87
+ return owned?.length ? owned.map(c => c.command).join('\n') : step.task;
88
+ }
89
+ export function reflectFromStepOutcome(step, goal) {
90
+ const log = step.attempts_log ?? [], current = log.at(-1), previous = log.at(-2);
91
+ if (!current)
92
+ return [];
93
+ const paths = [...new Set([...(step.expected_artifacts ?? []).map(a => a.path), ...current.evidence_refs, ...(previous?.evidence_refs ?? [])].filter(ref => !/^(ep:|ace:|goal:|https?:|vericify:)/.test(ref)).map(p => p.replace(/\\/g, '/').replace(/^\.\//, '').split('/').slice(0, 2).join('/')))];
94
+ const tags = ['test', 'build', 'store', 'todo', 'handoff', 'scheduler', 'migration', 'docs', 'release', 'mcp', 'hook', 'schema'].filter(tag => learningTaskText(step).toLowerCase().includes(tag));
95
+ const ep = (attempt) => `ep:${goal.goal_id}:${step.step_id}:${attempt}`;
96
+ const contrast = current.status === 'done' && previous?.failure_signature && previous.status !== 'done' ? [{ signature: previous.failure_signature, excerpt: previous.failure_excerpt ?? previous.summary, refs: [ep(previous.attempt), ep(current.attempt), ...previous.evidence_refs, ...current.evidence_refs], paths }] : [];
97
+ for (const [failed, passed] of exactRedGreen(current.observed_runs ?? []))
98
+ contrast.push({ signature: failureSignature(failed.output_tail ?? '') ?? 'command-failed', excerpt: failed.output_tail ?? `Command failed: ${failed.command}`, refs: [ep(current.attempt), failed.record_id, passed.record_id, ...current.evidence_refs], paths: [...new Set([...(failed.paths ?? []), ...(passed.paths ?? [])])] });
99
+ return contrast.map(pair => ({ type: 'ADD', section: 'failure_modes', status: 'quarantined', scope: { role: step.role, paths: pair.paths, task_tags: tags, failure_signature: pair.signature }, content: `When ${pair.excerpt.split('\n')[0]} occurred at ${step.role}/${pair.paths.join(', ')}, the passing attempt did: ${current.summary.slice(0, 300)}`, evidence_refs: pair.refs, provenance: { source: 'harvest', run_id: ep(current.attempt) } }));
100
+ }
62
101
  //# sourceMappingURL=experience-reflector.js.map
@@ -1,5 +1,8 @@
1
1
  /**
2
- * ACE Goal Engine (WS-F).
2
+ * ACE Goal Engine (WS-F), with attached MCP execution for host-authored plans.
3
+ * Host goals use the same filesystem records and plan primitives through
4
+ * next_step/complete_step. They enforce their declared contract and explicitly
5
+ * label completion without verification commands as not machine-verified.
3
6
  *
4
7
  * `startGoal("<objective>")` compiles a plan with ACE's own planner, then a
5
8
  * self-paced driver loop (`runGoal`) executes it step-by-step under evidence-
@@ -9,7 +12,7 @@
9
12
  * structurally impossible (there is no code path from a model message to
10
13
  * `status: "done"`).
11
14
  *
12
- * That guarantee rests on the success contract carrying at least one
15
+ * In the engine-executed path, that guarantee rests on the success contract carrying at least one
13
16
  * machine-checkable obligation. A contract with none is refused at `startGoal`
14
17
  * and again at verify time with `contract_uncheckable`, never satisfied
15
18
  * vacuously — see {@link enforceableObligationCount}.
@@ -30,6 +33,7 @@ import type { BridgeResult } from "./model-bridge.js";
30
33
  import { type TaskPlan, type TaskStep } from "./orchestrator-supervisor.js";
31
34
  import type { ProposePlanResult } from "./plan-proposal.js";
32
35
  import { GoalRepository, type GoalEscalationKind, type GoalRecord, type SuccessContract } from "./store/repositories/goal-repository.js";
36
+ import { type CommandOptions, type CommandPolicy } from './progress-command.js';
33
37
  export type { GoalRecord, GoalStatus, GoalBudgets, SuccessContract, } from "./store/repositories/goal-repository.js";
34
38
  export interface CompiledPlan {
35
39
  proposal: ProposePlanResult;
@@ -40,6 +44,20 @@ export interface CompiledPlan {
40
44
  };
41
45
  }
42
46
  export interface GoalEngineDeps {
47
+ observations?: {
48
+ supported_requirements?: readonly ("action" | "command_pass")[];
49
+ late_evidence?: {
50
+ wait_ms: number;
51
+ poll_ms?: number;
52
+ };
53
+ readWindow: (window: NonNullable<TaskStep["observation_window"]>) => Promise<{
54
+ status: "available" | "pending" | "unavailable";
55
+ records: NonNullable<TaskStep["observation_refs"]>;
56
+ reason_code?: string;
57
+ query?: Record<string, unknown>;
58
+ coverage?: Record<string, unknown>;
59
+ }>;
60
+ };
43
61
  workspaceRoot?: string;
44
62
  /** Millisecond clock (injectable so budgets/heartbeats are deterministic). */
45
63
  now?: () => number;
@@ -48,7 +66,9 @@ export interface GoalEngineDeps {
48
66
  /** Compiles an objective into a validated proposal. Default: proposePlan+validatePlan. */
49
67
  compilePlan?: (objective: string) => Promise<CompiledPlan>;
50
68
  /** Runs a verification command; ok === (exit 0). Default: exec in workspace. */
51
- runVerification?: (command: string, workspaceRoot: string) => Promise<{
69
+ runVerification?: (command: string, workspaceRoot: string, options?: CommandOptions & {
70
+ timeout_ms?: number;
71
+ }) => Promise<{
52
72
  ok: boolean;
53
73
  output: string;
54
74
  }>;
@@ -62,7 +82,7 @@ export interface GoalEngineDeps {
62
82
  summary: string;
63
83
  payload: Record<string, unknown>;
64
84
  }) => Promise<void>;
65
- /** Vericify process-post sink. Default: appendVericifyProcessPostSafe. */
85
+ /** Vericify process-post sink. Default: appendAutomaticVericifyProcessPostSafe. */
66
86
  appendProcessPost?: (input: {
67
87
  kind: GoalEscalationKind | "progress" | "completion";
68
88
  summary: string;
@@ -71,13 +91,39 @@ export interface GoalEngineDeps {
71
91
  }) => Promise<void>;
72
92
  }
73
93
  export interface StartGoalOptions {
94
+ executor?: "engine" | "host";
95
+ agent?: string;
96
+ session_id?: string;
97
+ steps?: Array<{
98
+ id?: string;
99
+ task: string;
100
+ role?: string;
101
+ depends_on?: string[];
102
+ expected_artifacts?: Array<string | {
103
+ path: string;
104
+ required?: boolean;
105
+ transient?: boolean;
106
+ }>;
107
+ required_evidence_refs?: string[];
108
+ required_observation?: "action" | "command_pass";
109
+ }>;
110
+ todo_ids?: Record<string, string>;
74
111
  budget_hours?: number;
75
112
  max_ticks?: number;
76
113
  max_replans?: number;
77
114
  plan_only?: boolean;
78
115
  goal_id?: string;
79
116
  /** Shell commands that must exit 0 before the goal can reach `done`. */
80
- verify_commands?: string[];
117
+ verify_commands?: VerificationCommand[];
118
+ }
119
+ export type VerificationCommand = string | ({
120
+ cmd: string;
121
+ } & CommandPolicy);
122
+ export declare const verificationCommandText: (command: VerificationCommand) => string;
123
+ export interface ResumeGoalOptions {
124
+ /** New total allowance from the original start, not a restart of the clock. */
125
+ budget_hours?: number;
126
+ max_replans?: number;
81
127
  }
82
128
  interface ResolvedDeps {
83
129
  workspaceRoot: string;
@@ -91,6 +137,7 @@ interface ResolvedDeps {
91
137
  emitStatusEvent: NonNullable<GoalEngineDeps["emitStatusEvent"]>;
92
138
  appendProcessPost: NonNullable<GoalEngineDeps["appendProcessPost"]>;
93
139
  }
140
+ export declare function resolveGoalDeps(deps?: GoalEngineDeps): ResolvedDeps;
94
141
  /**
95
142
  * The number of machine-checkable obligations in a contract. Zero means the
96
143
  * only thing standing between the model and `status: "done"` is the model's own
@@ -104,6 +151,10 @@ export interface StartGoalResult {
104
151
  goal: GoalRecord;
105
152
  reason_code?: string;
106
153
  blocking_findings?: string[];
154
+ assignment?: import('./host-goal-engine.js').Assignment;
155
+ now?: string;
156
+ message?: string;
157
+ waiting_on?: string[];
107
158
  }
108
159
  export declare function startGoal(objective: string, options?: StartGoalOptions, deps?: GoalEngineDeps): Promise<StartGoalResult>;
109
160
  export interface TickGoalResult {
@@ -119,6 +170,7 @@ export interface ContractCheckResult {
119
170
  missing_artifacts: string[];
120
171
  missing_evidence_refs: string[];
121
172
  failed_commands: string[];
173
+ failure_signatures?: string[];
122
174
  /** True when the contract carries zero enforceable obligations. Never `ok`. */
123
175
  uncheckable: boolean;
124
176
  }
@@ -128,8 +180,11 @@ export interface RunGoalResult {
128
180
  plan?: TaskPlan;
129
181
  }
130
182
  export declare function runGoal(goalId: string, deps?: GoalEngineDeps): Promise<RunGoalResult>;
131
- export declare function resumeGoal(goalId: string, deps?: GoalEngineDeps): Promise<RunGoalResult>;
132
- export declare function stopGoal(goalId: string, deps?: GoalEngineDeps): GoalRecord;
183
+ export declare function resumeGoal(goalId: string, deps?: GoalEngineDeps, options?: ResumeGoalOptions): Promise<RunGoalResult>;
184
+ /** Operator-approved increases retain the original clock and all accepted work. */
185
+ export declare function recoverEngineGoalBudgets(goalId: string, options: ResumeGoalOptions, deps?: GoalEngineDeps): Promise<GoalRecord>;
186
+ export { beginStep, completeStep, applyHostResultToStep } from './host-goal-engine.js';
187
+ export declare function stopGoal(goalId: string, deps?: GoalEngineDeps): Promise<GoalRecord>;
133
188
  export interface GoalStatusView {
134
189
  goal: GoalRecord;
135
190
  plan?: TaskPlan;
@@ -152,4 +207,6 @@ export declare class GoalNotResumableError extends Error {
152
207
  readonly name = "GoalNotResumableError";
153
208
  constructor(goal_id: string, message: string);
154
209
  }
210
+ /** Learning groups related failures; loop detection must also retain exact test identities. */
211
+ export declare function failureProgressSignature(text: string): string;
155
212
  //# sourceMappingURL=goal-engine.d.ts.map