@vellumai/assistant 0.8.4 → 0.8.5

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 (438) hide show
  1. package/ARCHITECTURE.md +2 -2
  2. package/docs/browser-use-architecture-phase2.md +1 -1
  3. package/knip.json +2 -1
  4. package/openapi.yaml +809 -11
  5. package/package.json +1 -1
  6. package/src/__tests__/anthropic-provider.test.ts +34 -37
  7. package/src/__tests__/assistant-event-hub-self-exclusion.test.ts +293 -0
  8. package/src/__tests__/assistant-feature-flags-integration.test.ts +3 -3
  9. package/src/__tests__/audit-log-rotation.test.ts +70 -16
  10. package/src/__tests__/background-workers-disk-pressure.test.ts +3 -3
  11. package/src/__tests__/btw-routes.test.ts +2 -3
  12. package/src/__tests__/call-controller.test.ts +0 -1
  13. package/src/__tests__/cancel-resolves-conversation-key.test.ts +1 -1
  14. package/src/__tests__/channel-guardian.test.ts +3 -3
  15. package/src/__tests__/checker.test.ts +6 -15
  16. package/src/__tests__/compaction-events.test.ts +1 -0
  17. package/src/__tests__/compactor-call-site-logging.test.ts +214 -0
  18. package/src/__tests__/computer-use-skill-manifest-regression.test.ts +5 -11
  19. package/src/__tests__/computer-use-tools.test.ts +2 -4
  20. package/src/__tests__/confirmation-request-guardian-bridge.test.ts +0 -1
  21. package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +1 -1
  22. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +1 -1
  23. package/src/__tests__/conversation-agent-loop-overflow.test.ts +197 -2
  24. package/src/__tests__/conversation-agent-loop.test.ts +163 -122
  25. package/src/__tests__/conversation-app-control-instantiation.test.ts +2 -5
  26. package/src/__tests__/conversation-clear-safety.test.ts +25 -25
  27. package/src/__tests__/conversation-delete-schedule-cleanup.test.ts +1 -1
  28. package/src/__tests__/conversation-disk-view-integration.test.ts +2 -2
  29. package/src/__tests__/conversation-error.test.ts +31 -0
  30. package/src/__tests__/conversation-fork-crud.test.ts +178 -15
  31. package/src/__tests__/conversation-lifecycle.test.ts +52 -11
  32. package/src/__tests__/{conversation-load-cleaned-at.test.ts → conversation-load-history-stripped.test.ts} +13 -13
  33. package/src/__tests__/conversation-provider-retry-repair.test.ts +1 -0
  34. package/src/__tests__/conversation-routes-disk-view.test.ts +109 -0
  35. package/src/__tests__/conversation-routes-slash-commands.test.ts +35 -0
  36. package/src/__tests__/conversation-skill-tools.test.ts +2 -5
  37. package/src/__tests__/conversation-store.test.ts +1 -1
  38. package/src/__tests__/conversation-sync-tags.test.ts +99 -32
  39. package/src/__tests__/conversation-workspace-cache-state.test.ts +1 -0
  40. package/src/__tests__/conversation-workspace-injection.test.ts +1 -1
  41. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +1 -1
  42. package/src/__tests__/credential-execution-feature-gates.test.ts +9 -7
  43. package/src/__tests__/credential-execution-tools.test.ts +6 -6
  44. package/src/__tests__/credential-security-invariants.test.ts +1 -0
  45. package/src/__tests__/credential-vault-unit.test.ts +2 -2
  46. package/src/__tests__/dynamic-page-surface.test.ts +2 -2
  47. package/src/__tests__/email-html-renderer.test.ts +12 -0
  48. package/src/__tests__/gateway-flag-listener.test.ts +237 -0
  49. package/src/__tests__/gemini-provider.test.ts +78 -0
  50. package/src/__tests__/guardian-dispatch.test.ts +0 -1
  51. package/src/__tests__/guardian-outbound-http.test.ts +7 -5
  52. package/src/__tests__/handlers-user-message-approval-consumption.test.ts +1 -1
  53. package/src/__tests__/heartbeat-disk-pressure.test.ts +4 -0
  54. package/src/__tests__/heartbeat-service.test.ts +4 -0
  55. package/src/__tests__/host-shell-tool.test.ts +1 -1
  56. package/src/__tests__/init-feature-flag-overrides.test.ts +5 -6
  57. package/src/__tests__/list-messages-tool-merge.test.ts +70 -11
  58. package/src/__tests__/llm-request-log-call-site.test.ts +136 -0
  59. package/src/__tests__/llm-request-log-source-clickhouse.test.ts +26 -0
  60. package/src/__tests__/llm-resolver.test.ts +77 -9
  61. package/src/__tests__/llm-usage-store.test.ts +66 -0
  62. package/src/__tests__/logger.test.ts +89 -0
  63. package/src/__tests__/mcp-abort-signal.test.ts +2 -2
  64. package/src/__tests__/media-generate-image.test.ts +31 -0
  65. package/src/__tests__/memory-v2-static-injector.test.ts +7 -7
  66. package/src/__tests__/model-intents.test.ts +2 -4
  67. package/src/__tests__/notification-guardian-path.test.ts +0 -1
  68. package/src/__tests__/onboarding-template-contract.test.ts +1 -1
  69. package/src/__tests__/openai-provider.test.ts +46 -0
  70. package/src/__tests__/openai-responses-provider.test.ts +114 -12
  71. package/src/__tests__/pending-interactions-resolved-event.test.ts +0 -1
  72. package/src/__tests__/platform-bash-auto-approve.test.ts +2 -2
  73. package/src/__tests__/platform.test.ts +2 -2
  74. package/src/__tests__/plugin-api-tool-definition.test.ts +92 -0
  75. package/src/__tests__/plugin-bootstrap.test.ts +2 -2
  76. package/src/__tests__/plugin-tool-contribution.test.ts +13 -6
  77. package/src/__tests__/plugin-types.test.ts +3 -2
  78. package/src/__tests__/prechat-onboarding-contract.test.ts +131 -98
  79. package/src/__tests__/pricing.test.ts +12 -0
  80. package/src/__tests__/prune-jobs-changes-parser.test.ts +61 -0
  81. package/src/__tests__/registry.test.ts +2 -8
  82. package/src/__tests__/require-fresh-approval.test.ts +2 -2
  83. package/src/__tests__/runtime-events-sse-bilingual.test.ts +154 -0
  84. package/src/__tests__/shell-tool-proxy-mode.test.ts +1 -1
  85. package/src/__tests__/skill-feature-flags.test.ts +2 -2
  86. package/src/__tests__/skill-projection-feature-flag.test.ts +4 -7
  87. package/src/__tests__/skill-projection.benchmark.test.ts +2 -6
  88. package/src/__tests__/skill-tool-factory.test.ts +1 -1
  89. package/src/__tests__/subagent-notify-parent.test.ts +1 -1
  90. package/src/__tests__/suggestion-routes.test.ts +1 -0
  91. package/src/__tests__/sync-message-contract.test.ts +59 -0
  92. package/src/__tests__/system-prompt.test.ts +145 -131
  93. package/src/__tests__/terminal-tools.test.ts +1 -1
  94. package/src/__tests__/tool-approval-handler.test.ts +1 -5
  95. package/src/__tests__/tool-execute-pipeline.test.ts +2 -2
  96. package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +2 -5
  97. package/src/__tests__/tool-executor-lifecycle-events.test.ts +15 -5
  98. package/src/__tests__/tool-executor.test.ts +9 -62
  99. package/src/__tests__/tool-grant-request-escalation.test.ts +1 -6
  100. package/src/__tests__/trusted-contact-approval-notifier.test.ts +0 -1
  101. package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +1 -6
  102. package/src/__tests__/trusted-contact-multichannel.test.ts +0 -1
  103. package/src/__tests__/ui-file-upload-surface.test.ts +2 -2
  104. package/src/__tests__/usage-routes.test.ts +3 -0
  105. package/src/__tests__/verification-control-plane-policy.test.ts +2 -2
  106. package/src/__tests__/workspace-git-service.test.ts +6 -5
  107. package/src/__tests__/workspace-migration-089-move-memory-tree-out-of-v3.test.ts +86 -0
  108. package/src/acp/__tests__/prepare-agent-env.test.ts +146 -0
  109. package/src/acp/prepare-agent-env.ts +78 -0
  110. package/src/acp/session-manager.ts +1 -1
  111. package/src/agent/loop.ts +8 -0
  112. package/src/api/README.md +5 -0
  113. package/src/api/index.ts +4 -0
  114. package/src/api/package.json +10 -0
  115. package/src/background-wake/background-wake-routes.test.ts +233 -0
  116. package/src/background-wake/runtime-registry.ts +24 -0
  117. package/src/cli/commands/__tests__/browser.test.ts +23 -5
  118. package/src/cli/commands/__tests__/domain-register.test.ts +110 -0
  119. package/src/cli/commands/__tests__/domain-status.test.ts +33 -33
  120. package/src/cli/commands/__tests__/inference-send.test.ts +108 -5
  121. package/src/cli/commands/__tests__/memory-v2-compare-render.test.ts +98 -0
  122. package/src/cli/commands/__tests__/memory-v2.test.ts +1 -0
  123. package/src/cli/commands/__tests__/memory-v3-render.test.ts +340 -0
  124. package/src/cli/commands/browser.ts +247 -0
  125. package/src/cli/commands/domain.ts +91 -41
  126. package/src/cli/commands/inference.ts +93 -40
  127. package/src/cli/commands/memory-v2-compare-render.ts +115 -0
  128. package/src/cli/commands/memory-v2.ts +176 -1
  129. package/src/cli/commands/memory-v3-render.ts +344 -0
  130. package/src/cli/commands/memory-v3.ts +316 -0
  131. package/src/cli/program.ts +2 -0
  132. package/src/config/assistant-feature-flags.ts +21 -9
  133. package/src/config/bundled-skills/document-editor/SKILL.md +11 -2
  134. package/src/config/bundled-skills/document-editor/TOOLS.json +18 -0
  135. package/src/config/bundled-skills/document-editor/tools/document-open.ts +12 -0
  136. package/src/config/bundled-skills/image-studio/SKILL.md +4 -0
  137. package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +2 -2
  138. package/src/config/bundled-skills/media-processing/tools/ingest-media.ts +13 -8
  139. package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +10 -3
  140. package/src/config/bundled-skills/phone-calls/references/TRANSCRIPTS.md +16 -14
  141. package/src/config/bundled-skills/playbooks/tools/playbook-create.ts +7 -2
  142. package/src/config/bundled-skills/playbooks/tools/playbook-update.ts +7 -2
  143. package/src/config/bundled-tool-registry.ts +2 -0
  144. package/src/config/call-site-defaults.ts +7 -6
  145. package/src/config/feature-flag-registry.json +16 -0
  146. package/src/config/schemas/__tests__/memory-v2.test.ts +213 -1
  147. package/src/config/schemas/call-site-catalog.ts +21 -7
  148. package/src/config/schemas/llm.ts +12 -1
  149. package/src/config/schemas/memory-v2.ts +246 -0
  150. package/src/config/schemas/memory.ts +2 -1
  151. package/src/context/compactor.ts +52 -0
  152. package/src/conversations/__tests__/message-consolidation.test.ts +350 -0
  153. package/src/conversations/message-consolidation.ts +404 -0
  154. package/src/daemon/__tests__/conversation-tool-setup-exclude.test.ts +1 -1
  155. package/src/daemon/__tests__/meet-manifest-loader.test.ts +1 -1
  156. package/src/daemon/conversation-agent-loop-handlers.ts +2 -13
  157. package/src/daemon/conversation-agent-loop.ts +126 -76
  158. package/src/daemon/conversation-error.ts +31 -1
  159. package/src/daemon/conversation-lifecycle.ts +27 -22
  160. package/src/daemon/conversation-runtime-assembly.ts +10 -9
  161. package/src/daemon/conversation-tool-setup.ts +63 -3
  162. package/src/daemon/conversation-usage.ts +2 -0
  163. package/src/daemon/conversation.ts +14 -29
  164. package/src/daemon/disk-pressure-guard.ts +14 -2
  165. package/src/daemon/handlers/config-model.test.ts +1 -0
  166. package/src/daemon/handlers/conversations.ts +11 -3
  167. package/src/daemon/host-browser-proxy.ts +5 -5
  168. package/src/daemon/host-cu-proxy.ts +4 -4
  169. package/src/daemon/host-file-proxy.ts +4 -4
  170. package/src/daemon/host-proxy-base.ts +4 -4
  171. package/src/daemon/host-transfer-proxy.ts +10 -10
  172. package/src/daemon/lifecycle.ts +23 -20
  173. package/src/daemon/meet-manifest-loader.ts +1 -7
  174. package/src/daemon/message-types/conversations.ts +6 -9
  175. package/src/daemon/message-types/home.ts +1 -13
  176. package/src/daemon/message-types/messages.ts +6 -14
  177. package/src/daemon/message-types/sync.ts +14 -0
  178. package/src/daemon/shutdown-handlers.ts +24 -5
  179. package/src/daemon/switch-inference-profile-tool.ts +52 -0
  180. package/src/daemon/tool-setup-types.ts +13 -0
  181. package/src/events/relationship-state-updated.ts +25 -0
  182. package/src/heartbeat/__tests__/heartbeat-service.test.ts +1 -1
  183. package/src/home/home-greeting.ts +0 -9
  184. package/src/home/suggested-prompts.ts +0 -9
  185. package/src/ipc/gateway-flag-listener.ts +123 -0
  186. package/src/ipc/skill-routes/registries.ts +8 -12
  187. package/src/memory/__tests__/db-async-query.test.ts +165 -0
  188. package/src/memory/__tests__/db-maintenance.test.ts +115 -0
  189. package/src/memory/__tests__/jobs-store-enqueue-gate.test.ts +241 -0
  190. package/src/memory/__tests__/jobs-store-job-classes.test.ts +28 -1
  191. package/src/memory/__tests__/memory-retrospective-job.test.ts +7 -0
  192. package/src/memory/auto-analysis-enqueue.ts +5 -1
  193. package/src/memory/conversation-crud.ts +71 -70
  194. package/src/memory/conversation-starters-cadence.ts +3 -1
  195. package/src/memory/conversation-title-service.ts +19 -3
  196. package/src/memory/db-async-query.ts +214 -0
  197. package/src/memory/db-init.ts +10 -0
  198. package/src/memory/db-maintenance.ts +30 -21
  199. package/src/memory/graph/bootstrap.ts +8 -1
  200. package/src/memory/graph/capability-seed.ts +7 -3
  201. package/src/memory/graph/conversation-graph-memory.ts +100 -17
  202. package/src/memory/graph/extraction.ts +1 -5
  203. package/src/memory/graph/graph-search.ts +7 -1
  204. package/src/memory/indexer.ts +28 -18
  205. package/src/memory/job-handlers/cleanup.ts +76 -18
  206. package/src/memory/job-handlers/conversation-starters.ts +1 -4
  207. package/src/memory/jobs/embed-pkb-file.ts +6 -1
  208. package/src/memory/jobs-store.ts +14 -0
  209. package/src/memory/jobs-worker.ts +55 -22
  210. package/src/memory/llm-request-log-source-clickhouse.ts +42 -2
  211. package/src/memory/llm-request-log-source-local.ts +7 -0
  212. package/src/memory/llm-request-log-source.ts +9 -2
  213. package/src/memory/llm-request-log-store.ts +43 -1
  214. package/src/memory/llm-usage-store.ts +24 -0
  215. package/src/memory/memory-retrospective-enqueue.ts +8 -1
  216. package/src/memory/memory-retrospective-job.ts +5 -0
  217. package/src/memory/memory-v2-activation-log-store.ts +15 -6
  218. package/src/memory/migrations/260-rename-cleaned-at.ts +44 -0
  219. package/src/memory/migrations/261-llm-usage-add-raw-usage.ts +36 -0
  220. package/src/memory/migrations/262-memory-v3-coactivation.ts +57 -0
  221. package/src/memory/migrations/263-memory-v3-auto-edges.ts +50 -0
  222. package/src/memory/migrations/264-llm-request-log-call-site.ts +29 -0
  223. package/src/memory/migrations/index.ts +17 -0
  224. package/src/memory/migrations/registry.ts +33 -0
  225. package/src/memory/schema/conversations.ts +1 -1
  226. package/src/memory/schema/infrastructure.ts +21 -0
  227. package/src/memory/tool-usage-store.ts +36 -8
  228. package/src/memory/v2/__tests__/consolidation-job.test.ts +1 -0
  229. package/src/memory/v2/__tests__/harness-compare.test.ts +186 -0
  230. package/src/memory/v2/__tests__/harness-metrics.test.ts +74 -0
  231. package/src/memory/v2/__tests__/harness-oracle.test.ts +257 -0
  232. package/src/memory/v2/__tests__/harness-replay-input.test.ts +225 -0
  233. package/src/memory/v2/__tests__/harness-runner.test.ts +109 -0
  234. package/src/memory/v2/__tests__/injection.test.ts +127 -98
  235. package/src/memory/v2/__tests__/qdrant.test.ts +36 -0
  236. package/src/memory/v2/__tests__/router.test.ts +171 -3
  237. package/src/memory/v2/harness/compare.ts +57 -0
  238. package/src/memory/v2/harness/metrics.ts +124 -0
  239. package/src/memory/v2/harness/oracle.ts +145 -0
  240. package/src/memory/v2/harness/replay-input.ts +224 -0
  241. package/src/memory/v2/harness/retriever.ts +74 -0
  242. package/src/memory/v2/harness/router-retriever.ts +43 -0
  243. package/src/memory/v2/harness/runner.ts +106 -0
  244. package/src/memory/v2/harness/trace.ts +58 -0
  245. package/src/memory/v2/injection.ts +21 -15
  246. package/src/memory/v2/prompts/router.ts +26 -1
  247. package/src/memory/v2/qdrant.ts +14 -2
  248. package/src/memory/v2/router.ts +171 -18
  249. package/src/memory/v3/__tests__/coactivation-store.test.ts +422 -0
  250. package/src/memory/v3/__tests__/consolidation-job.test.ts +468 -0
  251. package/src/memory/v3/__tests__/edge-learning-job.test.ts +324 -0
  252. package/src/memory/v3/__tests__/edges.test.ts +563 -0
  253. package/src/memory/v3/__tests__/filter.test.ts +512 -0
  254. package/src/memory/v3/__tests__/gate.test.ts +574 -0
  255. package/src/memory/v3/__tests__/index-composition.test.ts +233 -0
  256. package/src/memory/v3/__tests__/loop.test.ts +530 -0
  257. package/src/memory/v3/__tests__/retriever.test.ts +226 -0
  258. package/src/memory/v3/__tests__/scouts.test.ts +440 -0
  259. package/src/memory/v3/__tests__/shadow-middleware.test.ts +312 -0
  260. package/src/memory/v3/__tests__/system-prompts.test.ts +154 -0
  261. package/src/memory/v3/__tests__/traversal.test.ts +469 -0
  262. package/src/memory/v3/__tests__/tree-index.test.ts +280 -0
  263. package/src/memory/v3/__tests__/tree-store.test.ts +529 -0
  264. package/src/memory/v3/__tests__/tree-walk.test.ts +707 -0
  265. package/src/memory/v3/__tests__/validate.test.ts +245 -0
  266. package/src/memory/v3/auto-edges.ts +223 -0
  267. package/src/memory/v3/coactivation-store.ts +124 -0
  268. package/src/memory/v3/consolidation-job.ts +323 -0
  269. package/src/memory/v3/edge-learning-job.ts +160 -0
  270. package/src/memory/v3/edges.ts +249 -0
  271. package/src/memory/v3/filter.ts +281 -0
  272. package/src/memory/v3/gate.ts +334 -0
  273. package/src/memory/v3/index-composition.ts +113 -0
  274. package/src/memory/v3/llm-capture.ts +46 -0
  275. package/src/memory/v3/loop.ts +382 -0
  276. package/src/memory/v3/maintenance.ts +144 -0
  277. package/src/memory/v3/prompt-context.ts +33 -0
  278. package/src/memory/v3/prompts/consolidation.ts +458 -0
  279. package/src/memory/v3/prompts/system-prompts.ts +196 -0
  280. package/src/memory/v3/retriever.ts +33 -0
  281. package/src/memory/v3/scouts.ts +420 -0
  282. package/src/memory/v3/shadow-middleware.ts +305 -0
  283. package/src/memory/v3/traversal.ts +206 -0
  284. package/src/memory/v3/tree-index.ts +237 -0
  285. package/src/memory/v3/tree-store.ts +394 -0
  286. package/src/memory/v3/tree-walk.ts +351 -0
  287. package/src/memory/v3/types.ts +65 -0
  288. package/src/memory/v3/validate.ts +300 -0
  289. package/src/notifications/adapters/macos.ts +18 -1
  290. package/src/notifications/adapters/platform.ts +1 -1
  291. package/src/notifications/decision-engine.ts +1 -4
  292. package/src/notifications/emit-signal.ts +29 -49
  293. package/src/permissions/prompter.ts +3 -3
  294. package/src/permissions/question-prompter.ts +5 -2
  295. package/src/permissions/secret-prompter.ts +2 -2
  296. package/src/plugin-api/index.ts +4 -0
  297. package/src/plugin-api/types.ts +7 -33
  298. package/src/plugins/defaults/index.ts +6 -0
  299. package/src/plugins/defaults/injectors.ts +18 -11
  300. package/src/plugins/external-plugin-loader.ts +5 -68
  301. package/src/plugins/types.ts +11 -16
  302. package/src/proactive-artifact/aux-message-injector.ts +17 -4
  303. package/src/prompts/__tests__/task-progress-hint-section.test.ts +3 -9
  304. package/src/prompts/persona-resolver.ts +36 -21
  305. package/src/prompts/sections.ts +39 -7
  306. package/src/prompts/system-prompt.ts +50 -185
  307. package/src/prompts/templates/BOOTSTRAP.md +2 -2
  308. package/src/prompts/templates/system-sections.ts +230 -8
  309. package/src/providers/__tests__/connection-model-compat.test.ts +234 -0
  310. package/src/providers/__tests__/retry-callsite.test.ts +85 -5
  311. package/src/providers/anthropic/client.ts +32 -66
  312. package/src/providers/call-site-routing.ts +14 -2
  313. package/src/providers/connection-model-compat.ts +38 -0
  314. package/src/providers/connection-resolution.ts +16 -2
  315. package/src/providers/gemini/client.ts +49 -6
  316. package/src/providers/inference/adapter-factory.ts +3 -0
  317. package/src/providers/minimax/client.ts +106 -0
  318. package/src/providers/model-catalog.ts +43 -0
  319. package/src/providers/model-intents.ts +1 -1
  320. package/src/providers/openai/chat-completions-provider.ts +6 -3
  321. package/src/providers/openai/codex-models.ts +18 -0
  322. package/src/providers/openai/responses-provider.ts +78 -21
  323. package/src/providers/provider-send-message.ts +7 -1
  324. package/src/providers/retry.ts +34 -3
  325. package/src/providers/thinking-config.ts +26 -1
  326. package/src/providers/usage-tracking.ts +2 -0
  327. package/src/runtime/AGENTS.md +2 -2
  328. package/src/runtime/agent-wake.ts +1 -0
  329. package/src/runtime/assistant-event-hub.ts +76 -6
  330. package/src/runtime/auth/route-policy.ts +36 -0
  331. package/src/runtime/btw-sidechain.ts +0 -6
  332. package/src/runtime/http-types.ts +0 -2
  333. package/src/runtime/migrations/vbundle-builder.ts +10 -3
  334. package/src/runtime/pending-interactions.ts +0 -1
  335. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +106 -0
  336. package/src/runtime/routes/__tests__/memory-v2-simulate-route.test.ts +25 -6
  337. package/src/runtime/routes/__tests__/plugins-routes.test.ts +512 -0
  338. package/src/runtime/routes/acp-routes.test.ts +255 -6
  339. package/src/runtime/routes/acp-routes.ts +8 -1
  340. package/src/runtime/routes/avatar-routes.ts +10 -10
  341. package/src/runtime/routes/background-wake-routes.ts +188 -0
  342. package/src/runtime/routes/browser-tabs-routes.ts +200 -0
  343. package/src/runtime/routes/btw-routes.ts +0 -6
  344. package/src/runtime/routes/conversation-cli-routes.ts +1 -1
  345. package/src/runtime/routes/conversation-list-routes.ts +12 -4
  346. package/src/runtime/routes/conversation-management-routes.ts +77 -20
  347. package/src/runtime/routes/conversation-query-routes.ts +142 -36
  348. package/src/runtime/routes/conversation-routes.ts +252 -410
  349. package/src/runtime/routes/conversation-starter-routes.ts +6 -3
  350. package/src/runtime/routes/disk-pressure-routes.ts +1 -1
  351. package/src/runtime/routes/domain-routes.ts +60 -10
  352. package/src/runtime/routes/email-routes.ts +5 -2
  353. package/src/runtime/routes/events-routes.ts +54 -10
  354. package/src/runtime/routes/group-routes.ts +24 -8
  355. package/src/runtime/routes/host-browser-routes.ts +10 -2
  356. package/src/runtime/routes/host-cu-routes.ts +2 -2
  357. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +96 -3
  358. package/src/runtime/routes/index.ts +8 -0
  359. package/src/runtime/routes/inference-profile-session-handler.ts +22 -12
  360. package/src/runtime/routes/inference-profile-session-routes.ts +7 -1
  361. package/src/runtime/routes/llm-call-sites-routes.ts +32 -5
  362. package/src/runtime/routes/memory-item-routes.ts +8 -3
  363. package/src/runtime/routes/memory-v2-routes.ts +215 -5
  364. package/src/runtime/routes/memory-v3-routes.ts +316 -0
  365. package/src/runtime/routes/migration-routes.ts +21 -24
  366. package/src/runtime/routes/plugins-routes.ts +337 -0
  367. package/src/runtime/routes/rename-conversation-routes.ts +6 -2
  368. package/src/runtime/routes/secret-routes.ts +25 -5
  369. package/src/runtime/routes/settings-routes.ts +12 -11
  370. package/src/runtime/routes/slack-channel-routes.ts +5 -4
  371. package/src/runtime/routes/workspace-routes.ts +25 -10
  372. package/src/runtime/sync/resource-sync-events.ts +106 -38
  373. package/src/runtime/sync/sync-publisher.test.ts +49 -0
  374. package/src/runtime/sync/sync-publisher.ts +2 -1
  375. package/src/runtime/verification-outbound-actions.ts +73 -1
  376. package/src/telemetry/types.ts +12 -0
  377. package/src/telemetry/usage-telemetry-reporter.test.ts +48 -0
  378. package/src/telemetry/usage-telemetry-reporter.ts +1 -0
  379. package/src/tools/acp/spawn.test.ts +119 -0
  380. package/src/tools/acp/spawn.ts +15 -2
  381. package/src/tools/apps/definitions.ts +2 -8
  382. package/src/tools/ask-question/ask-question-tool.test.ts +3 -3
  383. package/src/tools/ask-question/ask-question-tool.ts +38 -45
  384. package/src/tools/browser/__tests__/pinned-tabs.test.ts +70 -0
  385. package/src/tools/browser/browser-execution.ts +16 -3
  386. package/src/tools/browser/cdp-client/__tests__/browser-tabs-factory.test.ts +402 -0
  387. package/src/tools/browser/cdp-client/__tests__/types.test.ts +3 -0
  388. package/src/tools/browser/cdp-client/cdp-inspect-client.ts +12 -0
  389. package/src/tools/browser/cdp-client/extension-cdp-client.ts +27 -1
  390. package/src/tools/browser/cdp-client/factory.ts +100 -17
  391. package/src/tools/browser/cdp-client/local-cdp-client.ts +12 -0
  392. package/src/tools/browser/cdp-client/types.ts +65 -0
  393. package/src/tools/browser/pinned-tabs.ts +96 -40
  394. package/src/tools/computer-use/definitions.ts +22 -78
  395. package/src/tools/credential-execution/make-authenticated-request.ts +3 -9
  396. package/src/tools/credential-execution/manage-secure-command-tool.ts +3 -9
  397. package/src/tools/credential-execution/run-authenticated-command.ts +3 -9
  398. package/src/tools/credentials/vault.ts +3 -9
  399. package/src/tools/document/document-tool.ts +59 -0
  400. package/src/tools/execution-target.ts +21 -23
  401. package/src/tools/executor.ts +6 -1
  402. package/src/tools/filesystem/edit.ts +3 -9
  403. package/src/tools/filesystem/list.ts +3 -9
  404. package/src/tools/filesystem/read.ts +3 -9
  405. package/src/tools/filesystem/write.ts +3 -9
  406. package/src/tools/host-filesystem/edit.ts +3 -9
  407. package/src/tools/host-filesystem/read.ts +3 -9
  408. package/src/tools/host-filesystem/transfer.ts +3 -9
  409. package/src/tools/host-filesystem/write.ts +3 -9
  410. package/src/tools/host-terminal/host-shell.ts +3 -9
  411. package/src/tools/mcp/mcp-tool-factory.ts +1 -8
  412. package/src/tools/memory/register.test.ts +1 -1
  413. package/src/tools/memory/register.ts +4 -9
  414. package/src/tools/network/web-fetch.ts +3 -9
  415. package/src/tools/network/web-search.ts +25 -32
  416. package/src/tools/registry.ts +7 -23
  417. package/src/tools/schema-transforms.ts +1 -1
  418. package/src/tools/skills/execute.ts +3 -9
  419. package/src/tools/skills/load.ts +3 -9
  420. package/src/tools/skills/skill-tool-factory.ts +1 -8
  421. package/src/tools/subagent/notify-parent.ts +3 -9
  422. package/src/tools/system/request-permission.ts +3 -9
  423. package/src/tools/terminal/shell.ts +3 -9
  424. package/src/tools/tool-defaults.ts +94 -0
  425. package/src/tools/types.ts +27 -98
  426. package/src/tools/ui-surface/definitions.ts +6 -22
  427. package/src/usage/pricing.ts +23 -0
  428. package/src/usage/types.ts +12 -0
  429. package/src/util/logger.ts +16 -7
  430. package/src/util/platform.ts +7 -2
  431. package/src/util/sqlite3-runtime.ts +65 -0
  432. package/src/workspace/migrations/086-revert-stale-gemini-mis-rewrites.ts +1 -0
  433. package/src/workspace/migrations/089-move-memory-tree-out-of-v3.ts +86 -0
  434. package/src/workspace/migrations/registry.ts +2 -0
  435. package/src/__tests__/compaction-strip-metadata-clear.test.ts +0 -206
  436. package/src/__tests__/message-complete-display-id.test.ts +0 -175
  437. package/src/daemon/query-complexity-router.ts +0 -75
  438. package/src/prompts/cache-boundary.ts +0 -8
package/src/agent/loop.ts CHANGED
@@ -103,6 +103,14 @@ export type AgentLoopExitReason =
103
103
  | "checkpoint_handoff"
104
104
  /** Context-window recovery exhausted and the turn ended with an error. */
105
105
  | "context_too_large"
106
+ /**
107
+ * Auto-compress rerun (post-emergency-compaction, post-tier reducer)
108
+ * still yielded at the mid-loop budget checkpoint — the turn silently
109
+ * terminated with no further recovery layer to re-enter. Pure
110
+ * observability signal so the silent stall is attributable instead of
111
+ * leaving `agent_loop_exit_reason` NULL.
112
+ */
113
+ | "budget_yield_unrecovered"
106
114
  /** User cancellation landed after a non-terminal checkpoint yield. */
107
115
  | "aborted_after_checkpoint"
108
116
  /** Signal aborted while the catch handler was synthesizing an error turn. */
@@ -0,0 +1,5 @@
1
+ # @vellumai/assistant-api
2
+
3
+ Public API surface for consumers of the assistant API (web client, gateway,
4
+ evals, future external clients). This directory is the **source of truth** for
5
+ the wire contracts the assistant exposes: schemas, types, and pure helpers.
@@ -0,0 +1,4 @@
1
+ export {
2
+ type RelationshipStateUpdated,
3
+ RelationshipStateUpdatedSchema,
4
+ } from "../events/relationship-state-updated.js";
@@ -0,0 +1,10 @@
1
+ {
2
+ "name": "@vellumai/assistant-api",
3
+ "version": "0.0.0-source",
4
+ "description": "Public API surface for consumers of the assistant API (web client, gateway, evals, etc.).",
5
+ "type": "module",
6
+ "private": true,
7
+ "exports": {
8
+ ".": "./index.ts"
9
+ }
10
+ }
@@ -0,0 +1,233 @@
1
+ import { afterEach, beforeEach, describe, expect, mock, test } from "bun:test";
2
+
3
+ import type { BackgroundWakeIntent } from "./next-wake.js";
4
+ import {
5
+ clearBackgroundWakeRuntime,
6
+ registerBackgroundWakeRuntime,
7
+ } from "./runtime-registry.js";
8
+
9
+ type MockIntent = BackgroundWakeIntent;
10
+
11
+ let computedIntent: MockIntent | null;
12
+ let computeCalls: number;
13
+
14
+ const { ROUTES, setBackgroundWakeIntentComputerForTest } =
15
+ await import("../runtime/routes/background-wake-routes.js");
16
+
17
+ function findHandler(operationId: string) {
18
+ const route = ROUTES.find(
19
+ (candidate) => candidate.operationId === operationId,
20
+ );
21
+ if (!route) throw new Error(`Route ${operationId} not found`);
22
+ return route.handler;
23
+ }
24
+
25
+ const NOW = 1_800_000_000_000;
26
+
27
+ describe("background wake runtime routes", () => {
28
+ beforeEach(() => {
29
+ clearBackgroundWakeRuntime();
30
+ computeCalls = 0;
31
+ computedIntent = intentFixture({ nextWakeAt: Date.now() + 10 * 60_000 });
32
+ setBackgroundWakeIntentComputerForTest(() => {
33
+ computeCalls += 1;
34
+ return computedIntent;
35
+ });
36
+ });
37
+
38
+ afterEach(() => {
39
+ setBackgroundWakeIntentComputerForTest(null);
40
+ });
41
+
42
+ test("intent route returns the current computed wake intent", async () => {
43
+ const handler = findHandler("getBackgroundWakeIntent");
44
+
45
+ expect(await handler({})).toEqual({ intent: computedIntent });
46
+ expect(computeCalls).toBe(1);
47
+ });
48
+
49
+ test("intent route returns null when no wake intent exists", async () => {
50
+ computedIntent = null;
51
+ const handler = findHandler("getBackgroundWakeIntent");
52
+
53
+ expect(await handler({})).toEqual({ intent: null });
54
+ });
55
+
56
+ test("prepare-sleep defers when the next wake is inside the local window", async () => {
57
+ computedIntent = intentFixture({ nextWakeAt: Date.now() + 30_000 });
58
+ const handler = findHandler("prepareBackgroundWakeSleep");
59
+
60
+ expect(await handler({})).toEqual({
61
+ intent: computedIntent,
62
+ deferSleep: true,
63
+ });
64
+ });
65
+
66
+ test("prepare-sleep allows sleep when the next wake is outside the local window", async () => {
67
+ computedIntent = intentFixture({ nextWakeAt: Date.now() + 5 * 60_000 });
68
+ const handler = findHandler("prepareBackgroundWakeSleep");
69
+
70
+ expect(await handler({})).toEqual({
71
+ intent: computedIntent,
72
+ deferSleep: false,
73
+ });
74
+ });
75
+
76
+ test("drain-due fails when the runtime registry is missing", async () => {
77
+ const handler = findHandler("drainDueBackgroundWake");
78
+
79
+ await expect(handler({ body: drainBodyFixture() })).rejects.toThrow(
80
+ "Background wake runtime is not registered",
81
+ );
82
+ });
83
+
84
+ test("drain-due invokes due heartbeat and scheduler work", async () => {
85
+ const heartbeatRunOnce = mock(async () => true);
86
+ const schedulerRunOnce = mock(async () => 2);
87
+ registerBackgroundWakeRuntime({
88
+ heartbeat: {
89
+ nextRunAt: Date.now() - 1,
90
+ runOnce: heartbeatRunOnce,
91
+ },
92
+ scheduler: {
93
+ runOnce: schedulerRunOnce,
94
+ },
95
+ });
96
+ computedIntent = intentFixture({
97
+ nextWakeAt: NOW + 60_000,
98
+ sourceGeneration: "next-generation",
99
+ });
100
+ const handler = findHandler("drainDueBackgroundWake");
101
+
102
+ const response = await handler({ body: drainBodyFixture() });
103
+
104
+ expect(heartbeatRunOnce).toHaveBeenCalledTimes(1);
105
+ expect(heartbeatRunOnce).toHaveBeenCalledWith();
106
+ expect(schedulerRunOnce).toHaveBeenCalledTimes(1);
107
+ expect(response).toEqual({
108
+ leaseId: "lease-123",
109
+ reason: "schedule",
110
+ sourceGeneration: "source-generation",
111
+ startedAt: NOW,
112
+ deadlineAt: NOW + 30_000,
113
+ counts: {
114
+ heartbeat: 1,
115
+ scheduler: 2,
116
+ total: 3,
117
+ },
118
+ nextIntent: computedIntent,
119
+ });
120
+ });
121
+
122
+ test("drain-due skips heartbeat when it is not due and reports no scheduler work", async () => {
123
+ const heartbeatRunOnce = mock(async () => true);
124
+ const schedulerRunOnce = mock(async () => 0);
125
+ registerBackgroundWakeRuntime({
126
+ heartbeat: {
127
+ nextRunAt: Date.now() + 5 * 60_000,
128
+ runOnce: heartbeatRunOnce,
129
+ },
130
+ scheduler: {
131
+ runOnce: schedulerRunOnce,
132
+ },
133
+ });
134
+ const handler = findHandler("drainDueBackgroundWake");
135
+
136
+ const response = (await handler({ body: drainBodyFixture() })) as {
137
+ counts: { heartbeat: number; scheduler: number; total: number };
138
+ };
139
+
140
+ expect(heartbeatRunOnce).not.toHaveBeenCalled();
141
+ expect(schedulerRunOnce).toHaveBeenCalledTimes(1);
142
+ expect(response.counts).toEqual({
143
+ heartbeat: 0,
144
+ scheduler: 0,
145
+ total: 0,
146
+ });
147
+ });
148
+
149
+ test("drain-due recomputes the next intent after due work drains", async () => {
150
+ const recomputedIntent = intentFixture({
151
+ nextWakeAt: NOW + 2 * 60_000,
152
+ sourceGeneration: "after-drain",
153
+ });
154
+ const schedulerRunOnce = mock(async () => {
155
+ computedIntent = recomputedIntent;
156
+ return 1;
157
+ });
158
+ registerBackgroundWakeRuntime({
159
+ heartbeat: {
160
+ nextRunAt: null,
161
+ runOnce: mock(async () => true),
162
+ },
163
+ scheduler: {
164
+ runOnce: schedulerRunOnce,
165
+ },
166
+ });
167
+ const handler = findHandler("drainDueBackgroundWake");
168
+
169
+ const response = (await handler({ body: drainBodyFixture() })) as {
170
+ nextIntent: MockIntent | null;
171
+ };
172
+
173
+ expect(response.nextIntent).toEqual(recomputedIntent);
174
+ });
175
+
176
+ test("drain-due accepts vembda snake_case payload aliases", async () => {
177
+ const schedulerRunOnce = mock(async () => 0);
178
+ registerBackgroundWakeRuntime({
179
+ heartbeat: {
180
+ nextRunAt: null,
181
+ runOnce: mock(async () => false),
182
+ },
183
+ scheduler: {
184
+ runOnce: schedulerRunOnce,
185
+ },
186
+ });
187
+ const handler = findHandler("drainDueBackgroundWake");
188
+
189
+ const response = await handler({
190
+ body: {
191
+ lease_id: "lease-snake",
192
+ reason: "refresh",
193
+ source_generation: "generation-snake",
194
+ started_at: new Date(NOW).toISOString(),
195
+ deadline_at: String(NOW + 30_000),
196
+ },
197
+ });
198
+
199
+ expect(response).toMatchObject({
200
+ leaseId: "lease-snake",
201
+ reason: "refresh",
202
+ sourceGeneration: "generation-snake",
203
+ startedAt: NOW,
204
+ deadlineAt: NOW + 30_000,
205
+ });
206
+ });
207
+ });
208
+
209
+ function drainBodyFixture() {
210
+ return {
211
+ leaseId: "lease-123",
212
+ reason: "schedule",
213
+ sourceGeneration: "source-generation",
214
+ startedAt: NOW,
215
+ deadlineAt: NOW + 30_000,
216
+ };
217
+ }
218
+
219
+ function intentFixture(overrides: Partial<MockIntent>): MockIntent {
220
+ const nextWakeAt = overrides.nextWakeAt ?? NOW + 60_000;
221
+ return {
222
+ nextWakeAt,
223
+ actualNextDueAt: nextWakeAt,
224
+ reason: "schedule",
225
+ sourceGeneration: "source-generation",
226
+ computedAt: NOW - 1_000,
227
+ sourcePayload: {
228
+ heartbeat: null,
229
+ schedules: [],
230
+ },
231
+ ...overrides,
232
+ };
233
+ }
@@ -0,0 +1,24 @@
1
+ import type { HeartbeatService } from "../heartbeat/heartbeat-service.js";
2
+ import type { SchedulerHandle } from "../schedule/scheduler.js";
3
+
4
+ export interface BackgroundWakeRuntime {
5
+ scheduler: Pick<SchedulerHandle, "runOnce">;
6
+ heartbeat: Pick<HeartbeatService, "nextRunAt" | "runOnce">;
7
+ }
8
+
9
+ let runtime: BackgroundWakeRuntime | null = null;
10
+
11
+ export function registerBackgroundWakeRuntime(
12
+ nextRuntime: BackgroundWakeRuntime,
13
+ ): void {
14
+ runtime = nextRuntime;
15
+ }
16
+
17
+ export function getBackgroundWakeRuntime(): BackgroundWakeRuntime | null {
18
+ return runtime;
19
+ }
20
+
21
+ /** @internal Test helper for module-level route state. */
22
+ export function clearBackgroundWakeRuntime(): void {
23
+ runtime = null;
24
+ }
@@ -131,26 +131,44 @@ beforeEach(() => {
131
131
  // ---------------------------------------------------------------------------
132
132
 
133
133
  describe("subcommand registration", () => {
134
- test("registers exactly 17 subcommands", () => {
134
+ test("registers one direct subcommand per BROWSER_OPERATIONS entry plus 'tabs' group", () => {
135
135
  const program = new Command();
136
136
  registerBrowserCommand(program);
137
137
  const browser = program.commands.find((c) => c.name() === "browser");
138
138
  expect(browser).toBeDefined();
139
- const subcommands = browser!.commands;
140
- expect(subcommands).toHaveLength(17);
139
+ // 17 operation commands + 1 'tabs' grouping subcommand
140
+ expect(browser!.commands).toHaveLength(BROWSER_OPERATIONS.length + 1);
141
141
  });
142
142
 
143
- test("subcommand names match kebab-cased BROWSER_OPERATIONS", () => {
143
+ test("operation subcommand names match kebab-cased BROWSER_OPERATIONS", () => {
144
144
  const program = new Command();
145
145
  registerBrowserCommand(program);
146
146
  const browser = program.commands.find((c) => c.name() === "browser");
147
- const subcommandNames = browser!.commands.map((c) => c.name()).sort();
147
+ // Filter out the 'tabs' grouping subcommand — it's not a BROWSER_OPERATIONS entry.
148
+ const subcommandNames = browser!.commands
149
+ .filter((c) => c.name() !== "tabs")
150
+ .map((c) => c.name())
151
+ .sort();
148
152
  const expectedNames = BROWSER_OPERATIONS.map((op) =>
149
153
  op.replace(/_/g, "-"),
150
154
  ).sort();
151
155
  expect(subcommandNames).toEqual(expectedNames);
152
156
  });
153
157
 
158
+ test("registers 'tabs' subcommand group with list/select/new/close", () => {
159
+ const program = new Command();
160
+ registerBrowserCommand(program);
161
+ const browser = program.commands.find((c) => c.name() === "browser");
162
+ const tabs = browser!.commands.find((c) => c.name() === "tabs");
163
+ expect(tabs).toBeDefined();
164
+ expect(tabs!.commands.map((c) => c.name()).sort()).toEqual([
165
+ "close",
166
+ "list",
167
+ "new",
168
+ "select",
169
+ ]);
170
+ });
171
+
154
172
  test("all 17 operations from BROWSER_OPERATIONS are covered", () => {
155
173
  expect(BROWSER_OPERATIONS).toHaveLength(17);
156
174
  expect(BROWSER_OPERATION_META).toHaveLength(17);
@@ -204,4 +204,114 @@ describe("assistant domain register", () => {
204
204
  await runDomainCommand("domain", "register", "velly");
205
205
  expect(process.exitCode).not.toBe(0);
206
206
  });
207
+
208
+ test("--email-username is included in IPC body", async () => {
209
+ mockIpcCallFn = mock(() =>
210
+ Promise.resolve({
211
+ ok: true,
212
+ result: {
213
+ id: "550e8400-e29b-41d4-a716-446655440000",
214
+ domain: "velly.vellum.me",
215
+ status: "active",
216
+ verified: true,
217
+ },
218
+ }),
219
+ );
220
+
221
+ await runDomainCommand(
222
+ "domain",
223
+ "register",
224
+ "velly",
225
+ "--email-username",
226
+ "hello",
227
+ );
228
+
229
+ expect(mockIpcCallFn).toHaveBeenCalledWith("domain_register", {
230
+ body: { subdomain: "velly", email_username: "hello" },
231
+ });
232
+ expect(process.exitCode).toBe(0);
233
+ });
234
+
235
+ test("email error in response is surfaced as warning", async () => {
236
+ mockIpcCallFn = mock(() =>
237
+ Promise.resolve({
238
+ ok: true,
239
+ result: {
240
+ id: "550e8400-e29b-41d4-a716-446655440000",
241
+ domain: "velly.vellum.me",
242
+ status: "active",
243
+ verified: true,
244
+ email_error: {
245
+ detail: "MX records not ready",
246
+ code: "email_setup_failed",
247
+ },
248
+ },
249
+ }),
250
+ );
251
+
252
+ await runDomainCommand(
253
+ "domain",
254
+ "register",
255
+ "velly",
256
+ "--email-username",
257
+ "hello",
258
+ );
259
+
260
+ expect(process.exitCode).toBe(0);
261
+ });
262
+
263
+ test("--json includes email_error in output", async () => {
264
+ mockIpcCallFn = mock(() =>
265
+ Promise.resolve({
266
+ ok: true,
267
+ result: {
268
+ id: "550e8400-e29b-41d4-a716-446655440000",
269
+ domain: "velly.vellum.me",
270
+ status: "active",
271
+ verified: true,
272
+ email_error: {
273
+ detail: "MX records not ready",
274
+ code: "email_setup_failed",
275
+ },
276
+ },
277
+ }),
278
+ );
279
+
280
+ const output = await runDomainCommand(
281
+ "domain",
282
+ "--json",
283
+ "register",
284
+ "velly",
285
+ "--email-username",
286
+ "hello",
287
+ );
288
+
289
+ const parsed = JSON.parse(output.trim());
290
+ expect(parsed.email_error).toEqual({
291
+ detail: "MX records not ready",
292
+ code: "email_setup_failed",
293
+ });
294
+ expect(process.exitCode).toBe(0);
295
+ });
296
+
297
+ test("without --email-username behavior is unchanged", async () => {
298
+ mockIpcCallFn = mock(() =>
299
+ Promise.resolve({
300
+ ok: true,
301
+ result: {
302
+ id: "550e8400-e29b-41d4-a716-446655440000",
303
+ domain: "velly.vellum.me",
304
+ status: "active",
305
+ verified: true,
306
+ },
307
+ }),
308
+ );
309
+
310
+ await runDomainCommand("domain", "register", "velly");
311
+
312
+ expect(mockIpcCallFn).toHaveBeenCalledWith("domain_register", {
313
+ body: { subdomain: "velly" },
314
+ });
315
+ expect(process.exitCode).toBe(0);
316
+ });
207
317
  });
@@ -2,9 +2,9 @@
2
2
  * Tests for the domain status CLI subcommand (thin IPC wrapper).
3
3
  *
4
4
  * Validates:
5
- * - status calls domain_status
5
+ * - status calls domain_status then domain_verification_status
6
6
  * - --json outputs structured response
7
- * - no domain shows helpful message
7
+ * - unknown subdomain shows helpful message
8
8
  * - error responses are surfaced correctly
9
9
  */
10
10
 
@@ -99,15 +99,16 @@ async function runDomainCommand(...args: string[]) {
99
99
  // status
100
100
  // ---------------------------------------------------------------------------
101
101
 
102
- describe("assistant domain status", () => {
103
- test("calls domain_status", async () => {
104
- mockIpcCallFn = mock(() =>
105
- Promise.resolve({
102
+ function mockDomainStatusWithVerification() {
103
+ mockIpcCallFn = mock((method: string) => {
104
+ if (method === "domain_status") {
105
+ return Promise.resolve({
106
106
  ok: true,
107
107
  result: {
108
108
  results: [
109
109
  {
110
110
  id: "550e8400-e29b-41d4-a716-446655440000",
111
+ subdomain: "becky",
111
112
  domain: "becky.vellum.me",
112
113
  status: "active",
113
114
  verified: true,
@@ -115,38 +116,37 @@ describe("assistant domain status", () => {
115
116
  },
116
117
  ],
117
118
  },
118
- }),
119
- );
119
+ });
120
+ }
121
+ return Promise.resolve({
122
+ ok: true,
123
+ result: {
124
+ domain: "becky.vellum.me",
125
+ status: "verified",
126
+ message: "DNS records have been verified.",
127
+ },
128
+ });
129
+ }) as unknown as typeof mockIpcCallFn;
130
+ }
120
131
 
121
- await runDomainCommand("domain", "status");
132
+ describe("assistant domain status", () => {
133
+ test("calls domain_status and domain_verification_status", async () => {
134
+ mockDomainStatusWithVerification();
122
135
 
123
- expect(mockIpcCallFn).toHaveBeenCalledWith("domain_status");
136
+ await runDomainCommand("domain", "status", "becky");
137
+
138
+ expect(mockIpcCallFn).toHaveBeenCalledTimes(2);
124
139
  expect(process.exitCode).toBe(0);
125
140
  });
126
141
 
127
142
  test("--json outputs structured response", async () => {
128
- mockIpcCallFn = mock(() =>
129
- Promise.resolve({
130
- ok: true,
131
- result: {
132
- results: [
133
- {
134
- id: "550e8400-e29b-41d4-a716-446655440000",
135
- domain: "becky.vellum.me",
136
- status: "active",
137
- verified: true,
138
- created_at: "2026-04-15T19:00:00Z",
139
- },
140
- ],
141
- },
142
- }),
143
- );
143
+ mockDomainStatusWithVerification();
144
144
 
145
- const output = await runDomainCommand("domain", "--json", "status");
145
+ const output = await runDomainCommand("domain", "--json", "status", "becky");
146
146
 
147
147
  const parsed = JSON.parse(output.trim());
148
- expect(parsed.results).toHaveLength(1);
149
- expect(parsed.results[0].domain).toBe("becky.vellum.me");
148
+ expect(parsed.domain.domain).toBe("becky.vellum.me");
149
+ expect(parsed.verification.status).toBe("verified");
150
150
  expect(process.exitCode).toBe(0);
151
151
  });
152
152
 
@@ -158,8 +158,8 @@ describe("assistant domain status", () => {
158
158
  }),
159
159
  );
160
160
 
161
- await runDomainCommand("domain", "status");
162
- expect(process.exitCode).toBe(0);
161
+ await runDomainCommand("domain", "status", "becky");
162
+ expect(process.exitCode).toBe(1);
163
163
  });
164
164
 
165
165
  test("IPC error with --json outputs error envelope", async () => {
@@ -171,7 +171,7 @@ describe("assistant domain status", () => {
171
171
  }),
172
172
  ) as unknown as typeof mockIpcCallFn;
173
173
 
174
- const output = await runDomainCommand("domain", "--json", "status");
174
+ const output = await runDomainCommand("domain", "--json", "status", "becky");
175
175
 
176
176
  expect(process.exitCode).not.toBe(0);
177
177
  const parsed = JSON.parse(output.trim());
@@ -187,7 +187,7 @@ describe("assistant domain status", () => {
187
187
  }),
188
188
  ) as unknown as typeof mockIpcCallFn;
189
189
 
190
- await runDomainCommand("domain", "status");
190
+ await runDomainCommand("domain", "status", "becky");
191
191
  expect(process.exitCode).not.toBe(0);
192
192
  });
193
193
  });