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,5 +1,5 @@
1
1
  import { describe, test, expect, beforeEach, afterEach, mock } from 'bun:test';
2
- import { mkdirSync, rmSync, existsSync } from 'node:fs';
2
+ import { mkdirSync, rmSync, existsSync, readFileSync } from 'node:fs';
3
3
  import { join } from 'node:path';
4
4
  import { tmpdir } from 'node:os';
5
5
 
@@ -51,13 +51,24 @@ mock.module('../config/loader.js', () => ({
51
51
 
52
52
  // ── Import after mocks ───────────────────────────────────────────────
53
53
  const { buildSystemPrompt } = await import('../config/system-prompt.js');
54
- const { taskListAddTool } = await import('../tools/tasks/work-item-enqueue.js');
55
- const { reminderTool } = await import('../tools/reminder/reminder.js');
56
54
 
57
- // schedule_create is registered via side-effect import; import the module
58
- // to access the tool description through the registry.
59
- await import('../tools/schedule/create.js');
60
- const { getTool } = await import('../tools/registry.js');
55
+ // Load task_list_add description from the bundled skill TOOLS.json
56
+ const tasksToolsJson = JSON.parse(
57
+ readFileSync(join(import.meta.dirname, '../config/bundled-skills/tasks/TOOLS.json'), 'utf-8'),
58
+ );
59
+ const taskListAddDef = tasksToolsJson.tools.find((t: { name: string }) => t.name === 'task_list_add');
60
+
61
+ // Load reminder_create description from the bundled skill TOOLS.json
62
+ const reminderToolsJson = JSON.parse(
63
+ readFileSync(join(import.meta.dirname, '../config/bundled-skills/reminder/TOOLS.json'), 'utf-8'),
64
+ );
65
+ const reminderCreateDef = reminderToolsJson.tools.find((t: { name: string }) => t.name === 'reminder_create');
66
+
67
+ // Load schedule_create description from the bundled skill TOOLS.json
68
+ const scheduleToolsJson = JSON.parse(
69
+ readFileSync(join(import.meta.dirname, '../config/bundled-skills/schedule/TOOLS.json'), 'utf-8'),
70
+ );
71
+ const scheduleCreateDef = scheduleToolsJson.tools.find((t: { name: string }) => t.name === 'schedule_create');
61
72
 
62
73
  // =====================================================================
63
74
  // 1. System prompt: buildTaskScheduleReminderRoutingSection
@@ -81,9 +92,9 @@ describe('Task/Schedule/Reminder routing section in system prompt', () => {
81
92
 
82
93
  test('routing section explains all three subsystems', () => {
83
94
  const prompt = buildSystemPrompt();
84
- expect(prompt).toContain('### Task Queue (task_list_add / task_list_show)');
95
+ expect(prompt).toContain('### Task Queue (task_list_add / task_list_show / task_list_update / task_list_remove)');
85
96
  expect(prompt).toContain('### Schedules (schedule_create / schedule_list / schedule_update / schedule_delete)');
86
- expect(prompt).toContain('### Reminders (reminder)');
97
+ expect(prompt).toContain('### Reminders (reminder_create / reminder_list / reminder_cancel)');
87
98
  });
88
99
 
89
100
  test('routing section contains key routing phrases for task queue', () => {
@@ -103,10 +114,30 @@ describe('Task/Schedule/Reminder routing section in system prompt', () => {
103
114
  test('routing section clarifies schedules are for recurring automation only', () => {
104
115
  const prompt = buildSystemPrompt();
105
116
  expect(prompt).toContain('recurring automated jobs');
106
- expect(prompt).toContain('cron schedule');
117
+ expect(prompt).toContain('recurrence schedule (cron or RRULE)');
107
118
  expect(prompt).toContain('ONLY when the user explicitly wants');
108
119
  });
109
120
 
121
+ test('routing section documents supported RRULE set constructs', () => {
122
+ const prompt = buildSystemPrompt();
123
+ expect(prompt).toContain('#### RRULE Set Constructs');
124
+ expect(prompt).toContain('**RDATE**');
125
+ expect(prompt).toContain('**EXDATE**');
126
+ expect(prompt).toContain('**EXRULE**');
127
+ expect(prompt).toContain('multiple RRULE lines form a union');
128
+ });
129
+
130
+ test('routing section documents bounded recurrence patterns', () => {
131
+ const prompt = buildSystemPrompt();
132
+ expect(prompt).toContain('Bounded recurrence');
133
+ expect(prompt).toContain('COUNT or UNTIL');
134
+ });
135
+
136
+ test('routing section states exclusion precedence', () => {
137
+ const prompt = buildSystemPrompt();
138
+ expect(prompt).toContain('Exclusions (EXDATE, EXRULE) take precedence over inclusions (RRULE, RDATE)');
139
+ });
140
+
110
141
  test('routing section clarifies reminders are for time-triggered notifications', () => {
111
142
  const prompt = buildSystemPrompt();
112
143
  expect(prompt).toContain('one-time time-triggered notifications');
@@ -117,7 +148,7 @@ describe('Task/Schedule/Reminder routing section in system prompt', () => {
117
148
  const prompt = buildSystemPrompt();
118
149
  expect(prompt).toContain('### Common mistakes to avoid');
119
150
  // The key mis-routing guard: "add this to my tasks" should go to task_list_add
120
- expect(prompt).toContain('"Add this to my tasks" → task_list_add (NOT schedule_create or reminder)');
151
+ expect(prompt).toContain('"Add this to my tasks" → task_list_add (NOT schedule_create or reminder_create)');
121
152
  });
122
153
 
123
154
  test('routing section distinguishes timed vs untimed "remind me"', () => {
@@ -125,7 +156,7 @@ describe('Task/Schedule/Reminder routing section in system prompt', () => {
125
156
  // Without a time → task queue
126
157
  expect(prompt).toContain('"Remind me to buy groceries" without a time → task_list_add');
127
158
  // With a time → reminder
128
- expect(prompt).toContain('"Remind me at 5pm to buy groceries" → reminder');
159
+ expect(prompt).toContain('"Remind me at 5pm to buy groceries" → reminder_create');
129
160
  });
130
161
 
131
162
  test('routing section appears after tool routing by content type', () => {
@@ -144,85 +175,70 @@ describe('Task/Schedule/Reminder routing section in system prompt', () => {
144
175
 
145
176
  describe('task_list_add tool description', () => {
146
177
  test('mentions "add to my tasks" routing phrase', () => {
147
- const def = taskListAddTool.getDefinition();
178
+ const def = taskListAddDef;
148
179
  expect(def.description).toContain('add to my tasks');
149
180
  });
150
181
 
151
182
  test('mentions "add to my queue" routing phrase', () => {
152
- const def = taskListAddTool.getDefinition();
183
+ const def = taskListAddDef;
153
184
  expect(def.description).toContain('add to my queue');
154
185
  });
155
186
 
156
187
  test('mentions "put this on my task list" routing phrase', () => {
157
- const def = taskListAddTool.getDefinition();
188
+ const def = taskListAddDef;
158
189
  expect(def.description).toContain('put this on my task list');
159
190
  });
160
191
 
161
192
  test('mentions ad-hoc title-only mode', () => {
162
- const def = taskListAddTool.getDefinition();
193
+ const def = taskListAddDef;
163
194
  expect(def.description).toContain('just a title');
164
195
  });
165
196
 
166
197
  test('explicitly warns NOT to use schedule_create or reminder for task requests', () => {
167
- const def = taskListAddTool.getDefinition();
198
+ const def = taskListAddDef;
168
199
  expect(def.description).toContain('Do NOT use schedule_create or reminder');
169
200
  });
170
201
  });
171
202
 
172
203
  describe('schedule_create tool description', () => {
173
204
  test('mentions recurring scheduled automation', () => {
174
- const tool = getTool('schedule_create');
175
- expect(tool).toBeDefined();
176
- const def = tool!.getDefinition();
177
- expect(def.description).toContain('recurring');
205
+ expect(scheduleCreateDef).toBeDefined();
206
+ expect(scheduleCreateDef.description).toContain('recurring');
178
207
  });
179
208
 
180
209
  test('mentions cron interval', () => {
181
- const tool = getTool('schedule_create');
182
- const def = tool!.getDefinition();
183
- expect(def.description).toContain('cron');
210
+ expect(scheduleCreateDef.description).toContain('cron');
184
211
  });
185
212
 
186
213
  test('warns against using for "add to my tasks" requests', () => {
187
- const tool = getTool('schedule_create');
188
- const def = tool!.getDefinition();
189
- expect(def.description).toContain('Do NOT use this for "add to my tasks"');
214
+ expect(scheduleCreateDef.description).toContain('Do NOT use this for "add to my tasks"');
190
215
  });
191
216
 
192
217
  test('redirects to task_list_add for task queue items', () => {
193
- const tool = getTool('schedule_create');
194
- const def = tool!.getDefinition();
195
- expect(def.description).toContain('task_list_add');
218
+ expect(scheduleCreateDef.description).toContain('task_list_add');
196
219
  });
197
220
 
198
221
  test('does NOT suggest it handles task queue items', () => {
199
- const tool = getTool('schedule_create');
200
- const def = tool!.getDefinition();
201
- // Should not claim to handle one-off task items
202
- expect(def.description).not.toContain('task queue');
203
- expect(def.description).not.toContain('one-off');
222
+ expect(scheduleCreateDef.description).not.toContain('task queue');
223
+ expect(scheduleCreateDef.description).not.toContain('one-off');
204
224
  });
205
225
  });
206
226
 
207
227
  describe('reminder tool description', () => {
208
228
  test('mentions time-based reminders', () => {
209
- const def = reminderTool.getDefinition();
210
- expect(def.description).toContain('time-based reminders');
229
+ expect(reminderCreateDef.description).toContain('time-based reminder');
211
230
  });
212
231
 
213
232
  test('scopes to time-triggered notifications only', () => {
214
- const def = reminderTool.getDefinition();
215
- expect(def.description).toContain('ONLY when the user wants a time-triggered notification');
233
+ expect(reminderCreateDef.description).toContain('ONLY when the user wants a time-triggered notification');
216
234
  });
217
235
 
218
236
  test('warns against using for "add to my tasks" requests', () => {
219
- const def = reminderTool.getDefinition();
220
- expect(def.description).toContain('Do NOT use this for "add to my tasks"');
237
+ expect(reminderCreateDef.description).toContain('Do NOT use this for "add to my tasks"');
221
238
  });
222
239
 
223
240
  test('redirects to task_list_add for task queue items', () => {
224
- const def = reminderTool.getDefinition();
225
- expect(def.description).toContain('task_list_add');
241
+ expect(reminderCreateDef.description).toContain('task_list_add');
226
242
  });
227
243
  });
228
244
 
@@ -232,24 +248,15 @@ describe('reminder tool description', () => {
232
248
 
233
249
  describe('cross-tool routing consistency', () => {
234
250
  test('all three tools reference task_list_add as the task-queue tool', () => {
235
- const enqueueDef = taskListAddTool.getDefinition();
236
- const scheduleTool = getTool('schedule_create')!;
237
- const scheduleDef = scheduleTool.getDefinition();
238
- const reminderDef = reminderTool.getDefinition();
239
-
240
251
  // task_list_add is the canonical name in all three descriptions
241
- expect(enqueueDef.name).toBe('task_list_add');
242
- expect(scheduleDef.description).toContain('task_list_add');
243
- expect(reminderDef.description).toContain('task_list_add');
252
+ expect(taskListAddDef.name).toBe('task_list_add');
253
+ expect(scheduleCreateDef.description).toContain('task_list_add');
254
+ expect(reminderCreateDef.description).toContain('task_list_add');
244
255
  });
245
256
 
246
257
  test('schedule_create and reminder both reject "add to my queue" usage', () => {
247
- const scheduleTool = getTool('schedule_create')!;
248
- const scheduleDef = scheduleTool.getDefinition();
249
- const reminderDef = reminderTool.getDefinition();
250
-
251
258
  // Both should redirect away from task-queue requests
252
- expect(scheduleDef.description).toContain('add to my queue');
253
- expect(reminderDef.description).toContain('add to my queue');
259
+ expect(scheduleCreateDef.description).toContain('add to my queue');
260
+ expect(reminderCreateDef.description).toContain('add to my queue');
254
261
  });
255
262
  });
@@ -0,0 +1,237 @@
1
+ /**
2
+ * IPC Serialization/Parsing Benchmark
3
+ *
4
+ * Measures serialize + parse round-trip performance in isolation
5
+ * (no daemon required). Target ranges:
6
+ * - Small message p95: < 1ms (averaged over 1000 runs)
7
+ * - Large message (1MB): < 50ms
8
+ * - Rapid-fire: no message loss across 100 messages
9
+ * - Round-trip: content preserved exactly
10
+ */
11
+ import { afterAll, beforeAll, describe, expect, mock, test } from 'bun:test';
12
+ import * as net from 'node:net';
13
+ import * as os from 'node:os';
14
+ import * as path from 'node:path';
15
+ import * as fs from 'node:fs';
16
+
17
+ mock.module('../util/logger.js', () => ({
18
+ getLogger: () =>
19
+ new Proxy({} as Record<string, unknown>, {
20
+ get: () => () => {},
21
+ }),
22
+ }));
23
+
24
+ import { serialize, createMessageParser } from '../daemon/ipc-protocol.js';
25
+ import type { ClientMessage, ServerMessage } from '../daemon/ipc-contract.js';
26
+
27
+ function percentile(values: number[], p: number): number {
28
+ const sorted = [...values].sort((a, b) => a - b);
29
+ const idx = Math.ceil((p / 100) * sorted.length) - 1;
30
+ return sorted[Math.max(0, idx)];
31
+ }
32
+
33
+ describe('IPC round-trip benchmark', () => {
34
+ test('small message serialize + parse p95 < 1ms over 1000 runs', () => {
35
+ const msg: ClientMessage = { type: 'ping' };
36
+ const parser = createMessageParser();
37
+ const timings: number[] = [];
38
+
39
+ for (let i = 0; i < 1000; i++) {
40
+ const start = performance.now();
41
+ const serialized = serialize(msg);
42
+ const parsed = parser.feed(serialized);
43
+ const elapsed = performance.now() - start;
44
+ timings.push(elapsed);
45
+
46
+ // Sanity: each iteration should yield exactly one message
47
+ expect(parsed).toHaveLength(1);
48
+ }
49
+
50
+ const p95 = percentile(timings, 95);
51
+ expect(p95).toBeLessThan(1);
52
+ });
53
+
54
+ test('large message (1MB) serialize + parse < 50ms', () => {
55
+ // Build a ~1MB payload using assistant_text_delta with a large text field
56
+ const largeText = 'x'.repeat(1024 * 1024);
57
+ const msg: ServerMessage = { type: 'assistant_text_delta', text: largeText };
58
+ const parser = createMessageParser();
59
+ const timings: number[] = [];
60
+
61
+ for (let i = 0; i < 10; i++) {
62
+ const start = performance.now();
63
+ const serialized = serialize(msg);
64
+ const parsed = parser.feed(serialized);
65
+ const elapsed = performance.now() - start;
66
+ timings.push(elapsed);
67
+
68
+ expect(parsed).toHaveLength(1);
69
+ }
70
+
71
+ const p95 = percentile(timings, 95);
72
+ expect(p95).toBeLessThan(50);
73
+ });
74
+
75
+ test('no message loss under rapid-fire (100 messages)', () => {
76
+ const parser = createMessageParser();
77
+ const messages: ClientMessage[] = [];
78
+
79
+ for (let i = 0; i < 100; i++) {
80
+ messages.push({ type: 'session_list' } as ClientMessage);
81
+ }
82
+
83
+ // Serialize all messages and concatenate into a single buffer
84
+ const combined = messages.map((m) => serialize(m)).join('');
85
+
86
+ // Feed the entire buffer at once
87
+ const parsed = parser.feed(combined);
88
+
89
+ expect(parsed).toHaveLength(100);
90
+ for (const p of parsed) {
91
+ expect(p).toHaveProperty('type', 'session_list');
92
+ }
93
+ });
94
+
95
+ test('serialize + parse round-trip preserves message content', () => {
96
+ const parser = createMessageParser();
97
+
98
+ const clientMsg: ClientMessage = {
99
+ type: 'user_message',
100
+ sessionId: 'sess-abc-123',
101
+ content: 'Hello, world! Special chars: \u00e9\u00e0\u00fc \ud83d\ude00 "quotes" & <angle>',
102
+ attachments: [
103
+ {
104
+ filename: 'test.txt',
105
+ mimeType: 'text/plain',
106
+ data: 'SGVsbG8gV29ybGQ=',
107
+ },
108
+ ],
109
+ };
110
+
111
+ const serialized = serialize(clientMsg);
112
+ const parsed = parser.feed(serialized);
113
+
114
+ expect(parsed).toHaveLength(1);
115
+ const roundTripped = parsed[0] as ClientMessage;
116
+ expect(roundTripped).toEqual(clientMsg);
117
+
118
+ // Verify specific fields survived the round-trip
119
+ expect(roundTripped.type).toBe('user_message');
120
+ if (roundTripped.type === 'user_message') {
121
+ expect(roundTripped.sessionId).toBe('sess-abc-123');
122
+ expect(roundTripped.content).toContain('\ud83d\ude00');
123
+ expect(roundTripped.attachments).toHaveLength(1);
124
+ expect(roundTripped.attachments![0].filename).toBe('test.txt');
125
+ }
126
+ });
127
+ });
128
+
129
+ describe('IPC Unix socket round-trip benchmark', () => {
130
+ let server: net.Server;
131
+ let client: net.Socket;
132
+ let tmpDir: string;
133
+ let socketPath: string;
134
+
135
+ beforeAll(async () => {
136
+ tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'ipc-bench-'));
137
+ socketPath = path.join(tmpDir, 'bench.sock');
138
+
139
+ // Server: parse incoming messages, echo back a session_list_response for each
140
+ server = net.createServer((socket) => {
141
+ const parser = createMessageParser();
142
+ socket.on('data', (data) => {
143
+ const msgs = parser.feed(data.toString());
144
+ for (const _msg of msgs) {
145
+ const response: ServerMessage = {
146
+ type: 'session_list_response',
147
+ sessions: [],
148
+ };
149
+ socket.write(serialize(response));
150
+ }
151
+ });
152
+ });
153
+
154
+ await new Promise<void>((resolve) => server.listen(socketPath, resolve));
155
+
156
+ client = net.createConnection(socketPath);
157
+ await new Promise<void>((resolve) => client.on('connect', resolve));
158
+ });
159
+
160
+ afterAll(async () => {
161
+ client?.destroy();
162
+ await new Promise<void>((resolve) => server?.close(() => resolve()));
163
+ try { fs.unlinkSync(socketPath); } catch { /* server.close() may already remove it */ }
164
+ try { fs.rmdirSync(tmpDir); } catch { /* best-effort */ }
165
+ });
166
+
167
+ test('session_list round-trip p50 < 5ms, p99 < 50ms', async () => {
168
+ const clientParser = createMessageParser();
169
+ const timings: number[] = [];
170
+ const iterations = 50;
171
+
172
+ for (let i = 0; i < iterations; i++) {
173
+ const start = performance.now();
174
+
175
+ const responsePromise = new Promise<ServerMessage>((resolve) => {
176
+ const handler = (data: Buffer) => {
177
+ const msgs = clientParser.feed(data.toString());
178
+ if (msgs.length > 0) {
179
+ client.removeListener('data', handler);
180
+ resolve(msgs[0] as ServerMessage);
181
+ }
182
+ };
183
+ client.on('data', handler);
184
+ });
185
+
186
+ const request: ClientMessage = { type: 'session_list' };
187
+ client.write(serialize(request));
188
+
189
+ const response = await responsePromise;
190
+ const elapsed = performance.now() - start;
191
+ timings.push(elapsed);
192
+
193
+ expect(response.type).toBe('session_list_response');
194
+ }
195
+
196
+ const p50 = percentile(timings, 50);
197
+ const p99 = percentile(timings, 99);
198
+ expect(p50).toBeLessThan(5);
199
+ expect(p99).toBeLessThan(50);
200
+ });
201
+
202
+ test('rapid-fire: 100 messages over socket without loss', async () => {
203
+ const clientParser = createMessageParser();
204
+ const messageCount = 100;
205
+ const received: ServerMessage[] = [];
206
+
207
+ const allReceived = new Promise<void>((resolve) => {
208
+ const handler = (data: Buffer) => {
209
+ const msgs = clientParser.feed(data.toString());
210
+ for (const msg of msgs) {
211
+ received.push(msg as ServerMessage);
212
+ }
213
+ if (received.length >= messageCount) {
214
+ client.removeListener('data', handler);
215
+ resolve();
216
+ }
217
+ };
218
+ client.on('data', handler);
219
+ });
220
+
221
+ const start = performance.now();
222
+ for (let i = 0; i < messageCount; i++) {
223
+ const request: ClientMessage = { type: 'session_list' };
224
+ client.write(serialize(request));
225
+ }
226
+
227
+ await allReceived;
228
+ const elapsed = performance.now() - start;
229
+
230
+ expect(received).toHaveLength(messageCount);
231
+ for (const msg of received) {
232
+ expect(msg.type).toBe('session_list_response');
233
+ }
234
+ // All 100 messages should complete well within 100ms on a local socket
235
+ expect(elapsed).toBeLessThan(100);
236
+ });
237
+ });
@@ -343,6 +343,16 @@ const clientMessages: Record<ClientMessageType, ClientMessage> = {
343
343
  type: 'vercel_api_config',
344
344
  action: 'get',
345
345
  },
346
+ twitter_integration_config: {
347
+ type: 'twitter_integration_config',
348
+ action: 'get',
349
+ },
350
+ twitter_auth_start: {
351
+ type: 'twitter_auth_start',
352
+ },
353
+ twitter_auth_status: {
354
+ type: 'twitter_auth_status',
355
+ },
346
356
  link_open_request: {
347
357
  type: 'link_open_request',
348
358
  url: 'https://example.com',
@@ -423,14 +433,6 @@ const clientMessages: Record<ClientMessageType, ClientMessage> = {
423
433
  type: 'work_item_get',
424
434
  id: 'wi-001',
425
435
  },
426
- work_item_create: {
427
- type: 'work_item_create',
428
- taskId: 'task-001',
429
- title: 'Process report',
430
- notes: 'High priority',
431
- priorityTier: 1,
432
- sortIndex: 0,
433
- },
434
436
  work_item_update: {
435
437
  type: 'work_item_update',
436
438
  id: 'wi-001',
@@ -453,6 +455,19 @@ const clientMessages: Record<ClientMessageType, ClientMessage> = {
453
455
  type: 'work_item_output',
454
456
  id: 'wi-001',
455
457
  },
458
+ work_item_preflight: {
459
+ type: 'work_item_preflight',
460
+ id: 'wi-001',
461
+ },
462
+ work_item_approve_permissions: {
463
+ type: 'work_item_approve_permissions',
464
+ id: 'wi-001',
465
+ approvedTools: ['bash', 'file_write'],
466
+ },
467
+ work_item_cancel: {
468
+ type: 'work_item_cancel',
469
+ id: 'wi-001',
470
+ },
456
471
  document_save: {
457
472
  type: 'document_save',
458
473
  surfaceId: 'doc-001',
@@ -476,7 +491,6 @@ const clientMessages: Record<ClientMessageType, ClientMessage> = {
476
491
  subagent_status: {
477
492
  type: 'subagent_status',
478
493
  subagentId: 'sub-001',
479
- sessionId: 'sess-001',
480
494
  },
481
495
  subagent_message: {
482
496
  type: 'subagent_message',
@@ -907,6 +921,8 @@ const serverMessages: Record<ServerMessageType, ServerMessage> = {
907
921
  id: 'sched-001',
908
922
  name: 'Daily standup reminder',
909
923
  enabled: true,
924
+ syntax: 'cron',
925
+ expression: '0 9 * * 1-5',
910
926
  cronExpression: '0 9 * * 1-5',
911
927
  timezone: 'America/Los_Angeles',
912
928
  message: 'Remind me about the standup',
@@ -1114,6 +1130,25 @@ const serverMessages: Record<ServerMessageType, ServerMessage> = {
1114
1130
  hasToken: true,
1115
1131
  success: true,
1116
1132
  },
1133
+ twitter_integration_config_response: {
1134
+ type: 'twitter_integration_config_response',
1135
+ success: true,
1136
+ mode: 'local_byo',
1137
+ managedAvailable: false,
1138
+ localClientConfigured: true,
1139
+ connected: false,
1140
+ },
1141
+ twitter_auth_result: {
1142
+ type: 'twitter_auth_result',
1143
+ success: true,
1144
+ accountInfo: '@vellum_test',
1145
+ },
1146
+ twitter_auth_status_response: {
1147
+ type: 'twitter_auth_status_response',
1148
+ connected: true,
1149
+ accountInfo: '@vellum_test',
1150
+ mode: 'local_byo',
1151
+ },
1117
1152
  open_url: {
1118
1153
  type: 'open_url',
1119
1154
  url: 'https://example.com',
@@ -1283,25 +1318,6 @@ const serverMessages: Record<ServerMessageType, ServerMessage> = {
1283
1318
  updatedAt: 1700000000,
1284
1319
  },
1285
1320
  },
1286
- work_item_create_response: {
1287
- type: 'work_item_create_response',
1288
- item: {
1289
- id: 'wi-001',
1290
- taskId: 'task-001',
1291
- title: 'Process report',
1292
- notes: null,
1293
- status: 'queued',
1294
- priorityTier: 1,
1295
- sortIndex: null,
1296
- lastRunId: null,
1297
- lastRunConversationId: null,
1298
- lastRunStatus: null,
1299
- sourceType: null,
1300
- sourceId: null,
1301
- createdAt: 1700000000,
1302
- updatedAt: 1700000000,
1303
- },
1304
- },
1305
1321
  work_item_update_response: {
1306
1322
  type: 'work_item_update_response',
1307
1323
  item: {
@@ -1346,6 +1362,24 @@ const serverMessages: Record<ServerMessageType, ServerMessage> = {
1346
1362
  highlights: ['- Key finding 1', '- Key finding 2'],
1347
1363
  },
1348
1364
  },
1365
+ work_item_preflight_response: {
1366
+ type: 'work_item_preflight_response',
1367
+ id: 'wi-001',
1368
+ success: true,
1369
+ permissions: [
1370
+ { tool: 'bash', description: 'Run shell commands', riskLevel: 'medium', currentDecision: 'prompt' },
1371
+ ],
1372
+ },
1373
+ work_item_approve_permissions_response: {
1374
+ type: 'work_item_approve_permissions_response',
1375
+ id: 'wi-001',
1376
+ success: true,
1377
+ },
1378
+ work_item_cancel_response: {
1379
+ type: 'work_item_cancel_response',
1380
+ id: 'wi-001',
1381
+ success: true,
1382
+ },
1349
1383
  work_item_status_changed: {
1350
1384
  type: 'work_item_status_changed',
1351
1385
  item: {
@@ -23,7 +23,7 @@ mock.module('../util/logger.js', () => ({
23
23
  }),
24
24
  }));
25
25
 
26
- import { initializeDb, getDb } from '../memory/db.js';
26
+ import { initializeDb, getDb, resetDb } from '../memory/db.js';
27
27
  import { recordUsageEvent, listUsageEvents } from '../memory/llm-usage-store.js';
28
28
  import type { UsageEventInput, PricingResult } from '../usage/types.js';
29
29
 
@@ -31,6 +31,7 @@ import type { UsageEventInput, PricingResult } from '../usage/types.js';
31
31
  initializeDb();
32
32
 
33
33
  afterAll(() => {
34
+ resetDb();
34
35
  try { rmSync(testDir, { recursive: true }); } catch { /* best effort */ }
35
36
  });
36
37
 
@@ -43,7 +44,6 @@ function makeInput(overrides?: Partial<UsageEventInput>): UsageEventInput {
43
44
  cacheCreationInputTokens: null,
44
45
  cacheReadInputTokens: null,
45
46
  actor: 'main_agent',
46
- assistantId: null,
47
47
  conversationId: null,
48
48
  runId: null,
49
49
  requestId: null,
@@ -86,7 +86,7 @@ describe('recordUsageEvent', () => {
86
86
  });
87
87
 
88
88
  test('persists a priced event that can be retrieved', () => {
89
- const input = makeInput({ assistantId: 'a1', conversationId: 'c1' });
89
+ const input = makeInput({ conversationId: 'c1' });
90
90
  const event = recordUsageEvent(input, pricedResult);
91
91
 
92
92
  const events = listUsageEvents();
@@ -94,7 +94,6 @@ describe('recordUsageEvent', () => {
94
94
  expect(events[0].id).toBe(event.id);
95
95
  expect(events[0].estimatedCostUsd).toBe(0.0045);
96
96
  expect(events[0].pricingStatus).toBe('priced');
97
- expect(events[0].assistantId).toBe('a1');
98
97
  expect(events[0].conversationId).toBe('c1');
99
98
  });
100
99
 
@@ -113,7 +112,6 @@ describe('recordUsageEvent', () => {
113
112
 
114
113
  test('handles null optional fields', () => {
115
114
  const input = makeInput({
116
- assistantId: null,
117
115
  conversationId: null,
118
116
  runId: null,
119
117
  requestId: null,
@@ -124,7 +122,6 @@ describe('recordUsageEvent', () => {
124
122
 
125
123
  const events = listUsageEvents();
126
124
  expect(events).toHaveLength(1);
127
- expect(events[0].assistantId).toBeNull();
128
125
  expect(events[0].conversationId).toBeNull();
129
126
  expect(events[0].runId).toBeNull();
130
127
  expect(events[0].requestId).toBeNull();
@@ -134,7 +131,6 @@ describe('recordUsageEvent', () => {
134
131
 
135
132
  test('handles populated optional fields', () => {
136
133
  const input = makeInput({
137
- assistantId: 'assistant-1',
138
134
  conversationId: 'conv-1',
139
135
  runId: 'run-1',
140
136
  requestId: 'req-1',
@@ -145,7 +141,6 @@ describe('recordUsageEvent', () => {
145
141
 
146
142
  const events = listUsageEvents();
147
143
  expect(events).toHaveLength(1);
148
- expect(events[0].assistantId).toBe('assistant-1');
149
144
  expect(events[0].conversationId).toBe('conv-1');
150
145
  expect(events[0].runId).toBe('run-1');
151
146
  expect(events[0].requestId).toBe('req-1');