@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
@@ -2,6 +2,7 @@
2
2
  * Job scheduler tool registrations.
3
3
  */
4
4
  import { z } from "zod";
5
+ import { resolveWorkspaceRoot } from "./helpers.js";
5
6
  import { acknowledgeJob, completeJob, dispatchJobNow, dispatchJobs, enqueueJob, getJobLockTablePath, getJobQueuePath, getSchedulerLeasePath, heartbeatJob, reapStaleRunningJobsTick, readJobQueue, readJobLockTable, readSchedulerLease, } from "./job-scheduler.js";
6
7
  // Event emission handled in core job-scheduler.ts — no wrapper duplication.
7
8
  const PRIORITY_BAND_ENUM = z.enum(["P0", "P1", "P2", "P3"]);
@@ -22,6 +23,7 @@ function asJsonBlock(value) {
22
23
  return `\`\`\`json\n${JSON.stringify(value, null, 2)}\n\`\`\``;
23
24
  }
24
25
  export function registerSchedulerTools(server) {
26
+ const workspaceRoot = resolveWorkspaceRoot();
25
27
  server.tool("enqueue_job", "Add a handoff job to the scheduler queue with priority/dependency/resource metadata", {
26
28
  kind: z.string().describe("Job kind/type identifier"),
27
29
  payload: z
@@ -46,7 +48,7 @@ export function registerSchedulerTools(server) {
46
48
  backoff_ms: z.number().int().min(1000).max(86_400_000).optional(),
47
49
  job_id: z.string().optional().describe("Optional caller-provided job id"),
48
50
  }, async (input) => {
49
- const result = await enqueueJob(input);
51
+ const result = await enqueueJob(input, workspaceRoot);
50
52
  return {
51
53
  content: [
52
54
  {
@@ -78,15 +80,15 @@ export function registerSchedulerTools(server) {
78
80
  .describe("Include lock table payload (default true)"),
79
81
  limit: z.number().int().min(1).max(1000).optional().describe("Max jobs returned"),
80
82
  }, async ({ status, include_locks, limit }) => {
81
- const queue = readJobQueue();
83
+ const queue = readJobQueue(workspaceRoot);
82
84
  const filtered = queue.jobs.filter((job) => (status ? job.status === status : true));
83
85
  const clipped = typeof limit === "number" ? filtered.slice(0, limit) : filtered;
84
- const lockTable = readJobLockTable();
85
- const lease = readSchedulerLease();
86
+ const lockTable = readJobLockTable(workspaceRoot);
87
+ const lease = readSchedulerLease(workspaceRoot);
86
88
  const payload = {
87
- queue_path: getJobQueuePath(),
88
- lock_path: getJobLockTablePath(),
89
- lease_path: getSchedulerLeasePath(),
89
+ queue_path: getJobQueuePath(workspaceRoot),
90
+ lock_path: getJobLockTablePath(workspaceRoot),
91
+ lease_path: getSchedulerLeasePath(workspaceRoot),
90
92
  total_jobs: queue.jobs.length,
91
93
  returned_jobs: clipped.length,
92
94
  jobs: clipped,
@@ -109,7 +111,7 @@ export function registerSchedulerTools(server) {
109
111
  action: z.enum(["accept", "reject", "cancel", "resume"]),
110
112
  reason: z.string().optional(),
111
113
  }, async ({ job_id, action, reason }) => {
112
- const result = await acknowledgeJob({ job_id, action, reason });
114
+ const result = await acknowledgeJob({ job_id, action, reason }, workspaceRoot);
113
115
  return {
114
116
  content: [
115
117
  {
@@ -135,7 +137,7 @@ export function registerSchedulerTools(server) {
135
137
  lease_ttl_seconds: z.number().int().min(5).max(3600).optional(),
136
138
  now_iso: z.string().optional().describe("Optional deterministic clock override"),
137
139
  }, async (input) => {
138
- const result = await dispatchJobs(input);
140
+ const result = await dispatchJobs(input, workspaceRoot);
139
141
  return {
140
142
  content: [
141
143
  {
@@ -144,6 +146,7 @@ export function registerSchedulerTools(server) {
144
146
  result.ok ? "✅ Scheduler dispatch completed" : "⚠️ Scheduler lease not acquired",
145
147
  `Owner: ${result.owner}`,
146
148
  `Lease acquired: ${result.lease_acquired}`,
149
+ `Lease retained for execution: ${result.lease_retained}`,
147
150
  `Queue: ${result.queue_path}`,
148
151
  `Locks: ${result.lock_path}`,
149
152
  asJsonBlock(result),
@@ -157,7 +160,7 @@ export function registerSchedulerTools(server) {
157
160
  owner: z.string().optional(),
158
161
  now_iso: z.string().optional(),
159
162
  }, async ({ job_id, owner, now_iso }) => {
160
- const result = await dispatchJobNow({ job_id, owner, now_iso });
163
+ const result = await dispatchJobNow({ job_id, owner, now_iso }, workspaceRoot);
161
164
  return {
162
165
  content: [
163
166
  {
@@ -184,7 +187,7 @@ export function registerSchedulerTools(server) {
184
187
  evidence_ref,
185
188
  error,
186
189
  now_iso,
187
- });
190
+ }, workspaceRoot);
188
191
  return {
189
192
  content: [
190
193
  {
@@ -202,7 +205,7 @@ export function registerSchedulerTools(server) {
202
205
  lease_ttl_seconds: z.number().int().min(5).max(3600).optional(),
203
206
  now_iso: z.string().optional().describe("Optional deterministic clock override"),
204
207
  }, async ({ job_id, owner, lease_ttl_seconds, now_iso }) => {
205
- const result = await heartbeatJob({ job_id, owner, lease_ttl_seconds, now_iso });
208
+ const result = await heartbeatJob({ job_id, owner, lease_ttl_seconds, now_iso }, workspaceRoot);
206
209
  return {
207
210
  content: [
208
211
  {
@@ -224,7 +227,7 @@ export function registerSchedulerTools(server) {
224
227
  .describe("Staleness window in seconds (default 120)"),
225
228
  now_iso: z.string().optional().describe("Optional deterministic clock override"),
226
229
  }, async ({ heartbeat_stale_seconds, now_iso }) => {
227
- const result = await reapStaleRunningJobsTick({ heartbeat_stale_seconds, now_iso });
230
+ const result = await reapStaleRunningJobsTick({ heartbeat_stale_seconds, now_iso }, workspaceRoot);
228
231
  return {
229
232
  content: [
230
233
  {
@@ -246,9 +249,9 @@ export function registerSchedulerTools(server) {
246
249
  text: [
247
250
  "# Lock Table",
248
251
  "",
249
- `Path: ${getJobLockTablePath()}`,
252
+ `Path: ${getJobLockTablePath(workspaceRoot)}`,
250
253
  "",
251
- asJsonBlock(readJobLockTable()),
254
+ asJsonBlock(readJobLockTable(workspaceRoot)),
252
255
  ].join("\n"),
253
256
  },
254
257
  ],
@@ -260,9 +263,9 @@ export function registerSchedulerTools(server) {
260
263
  text: [
261
264
  "# Scheduler Lease",
262
265
  "",
263
- `Path: ${getSchedulerLeasePath()}`,
266
+ `Path: ${getSchedulerLeasePath(workspaceRoot)}`,
264
267
  "",
265
- asJsonBlock(readSchedulerLease() ?? null),
268
+ asJsonBlock(readSchedulerLease(workspaceRoot) ?? null),
266
269
  ].join("\n"),
267
270
  },
268
271
  ],
@@ -1,35 +1,44 @@
1
- /**
2
- * TODO, task management, and run-ledger tool registrations.
3
- */
1
+ import { resolveCurrentWork, formatCurrentWork } from "./ace-autonomy.js";
4
2
  import { z } from "zod";
5
- import { ACE_TASKS_ROOT_REL, readTaskArtifact, resolveWritableTaskPath, safeWriteAsync, } from "./helpers.js";
3
+ import { ACE_TASKS_ROOT_REL, resolveWritableTaskPath, } from "./helpers.js";
6
4
  import { TODO_STATUS_ENUM } from "./shared.js";
7
- import { appendTodoItemSafe, getTodoStatePath, readTodoState, syncTodoStateSafe, transitionTodoNodeSafe, } from "./todo-state.js";
5
+ import { appendTodoItemSafe, deleteTodoItemSafe, getTodoStatePath, syncTodoStateSafe, transitionTodoNodeSafe, } from "./todo-state.js";
8
6
  import { appendRunLedgerEntrySafe, getRunLedgerPath, readRunLedger, } from "./run-ledger.js";
9
- import { refreshKanbanArtifacts } from "./kanban.js";
7
+ import { formatKanbanRefresh, refreshKanbanArtifacts } from "./kanban.js";
8
+ import { hostAgent } from './host-work-context.js';
9
+ import { readStoreJsonSync } from './store/store-snapshot.js';
10
+ import { resolveWorkspaceRoot } from './helpers.js';
11
+ import { GoalRepository } from './store/repositories/goal-repository.js';
12
+ import { deriveLinkedTodo } from './linked-work.js';
13
+ function todoRefusal(reason_code, message, options = [{ tool: "get_todo_state", args: {}, why: "Read current task identities and statuses." }]) {
14
+ const now = formatCurrentWork(resolveCurrentWork(), "line");
15
+ return { isError: true, structuredContent: { reason_code, message, options, now }, content: [{ type: "text", text: [message, ...options.map((o) => `${o.tool}(${JSON.stringify(o.args)}): ${o.why}`), now].join("\n") }] };
16
+ }
17
+ function importNotes(result) {
18
+ return [...(result.import_warnings ?? []).map((warning) => `Import warning: ${warning}`), ...(result.projection_pending ? ["Canonical todo state is current; markdown refresh pending."] : [])].join("\n");
19
+ }
10
20
  export function registerTodoTools(server) {
11
- server.tool("get_todo", "Read the current swarm TODO execution board", {}, async () => ({
12
- content: [{ type: "text", text: readTaskArtifact("todo") }],
13
- }));
14
- server.tool("get_todo_state", "Read synced TODO node state with dependencies and explicit statuses", {}, async () => ({
15
- content: [
16
- {
17
- type: "text",
18
- text: `# TODO State\n\nPath: ${getTodoStatePath()}\n\n\`\`\`json\n${JSON.stringify(readTodoState(), null, 2)}\n\`\`\``,
19
- },
20
- ],
21
- }));
22
- server.tool("update_todo", "Replace TODO board content, append a new TODO item, or transition a TODO node status with gate validation", {
21
+ server.tool("get_todo", "Read the current swarm TODO execution board", {}, async () => {
22
+ const synced = await syncTodoStateSafe();
23
+ return { structuredContent: { ...synced }, content: [{ type: "text", text: [synced.markdown, importNotes(synced)].filter(Boolean).join("\n") }] };
24
+ });
25
+ server.tool("get_todo_state", "Read synced TODO node state with dependencies and explicit statuses", {}, async () => {
26
+ const synced = await syncTodoStateSafe();
27
+ return { structuredContent: { ...synced }, content: [{ type: "text", text: `# TODO State\n\nPath: ${getTodoStatePath()}\n\n\`\`\`json\n${JSON.stringify(synced.state, null, 2)}\n\`\`\`\n${importNotes(synced)}` }] };
28
+ });
29
+ server.tool("update_todo", "Import TODO edits without deleting absent rows; append, explicitly delete, or transition a task", {
23
30
  new_content: z
24
31
  .string()
25
32
  .optional()
26
- .describe("Full updated TODO markdown content (full replace mode)"),
33
+ .describe("TODO markdown to import; omitted rows are retained, use delete_id to remove"),
34
+ delete_id: z.string().optional().describe("Explicitly delete this task; omission from markdown never deletes"),
27
35
  node_id: z
28
36
  .string()
29
37
  .optional()
30
38
  .describe("Todo node id to transition (transition mode)"),
31
39
  status: TODO_STATUS_ENUM.optional().describe("Target status for transition mode"),
32
40
  note: z.string().optional().describe("Optional transition context note"),
41
+ agent: z.string().optional().describe('Host label when completing a linked goal step'),
33
42
  append_title: z
34
43
  .string()
35
44
  .optional()
@@ -48,146 +57,149 @@ export function registerTodoTools(server) {
48
57
  .string()
49
58
  .optional()
50
59
  .describe("Optional explicit node id for the new append-mode item"),
51
- }, async ({ new_content, node_id, status, note, append_title, append_section, append_depends_on, append_id, }) => {
52
- if (typeof append_title === "string") {
53
- const appended = await appendTodoItemSafe(append_title, {
54
- section: append_section,
55
- depends_on: append_depends_on,
56
- id: append_id,
57
- });
58
- if (!appended.ok) {
60
+ }, async ({ new_content, delete_id, node_id, status, note, append_title, append_section, append_depends_on, append_id, agent, }, extra) => {
61
+ try {
62
+ if (delete_id) {
63
+ const deleted = await deleteTodoItemSafe(delete_id);
64
+ if (!deleted.ok)
65
+ return todoRefusal("unknown_todo", deleted.error ?? "Todo not found.");
66
+ const kanban = refreshKanbanArtifacts("tool:update_todo");
67
+ return { structuredContent: { ...deleted }, content: [{ type: "text", text: [`TODO deleted: ${delete_id}`, importNotes(deleted), formatKanbanRefresh(kanban)].filter(Boolean).join("\n") }] };
68
+ }
69
+ if (typeof append_title === "string") {
70
+ const appended = await appendTodoItemSafe(append_title, {
71
+ section: append_section,
72
+ depends_on: append_depends_on,
73
+ id: append_id,
74
+ });
75
+ if (!appended.ok) {
76
+ return todoRefusal("todo_append_rejected", appended.error ?? "Failed to append TODO item.");
77
+ }
78
+ const runLedger = await appendRunLedgerEntrySafe({
79
+ tool: "update_todo",
80
+ category: "info",
81
+ message: `Appended TODO item ${appended.node_id}`,
82
+ artifacts: [`${ACE_TASKS_ROOT_REL}/todo.md`, "agent-state/todo-state.json"],
83
+ metadata: {
84
+ mode: "append",
85
+ node_id: appended.node_id,
86
+ todo_id: appended.node_id,
87
+ section: appended.section,
88
+ },
89
+ });
90
+ const kanban = refreshKanbanArtifacts("tool:update_todo");
91
+ const counts = kanban.counts;
59
92
  return {
93
+ structuredContent: { ...appended },
60
94
  content: [
61
- { type: "text", text: `❌ ${appended.error ?? "Failed to append TODO item."}` },
95
+ {
96
+ type: "text",
97
+ text: [
98
+ `✅ TODO item appended: ${appended.node_id}`,
99
+ `Section: ${appended.section}`,
100
+ `TODO state: ${appended.path}`,
101
+ `TODO markdown: ${appended.todo_path}`,
102
+ importNotes(appended),
103
+ `Run ledger: ${runLedger.path} (${runLedger.entry.id})`,
104
+ formatKanbanRefresh(kanban),
105
+ `Kanban counts: backlog=${counts.backlog}, blocked=${counts.blocked}, in_progress=${counts.in_progress}, gated=${counts.gated}, done=${counts.done}`,
106
+ ].join("\n"),
107
+ },
62
108
  ],
63
109
  };
64
110
  }
65
- const runLedger = await appendRunLedgerEntrySafe({
66
- tool: "update_todo",
67
- category: "info",
68
- message: `Appended TODO item ${appended.node_id}`,
69
- artifacts: [`${ACE_TASKS_ROOT_REL}/todo.md`, "agent-state/todo-state.json"],
70
- metadata: {
71
- mode: "append",
72
- node_id: appended.node_id,
73
- section: appended.section,
74
- },
75
- });
76
- const kanban = refreshKanbanArtifacts("tool:update_todo");
77
- const counts = kanban.counts;
78
- return {
79
- content: [
80
- {
81
- type: "text",
82
- text: [
83
- `✅ TODO item appended: ${appended.node_id}`,
84
- `Section: ${appended.section}`,
85
- `TODO state: ${appended.path}`,
86
- `TODO markdown: ${appended.todo_path}`,
87
- `Run ledger: ${runLedger.path} (${runLedger.entry.id})`,
88
- `Kanban updated: ${kanban.html_path}`,
89
- `Kanban counts: backlog=${counts.backlog}, blocked=${counts.blocked}, in_progress=${counts.in_progress}, gated=${counts.gated}, done=${counts.done}`,
90
- ].join("\n"),
111
+ if (typeof new_content === "string") {
112
+ const synced = await syncTodoStateSafe(new_content);
113
+ const path = resolveWritableTaskPath("todo");
114
+ const runLedger = await appendRunLedgerEntrySafe({
115
+ tool: "update_todo",
116
+ category: "major_update",
117
+ message: "Imported TODO markdown edits; omitted tasks retained",
118
+ artifacts: [`${ACE_TASKS_ROOT_REL}/todo.md`, "agent-state/todo-state.json"],
119
+ metadata: {
120
+ mode: "replace",
121
+ node_count: synced.state.order.length,
91
122
  },
92
- ],
93
- };
94
- }
95
- if (typeof new_content === "string") {
96
- const synced = await syncTodoStateSafe(new_content);
97
- const path = await safeWriteAsync(resolveWritableTaskPath("todo"), new_content);
98
- const runLedger = await appendRunLedgerEntrySafe({
99
- tool: "update_todo",
100
- category: "major_update",
101
- message: "Replaced TODO markdown board content",
102
- artifacts: [`${ACE_TASKS_ROOT_REL}/todo.md`, "agent-state/todo-state.json"],
103
- metadata: {
104
- mode: "replace",
105
- node_count: synced.state.order.length,
106
- },
107
- });
108
- const kanban = refreshKanbanArtifacts("tool:update_todo");
109
- const counts = kanban.counts;
110
- return {
111
- content: [
112
- {
113
- type: "text",
114
- text: [
115
- `✅ TODO updated: ${path}`,
116
- `TODO state synced: ${synced.path}`,
117
- `Run ledger: ${runLedger.path} (${runLedger.entry.id})`,
118
- `Kanban updated: ${kanban.html_path}`,
119
- `Kanban counts: backlog=${counts.backlog}, blocked=${counts.blocked}, in_progress=${counts.in_progress}, gated=${counts.gated}, done=${counts.done}`,
120
- ].join("\n"),
121
- },
122
- ],
123
- };
124
- }
125
- if (node_id && status) {
126
- const transition = await transitionTodoNodeSafe(node_id, status);
127
- if (!transition.ok) {
128
- const detailLines = [
129
- transition.error
130
- ? `❌ ${transition.error}`
131
- : "❌ TODO transition failed.",
132
- transition.node_id ? `Node: ${transition.node_id}` : "",
133
- transition.from && transition.to
134
- ? `Attempted: ${transition.from} -> ${transition.to}`
135
- : "",
136
- transition.allowed?.length
137
- ? `Allowed next states: ${transition.allowed.join(", ")}`
138
- : "",
139
- transition.unresolved_dependencies?.length
140
- ? `Unresolved dependencies: ${transition.unresolved_dependencies.join(", ")}`
141
- : "",
142
- ].filter(Boolean);
123
+ });
124
+ const kanban = refreshKanbanArtifacts("tool:update_todo");
125
+ const counts = kanban.counts;
143
126
  return {
144
- content: [{ type: "text", text: detailLines.join("\n") }],
127
+ structuredContent: { ...synced },
128
+ content: [
129
+ {
130
+ type: "text",
131
+ text: [
132
+ `✅ TODO updated: ${path}`,
133
+ `TODO state synced: ${synced.path}`,
134
+ importNotes(synced),
135
+ `Run ledger: ${runLedger.path} (${runLedger.entry.id})`,
136
+ formatKanbanRefresh(kanban),
137
+ `Kanban counts: backlog=${counts.backlog}, blocked=${counts.blocked}, in_progress=${counts.in_progress}, gated=${counts.gated}, done=${counts.done}`,
138
+ ].join("\n"),
139
+ },
140
+ ],
145
141
  };
146
142
  }
147
- const previous = transition.from ?? status;
148
- const category = previous === "done" && status !== "done"
149
- ? "regression"
150
- : "major_update";
151
- const runLedger = await appendRunLedgerEntrySafe({
152
- tool: "update_todo",
153
- category,
154
- message: `Transitioned TODO node ${node_id}: ${previous} -> ${status}`,
155
- artifacts: [`${ACE_TASKS_ROOT_REL}/todo.md`, "agent-state/todo-state.json"],
156
- metadata: {
157
- mode: "transition",
158
- node_id,
159
- from: previous,
160
- to: status,
161
- note: note ?? "",
162
- },
163
- });
164
- const kanban = refreshKanbanArtifacts("tool:update_todo");
165
- const counts = kanban.counts;
166
- return {
167
- content: [
168
- {
169
- type: "text",
170
- text: [
171
- `✅ TODO transition applied: ${node_id}`,
172
- `Transition: ${previous} -> ${status}`,
173
- `TODO state: ${transition.path}`,
174
- `TODO markdown: ${transition.todo_path}`,
175
- `Run ledger: ${runLedger.path} (${runLedger.entry.id})`,
176
- `Kanban updated: ${kanban.html_path}`,
177
- `Kanban counts: backlog=${counts.backlog}, blocked=${counts.blocked}, in_progress=${counts.in_progress}, gated=${counts.gated}, done=${counts.done}`,
178
- ].join("\n"),
143
+ if (node_id && status) {
144
+ const rawTodo = readStoreJsonSync(resolveWorkspaceRoot(), `state/todo/${node_id}`);
145
+ const linked = rawTodo && deriveLinkedTodo(rawTodo, resolveWorkspaceRoot()).step_ref;
146
+ if (linked) {
147
+ if (status !== 'done' && status !== 'blocked')
148
+ return todoRefusal('linked_step_owned', 'This todo is a step view. Use next_step to start/resume its goal; complete_step records its outcome.');
149
+ const step = new GoalRepository(resolveWorkspaceRoot()).getPlan(linked.goal_id)?.steps.find(s => s.step_id === linked.step_id);
150
+ const { completeStep } = await import('./host-goal-engine.js');
151
+ const result = await completeStep(linked.goal_id, linked.step_id, { status, summary: note || `Todo ${node_id} ${status}`, evidence: [{ ref: `host:todo:${node_id}`, kind: 'note', detail: note }] }, { agent: hostAgent(agent, extra.sessionId), attempt: step?.attempt ?? 0 });
152
+ return { isError: !!result.isError, structuredContent: { ...result }, content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
153
+ }
154
+ const transition = await transitionTodoNodeSafe(node_id, status);
155
+ if (!transition.ok) {
156
+ const reason = transition.unresolved_dependencies?.length ? "todo_dependencies_unmet" : transition.allowed ? "todo_transition_invalid" : "unknown_todo";
157
+ return todoRefusal(reason, [transition.error ?? "TODO transition failed.", transition.allowed?.length ? `Allowed next states: ${transition.allowed.join(", ")}.` : "", transition.unresolved_dependencies?.length ? `Waiting on: ${transition.unresolved_dependencies.join(", ")}.` : ""].filter(Boolean).join(" "));
158
+ }
159
+ const previous = transition.from ?? status;
160
+ const category = previous === "done" && status !== "done"
161
+ ? "regression"
162
+ : "major_update";
163
+ const runLedger = await appendRunLedgerEntrySafe({
164
+ tool: "update_todo",
165
+ category,
166
+ message: `Transitioned TODO node ${node_id}: ${previous} -> ${status}`,
167
+ artifacts: [`${ACE_TASKS_ROOT_REL}/todo.md`, "agent-state/todo-state.json"],
168
+ metadata: {
169
+ mode: "transition",
170
+ node_id,
171
+ todo_id: node_id,
172
+ from: previous,
173
+ to: status,
174
+ note: note ?? "",
179
175
  },
180
- ],
181
- };
176
+ });
177
+ const kanban = refreshKanbanArtifacts("tool:update_todo");
178
+ const counts = kanban.counts;
179
+ return {
180
+ structuredContent: { ...transition },
181
+ content: [
182
+ {
183
+ type: "text",
184
+ text: [
185
+ `✅ TODO transition applied: ${node_id}`,
186
+ `Transition: ${previous} -> ${status}`,
187
+ `TODO state: ${transition.path}`,
188
+ `TODO markdown: ${transition.todo_path}`,
189
+ importNotes(transition),
190
+ `Run ledger: ${runLedger.path} (${runLedger.entry.id})`,
191
+ formatKanbanRefresh(kanban),
192
+ `Kanban counts: backlog=${counts.backlog}, blocked=${counts.blocked}, in_progress=${counts.in_progress}, gated=${counts.gated}, done=${counts.done}`,
193
+ ].join("\n"),
194
+ },
195
+ ],
196
+ };
197
+ }
198
+ return todoRefusal("todo_arguments_missing", "Provide append_title, new_content, delete_id, or node_id with status.");
199
+ }
200
+ catch (error) {
201
+ return todoRefusal("todo_write_failed", `Could not save the todo change: ${error instanceof Error ? error.message : String(error)}`);
182
202
  }
183
- return {
184
- content: [
185
- {
186
- type: "text",
187
- text: "❌ Provide either `new_content` (full replace) or `node_id` + `status` (transition mode).",
188
- },
189
- ],
190
- };
191
203
  });
192
204
  server.tool("get_run_ledger", "Read run-ledger milestone/regression history", {
193
205
  limit: z
@@ -137,6 +137,14 @@ export declare function appendVericifyProcessPostSafe(input: {
137
137
  post?: VericifyProcessPost;
138
138
  error?: string;
139
139
  }>;
140
+ /**
141
+ * Compatibility sink for ACE-generated summaries. Native Vericify owns process
142
+ * capture; these duplicate posts are disabled unless an operator explicitly
143
+ * requests the legacy recorder. Manual APIs above remain available unchanged.
144
+ */
145
+ export declare function appendAutomaticVericifyProcessPostSafe(input: Parameters<typeof appendVericifyProcessPostSafe>[0]): Promise<Awaited<ReturnType<typeof appendVericifyProcessPostSafe>> & {
146
+ skipped?: boolean;
147
+ }>;
140
148
  export declare function buildVericifyBridgeSnapshot(): VericifyBridgeSnapshot;
141
149
  export declare function refreshVericifyBridgeSnapshot(): {
142
150
  ok: boolean;
@@ -95,11 +95,17 @@ function parseBridgeSnapshot(raw) {
95
95
  function readBridgeConfig() {
96
96
  const config = readRuntimeProfile().observability.vericify_bridge ?? {
97
97
  enabled: false,
98
+ legacy_auto_posts: false,
99
+ native: { enabled: false },
98
100
  bridge_path: VERICIFY_BRIDGE_SNAPSHOT_REL_PATH,
99
101
  process_post_path: VERICIFY_PROCESS_POST_LOG_REL_PATH,
100
102
  };
101
103
  return {
102
104
  enabled: Boolean(config.enabled),
105
+ // Older profiles only carried `enabled`, which controls bridge reads and
106
+ // explicit manual APIs. It does not opt into a second automatic recorder.
107
+ legacy_auto_posts: config.legacy_auto_posts === true,
108
+ native_enabled: config.native?.enabled === true,
103
109
  bridge_path: config.bridge_path || VERICIFY_BRIDGE_SNAPSHOT_REL_PATH,
104
110
  process_post_path: config.process_post_path || VERICIFY_PROCESS_POST_LOG_REL_PATH,
105
111
  };
@@ -426,6 +432,18 @@ export async function appendVericifyProcessPostSafe(input) {
426
432
  };
427
433
  }
428
434
  }
435
+ /**
436
+ * Compatibility sink for ACE-generated summaries. Native Vericify owns process
437
+ * capture; these duplicate posts are disabled unless an operator explicitly
438
+ * requests the legacy recorder. Manual APIs above remain available unchanged.
439
+ */
440
+ export async function appendAutomaticVericifyProcessPostSafe(input) {
441
+ const config = readBridgeConfig();
442
+ if (!config.enabled || !config.legacy_auto_posts || config.native_enabled) {
443
+ return { ok: true, skipped: true, path: processPostLogPath() };
444
+ }
445
+ return appendVericifyProcessPostSafe(input);
446
+ }
429
447
  function buildActiveRunRefs() {
430
448
  const executorRegistryPath = "agent-state/runtime-executor-sessions.json";
431
449
  const raw = readConfiguredText(executorRegistryPath);
@@ -1,10 +1,14 @@
1
+ import { createNativeObservationAdapter } from "./vericify-native.js";
1
2
  export declare function getVericifyContextPacket(input?: {
2
3
  workspaceRoot?: string;
3
4
  runId?: string;
5
+ mode?: "configured" | "legacy";
4
6
  }): Promise<Record<string, unknown>>;
5
7
  export declare function getVericifyDelta(input: {
6
8
  since: string;
7
9
  workspaceRoot?: string;
8
10
  runId?: string;
11
+ mode?: "configured" | "legacy";
9
12
  }): Promise<Record<string, unknown>>;
13
+ export declare function configuredObservationAdapter(workspaceRoot: string): ReturnType<typeof createNativeObservationAdapter> | undefined;
10
14
  //# sourceMappingURL=vericify-context.d.ts.map
@@ -2,7 +2,9 @@ import { createRequire } from "node:module";
2
2
  import { existsSync } from "node:fs";
3
3
  import { dirname, resolve } from "node:path";
4
4
  import { fileURLToPath, pathToFileURL } from "node:url";
5
- import { resolveWorkspaceRoot } from "./helpers.js";
5
+ import { resolveWorkspaceRoot, withWorkspaceRoot } from "./helpers.js";
6
+ import { readRuntimeProfile } from "./runtime-profile.js";
7
+ import { createNativeObservationAdapter, getNativeVericifyContext } from "./vericify-native.js";
6
8
  const requireFromModule = createRequire(import.meta.url);
7
9
  const PACKAGE_ROOT = resolve(dirname(fileURLToPath(import.meta.url)), "..");
8
10
  function tryResolveVericifyApi(searchFrom) {
@@ -47,8 +49,8 @@ function resolveVericifyApiPath(workspaceRoot) {
47
49
  "or set VERICIFY_API_PATH to an installed `vericify/api` entry file.",
48
50
  ].join(" "));
49
51
  }
50
- async function loadVericifyApi(workspaceRoot) {
51
- const apiPath = resolveVericifyApiPath(workspaceRoot);
52
+ async function loadVericifyApi(workspaceRoot, explicitPath) {
53
+ const apiPath = explicitPath ? resolve(explicitPath) : resolveVericifyApiPath(workspaceRoot);
52
54
  const loaded = await import(pathToFileURL(apiPath).href);
53
55
  if (typeof loaded.loadWorkspaceState !== "function" ||
54
56
  typeof loaded.buildCompactPacket !== "function" ||
@@ -62,7 +64,12 @@ export async function getVericifyContextPacket(input) {
62
64
  const workspaceRoot = input?.workspaceRoot
63
65
  ? resolve(input.workspaceRoot)
64
66
  : resolveWorkspaceRoot();
65
- const api = await loadVericifyApi(workspaceRoot);
67
+ const configured = input?.mode === "configured" ? configuredVericify(workspaceRoot) : undefined;
68
+ if (configured?.native?.enabled)
69
+ return { ...(await getNativeVericifyContext({ config: configured.native, workspaceRoot })) };
70
+ if (input?.mode === "configured" && !configured?.apiPath)
71
+ return { status: "unavailable", reason_code: "vericify_not_configured", records: [] };
72
+ const api = await loadVericifyApi(workspaceRoot, configured?.apiPath);
66
73
  const workspaceState = api.loadWorkspaceState(workspaceRoot);
67
74
  const projected = api.projectWorkspaceState(workspaceState);
68
75
  return api.buildCompactPacket(projected, {
@@ -73,7 +80,12 @@ export async function getVericifyDelta(input) {
73
80
  const workspaceRoot = input.workspaceRoot
74
81
  ? resolve(input.workspaceRoot)
75
82
  : resolveWorkspaceRoot();
76
- const api = await loadVericifyApi(workspaceRoot);
83
+ const configured = input.mode === "configured" ? configuredVericify(workspaceRoot) : undefined;
84
+ if (configured?.native?.enabled)
85
+ return { ...(await getNativeVericifyContext({ config: configured.native, workspaceRoot, since: input.since })) };
86
+ if (input.mode === "configured" && !configured?.apiPath)
87
+ return { status: "unavailable", reason_code: "vericify_not_configured", records: [] };
88
+ const api = await loadVericifyApi(workspaceRoot, configured?.apiPath);
77
89
  const workspaceState = api.loadWorkspaceState(workspaceRoot);
78
90
  const projected = api.projectWorkspaceState(workspaceState);
79
91
  return api.buildCompactDelta(projected, {
@@ -81,4 +93,13 @@ export async function getVericifyDelta(input) {
81
93
  since: input.since,
82
94
  });
83
95
  }
96
+ /** Explicit public configuration; programmatic legacy helpers above retain historical discovery. */
97
+ function configuredVericify(workspaceRoot) {
98
+ const bridge = withWorkspaceRoot(workspaceRoot, () => readRuntimeProfile().observability.vericify_bridge);
99
+ return { native: bridge?.native, apiPath: bridge?.api_path || process.env.VERICIFY_API_PATH?.trim() };
100
+ }
101
+ export function configuredObservationAdapter(workspaceRoot) {
102
+ const config = configuredVericify(workspaceRoot).native;
103
+ return config?.enabled ? createNativeObservationAdapter(config, workspaceRoot) : undefined;
104
+ }
84
105
  //# sourceMappingURL=vericify-context.js.map