vellum 0.2.0 → 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 (361) 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 +161 -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__/app-bundler.test.ts +12 -33
  11. package/src/__tests__/asset-materialize-tool.test.ts +16 -15
  12. package/src/__tests__/asset-search-tool.test.ts +23 -22
  13. package/src/__tests__/attachments-store.test.ts +56 -127
  14. package/src/__tests__/browser-skill-baseline-tool-payload.test.ts +5 -4
  15. package/src/__tests__/browser-skill-endstate.test.ts +5 -8
  16. package/src/__tests__/call-bridge.test.ts +385 -0
  17. package/src/__tests__/call-constants.test.ts +40 -0
  18. package/src/__tests__/call-orchestrator.test.ts +454 -0
  19. package/src/__tests__/call-recovery.test.ts +518 -0
  20. package/src/__tests__/call-routes-http.test.ts +459 -0
  21. package/src/__tests__/call-state-machine.test.ts +143 -0
  22. package/src/__tests__/call-state.test.ts +133 -0
  23. package/src/__tests__/call-store.test.ts +691 -0
  24. package/src/__tests__/cli-discover.test.ts +1 -1
  25. package/src/__tests__/commit-message-enrichment-service.test.ts +550 -0
  26. package/src/__tests__/compaction.benchmark.test.ts +176 -0
  27. package/src/__tests__/computer-use-tools.test.ts +250 -0
  28. package/src/__tests__/config-schema.test.ts +348 -3
  29. package/src/__tests__/conflict-store.test.ts +2 -1
  30. package/src/__tests__/contacts-tools.test.ts +331 -0
  31. package/src/__tests__/conversation-store.test.ts +30 -32
  32. package/src/__tests__/credential-security-invariants.test.ts +4 -0
  33. package/src/__tests__/date-context.test.ts +373 -0
  34. package/src/__tests__/db-schedule-syntax-migration.test.ts +129 -0
  35. package/src/__tests__/doordash-session.test.ts +9 -0
  36. package/src/__tests__/fixtures/media-reuse-fixtures.ts +3 -3
  37. package/src/__tests__/followup-tools.test.ts +303 -0
  38. package/src/__tests__/handlers-twitter-config.test.ts +718 -0
  39. package/src/__tests__/intent-routing.test.ts +64 -57
  40. package/src/__tests__/ipc-roundtrip.benchmark.test.ts +237 -0
  41. package/src/__tests__/ipc-snapshot.test.ts +96 -28
  42. package/src/__tests__/llm-usage-store.test.ts +3 -8
  43. package/src/__tests__/media-generate-image.test.ts +1 -1
  44. package/src/__tests__/media-reuse-story.e2e.test.ts +7 -7
  45. package/src/__tests__/memory-retrieval.benchmark.test.ts +430 -0
  46. package/src/__tests__/parallel-tool.benchmark.test.ts +294 -0
  47. package/src/__tests__/playbook-tools.test.ts +342 -0
  48. package/src/__tests__/profile-compiler.test.ts +2 -1
  49. package/src/__tests__/provider-streaming.benchmark.test.ts +773 -0
  50. package/src/__tests__/recurrence-engine-rruleset.test.ts +78 -0
  51. package/src/__tests__/recurrence-engine.test.ts +69 -0
  52. package/src/__tests__/recurrence-types.test.ts +71 -0
  53. package/src/__tests__/registry.test.ts +17 -10
  54. package/src/__tests__/relay-server.test.ts +633 -0
  55. package/src/__tests__/reminder-store.test.ts +6 -3
  56. package/src/__tests__/reminder.test.ts +43 -77
  57. package/src/__tests__/run-orchestrator-assistant-events.test.ts +222 -0
  58. package/src/__tests__/run-orchestrator.test.ts +7 -7
  59. package/src/__tests__/runtime-attachment-metadata.test.ts +19 -20
  60. package/src/__tests__/runtime-runs-http.test.ts +5 -23
  61. package/src/__tests__/runtime-runs.test.ts +11 -11
  62. package/src/__tests__/schedule-store.test.ts +482 -0
  63. package/src/__tests__/schedule-tools.test.ts +700 -0
  64. package/src/__tests__/scheduler-recurrence.test.ts +329 -0
  65. package/src/__tests__/server-history-render.test.ts +14 -13
  66. package/src/__tests__/session-error.test.ts +28 -0
  67. package/src/__tests__/session-init.benchmark.test.ts +462 -0
  68. package/src/__tests__/session-queue.test.ts +89 -16
  69. package/src/__tests__/session-runtime-assembly.test.ts +161 -0
  70. package/src/__tests__/session-surfaces-task-progress.test.ts +104 -0
  71. package/src/__tests__/signup-e2e.test.ts +2 -1
  72. package/src/__tests__/skill-projection.benchmark.test.ts +328 -0
  73. package/src/__tests__/skill-script-runner.test.ts +159 -0
  74. package/src/__tests__/speaker-identification.test.ts +52 -0
  75. package/src/__tests__/subagent-manager-notify.test.ts +42 -10
  76. package/src/__tests__/subagent-tools.test.ts +141 -41
  77. package/src/__tests__/task-compiler.test.ts +2 -1
  78. package/src/__tests__/task-runner.test.ts +2 -1
  79. package/src/__tests__/task-scheduler.test.ts +2 -1
  80. package/src/__tests__/task-tools.test.ts +49 -56
  81. package/src/__tests__/tool-audit-listener.test.ts +1 -0
  82. package/src/__tests__/tool-domain-event-publisher.test.ts +2 -0
  83. package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +500 -0
  84. package/src/__tests__/tool-executor.test.ts +13 -17
  85. package/src/__tests__/turn-commit.test.ts +273 -2
  86. package/src/__tests__/twilio-provider.test.ts +143 -0
  87. package/src/__tests__/twilio-routes.test.ts +789 -0
  88. package/src/__tests__/twitter-auth-handler.test.ts +581 -0
  89. package/src/__tests__/view-image-tool.test.ts +217 -0
  90. package/src/__tests__/workspace-git-service.test.ts +403 -0
  91. package/src/__tests__/workspace-heartbeat-service.test.ts +141 -2
  92. package/src/agent-heartbeat/agent-heartbeat-service.ts +155 -0
  93. package/src/bundler/app-bundler.ts +35 -14
  94. package/src/calls/call-bridge.ts +95 -0
  95. package/src/calls/call-constants.ts +48 -0
  96. package/src/calls/call-domain.ts +276 -0
  97. package/src/calls/call-orchestrator.ts +390 -0
  98. package/src/calls/call-recovery.ts +207 -0
  99. package/src/calls/call-state-machine.ts +68 -0
  100. package/src/calls/call-state.ts +64 -0
  101. package/src/calls/call-store.ts +416 -0
  102. package/src/calls/relay-server.ts +335 -0
  103. package/src/calls/speaker-identification.ts +213 -0
  104. package/src/calls/twilio-config.ts +34 -0
  105. package/src/calls/twilio-provider.ts +173 -0
  106. package/src/calls/twilio-routes.ts +250 -0
  107. package/src/calls/types.ts +37 -0
  108. package/src/calls/voice-provider.ts +14 -0
  109. package/src/cli/config-commands.ts +334 -0
  110. package/src/cli/core-commands.ts +776 -0
  111. package/src/cli/doordash.ts +256 -25
  112. package/src/cli/ipc-client.ts +82 -0
  113. package/src/cli/map.ts +246 -0
  114. package/src/cli/twitter.ts +575 -0
  115. package/src/cli.ts +7 -5
  116. package/src/commands/__tests__/cc-command-registry.test.ts +319 -0
  117. package/src/commands/cc-command-registry.ts +209 -0
  118. package/src/config/bundled-skills/contacts/SKILL.md +39 -0
  119. package/src/config/bundled-skills/contacts/TOOLS.json +122 -0
  120. package/src/config/bundled-skills/contacts/tools/contact-merge.ts +9 -0
  121. package/src/config/bundled-skills/contacts/tools/contact-search.ts +9 -0
  122. package/src/config/bundled-skills/contacts/tools/contact-upsert.ts +9 -0
  123. package/src/config/bundled-skills/document/SKILL.md +18 -0
  124. package/src/config/bundled-skills/document/TOOLS.json +53 -0
  125. package/src/config/bundled-skills/document/tools/document-create.ts +9 -0
  126. package/src/config/bundled-skills/document/tools/document-update.ts +9 -0
  127. package/src/config/bundled-skills/doordash/SKILL.md +163 -0
  128. package/src/config/bundled-skills/followups/SKILL.md +32 -0
  129. package/src/config/bundled-skills/followups/TOOLS.json +100 -0
  130. package/src/config/bundled-skills/followups/tools/followup-create.ts +9 -0
  131. package/src/config/bundled-skills/followups/tools/followup-list.ts +9 -0
  132. package/src/config/bundled-skills/followups/tools/followup-resolve.ts +9 -0
  133. package/src/config/bundled-skills/image-studio/TOOLS.json +2 -2
  134. package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +2 -24
  135. package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +2 -1
  136. package/src/config/bundled-skills/playbooks/SKILL.md +31 -0
  137. package/src/config/bundled-skills/playbooks/TOOLS.json +126 -0
  138. package/src/config/bundled-skills/playbooks/tools/playbook-create.ts +9 -0
  139. package/src/config/bundled-skills/playbooks/tools/playbook-delete.ts +9 -0
  140. package/src/config/bundled-skills/playbooks/tools/playbook-list.ts +9 -0
  141. package/src/config/bundled-skills/playbooks/tools/playbook-update.ts +9 -0
  142. package/src/config/bundled-skills/reminder/SKILL.md +20 -0
  143. package/src/config/bundled-skills/reminder/TOOLS.json +67 -0
  144. package/src/config/bundled-skills/reminder/tools/reminder-cancel.ts +9 -0
  145. package/src/config/bundled-skills/reminder/tools/reminder-create.ts +9 -0
  146. package/src/config/bundled-skills/reminder/tools/reminder-list.ts +9 -0
  147. package/src/config/bundled-skills/schedule/SKILL.md +74 -0
  148. package/src/config/bundled-skills/schedule/TOOLS.json +135 -0
  149. package/src/config/bundled-skills/schedule/tools/schedule-create.ts +9 -0
  150. package/src/config/bundled-skills/schedule/tools/schedule-delete.ts +9 -0
  151. package/src/config/bundled-skills/schedule/tools/schedule-list.ts +9 -0
  152. package/src/config/bundled-skills/schedule/tools/schedule-update.ts +9 -0
  153. package/src/config/bundled-skills/subagent/SKILL.md +25 -0
  154. package/src/config/bundled-skills/subagent/TOOLS.json +107 -0
  155. package/src/config/bundled-skills/subagent/tools/subagent-abort.ts +9 -0
  156. package/src/config/bundled-skills/subagent/tools/subagent-message.ts +9 -0
  157. package/src/config/bundled-skills/subagent/tools/subagent-read.ts +9 -0
  158. package/src/config/bundled-skills/subagent/tools/subagent-spawn.ts +9 -0
  159. package/src/config/bundled-skills/subagent/tools/subagent-status.ts +9 -0
  160. package/src/config/bundled-skills/tasks/SKILL.md +28 -0
  161. package/src/config/bundled-skills/tasks/TOOLS.json +256 -0
  162. package/src/config/bundled-skills/tasks/tools/task-delete.ts +9 -0
  163. package/src/config/bundled-skills/tasks/tools/task-list-add.ts +9 -0
  164. package/src/config/bundled-skills/tasks/tools/task-list-remove.ts +9 -0
  165. package/src/config/bundled-skills/tasks/tools/task-list-show.ts +9 -0
  166. package/src/config/bundled-skills/tasks/tools/task-list-update.ts +9 -0
  167. package/src/config/bundled-skills/tasks/tools/task-list.ts +9 -0
  168. package/src/config/bundled-skills/tasks/tools/task-run.ts +9 -0
  169. package/src/config/bundled-skills/tasks/tools/task-save.ts +9 -0
  170. package/src/config/bundled-skills/twitter/SKILL.md +134 -0
  171. package/src/config/bundled-skills/watcher/SKILL.md +27 -0
  172. package/src/config/bundled-skills/watcher/TOOLS.json +147 -0
  173. package/src/config/bundled-skills/watcher/tools/watcher-create.ts +9 -0
  174. package/src/config/bundled-skills/watcher/tools/watcher-delete.ts +9 -0
  175. package/src/config/bundled-skills/watcher/tools/watcher-digest.ts +9 -0
  176. package/src/config/bundled-skills/watcher/tools/watcher-list.ts +9 -0
  177. package/src/config/bundled-skills/watcher/tools/watcher-update.ts +9 -0
  178. package/src/config/defaults.ts +44 -0
  179. package/src/config/loader.ts +4 -1
  180. package/src/config/schema.ts +218 -1
  181. package/src/config/system-prompt.ts +100 -6
  182. package/src/config/templates/IDENTITY.md +7 -0
  183. package/src/config/types.ts +5 -0
  184. package/src/contacts/contact-store.ts +4 -4
  185. package/src/daemon/assistant-attachments.ts +10 -0
  186. package/src/daemon/classifier.ts +3 -1
  187. package/src/daemon/computer-use-session.ts +3 -1
  188. package/src/daemon/date-context.ts +136 -0
  189. package/src/daemon/handlers/apps.ts +16 -1
  190. package/src/daemon/handlers/browser.ts +54 -0
  191. package/src/daemon/handlers/computer-use.ts +7 -1
  192. package/src/daemon/handlers/config.ts +192 -4
  193. package/src/daemon/handlers/diagnostics.ts +5 -1
  194. package/src/daemon/handlers/documents.ts +18 -29
  195. package/src/daemon/handlers/home-base.ts +5 -1
  196. package/src/daemon/handlers/index.ts +40 -271
  197. package/src/daemon/handlers/misc.ts +9 -1
  198. package/src/daemon/handlers/publish.ts +6 -1
  199. package/src/daemon/handlers/sessions.ts +65 -12
  200. package/src/daemon/handlers/shared.ts +36 -1
  201. package/src/daemon/handlers/signing.ts +37 -0
  202. package/src/daemon/handlers/skills.ts +20 -6
  203. package/src/daemon/handlers/subagents.ts +8 -3
  204. package/src/daemon/handlers/twitter-auth.ts +169 -0
  205. package/src/daemon/handlers/work-items.ts +495 -39
  206. package/src/daemon/ipc-contract-inventory.json +40 -4
  207. package/src/daemon/ipc-contract.ts +185 -37
  208. package/src/daemon/ipc-protocol.ts +7 -2
  209. package/src/daemon/lifecycle.ts +48 -5
  210. package/src/daemon/main.ts +10 -4
  211. package/src/daemon/ride-shotgun-handler.ts +74 -10
  212. package/src/daemon/server.ts +144 -29
  213. package/src/daemon/session-agent-loop.ts +887 -0
  214. package/src/daemon/session-attachments.ts +28 -5
  215. package/src/daemon/session-error.ts +24 -3
  216. package/src/daemon/session-lifecycle.ts +147 -0
  217. package/src/daemon/session-media-retry.ts +147 -0
  218. package/src/daemon/session-messaging.ts +145 -0
  219. package/src/daemon/session-notifiers.ts +164 -0
  220. package/src/daemon/session-process.ts +2 -2
  221. package/src/daemon/session-queue-manager.ts +1 -0
  222. package/src/daemon/session-runtime-assembly.ts +52 -0
  223. package/src/daemon/session-skill-tools.ts +124 -5
  224. package/src/daemon/session-slash.ts +3 -0
  225. package/src/daemon/session-surfaces.ts +77 -2
  226. package/src/daemon/session-tool-setup.ts +222 -2
  227. package/src/daemon/session-usage.ts +0 -2
  228. package/src/daemon/session.ts +114 -1365
  229. package/src/daemon/video-thumbnail.ts +60 -0
  230. package/src/doordash/client.ts +121 -27
  231. package/src/doordash/queries.ts +1 -2
  232. package/src/export/formatter.ts +3 -1
  233. package/src/followups/followup-store.ts +4 -2
  234. package/src/followups/types.ts +6 -0
  235. package/src/hooks/templates.ts +1 -1
  236. package/src/index.ts +32 -1151
  237. package/src/media/gemini-image-service.ts +1 -1
  238. package/src/memory/attachments-store.ts +28 -83
  239. package/src/memory/channel-delivery-store.ts +7 -21
  240. package/src/memory/clarification-resolver.ts +6 -5
  241. package/src/memory/contradiction-checker.ts +3 -2
  242. package/src/memory/conversation-key-store.ts +10 -29
  243. package/src/memory/conversation-store.ts +2 -1
  244. package/src/memory/db.ts +362 -2
  245. package/src/memory/entity-extractor.ts +6 -3
  246. package/src/memory/items-extractor.ts +5 -4
  247. package/src/memory/jobs-store.ts +3 -2
  248. package/src/memory/llm-usage-store.ts +1 -2
  249. package/src/memory/runs-store.ts +1 -2
  250. package/src/memory/schema.ts +65 -2
  251. package/src/messaging/style-analyzer.ts +3 -2
  252. package/src/messaging/thread-summarizer.ts +8 -12
  253. package/src/messaging/triage-engine.ts +4 -2
  254. package/src/providers/openrouter/client.ts +20 -0
  255. package/src/providers/registry.ts +8 -0
  256. package/src/runtime/http-server.ts +277 -25
  257. package/src/runtime/http-types.ts +0 -2
  258. package/src/runtime/routes/attachment-routes.ts +5 -6
  259. package/src/runtime/routes/call-routes.ts +140 -0
  260. package/src/runtime/routes/channel-routes.ts +12 -19
  261. package/src/runtime/routes/conversation-routes.ts +5 -9
  262. package/src/runtime/routes/run-routes.ts +4 -8
  263. package/src/runtime/run-orchestrator.ts +39 -6
  264. package/src/schedule/recurrence-engine.ts +138 -0
  265. package/src/schedule/recurrence-types.ts +67 -0
  266. package/src/schedule/schedule-store.ts +102 -57
  267. package/src/schedule/scheduler.ts +9 -6
  268. package/src/security/oauth2.ts +29 -4
  269. package/src/security/secret-allowlist.ts +46 -0
  270. package/src/skills/clawhub.ts +1 -1
  271. package/src/subagent/manager.ts +40 -8
  272. package/src/swarm/backend-claude-code.ts +64 -9
  273. package/src/swarm/worker-prompts.ts +2 -1
  274. package/src/tasks/SPEC.md +34 -28
  275. package/src/tasks/ephemeral-permissions.ts +16 -7
  276. package/src/tasks/task-compiler.ts +5 -4
  277. package/src/tasks/task-runner.ts +10 -5
  278. package/src/tasks/task-scheduler.ts +1 -1
  279. package/src/tasks/tool-sanitizer.ts +36 -0
  280. package/src/tools/assets/search.ts +4 -4
  281. package/src/tools/browser/api-map.ts +220 -0
  282. package/src/tools/browser/auto-navigate.ts +270 -0
  283. package/src/tools/browser/browser-execution.ts +2 -1
  284. package/src/tools/browser/browser-manager.ts +2 -2
  285. package/src/tools/browser/network-recorder.ts +5 -4
  286. package/src/tools/browser/x-auto-navigate.ts +207 -0
  287. package/src/tools/calls/call-end.ts +67 -0
  288. package/src/tools/calls/call-start.ts +73 -0
  289. package/src/tools/calls/call-status.ts +81 -0
  290. package/src/tools/claude-code/claude-code.ts +77 -11
  291. package/src/tools/contacts/contact-merge.ts +46 -78
  292. package/src/tools/contacts/contact-search.ts +35 -79
  293. package/src/tools/contacts/contact-upsert.ts +35 -108
  294. package/src/tools/credentials/vault.ts +21 -5
  295. package/src/tools/document/document-tool.ts +71 -144
  296. package/src/tools/executor.ts +129 -10
  297. package/src/tools/followups/followup_create.ts +46 -88
  298. package/src/tools/followups/followup_list.ts +34 -74
  299. package/src/tools/followups/followup_resolve.ts +31 -66
  300. package/src/tools/host-terminal/cli-discover.ts +2 -1
  301. package/src/tools/host-terminal/host-shell.ts +10 -0
  302. package/src/tools/memory/handlers.ts +5 -4
  303. package/src/tools/network/__tests__/web-search.test.ts +427 -0
  304. package/src/tools/network/script-proxy/__tests__/logging.test.ts +248 -0
  305. package/src/tools/network/script-proxy/__tests__/policy.test.ts +234 -0
  306. package/src/tools/network/script-proxy/__tests__/router.test.ts +76 -0
  307. package/src/tools/network/web-fetch.ts +18 -6
  308. package/src/tools/playbooks/index.ts +4 -5
  309. package/src/tools/playbooks/playbook-create.ts +3 -47
  310. package/src/tools/playbooks/playbook-delete.ts +1 -25
  311. package/src/tools/playbooks/playbook-list.ts +1 -28
  312. package/src/tools/playbooks/playbook-update.ts +3 -51
  313. package/src/tools/registry.ts +2 -4
  314. package/src/tools/reminder/reminder.ts +5 -78
  315. package/src/tools/schedule/create.ts +69 -74
  316. package/src/tools/schedule/delete.ts +21 -47
  317. package/src/tools/schedule/list.ts +55 -74
  318. package/src/tools/schedule/update.ts +77 -84
  319. package/src/tools/subagent/abort.ts +29 -58
  320. package/src/tools/subagent/message.ts +30 -63
  321. package/src/tools/subagent/read.ts +53 -84
  322. package/src/tools/subagent/spawn.ts +43 -82
  323. package/src/tools/subagent/status.ts +42 -71
  324. package/src/tools/swarm/delegate.ts +2 -1
  325. package/src/tools/tasks/index.ts +8 -6
  326. package/src/tools/tasks/task-delete.ts +69 -56
  327. package/src/tools/tasks/task-list.ts +31 -52
  328. package/src/tools/tasks/task-run.ts +74 -102
  329. package/src/tools/tasks/task-save.ts +33 -65
  330. package/src/tools/tasks/work-item-enqueue.ts +192 -134
  331. package/src/tools/tasks/work-item-list.ts +33 -78
  332. package/src/tools/tasks/work-item-remove.ts +60 -0
  333. package/src/tools/tasks/work-item-update.ts +114 -0
  334. package/src/tools/terminal/backends/native.ts +3 -1
  335. package/src/tools/tool-manifest.ts +20 -74
  336. package/src/tools/types.ts +6 -0
  337. package/src/tools/ui-surface/definitions.ts +6 -1
  338. package/src/tools/watch/screen-watch.ts +3 -1
  339. package/src/tools/watcher/create.ts +52 -98
  340. package/src/tools/watcher/delete.ts +20 -46
  341. package/src/tools/watcher/digest.ts +36 -70
  342. package/src/tools/watcher/list.ts +49 -79
  343. package/src/tools/watcher/update.ts +45 -91
  344. package/src/twitter/client.ts +690 -0
  345. package/src/twitter/session.ts +91 -0
  346. package/src/usage/types.ts +0 -1
  347. package/src/util/truncate.ts +6 -0
  348. package/src/watcher/providers/slack.ts +2 -1
  349. package/src/watcher/watcher-store.ts +3 -2
  350. package/src/work-items/work-item-store.ts +236 -2
  351. package/src/workspace/commit-message-enrichment-service.ts +284 -0
  352. package/src/workspace/commit-message-provider.ts +95 -0
  353. package/src/workspace/git-service.ts +272 -52
  354. package/src/workspace/heartbeat-service.ts +70 -13
  355. package/src/workspace/provider-commit-message-generator.ts +242 -0
  356. package/src/workspace/turn-commit.ts +100 -51
  357. package/src/tools/contacts/index.ts +0 -4
  358. package/src/tools/document/index.ts +0 -5
  359. package/src/tools/followups/index.ts +0 -3
  360. package/src/tools/subagent/index.ts +0 -5
  361. /package/src/__tests__/{memory-context-benchmark.test.ts → memory-context-benchmark.benchmark.test.ts} +0 -0
@@ -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,54 +12,30 @@ 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 } 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.
32
21
 
33
- export const eagerModules: string[] = [
34
- './filesystem/read.js',
35
- './filesystem/write.js',
36
- './filesystem/edit.js',
37
- './network/web-search.js',
38
- './network/web-fetch.js',
39
- './skills/load.js',
40
- './skills/scaffold-managed.js',
41
- './skills/delete-managed.js',
42
- './system/request-permission.js',
43
- './schedule/create.js',
44
- './schedule/list.js',
45
- './schedule/update.js',
46
- './schedule/delete.js',
47
- './watcher/create.js',
48
- './watcher/list.js',
49
- './watcher/update.js',
50
- './watcher/delete.js',
51
- './watcher/digest.js',
52
- './playbooks/playbook-create.js',
53
- './playbooks/playbook-list.js',
54
- './playbooks/playbook-update.js',
55
- './playbooks/playbook-delete.js',
56
- './contacts/contact-upsert.js',
57
- './contacts/contact-search.js',
58
- './contacts/contact-merge.js',
59
- './assets/search.js',
60
- './assets/materialize.js',
61
- './filesystem/view-image.js',
62
- ];
22
+ export async function loadEagerModules(): Promise<void> {
23
+ await import('./filesystem/read.js');
24
+ await import('./filesystem/write.js');
25
+ await import('./filesystem/edit.js');
26
+ await import('./network/web-search.js');
27
+ await import('./network/web-fetch.js');
28
+ await import('./skills/load.js');
29
+ await import('./skills/scaffold-managed.js');
30
+ await import('./skills/delete-managed.js');
31
+ await import('./system/request-permission.js');
32
+ await import('./assets/search.js');
33
+ await import('./assets/materialize.js');
34
+ await import('./filesystem/view-image.js');
35
+ await import('./calls/call-start.js');
36
+ await import('./calls/call-status.js');
37
+ await import('./calls/call-end.js');
38
+ }
63
39
 
64
40
  // Tool names registered by the eager modules above. Listed explicitly so
65
41
  // initializeTools() can recognise ESM-cached eager-module tools that were
@@ -75,25 +51,12 @@ export const eagerModuleToolNames: string[] = [
75
51
  'scaffold_managed_skill',
76
52
  'delete_managed_skill',
77
53
  'request_system_permission',
78
- 'schedule_create',
79
- 'schedule_list',
80
- 'schedule_update',
81
- 'schedule_delete',
82
- 'watcher_create',
83
- 'watcher_list',
84
- 'watcher_update',
85
- 'watcher_delete',
86
- 'watcher_digest',
87
- 'playbook_create',
88
- 'playbook_list',
89
- 'playbook_update',
90
- 'playbook_delete',
91
- 'contact_upsert',
92
- 'contact_search',
93
- 'contact_merge',
94
54
  'asset_search',
95
55
  'asset_materialize',
96
56
  'view_image',
57
+ 'call_start',
58
+ 'call_status',
59
+ 'call_end',
97
60
  ];
98
61
 
99
62
  // ── Explicit tool instances ─────────────────────────────────────────
@@ -106,26 +69,9 @@ export const explicitTools: Tool[] = [
106
69
  memoryUpdateTool,
107
70
  credentialStoreTool,
108
71
  accountManageTool,
109
- reminderTool,
110
72
  screenWatchTool,
111
73
  vellumSkillsCatalogTool,
112
- documentCreateTool,
113
- documentUpdateTool,
114
74
  cliDiscoverTool,
115
- followupCreateTool,
116
- followupListTool,
117
- followupResolveTool,
118
- taskSaveTool,
119
- taskRunTool,
120
- taskListTool,
121
- taskDeleteTool,
122
- taskListShowTool,
123
- taskListAddTool,
124
- subagentSpawnTool,
125
- subagentStatusTool,
126
- subagentAbortTool,
127
- subagentMessageTool,
128
- subagentReadTool,
129
75
  ];
130
76
 
131
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. */
@@ -35,6 +35,9 @@ export const uiShowTool: Tool = {
35
35
  'templateData shape: { location: string, currentTemp: number, feelsLike: number, unit: "F"|"C", condition: string, humidity: number, windSpeed: number, windDirection: string, ' +
36
36
  'hourly: Array<{ time: string, icon: string (SF Symbol name), temp: number }>, ' +
37
37
  'forecast: Array<{ day: string, icon: string (SF Symbol name), low: number, high: number, precip: number|null, condition: string }> }\n' +
38
+ ' Template "task_progress": renders a live-updating task progress widget showing structured step-by-step progress. ' +
39
+ 'templateData shape: { title: string, status: "in_progress"|"completed"|"failed", ' +
40
+ 'steps: Array<{ label: string, status: "pending"|"in_progress"|"completed"|"failed", detail?: string }> }\n' +
38
41
  '- table: Data table with columns, selectable rows, and action buttons. ' +
39
42
  'data shape: { columns: Array<{ id: string, label: string }>, rows: Array<{ id: string, cells: Record<string, string>, selectable?: boolean, selected?: boolean }>, selectionMode?: "none"|"single"|"multiple", caption?: string }\n' +
40
43
  '- form: Input form with typed fields. ' +
@@ -117,7 +120,9 @@ export const uiShowTool: Tool = {
117
120
 
118
121
  export const uiUpdateTool: Tool = {
119
122
  name: 'ui_update',
120
- 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.',
121
126
  category: 'ui-surface',
122
127
  defaultRiskLevel: RiskLevel.Low,
123
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
 
@@ -1,110 +1,64 @@
1
- import { RiskLevel } from '../../permissions/types.js';
2
- import type { Tool, ToolContext, ToolExecutionResult } from '../types.js';
3
- import type { ToolDefinition } from '../../providers/types.js';
4
- import { registerTool } from '../registry.js';
1
+ import type { ToolContext, ToolExecutionResult } from '../types.js';
5
2
  import { createWatcher } from '../../watcher/watcher-store.js';
6
3
  import { getWatcherProvider, listWatcherProviders } from '../../watcher/provider-registry.js';
7
4
 
8
- class WatcherCreateTool implements Tool {
9
- name = 'watcher_create';
10
- description = 'Create a new watcher that polls an external service for events and processes them with an action prompt';
11
- category = 'watcher';
12
- defaultRiskLevel = RiskLevel.Medium;
5
+ export async function executeWatcherCreate(
6
+ input: Record<string, unknown>,
7
+ _context: ToolContext,
8
+ ): Promise<ToolExecutionResult> {
9
+ const name = input.name as string;
10
+ const providerId = input.provider as string;
11
+ const actionPrompt = input.action_prompt as string;
12
+ const pollIntervalMs = (input.poll_interval_ms as number) ?? undefined;
13
+ const config = input.config as Record<string, unknown> | undefined;
13
14
 
14
- getDefinition(): ToolDefinition {
15
- return {
16
- name: this.name,
17
- description: this.description,
18
- input_schema: {
19
- type: 'object',
20
- properties: {
21
- name: {
22
- type: 'string',
23
- description: 'A human-readable name for this watcher (e.g. "My Gmail")',
24
- },
25
- provider: {
26
- type: 'string',
27
- description: 'The provider to poll (e.g. "gmail")',
28
- },
29
- action_prompt: {
30
- type: 'string',
31
- description: 'Instructions for the LLM on how to handle detected events. This prompt is sent along with event data to a background conversation.',
32
- },
33
- poll_interval_ms: {
34
- type: 'number',
35
- description: 'How often to poll in milliseconds. Defaults to 60000 (1 minute). Minimum 15000.',
36
- },
37
- credential_service: {
38
- type: 'string',
39
- description: 'Override the credential service to use. Defaults to the provider\'s required service.',
40
- },
41
- config: {
42
- type: 'object',
43
- description: 'Provider-specific configuration (e.g. filter criteria)',
44
- },
45
- },
46
- required: ['name', 'provider', 'action_prompt'],
47
- },
48
- };
15
+ if (!name || typeof name !== 'string') {
16
+ return { content: 'Error: name is required and must be a string', isError: true };
17
+ }
18
+ if (!providerId || typeof providerId !== 'string') {
19
+ return { content: 'Error: provider is required and must be a string', isError: true };
20
+ }
21
+ if (!actionPrompt || typeof actionPrompt !== 'string') {
22
+ return { content: 'Error: action_prompt is required and must be a string', isError: true };
49
23
  }
50
24
 
51
- async execute(input: Record<string, unknown>, _context: ToolContext): Promise<ToolExecutionResult> {
52
- const name = input.name as string;
53
- const providerId = input.provider as string;
54
- const actionPrompt = input.action_prompt as string;
55
- const pollIntervalMs = (input.poll_interval_ms as number) ?? undefined;
56
- const config = input.config as Record<string, unknown> | undefined;
57
-
58
- if (!name || typeof name !== 'string') {
59
- return { content: 'Error: name is required and must be a string', isError: true };
60
- }
61
- if (!providerId || typeof providerId !== 'string') {
62
- return { content: 'Error: provider is required and must be a string', isError: true };
63
- }
64
- if (!actionPrompt || typeof actionPrompt !== 'string') {
65
- return { content: 'Error: action_prompt is required and must be a string', isError: true };
66
- }
67
-
68
- const provider = getWatcherProvider(providerId);
69
- if (!provider) {
70
- const available = listWatcherProviders().map((p) => p.id).join(', ') || 'none';
71
- return { content: `Error: Unknown provider "${providerId}". Available: ${available}`, isError: true };
72
- }
25
+ const provider = getWatcherProvider(providerId);
26
+ if (!provider) {
27
+ const available = listWatcherProviders().map((p) => p.id).join(', ') || 'none';
28
+ return { content: `Error: Unknown provider "${providerId}". Available: ${available}`, isError: true };
29
+ }
73
30
 
74
- if (pollIntervalMs !== undefined && pollIntervalMs < 15000) {
75
- return { content: 'Error: poll_interval_ms must be at least 15000 (15 seconds)', isError: true };
76
- }
31
+ if (pollIntervalMs !== undefined && pollIntervalMs < 15000) {
32
+ return { content: 'Error: poll_interval_ms must be at least 15000 (15 seconds)', isError: true };
33
+ }
77
34
 
78
- const credentialService = (input.credential_service as string) ?? provider.requiredCredentialService;
35
+ const credentialService = (input.credential_service as string) ?? provider.requiredCredentialService;
79
36
 
80
- try {
81
- const watcher = createWatcher({
82
- name,
83
- providerId,
84
- actionPrompt,
85
- credentialService,
86
- pollIntervalMs,
87
- configJson: config ? JSON.stringify(config) : null,
88
- });
37
+ try {
38
+ const watcher = createWatcher({
39
+ name,
40
+ providerId,
41
+ actionPrompt,
42
+ credentialService,
43
+ pollIntervalMs,
44
+ configJson: config ? JSON.stringify(config) : null,
45
+ });
89
46
 
90
- const intervalSec = Math.round(watcher.pollIntervalMs / 1000);
91
- return {
92
- content: [
93
- 'Watcher created successfully.',
94
- ` Name: ${watcher.name}`,
95
- ` Provider: ${provider.displayName}`,
96
- ` Poll interval: ${intervalSec}s`,
97
- ` Credential: ${watcher.credentialService}`,
98
- ` Status: ${watcher.status}`,
99
- ` ID: ${watcher.id}`,
100
- ].join('\n'),
101
- isError: false,
102
- };
103
- } catch (err) {
104
- const msg = err instanceof Error ? err.message : String(err);
105
- return { content: `Error creating watcher: ${msg}`, isError: true };
106
- }
47
+ const intervalSec = Math.round(watcher.pollIntervalMs / 1000);
48
+ return {
49
+ content: [
50
+ 'Watcher created successfully.',
51
+ ` Name: ${watcher.name}`,
52
+ ` Provider: ${provider.displayName}`,
53
+ ` Poll interval: ${intervalSec}s`,
54
+ ` Credential: ${watcher.credentialService}`,
55
+ ` Status: ${watcher.status}`,
56
+ ` ID: ${watcher.id}`,
57
+ ].join('\n'),
58
+ isError: false,
59
+ };
60
+ } catch (err) {
61
+ const msg = err instanceof Error ? err.message : String(err);
62
+ return { content: `Error creating watcher: ${msg}`, isError: true };
107
63
  }
108
64
  }
109
-
110
- registerTool(new WatcherCreateTool());
@@ -1,53 +1,27 @@
1
- import { RiskLevel } from '../../permissions/types.js';
2
- import type { Tool, ToolContext, ToolExecutionResult } from '../types.js';
3
- import type { ToolDefinition } from '../../providers/types.js';
4
- import { registerTool } from '../registry.js';
1
+ import type { ToolContext, ToolExecutionResult } from '../types.js';
5
2
  import { getWatcher, deleteWatcher } from '../../watcher/watcher-store.js';
6
3
 
7
- class WatcherDeleteTool implements Tool {
8
- name = 'watcher_delete';
9
- description = 'Delete a watcher and all its event history';
10
- category = 'watcher';
11
- defaultRiskLevel = RiskLevel.Medium;
12
-
13
- getDefinition(): ToolDefinition {
14
- return {
15
- name: this.name,
16
- description: this.description,
17
- input_schema: {
18
- type: 'object',
19
- properties: {
20
- watcher_id: {
21
- type: 'string',
22
- description: 'The ID of the watcher to delete',
23
- },
24
- },
25
- required: ['watcher_id'],
26
- },
27
- };
4
+ export async function executeWatcherDelete(
5
+ input: Record<string, unknown>,
6
+ _context: ToolContext,
7
+ ): Promise<ToolExecutionResult> {
8
+ const watcherId = input.watcher_id as string;
9
+ if (!watcherId || typeof watcherId !== 'string') {
10
+ return { content: 'Error: watcher_id is required', isError: true };
28
11
  }
29
12
 
30
- async execute(input: Record<string, unknown>, _context: ToolContext): Promise<ToolExecutionResult> {
31
- const watcherId = input.watcher_id as string;
32
- if (!watcherId || typeof watcherId !== 'string') {
33
- return { content: 'Error: watcher_id is required', isError: true };
34
- }
35
-
36
- const watcher = getWatcher(watcherId);
37
- if (!watcher) {
38
- return { content: `Error: Watcher not found: ${watcherId}`, isError: true };
39
- }
40
-
41
- const deleted = deleteWatcher(watcherId);
42
- if (!deleted) {
43
- return { content: `Error: Failed to delete watcher: ${watcherId}`, isError: true };
44
- }
13
+ const watcher = getWatcher(watcherId);
14
+ if (!watcher) {
15
+ return { content: `Error: Watcher not found: ${watcherId}`, isError: true };
16
+ }
45
17
 
46
- return {
47
- content: `Watcher deleted: "${watcher.name}"`,
48
- isError: false,
49
- };
18
+ const deleted = deleteWatcher(watcherId);
19
+ if (!deleted) {
20
+ return { content: `Error: Failed to delete watcher: ${watcherId}`, isError: true };
50
21
  }
51
- }
52
22
 
53
- registerTool(new WatcherDeleteTool());
23
+ return {
24
+ content: `Watcher deleted: "${watcher.name}"`,
25
+ isError: false,
26
+ };
27
+ }
@@ -1,84 +1,50 @@
1
- import { RiskLevel } from '../../permissions/types.js';
2
- import type { Tool, ToolContext, ToolExecutionResult } from '../types.js';
3
- import type { ToolDefinition } from '../../providers/types.js';
4
- import { registerTool } from '../registry.js';
1
+ import type { ToolContext, ToolExecutionResult } from '../types.js';
5
2
  import { listWatchers, listWatcherEvents } from '../../watcher/watcher-store.js';
6
3
 
7
- class WatcherDigestTool implements Tool {
8
- name = 'watcher_digest';
9
- description = 'Get a summary of recent watcher activity. Use this when the user asks about what happened with their email, notifications, etc.';
10
- category = 'watcher';
11
- defaultRiskLevel = RiskLevel.Low;
4
+ export async function executeWatcherDigest(
5
+ input: Record<string, unknown>,
6
+ _context: ToolContext,
7
+ ): Promise<ToolExecutionResult> {
8
+ const watcherId = input.watcher_id as string | undefined;
9
+ const hours = (input.hours as number) ?? 24;
10
+ const limit = (input.limit as number) ?? 50;
12
11
 
13
- getDefinition(): ToolDefinition {
14
- return {
15
- name: this.name,
16
- description: this.description,
17
- input_schema: {
18
- type: 'object',
19
- properties: {
20
- watcher_id: {
21
- type: 'string',
22
- description: 'Filter to events from a specific watcher. If omitted, shows events from all watchers.',
23
- },
24
- hours: {
25
- type: 'number',
26
- description: 'How many hours back to look. Defaults to 24.',
27
- },
28
- limit: {
29
- type: 'number',
30
- description: 'Maximum number of events to return. Defaults to 50.',
31
- },
32
- },
33
- required: [],
34
- },
35
- };
36
- }
37
-
38
- async execute(input: Record<string, unknown>, _context: ToolContext): Promise<ToolExecutionResult> {
39
- const watcherId = input.watcher_id as string | undefined;
40
- const hours = (input.hours as number) ?? 24;
41
- const limit = (input.limit as number) ?? 50;
42
-
43
- const since = Date.now() - hours * 60 * 60 * 1000;
12
+ const since = Date.now() - hours * 60 * 60 * 1000;
44
13
 
45
- const events = listWatcherEvents({ watcherId, limit, since });
14
+ const events = listWatcherEvents({ watcherId, limit, since });
46
15
 
47
- if (events.length === 0) {
48
- const period = hours === 24 ? 'today' : `the last ${hours} hours`;
49
- return { content: `No watcher events detected ${period}.`, isError: false };
50
- }
16
+ if (events.length === 0) {
17
+ const period = hours === 24 ? 'today' : `the last ${hours} hours`;
18
+ return { content: `No watcher events detected ${period}.`, isError: false };
19
+ }
51
20
 
52
- // Group events by watcher
53
- const watcherMap = new Map<string, typeof events>();
54
- for (const event of events) {
55
- const existing = watcherMap.get(event.watcherId) ?? [];
56
- existing.push(event);
57
- watcherMap.set(event.watcherId, existing);
58
- }
21
+ // Group events by watcher
22
+ const watcherMap = new Map<string, typeof events>();
23
+ for (const event of events) {
24
+ const existing = watcherMap.get(event.watcherId) ?? [];
25
+ existing.push(event);
26
+ watcherMap.set(event.watcherId, existing);
27
+ }
59
28
 
60
- // Get watcher names
61
- const allWatchers = listWatchers();
62
- const nameMap = new Map(allWatchers.map((w) => [w.id, w.name]));
29
+ // Get watcher names
30
+ const allWatchers = listWatchers();
31
+ const nameMap = new Map(allWatchers.map((w) => [w.id, w.name]));
63
32
 
64
- const lines = [`Watcher activity (last ${hours}h, ${events.length} events):`];
33
+ const lines = [`Watcher activity (last ${hours}h, ${events.length} events):`];
65
34
 
66
- for (const [wId, wEvents] of watcherMap) {
67
- const name = nameMap.get(wId) ?? wId;
68
- lines.push('', `${name} (${wEvents.length} events):`);
35
+ for (const [wId, wEvents] of watcherMap) {
36
+ const name = nameMap.get(wId) ?? wId;
37
+ lines.push('', `${name} (${wEvents.length} events):`);
69
38
 
70
- for (const event of wEvents) {
71
- const time = new Date(event.createdAt).toLocaleString();
72
- const disposition = event.disposition !== 'pending' ? ` [${event.disposition}]` : '';
73
- lines.push(` - ${event.summary}${disposition} (${time})`);
74
- if (event.llmAction) {
75
- lines.push(` Action: ${event.llmAction}`);
76
- }
39
+ for (const event of wEvents) {
40
+ const time = new Date(event.createdAt).toLocaleString();
41
+ const disposition = event.disposition !== 'pending' ? ` [${event.disposition}]` : '';
42
+ lines.push(` - ${event.summary}${disposition} (${time})`);
43
+ if (event.llmAction) {
44
+ lines.push(` Action: ${event.llmAction}`);
77
45
  }
78
46
  }
79
-
80
- return { content: lines.join('\n'), isError: false };
81
47
  }
82
- }
83
48
 
84
- registerTool(new WatcherDigestTool());
49
+ return { content: lines.join('\n'), isError: false };
50
+ }