vellum 0.2.1 → 0.2.2

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 (349) hide show
  1. package/README.md +15 -2
  2. package/bun.lock +5 -2
  3. package/package.json +4 -2
  4. package/scripts/capture-x-graphql.ts +562 -0
  5. package/scripts/ipc/check-swift-decoder-drift.ts +2 -1
  6. package/scripts/test.sh +5 -0
  7. package/src/__tests__/__snapshots__/ipc-snapshot.test.ts.snap +133 -34
  8. package/src/__tests__/account-registry.test.ts +2 -1
  9. package/src/__tests__/agent-heartbeat-service.test.ts +250 -0
  10. package/src/__tests__/asset-materialize-tool.test.ts +16 -15
  11. package/src/__tests__/asset-search-tool.test.ts +23 -22
  12. package/src/__tests__/attachments-store.test.ts +56 -127
  13. package/src/__tests__/browser-skill-baseline-tool-payload.test.ts +5 -4
  14. package/src/__tests__/browser-skill-endstate.test.ts +4 -3
  15. package/src/__tests__/call-bridge.test.ts +385 -0
  16. package/src/__tests__/call-constants.test.ts +40 -0
  17. package/src/__tests__/call-orchestrator.test.ts +130 -4
  18. package/src/__tests__/call-recovery.test.ts +518 -0
  19. package/src/__tests__/call-routes-http.test.ts +459 -0
  20. package/src/__tests__/call-state-machine.test.ts +143 -0
  21. package/src/__tests__/call-store.test.ts +216 -1
  22. package/src/__tests__/cli-discover.test.ts +1 -1
  23. package/src/__tests__/commit-message-enrichment-service.test.ts +148 -7
  24. package/src/__tests__/compaction.benchmark.test.ts +176 -0
  25. package/src/__tests__/computer-use-tools.test.ts +250 -0
  26. package/src/__tests__/config-schema.test.ts +299 -3
  27. package/src/__tests__/conflict-store.test.ts +2 -1
  28. package/src/__tests__/contacts-tools.test.ts +331 -0
  29. package/src/__tests__/conversation-store.test.ts +30 -32
  30. package/src/__tests__/credential-security-invariants.test.ts +4 -0
  31. package/src/__tests__/date-context.test.ts +373 -0
  32. package/src/__tests__/db-schedule-syntax-migration.test.ts +129 -0
  33. package/src/__tests__/fixtures/media-reuse-fixtures.ts +3 -3
  34. package/src/__tests__/followup-tools.test.ts +303 -0
  35. package/src/__tests__/handlers-twitter-config.test.ts +718 -0
  36. package/src/__tests__/intent-routing.test.ts +64 -57
  37. package/src/__tests__/ipc-roundtrip.benchmark.test.ts +237 -0
  38. package/src/__tests__/ipc-snapshot.test.ts +62 -28
  39. package/src/__tests__/llm-usage-store.test.ts +3 -8
  40. package/src/__tests__/media-generate-image.test.ts +1 -1
  41. package/src/__tests__/media-reuse-story.e2e.test.ts +7 -7
  42. package/src/__tests__/memory-retrieval.benchmark.test.ts +430 -0
  43. package/src/__tests__/parallel-tool.benchmark.test.ts +294 -0
  44. package/src/__tests__/playbook-tools.test.ts +342 -0
  45. package/src/__tests__/profile-compiler.test.ts +2 -1
  46. package/src/__tests__/provider-streaming.benchmark.test.ts +773 -0
  47. package/src/__tests__/recurrence-engine-rruleset.test.ts +78 -0
  48. package/src/__tests__/recurrence-engine.test.ts +69 -0
  49. package/src/__tests__/recurrence-types.test.ts +71 -0
  50. package/src/__tests__/registry.test.ts +5 -3
  51. package/src/__tests__/relay-server.test.ts +633 -0
  52. package/src/__tests__/reminder-store.test.ts +6 -3
  53. package/src/__tests__/reminder.test.ts +43 -77
  54. package/src/__tests__/run-orchestrator-assistant-events.test.ts +8 -4
  55. package/src/__tests__/run-orchestrator.test.ts +4 -4
  56. package/src/__tests__/runtime-attachment-metadata.test.ts +7 -6
  57. package/src/__tests__/runtime-runs-http.test.ts +4 -4
  58. package/src/__tests__/runtime-runs.test.ts +4 -4
  59. package/src/__tests__/schedule-store.test.ts +482 -0
  60. package/src/__tests__/schedule-tools.test.ts +700 -0
  61. package/src/__tests__/scheduler-recurrence.test.ts +329 -0
  62. package/src/__tests__/server-history-render.test.ts +14 -13
  63. package/src/__tests__/session-error.test.ts +28 -0
  64. package/src/__tests__/session-init.benchmark.test.ts +462 -0
  65. package/src/__tests__/session-queue.test.ts +71 -48
  66. package/src/__tests__/session-runtime-assembly.test.ts +161 -0
  67. package/src/__tests__/session-surfaces-task-progress.test.ts +104 -0
  68. package/src/__tests__/signup-e2e.test.ts +2 -1
  69. package/src/__tests__/skill-projection.benchmark.test.ts +328 -0
  70. package/src/__tests__/skill-script-runner.test.ts +159 -0
  71. package/src/__tests__/speaker-identification.test.ts +52 -0
  72. package/src/__tests__/subagent-manager-notify.test.ts +42 -10
  73. package/src/__tests__/subagent-tools.test.ts +141 -41
  74. package/src/__tests__/task-compiler.test.ts +2 -1
  75. package/src/__tests__/task-runner.test.ts +2 -1
  76. package/src/__tests__/task-scheduler.test.ts +2 -1
  77. package/src/__tests__/task-tools.test.ts +49 -56
  78. package/src/__tests__/tool-audit-listener.test.ts +1 -0
  79. package/src/__tests__/tool-domain-event-publisher.test.ts +2 -0
  80. package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +500 -0
  81. package/src/__tests__/tool-executor.test.ts +13 -17
  82. package/src/__tests__/turn-commit.test.ts +218 -3
  83. package/src/__tests__/twilio-provider.test.ts +143 -0
  84. package/src/__tests__/twilio-routes.test.ts +789 -0
  85. package/src/__tests__/twitter-auth-handler.test.ts +581 -0
  86. package/src/__tests__/view-image-tool.test.ts +217 -0
  87. package/src/__tests__/workspace-git-service.test.ts +186 -0
  88. package/src/__tests__/workspace-heartbeat-service.test.ts +13 -3
  89. package/src/agent-heartbeat/agent-heartbeat-service.ts +155 -0
  90. package/src/bundler/app-bundler.ts +12 -8
  91. package/src/calls/call-bridge.ts +95 -0
  92. package/src/calls/call-constants.ts +43 -5
  93. package/src/calls/call-domain.ts +276 -0
  94. package/src/calls/call-orchestrator.ts +43 -17
  95. package/src/calls/call-recovery.ts +207 -0
  96. package/src/calls/call-state-machine.ts +68 -0
  97. package/src/calls/call-store.ts +192 -5
  98. package/src/calls/relay-server.ts +41 -4
  99. package/src/calls/speaker-identification.ts +213 -0
  100. package/src/calls/twilio-provider.ts +10 -6
  101. package/src/calls/twilio-routes.ts +90 -76
  102. package/src/calls/types.ts +1 -1
  103. package/src/cli/config-commands.ts +334 -0
  104. package/src/cli/core-commands.ts +776 -0
  105. package/src/cli/doordash.ts +251 -1
  106. package/src/cli/ipc-client.ts +82 -0
  107. package/src/cli/map.ts +246 -0
  108. package/src/cli/twitter.ts +575 -0
  109. package/src/cli.ts +7 -5
  110. package/src/commands/__tests__/cc-command-registry.test.ts +319 -0
  111. package/src/commands/cc-command-registry.ts +209 -0
  112. package/src/config/bundled-skills/contacts/SKILL.md +39 -0
  113. package/src/config/bundled-skills/contacts/TOOLS.json +122 -0
  114. package/src/config/bundled-skills/contacts/tools/contact-merge.ts +9 -0
  115. package/src/config/bundled-skills/contacts/tools/contact-search.ts +9 -0
  116. package/src/config/bundled-skills/contacts/tools/contact-upsert.ts +9 -0
  117. package/src/config/bundled-skills/document/SKILL.md +18 -0
  118. package/src/config/bundled-skills/document/TOOLS.json +53 -0
  119. package/src/config/bundled-skills/document/tools/document-create.ts +9 -0
  120. package/src/config/bundled-skills/document/tools/document-update.ts +9 -0
  121. package/src/config/bundled-skills/doordash/SKILL.md +82 -23
  122. package/src/config/bundled-skills/followups/SKILL.md +32 -0
  123. package/src/config/bundled-skills/followups/TOOLS.json +100 -0
  124. package/src/config/bundled-skills/followups/tools/followup-create.ts +9 -0
  125. package/src/config/bundled-skills/followups/tools/followup-list.ts +9 -0
  126. package/src/config/bundled-skills/followups/tools/followup-resolve.ts +9 -0
  127. package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +1 -23
  128. package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +2 -1
  129. package/src/config/bundled-skills/playbooks/SKILL.md +31 -0
  130. package/src/config/bundled-skills/playbooks/TOOLS.json +126 -0
  131. package/src/config/bundled-skills/playbooks/tools/playbook-create.ts +9 -0
  132. package/src/config/bundled-skills/playbooks/tools/playbook-delete.ts +9 -0
  133. package/src/config/bundled-skills/playbooks/tools/playbook-list.ts +9 -0
  134. package/src/config/bundled-skills/playbooks/tools/playbook-update.ts +9 -0
  135. package/src/config/bundled-skills/reminder/SKILL.md +20 -0
  136. package/src/config/bundled-skills/reminder/TOOLS.json +67 -0
  137. package/src/config/bundled-skills/reminder/tools/reminder-cancel.ts +9 -0
  138. package/src/config/bundled-skills/reminder/tools/reminder-create.ts +9 -0
  139. package/src/config/bundled-skills/reminder/tools/reminder-list.ts +9 -0
  140. package/src/config/bundled-skills/schedule/SKILL.md +74 -0
  141. package/src/config/bundled-skills/schedule/TOOLS.json +135 -0
  142. package/src/config/bundled-skills/schedule/tools/schedule-create.ts +9 -0
  143. package/src/config/bundled-skills/schedule/tools/schedule-delete.ts +9 -0
  144. package/src/config/bundled-skills/schedule/tools/schedule-list.ts +9 -0
  145. package/src/config/bundled-skills/schedule/tools/schedule-update.ts +9 -0
  146. package/src/config/bundled-skills/subagent/SKILL.md +25 -0
  147. package/src/config/bundled-skills/subagent/TOOLS.json +107 -0
  148. package/src/config/bundled-skills/subagent/tools/subagent-abort.ts +9 -0
  149. package/src/config/bundled-skills/subagent/tools/subagent-message.ts +9 -0
  150. package/src/config/bundled-skills/subagent/tools/subagent-read.ts +9 -0
  151. package/src/config/bundled-skills/subagent/tools/subagent-spawn.ts +9 -0
  152. package/src/config/bundled-skills/subagent/tools/subagent-status.ts +9 -0
  153. package/src/config/bundled-skills/tasks/SKILL.md +28 -0
  154. package/src/config/bundled-skills/tasks/TOOLS.json +256 -0
  155. package/src/config/bundled-skills/tasks/tools/task-delete.ts +9 -0
  156. package/src/config/bundled-skills/tasks/tools/task-list-add.ts +9 -0
  157. package/src/config/bundled-skills/tasks/tools/task-list-remove.ts +9 -0
  158. package/src/config/bundled-skills/tasks/tools/task-list-show.ts +9 -0
  159. package/src/config/bundled-skills/tasks/tools/task-list-update.ts +9 -0
  160. package/src/config/bundled-skills/tasks/tools/task-list.ts +9 -0
  161. package/src/config/bundled-skills/tasks/tools/task-run.ts +9 -0
  162. package/src/config/bundled-skills/tasks/tools/task-save.ts +9 -0
  163. package/src/config/bundled-skills/twitter/SKILL.md +134 -0
  164. package/src/config/bundled-skills/watcher/SKILL.md +27 -0
  165. package/src/config/bundled-skills/watcher/TOOLS.json +147 -0
  166. package/src/config/bundled-skills/watcher/tools/watcher-create.ts +9 -0
  167. package/src/config/bundled-skills/watcher/tools/watcher-delete.ts +9 -0
  168. package/src/config/bundled-skills/watcher/tools/watcher-digest.ts +9 -0
  169. package/src/config/bundled-skills/watcher/tools/watcher-list.ts +9 -0
  170. package/src/config/bundled-skills/watcher/tools/watcher-update.ts +9 -0
  171. package/src/config/defaults.ts +33 -0
  172. package/src/config/loader.ts +4 -1
  173. package/src/config/schema.ts +161 -1
  174. package/src/config/system-prompt.ts +61 -16
  175. package/src/config/templates/IDENTITY.md +7 -0
  176. package/src/config/types.ts +4 -0
  177. package/src/contacts/contact-store.ts +4 -4
  178. package/src/daemon/assistant-attachments.ts +10 -0
  179. package/src/daemon/classifier.ts +3 -1
  180. package/src/daemon/computer-use-session.ts +3 -1
  181. package/src/daemon/date-context.ts +136 -0
  182. package/src/daemon/handlers/apps.ts +16 -1
  183. package/src/daemon/handlers/browser.ts +54 -0
  184. package/src/daemon/handlers/computer-use.ts +7 -1
  185. package/src/daemon/handlers/config.ts +163 -5
  186. package/src/daemon/handlers/diagnostics.ts +5 -1
  187. package/src/daemon/handlers/documents.ts +18 -29
  188. package/src/daemon/handlers/home-base.ts +5 -1
  189. package/src/daemon/handlers/index.ts +40 -277
  190. package/src/daemon/handlers/misc.ts +9 -1
  191. package/src/daemon/handlers/publish.ts +6 -1
  192. package/src/daemon/handlers/sessions.ts +65 -12
  193. package/src/daemon/handlers/shared.ts +36 -1
  194. package/src/daemon/handlers/signing.ts +37 -0
  195. package/src/daemon/handlers/skills.ts +20 -6
  196. package/src/daemon/handlers/subagents.ts +8 -3
  197. package/src/daemon/handlers/twitter-auth.ts +169 -0
  198. package/src/daemon/handlers/work-items.ts +384 -68
  199. package/src/daemon/ipc-contract-inventory.json +28 -4
  200. package/src/daemon/ipc-contract.ts +133 -37
  201. package/src/daemon/ipc-protocol.ts +7 -2
  202. package/src/daemon/lifecycle.ts +21 -0
  203. package/src/daemon/main.ts +10 -4
  204. package/src/daemon/ride-shotgun-handler.ts +74 -10
  205. package/src/daemon/server.ts +143 -26
  206. package/src/daemon/session-agent-loop.ts +887 -0
  207. package/src/daemon/session-attachments.ts +28 -5
  208. package/src/daemon/session-error.ts +24 -3
  209. package/src/daemon/session-lifecycle.ts +147 -0
  210. package/src/daemon/session-media-retry.ts +147 -0
  211. package/src/daemon/session-messaging.ts +145 -0
  212. package/src/daemon/session-notifiers.ts +164 -0
  213. package/src/daemon/session-process.ts +2 -2
  214. package/src/daemon/session-queue-manager.ts +1 -0
  215. package/src/daemon/session-runtime-assembly.ts +52 -0
  216. package/src/daemon/session-skill-tools.ts +124 -5
  217. package/src/daemon/session-slash.ts +3 -0
  218. package/src/daemon/session-surfaces.ts +77 -2
  219. package/src/daemon/session-tool-setup.ts +216 -2
  220. package/src/daemon/session-usage.ts +0 -2
  221. package/src/daemon/session.ts +114 -1404
  222. package/src/daemon/video-thumbnail.ts +60 -0
  223. package/src/doordash/client.ts +121 -27
  224. package/src/doordash/queries.ts +1 -2
  225. package/src/export/formatter.ts +3 -1
  226. package/src/followups/followup-store.ts +4 -2
  227. package/src/followups/types.ts +6 -0
  228. package/src/hooks/templates.ts +1 -1
  229. package/src/index.ts +32 -1153
  230. package/src/memory/attachments-store.ts +28 -83
  231. package/src/memory/channel-delivery-store.ts +7 -21
  232. package/src/memory/clarification-resolver.ts +6 -5
  233. package/src/memory/contradiction-checker.ts +3 -2
  234. package/src/memory/conversation-key-store.ts +10 -29
  235. package/src/memory/conversation-store.ts +2 -1
  236. package/src/memory/db.ts +96 -2
  237. package/src/memory/entity-extractor.ts +6 -3
  238. package/src/memory/items-extractor.ts +5 -4
  239. package/src/memory/jobs-store.ts +3 -2
  240. package/src/memory/llm-usage-store.ts +1 -2
  241. package/src/memory/runs-store.ts +1 -2
  242. package/src/memory/schema.ts +23 -2
  243. package/src/messaging/style-analyzer.ts +3 -2
  244. package/src/messaging/thread-summarizer.ts +8 -12
  245. package/src/messaging/triage-engine.ts +4 -2
  246. package/src/providers/openrouter/client.ts +20 -0
  247. package/src/providers/registry.ts +8 -0
  248. package/src/runtime/http-server.ts +108 -20
  249. package/src/runtime/routes/attachment-routes.ts +2 -3
  250. package/src/runtime/routes/call-routes.ts +140 -0
  251. package/src/runtime/routes/channel-routes.ts +5 -10
  252. package/src/runtime/routes/conversation-routes.ts +5 -5
  253. package/src/runtime/routes/run-routes.ts +2 -2
  254. package/src/runtime/run-orchestrator.ts +9 -3
  255. package/src/schedule/recurrence-engine.ts +138 -0
  256. package/src/schedule/recurrence-types.ts +67 -0
  257. package/src/schedule/schedule-store.ts +102 -57
  258. package/src/schedule/scheduler.ts +9 -6
  259. package/src/security/oauth2.ts +29 -4
  260. package/src/security/secret-allowlist.ts +46 -0
  261. package/src/skills/clawhub.ts +1 -1
  262. package/src/subagent/manager.ts +40 -8
  263. package/src/swarm/backend-claude-code.ts +64 -9
  264. package/src/swarm/worker-prompts.ts +2 -1
  265. package/src/tasks/SPEC.md +34 -28
  266. package/src/tasks/ephemeral-permissions.ts +16 -7
  267. package/src/tasks/task-compiler.ts +5 -4
  268. package/src/tasks/task-runner.ts +10 -5
  269. package/src/tasks/task-scheduler.ts +1 -1
  270. package/src/tasks/tool-sanitizer.ts +36 -0
  271. package/src/tools/assets/search.ts +4 -4
  272. package/src/tools/browser/api-map.ts +220 -0
  273. package/src/tools/browser/auto-navigate.ts +270 -0
  274. package/src/tools/browser/browser-execution.ts +2 -1
  275. package/src/tools/browser/browser-manager.ts +2 -2
  276. package/src/tools/browser/network-recorder.ts +5 -4
  277. package/src/tools/browser/x-auto-navigate.ts +207 -0
  278. package/src/tools/calls/call-end.ts +17 -67
  279. package/src/tools/calls/call-start.ts +24 -85
  280. package/src/tools/calls/call-status.ts +35 -51
  281. package/src/tools/claude-code/claude-code.ts +77 -11
  282. package/src/tools/contacts/contact-merge.ts +46 -78
  283. package/src/tools/contacts/contact-search.ts +35 -79
  284. package/src/tools/contacts/contact-upsert.ts +35 -108
  285. package/src/tools/credentials/vault.ts +20 -4
  286. package/src/tools/document/document-tool.ts +71 -144
  287. package/src/tools/executor.ts +129 -10
  288. package/src/tools/followups/followup_create.ts +46 -88
  289. package/src/tools/followups/followup_list.ts +34 -74
  290. package/src/tools/followups/followup_resolve.ts +31 -66
  291. package/src/tools/host-terminal/cli-discover.ts +2 -1
  292. package/src/tools/host-terminal/host-shell.ts +10 -0
  293. package/src/tools/memory/handlers.ts +5 -4
  294. package/src/tools/network/__tests__/web-search.test.ts +427 -0
  295. package/src/tools/network/script-proxy/__tests__/logging.test.ts +248 -0
  296. package/src/tools/network/script-proxy/__tests__/policy.test.ts +234 -0
  297. package/src/tools/network/script-proxy/__tests__/router.test.ts +76 -0
  298. package/src/tools/network/web-fetch.ts +18 -6
  299. package/src/tools/playbooks/index.ts +4 -5
  300. package/src/tools/playbooks/playbook-create.ts +3 -47
  301. package/src/tools/playbooks/playbook-delete.ts +1 -25
  302. package/src/tools/playbooks/playbook-list.ts +1 -28
  303. package/src/tools/playbooks/playbook-update.ts +3 -51
  304. package/src/tools/reminder/reminder.ts +5 -78
  305. package/src/tools/schedule/create.ts +69 -74
  306. package/src/tools/schedule/delete.ts +21 -47
  307. package/src/tools/schedule/list.ts +55 -74
  308. package/src/tools/schedule/update.ts +77 -84
  309. package/src/tools/subagent/abort.ts +29 -58
  310. package/src/tools/subagent/message.ts +30 -63
  311. package/src/tools/subagent/read.ts +53 -84
  312. package/src/tools/subagent/spawn.ts +43 -82
  313. package/src/tools/subagent/status.ts +42 -71
  314. package/src/tools/swarm/delegate.ts +2 -1
  315. package/src/tools/tasks/index.ts +8 -8
  316. package/src/tools/tasks/task-delete.ts +60 -88
  317. package/src/tools/tasks/task-list.ts +31 -52
  318. package/src/tools/tasks/task-run.ts +72 -108
  319. package/src/tools/tasks/task-save.ts +33 -65
  320. package/src/tools/tasks/work-item-enqueue.ts +183 -215
  321. package/src/tools/tasks/work-item-list.ts +33 -63
  322. package/src/tools/tasks/work-item-remove.ts +45 -97
  323. package/src/tools/tasks/work-item-update.ts +91 -163
  324. package/src/tools/terminal/backends/native.ts +3 -1
  325. package/src/tools/tool-manifest.ts +0 -62
  326. package/src/tools/types.ts +6 -0
  327. package/src/tools/ui-surface/definitions.ts +3 -1
  328. package/src/tools/watch/screen-watch.ts +3 -1
  329. package/src/tools/watcher/create.ts +52 -98
  330. package/src/tools/watcher/delete.ts +20 -46
  331. package/src/tools/watcher/digest.ts +36 -70
  332. package/src/tools/watcher/list.ts +49 -79
  333. package/src/tools/watcher/update.ts +45 -91
  334. package/src/twitter/client.ts +690 -0
  335. package/src/twitter/session.ts +91 -0
  336. package/src/usage/types.ts +0 -1
  337. package/src/util/truncate.ts +6 -0
  338. package/src/watcher/providers/slack.ts +2 -1
  339. package/src/watcher/watcher-store.ts +3 -2
  340. package/src/work-items/work-item-store.ts +27 -2
  341. package/src/workspace/commit-message-enrichment-service.ts +31 -7
  342. package/src/workspace/git-service.ts +87 -22
  343. package/src/workspace/provider-commit-message-generator.ts +242 -0
  344. package/src/workspace/turn-commit.ts +62 -3
  345. package/src/tools/contacts/index.ts +0 -4
  346. package/src/tools/document/index.ts +0 -5
  347. package/src/tools/followups/index.ts +0 -3
  348. package/src/tools/subagent/index.ts +0 -5
  349. /package/src/__tests__/{memory-context-benchmark.test.ts → memory-context-benchmark.benchmark.test.ts} +0 -0
@@ -1,112 +1,60 @@
1
- import { RiskLevel } from '../../permissions/types.js';
2
- import type { Tool, ToolContext, ToolExecutionResult } from '../types.js';
3
- import type { ToolDefinition } from '../../providers/types.js';
1
+ import type { ToolContext, ToolExecutionResult } from '../types.js';
4
2
  import { resolveWorkItem, removeWorkItemFromQueue, identifyEntityById, buildTaskTemplateMismatchError, type WorkItemStatus } from '../../work-items/work-item-store.js';
5
3
  import { getLogger } from '../../util/logger.js';
6
4
 
7
5
  const log = getLogger('task-list-remove');
8
6
 
9
- const definition: ToolDefinition = {
10
- name: 'task_list_remove',
11
- description:
12
- 'Remove a task from the Task Queue. Identifies the task by work item ID, task ID, task name, or title. When multiple items match, use the disambiguation fields (priority_tier, status, created_order) to narrow down.',
13
- input_schema: {
14
- type: 'object',
15
- properties: {
16
- work_item_id: {
17
- type: 'string',
18
- description: 'Direct work item ID (most precise selector)',
19
- },
20
- task_id: {
21
- type: 'string',
22
- description: 'Task definition ID to find the work item for',
23
- },
24
- task_name: {
25
- type: 'string',
26
- description: 'Task name/title to search for (case-insensitive exact match)',
27
- },
28
- title: {
29
- type: 'string',
30
- description: 'Work item title to search for (case-insensitive exact match)',
31
- },
32
- priority_tier: {
33
- type: 'number',
34
- description: 'Disambiguator: filter by priority tier (0 = high, 1 = medium, 2 = low)',
35
- },
36
- status: {
37
- type: 'string',
38
- enum: ['queued', 'running', 'awaiting_review', 'failed'],
39
- description: 'Disambiguator: filter by work item status',
40
- },
41
- created_order: {
42
- type: 'number',
43
- description: 'Disambiguator: 1-indexed creation order among matches (1 = oldest, 2 = second oldest, etc.)',
44
- },
45
- },
46
- },
47
- };
48
-
49
- class TaskListRemoveTool implements Tool {
50
- name = 'task_list_remove';
51
- description = definition.description;
52
- category = 'tasks';
53
- defaultRiskLevel = RiskLevel.Low;
54
-
55
- getDefinition(): ToolDefinition {
56
- return definition;
57
- }
58
-
59
- async execute(input: Record<string, unknown>, _context: ToolContext): Promise<ToolExecutionResult> {
60
- const selectorType = input.work_item_id ? 'work_item_id' : input.task_id ? 'task_id' : input.task_name ? 'task_name' : input.title ? 'title' : 'none';
61
-
62
- try {
63
- const selector = {
64
- workItemId: input.work_item_id as string | undefined,
65
- taskId: input.task_id as string | undefined,
66
- title: (input.task_name ?? input.title) as string | undefined,
67
- priorityTier: input.priority_tier as number | undefined,
68
- status: input.status as WorkItemStatus | undefined,
69
- createdOrder: input.created_order as number | undefined,
70
- };
71
-
72
- const resolveResult = resolveWorkItem(selector);
73
-
74
- if (resolveResult.status === 'not_found') {
75
- // When the model passes an ID directly, check if it's a task template
76
- if (selector.workItemId) {
77
- const entity = identifyEntityById(selector.workItemId);
78
- if (entity.type === 'task_template') {
79
- log.warn({ selectorType, inputId: selector.workItemId }, 'task template ID passed as work_item_id');
80
- return {
81
- content: `Error: ${buildTaskTemplateMismatchError(selector.workItemId, entity.title!, 'task_delete to delete task templates')}`,
82
- isError: true,
83
- };
84
- }
7
+ export async function executeTaskListRemove(
8
+ input: Record<string, unknown>,
9
+ _context: ToolContext,
10
+ ): Promise<ToolExecutionResult> {
11
+ const selectorType = input.work_item_id ? 'work_item_id' : input.task_id ? 'task_id' : input.task_name ? 'task_name' : input.title ? 'title' : 'none';
12
+
13
+ try {
14
+ const selector = {
15
+ workItemId: input.work_item_id as string | undefined,
16
+ taskId: input.task_id as string | undefined,
17
+ title: (input.task_name ?? input.title) as string | undefined,
18
+ priorityTier: input.priority_tier as number | undefined,
19
+ status: input.status as WorkItemStatus | undefined,
20
+ createdOrder: input.created_order as number | undefined,
21
+ };
22
+
23
+ const resolveResult = resolveWorkItem(selector);
24
+
25
+ if (resolveResult.status === 'not_found') {
26
+ // When the model passes an ID directly, check if it's a task template
27
+ if (selector.workItemId) {
28
+ const entity = identifyEntityById(selector.workItemId);
29
+ if (entity.type === 'task_template') {
30
+ log.warn({ selectorType, inputId: selector.workItemId }, 'task template ID passed as work_item_id');
31
+ return {
32
+ content: `Error: ${buildTaskTemplateMismatchError(selector.workItemId, entity.title!, 'task_delete to delete task templates')}`,
33
+ isError: true,
34
+ };
85
35
  }
86
- log.warn({ selectorType, error: resolveResult.message }, 'work item not found for removal');
87
- return { content: `Error: ${resolveResult.message}`, isError: true };
88
36
  }
37
+ log.warn({ selectorType, error: resolveResult.message }, 'work item not found for removal');
38
+ return { content: `Error: ${resolveResult.message}`, isError: true };
39
+ }
89
40
 
90
- if (resolveResult.status === 'ambiguous') {
91
- log.warn({ selectorType, matchCount: resolveResult.matches.length }, 'ambiguous selector for removal');
92
- return { content: `Error: ${resolveResult.message}`, isError: true };
93
- }
41
+ if (resolveResult.status === 'ambiguous') {
42
+ log.warn({ selectorType, matchCount: resolveResult.matches.length }, 'ambiguous selector for removal');
43
+ return { content: `Error: ${resolveResult.message}`, isError: true };
44
+ }
94
45
 
95
- const item = resolveResult.workItem;
46
+ const item = resolveResult.workItem;
96
47
 
97
- log.info({ selectorType, selectorValue: input[selectorType], resolvedWorkItemId: item.id, title: item.title }, 'resolved work item for removal');
48
+ log.info({ selectorType, selectorValue: input[selectorType], resolvedWorkItemId: item.id, title: item.title }, 'resolved work item for removal');
98
49
 
99
- const removeResult = removeWorkItemFromQueue(item.id);
50
+ const removeResult = removeWorkItemFromQueue(item.id);
100
51
 
101
- log.info({ resolvedWorkItemId: item.id, deletedCount: 1 }, 'work item removed');
52
+ log.info({ resolvedWorkItemId: item.id, deletedCount: 1 }, 'work item removed');
102
53
 
103
- return { content: removeResult.message, isError: false };
104
- } catch (err) {
105
- const msg = err instanceof Error ? err.message : String(err);
106
- log.error({ selectorType, error: msg }, 'remove failed');
107
- return { content: `Error: ${msg}`, isError: true };
108
- }
54
+ return { content: removeResult.message, isError: false };
55
+ } catch (err) {
56
+ const msg = err instanceof Error ? err.message : String(err);
57
+ log.error({ selectorType, error: msg }, 'remove failed');
58
+ return { content: `Error: ${msg}`, isError: true };
109
59
  }
110
60
  }
111
-
112
- export const taskListRemoveTool = new TaskListRemoveTool();
@@ -1,6 +1,4 @@
1
- import { RiskLevel } from '../../permissions/types.js';
2
- import type { Tool, ToolContext, ToolExecutionResult } from '../types.js';
3
- import type { ToolDefinition } from '../../providers/types.js';
1
+ import type { ToolContext, ToolExecutionResult } from '../types.js';
4
2
  import { resolveWorkItem, updateWorkItem, identifyEntityById, buildTaskTemplateMismatchError, type WorkItemStatus } from '../../work-items/work-item-store.js';
5
3
  import { getLogger } from '../../util/logger.js';
6
4
 
@@ -12,175 +10,105 @@ const PRIORITY_LABELS: Record<number, string> = {
12
10
  2: 'low',
13
11
  };
14
12
 
15
- const definition: ToolDefinition = {
16
- name: 'task_list_update',
17
- description:
18
- 'Update an existing task in the Task Queue. Can change priority, notes, status, or sort order. Identifies the task by work item ID, task ID, task name, or title.',
19
- input_schema: {
20
- type: 'object',
21
- properties: {
22
- work_item_id: {
23
- type: 'string',
24
- description: 'Direct work item ID (most precise selector)',
25
- },
26
- task_id: {
27
- type: 'string',
28
- description: 'Task definition ID to find the work item for',
29
- },
30
- task_name: {
31
- type: 'string',
32
- description: 'Task name/title to search for (case-insensitive exact match)',
33
- },
34
- title: {
35
- type: 'string',
36
- description: 'Work item title to search for (case-insensitive exact match)',
37
- },
38
- priority_tier: {
39
- type: 'number',
40
- description: '0 = high, 1 = medium, 2 = low',
41
- },
42
- notes: {
43
- type: 'string',
44
- description: 'Updated notes for the work item',
45
- },
46
- status: {
47
- type: 'string',
48
- enum: ['queued', 'running', 'awaiting_review', 'failed', 'archived'],
49
- description: 'New status for the work item',
50
- },
51
- sort_index: {
52
- type: 'number',
53
- description: 'Manual sort order within the same priority tier',
54
- },
55
- filter_priority_tier: {
56
- type: 'number',
57
- description:
58
- 'Disambiguation filter: narrow by current priority tier (0=high, 1=medium, 2=low) when multiple items share the same title/task_id. This identifies WHICH item to update — it is NOT the new priority value.',
59
- },
60
- filter_status: {
61
- type: 'string',
62
- enum: ['queued', 'running', 'awaiting_review', 'failed', 'done', 'archived'],
63
- description:
64
- 'Disambiguation filter: narrow by current status when multiple items share the same title/task_id.',
65
- },
66
- created_order: {
67
- type: 'number',
68
- description:
69
- 'Disambiguation filter: pick the Nth oldest match (1 = oldest, 2 = second oldest, etc.) when multiple items share the same title/task_id.',
70
- },
71
- },
72
- },
73
- };
74
-
75
- class TaskListUpdateTool implements Tool {
76
- name = 'task_list_update';
77
- description = definition.description;
78
- category = 'tasks';
79
- defaultRiskLevel = RiskLevel.Low;
80
-
81
- getDefinition(): ToolDefinition {
82
- return definition;
83
- }
84
-
85
- async execute(input: Record<string, unknown>, _context: ToolContext): Promise<ToolExecutionResult> {
86
- const selectorType = input.work_item_id ? 'work_item_id' : input.task_id ? 'task_id' : input.task_name ? 'task_name' : input.title ? 'title' : 'none';
87
-
88
- try {
89
- // Build selector from whichever identifier was provided
90
- const selector = {
91
- workItemId: input.work_item_id as string | undefined,
92
- taskId: input.task_id as string | undefined,
93
- title: (input.task_name ?? input.title) as string | undefined,
94
- priorityTier: input.filter_priority_tier as number | undefined,
95
- status: input.filter_status as WorkItemStatus | undefined,
96
- createdOrder: input.created_order as number | undefined,
97
- };
98
-
99
- // Resolve the target work item
100
- const result = resolveWorkItem(selector);
101
-
102
- if (result.status === 'not_found') {
103
- // When the model passes an ID directly, check if it's a task template
104
- if (selector.workItemId) {
105
- const entity = identifyEntityById(selector.workItemId);
106
- if (entity.type === 'task_template') {
107
- log.warn({ selectorType, inputId: selector.workItemId }, 'task template ID passed as work_item_id');
108
- return {
109
- content: `Error: ${buildTaskTemplateMismatchError(selector.workItemId, entity.title!, 'task_delete to remove task templates, or task_list to view them')}`,
110
- isError: true,
111
- };
112
- }
13
+ export async function executeTaskListUpdate(
14
+ input: Record<string, unknown>,
15
+ _context: ToolContext,
16
+ ): Promise<ToolExecutionResult> {
17
+ const selectorType = input.work_item_id ? 'work_item_id' : input.task_id ? 'task_id' : input.task_name ? 'task_name' : input.title ? 'title' : 'none';
18
+
19
+ try {
20
+ // Build selector from whichever identifier was provided
21
+ const selector = {
22
+ workItemId: input.work_item_id as string | undefined,
23
+ taskId: input.task_id as string | undefined,
24
+ title: (input.task_name ?? input.title) as string | undefined,
25
+ priorityTier: input.filter_priority_tier as number | undefined,
26
+ status: input.filter_status as WorkItemStatus | undefined,
27
+ createdOrder: input.created_order as number | undefined,
28
+ };
29
+
30
+ // Resolve the target work item
31
+ const result = resolveWorkItem(selector);
32
+
33
+ if (result.status === 'not_found') {
34
+ // When the model passes an ID directly, check if it's a task template
35
+ if (selector.workItemId) {
36
+ const entity = identifyEntityById(selector.workItemId);
37
+ if (entity.type === 'task_template') {
38
+ log.warn({ selectorType, inputId: selector.workItemId }, 'task template ID passed as work_item_id');
39
+ return {
40
+ content: `Error: ${buildTaskTemplateMismatchError(selector.workItemId, entity.title!, 'task_delete to remove task templates, or task_list to view them')}`,
41
+ isError: true,
42
+ };
113
43
  }
114
- log.warn({ selectorType, error: result.message }, 'work item not found for update');
115
- return { content: `Error: ${result.message}`, isError: true };
116
44
  }
45
+ log.warn({ selectorType, error: result.message }, 'work item not found for update');
46
+ return { content: `Error: ${result.message}`, isError: true };
47
+ }
117
48
 
118
- if (result.status === 'ambiguous') {
119
- log.warn({ selectorType, matchCount: result.matches.length }, 'ambiguous selector for update');
120
- return { content: `Error: ${result.message}`, isError: true };
121
- }
49
+ if (result.status === 'ambiguous') {
50
+ log.warn({ selectorType, matchCount: result.matches.length }, 'ambiguous selector for update');
51
+ return { content: `Error: ${result.message}`, isError: true };
52
+ }
122
53
 
123
- const item = result.workItem;
54
+ const item = result.workItem;
124
55
 
125
- // Block direct transitions to 'done' — the only path to done is
126
- // through the Review action (handleWorkItemComplete in the daemon).
127
- if (input.status === 'done') {
128
- log.warn({ selectorType, resolvedWorkItemId: item.id }, 'rejected attempt to set status to done directly');
129
- return {
130
- content: 'Error: Cannot set status to \'done\' directly. Use the Review action in the Tasks window.',
131
- isError: true,
132
- };
133
- }
56
+ // Block direct transitions to 'done' — the only path to done is
57
+ // through the Review action (handleWorkItemComplete in the daemon).
58
+ if (input.status === 'done') {
59
+ log.warn({ selectorType, resolvedWorkItemId: item.id }, 'rejected attempt to set status to done directly');
60
+ return {
61
+ content: 'Error: Cannot set status to \'done\' directly. Use the Review action in the Tasks window.',
62
+ isError: true,
63
+ };
64
+ }
134
65
 
135
- log.info({ selectorType, selectorValue: input[selectorType], resolvedWorkItemId: item.id }, 'resolved work item for update');
136
-
137
- // Build updates from provided fields
138
- const updates: Partial<{
139
- priorityTier: number;
140
- notes: string;
141
- status: WorkItemStatus;
142
- sortIndex: number;
143
- }> = {};
144
- if (input.priority_tier !== undefined) updates.priorityTier = input.priority_tier as number;
145
- if (input.notes !== undefined) updates.notes = input.notes as string;
146
- if (input.status !== undefined) updates.status = input.status as WorkItemStatus;
147
- if (input.sort_index !== undefined) updates.sortIndex = input.sort_index as number;
148
-
149
- if (Object.keys(updates).length === 0) {
150
- log.warn({ selectorType, resolvedWorkItemId: item.id }, 'update called with no fields to update');
151
- return {
152
- content: 'No updates specified. Provide at least one field to update (priority_tier, notes, status, sort_index).',
153
- isError: true,
154
- };
155
- }
66
+ log.info({ selectorType, selectorValue: input[selectorType], resolvedWorkItemId: item.id }, 'resolved work item for update');
67
+
68
+ // Build updates from provided fields
69
+ const updates: Partial<{
70
+ priorityTier: number;
71
+ notes: string;
72
+ status: WorkItemStatus;
73
+ sortIndex: number;
74
+ }> = {};
75
+ if (input.priority_tier !== undefined) updates.priorityTier = input.priority_tier as number;
76
+ if (input.notes !== undefined) updates.notes = input.notes as string;
77
+ if (input.status !== undefined) updates.status = input.status as WorkItemStatus;
78
+ if (input.sort_index !== undefined) updates.sortIndex = input.sort_index as number;
79
+
80
+ if (Object.keys(updates).length === 0) {
81
+ log.warn({ selectorType, resolvedWorkItemId: item.id }, 'update called with no fields to update');
82
+ return {
83
+ content: 'No updates specified. Provide at least one field to update (priority_tier, notes, status, sort_index).',
84
+ isError: true,
85
+ };
86
+ }
156
87
 
157
- const updated = updateWorkItem(item.id, updates);
158
- if (!updated) {
159
- log.error({ selectorType, resolvedWorkItemId: item.id, updates }, 'updateWorkItem returned null');
160
- return {
161
- content: `Error: Failed to update work item "${item.title}".`,
162
- isError: true,
163
- };
164
- }
88
+ const updated = updateWorkItem(item.id, updates);
89
+ if (!updated) {
90
+ log.error({ selectorType, resolvedWorkItemId: item.id, updates }, 'updateWorkItem returned null');
91
+ return {
92
+ content: `Error: Failed to update work item "${item.title}".`,
93
+ isError: true,
94
+ };
95
+ }
165
96
 
166
- log.info({ resolvedWorkItemId: item.id, updatedFields: Object.keys(updates) }, 'work item updated');
97
+ log.info({ resolvedWorkItemId: item.id, updatedFields: Object.keys(updates) }, 'work item updated');
167
98
 
168
- // Build confirmation message
169
- const parts: string[] = [`Updated "${updated.title}"`];
170
- if (input.priority_tier !== undefined) {
171
- parts.push(`priority → ${PRIORITY_LABELS[updated.priorityTier] ?? updated.priorityTier}`);
172
- }
173
- if (input.notes !== undefined) parts.push('notes updated');
174
- if (input.status !== undefined) parts.push(`status → ${updated.status}`);
175
- if (input.sort_index !== undefined) parts.push(`sort index → ${updated.sortIndex}`);
176
-
177
- return { content: parts.join(', ') + '.', isError: false };
178
- } catch (err) {
179
- const msg = err instanceof Error ? err.message : String(err);
180
- log.error({ selectorType, error: msg }, 'update failed');
181
- return { content: `Error: ${msg}`, isError: true };
99
+ // Build confirmation message
100
+ const parts: string[] = [`Updated "${updated.title}"`];
101
+ if (input.priority_tier !== undefined) {
102
+ parts.push(`priority → ${PRIORITY_LABELS[updated.priorityTier] ?? updated.priorityTier}`);
182
103
  }
104
+ if (input.notes !== undefined) parts.push('notes updated');
105
+ if (input.status !== undefined) parts.push(`status → ${updated.status}`);
106
+ if (input.sort_index !== undefined) parts.push(`sort index → ${updated.sortIndex}`);
107
+
108
+ return { content: parts.join(', ') + '.', isError: false };
109
+ } catch (err) {
110
+ const msg = err instanceof Error ? err.message : String(err);
111
+ log.error({ selectorType, error: msg }, 'update failed');
112
+ return { content: `Error: ${msg}`, isError: true };
183
113
  }
184
114
  }
185
-
186
- export const taskListUpdateTool = new TaskListUpdateTool();
@@ -9,6 +9,8 @@ import type { SandboxBackend, SandboxResult } from './types.js';
9
9
 
10
10
  const log = getLogger('sandbox');
11
11
 
12
+ const HASH_DISPLAY_LENGTH = 12;
13
+
12
14
  /**
13
15
  * macOS sandbox-exec profile that restricts shell commands:
14
16
  * - Denies all by default
@@ -81,7 +83,7 @@ function getProfilePath(workingDir: string): string {
81
83
  if (!existsSync(dir)) {
82
84
  mkdirSync(dir, { recursive: true });
83
85
  }
84
- const hash = createHash('sha256').update(workingDir).digest('hex').slice(0, 12);
86
+ const hash = createHash('sha256').update(workingDir).digest('hex').slice(0, HASH_DISPLAY_LENGTH);
85
87
  const path = join(dir, `sandbox-profile-${hash}.sb`);
86
88
 
87
89
  const profile = SANDBOX_PROFILE.replace(/__WORKING_DIR__/g, workingDir);
@@ -12,20 +12,9 @@ import type { Tool } from './types.js';
12
12
  import { memorySearchTool, memorySaveTool, memoryUpdateTool } from './memory/register.js';
13
13
  import { credentialStoreTool } from './credentials/vault.js';
14
14
  import { accountManageTool } from './credentials/account-registry.js';
15
- import { reminderTool } from './reminder/reminder.js';
16
15
  import { screenWatchTool } from './watch/screen-watch.js';
17
16
  import { vellumSkillsCatalogTool } from './skills/vellum-catalog.js';
18
- import { documentCreateTool, documentUpdateTool } from './document/index.js';
19
17
  import { cliDiscoverTool } from './host-terminal/cli-discover.js';
20
- import { followupCreateTool, followupListTool, followupResolveTool } from './followups/index.js';
21
- import { taskSaveTool, taskRunTool, taskListTool, taskDeleteTool, taskListShowTool, taskListAddTool, taskListUpdateTool, taskListRemoveTool } from './tasks/index.js';
22
- import {
23
- subagentSpawnTool,
24
- subagentStatusTool,
25
- subagentAbortTool,
26
- subagentMessageTool,
27
- subagentReadTool,
28
- } from './subagent/index.js';
29
18
 
30
19
  // ── Eager side-effect modules ───────────────────────────────────────
31
20
  // Importing these modules triggers a top-level `registerTool()` call.
@@ -40,22 +29,6 @@ export async function loadEagerModules(): Promise<void> {
40
29
  await import('./skills/scaffold-managed.js');
41
30
  await import('./skills/delete-managed.js');
42
31
  await import('./system/request-permission.js');
43
- await import('./schedule/create.js');
44
- await import('./schedule/list.js');
45
- await import('./schedule/update.js');
46
- await import('./schedule/delete.js');
47
- await import('./watcher/create.js');
48
- await import('./watcher/list.js');
49
- await import('./watcher/update.js');
50
- await import('./watcher/delete.js');
51
- await import('./watcher/digest.js');
52
- await import('./playbooks/playbook-create.js');
53
- await import('./playbooks/playbook-list.js');
54
- await import('./playbooks/playbook-update.js');
55
- await import('./playbooks/playbook-delete.js');
56
- await import('./contacts/contact-upsert.js');
57
- await import('./contacts/contact-search.js');
58
- await import('./contacts/contact-merge.js');
59
32
  await import('./assets/search.js');
60
33
  await import('./assets/materialize.js');
61
34
  await import('./filesystem/view-image.js');
@@ -78,22 +51,6 @@ export const eagerModuleToolNames: string[] = [
78
51
  'scaffold_managed_skill',
79
52
  'delete_managed_skill',
80
53
  'request_system_permission',
81
- 'schedule_create',
82
- 'schedule_list',
83
- 'schedule_update',
84
- 'schedule_delete',
85
- 'watcher_create',
86
- 'watcher_list',
87
- 'watcher_update',
88
- 'watcher_delete',
89
- 'watcher_digest',
90
- 'playbook_create',
91
- 'playbook_list',
92
- 'playbook_update',
93
- 'playbook_delete',
94
- 'contact_upsert',
95
- 'contact_search',
96
- 'contact_merge',
97
54
  'asset_search',
98
55
  'asset_materialize',
99
56
  'view_image',
@@ -112,28 +69,9 @@ export const explicitTools: Tool[] = [
112
69
  memoryUpdateTool,
113
70
  credentialStoreTool,
114
71
  accountManageTool,
115
- reminderTool,
116
72
  screenWatchTool,
117
73
  vellumSkillsCatalogTool,
118
- documentCreateTool,
119
- documentUpdateTool,
120
74
  cliDiscoverTool,
121
- followupCreateTool,
122
- followupListTool,
123
- followupResolveTool,
124
- taskSaveTool,
125
- taskRunTool,
126
- taskListTool,
127
- taskDeleteTool,
128
- taskListShowTool,
129
- taskListAddTool,
130
- taskListUpdateTool,
131
- taskListRemoveTool,
132
- subagentSpawnTool,
133
- subagentStatusTool,
134
- subagentAbortTool,
135
- subagentMessageTool,
136
- subagentReadTool,
137
75
  ];
138
76
 
139
77
  // ── Lazy tool descriptors ───────────────────────────────────────────
@@ -52,6 +52,8 @@ export interface ToolExecutedEvent extends ToolLifecycleEventBase {
52
52
  result: ToolExecutionResult;
53
53
  }
54
54
 
55
+ export type ErrorCategory = 'permission_denied' | 'auth' | 'tool_failure' | 'unexpected';
56
+
55
57
  export interface ToolExecutionErrorEvent extends ToolLifecycleEventBase {
56
58
  type: 'error';
57
59
  riskLevel: string;
@@ -59,6 +61,8 @@ export interface ToolExecutionErrorEvent extends ToolLifecycleEventBase {
59
61
  durationMs: number;
60
62
  errorMessage: string;
61
63
  isExpected: boolean;
64
+ /** Classifies the error for downstream consumers (audit, alerting, monitoring). */
65
+ errorCategory: ErrorCategory;
62
66
  errorName?: string;
63
67
  errorStack?: string;
64
68
  }
@@ -89,6 +93,8 @@ export interface ToolContext {
89
93
  workingDir: string;
90
94
  sessionId: string;
91
95
  conversationId: string;
96
+ /** When set, the tool execution is part of a task run. Used to retrieve ephemeral permission rules. */
97
+ taskRunId?: string;
92
98
  /** Per-message request ID for log correlation across session/connection boundaries. */
93
99
  requestId?: string;
94
100
  /** Optional callback for streaming incremental output to the client. */
@@ -120,7 +120,9 @@ export const uiShowTool: Tool = {
120
120
 
121
121
  export const uiUpdateTool: Tool = {
122
122
  name: 'ui_update',
123
- description: "Update an existing surface's data. The provided data object is merged into the surface's current data.",
123
+ description:
124
+ "Update an existing surface's data. The provided data object is merged into the surface's current data.\n" +
125
+ 'For card templates (for example `task_progress`), update nested fields under `data.templateData` rather than sending template fields at the top level.',
124
126
  category: 'ui-surface',
125
127
  defaultRiskLevel: RiskLevel.Low,
126
128
  executionMode: 'proxy',
@@ -13,6 +13,8 @@ import type { WatchSession } from './watch-state.js';
13
13
 
14
14
  const log = getLogger('screen-watch');
15
15
 
16
+ const SHORT_HASH_LENGTH = 8;
17
+
16
18
  class ScreenWatchTool implements Tool {
17
19
  name = 'start_screen_watch';
18
20
  description = 'Start observing the screen at regular intervals for a specified duration. Captures OCR text from the active window and provides periodic commentary.';
@@ -77,7 +79,7 @@ class ScreenWatchTool implements Tool {
77
79
  }
78
80
 
79
81
  // Generate watchId
80
- const watchId = crypto.randomUUID().slice(0, 8);
82
+ const watchId = crypto.randomUUID().slice(0, SHORT_HASH_LENGTH);
81
83
  const now = Date.now();
82
84
  const durationSeconds = durationMinutes * 60;
83
85