@vellumai/assistant 0.12.1 → 0.12.2-staging.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 (577) hide show
  1. package/AGENTS.md +4 -0
  2. package/ARCHITECTURE.md +20 -21
  3. package/docs/architecture/turn-actor.md +15 -8
  4. package/docs/guardian-request-flow.md +16 -0
  5. package/node_modules/@vellumai/slack-text/src/index.ts +13 -8
  6. package/node_modules/@vellumai/slack-text/src/label-resolution-entities.test.ts +95 -0
  7. package/openapi.yaml +360 -51
  8. package/package.json +3 -1
  9. package/scripts/smoke-desktop-window-theme.ts +186 -0
  10. package/src/__tests__/always-loaded-tools-guard.test.ts +18 -10
  11. package/src/__tests__/anthropic-provider.test.ts +0 -63
  12. package/src/__tests__/app-compiler.test.ts +6 -0
  13. package/src/__tests__/app-control-tool-schemas.test.ts +5 -2
  14. package/src/__tests__/app-dir-path-guard.test.ts +1 -3
  15. package/src/__tests__/assistant-event-hub-machine-name.test.ts +6 -7
  16. package/src/__tests__/assistant-event-hub.test.ts +44 -0
  17. package/src/__tests__/computer-use-skill-manifest-regression.test.ts +1 -1
  18. package/src/__tests__/computer-use-skill-proxy-bridge.test.ts +5 -2
  19. package/src/__tests__/computer-use-tools.test.ts +19 -7
  20. package/src/__tests__/config-schema-cmd.test.ts +2 -2
  21. package/src/__tests__/config-schema.test.ts +28 -29
  22. package/src/__tests__/config-watcher.test.ts +23 -8
  23. package/src/__tests__/connection-model-compat.test.ts +2 -2
  24. package/src/__tests__/conversation-key-store-disk-view.test.ts +1 -1
  25. package/src/__tests__/conversation-pairing.test.ts +26 -0
  26. package/src/__tests__/conversation-process-app-control-preactivation.test.ts +4 -10
  27. package/src/__tests__/conversation-queue.test.ts +48 -207
  28. package/src/__tests__/conversation-retry-discard.test.ts +54 -1
  29. package/src/__tests__/conversation-runtime-assembly.test.ts +28 -0
  30. package/src/__tests__/conversation-skill-tools.test.ts +27 -0
  31. package/src/__tests__/conversation-surfaces-app-control.test.ts +8 -3
  32. package/src/__tests__/conversation-surfaces-point-at-budget.test.ts +1 -0
  33. package/src/__tests__/conversation-surfaces-point-at-capability.test.ts +1 -0
  34. package/src/__tests__/conversation-surfaces-task-progress.test.ts +67 -0
  35. package/src/__tests__/conversation-title-service.test.ts +14 -10
  36. package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +3 -5
  37. package/src/__tests__/conversation-tool-setup-attribution.test.ts +51 -0
  38. package/src/__tests__/credential-record-retire.test.ts +171 -1
  39. package/src/__tests__/credential-routes.test.ts +250 -3
  40. package/src/__tests__/credential-security-invariants.test.ts +5 -3
  41. package/src/__tests__/cu-unified-flow.test.ts +14 -4
  42. package/src/__tests__/document-sync-tags.test.ts +25 -0
  43. package/src/__tests__/drain-kick-guard.test.ts +0 -2
  44. package/src/__tests__/drain-requeue-on-contention.test.ts +0 -6
  45. package/src/__tests__/evict-conversations-for-reload.test.ts +1 -1
  46. package/src/__tests__/git-porcelain.test.ts +47 -0
  47. package/src/__tests__/heartbeat-service.test.ts +56 -40
  48. package/src/__tests__/helpers/set-workspace-mcp.ts +11 -0
  49. package/src/__tests__/host-bash-proxy.test.ts +26 -45
  50. package/src/__tests__/host-browser-proxy.test.ts +6 -17
  51. package/src/__tests__/host-cu-proxy.test.ts +596 -0
  52. package/src/__tests__/host-file-proxy-targeted.test.ts +23 -0
  53. package/src/__tests__/host-file-proxy.test.ts +11 -23
  54. package/src/__tests__/host-transfer-proxy-targeted.test.ts +30 -9
  55. package/src/__tests__/list-messages-camera-frame.test.ts +121 -0
  56. package/src/__tests__/llm-catalog-parity.test.ts +25 -0
  57. package/src/__tests__/mcp-auth-routes.test.ts +6 -9
  58. package/src/__tests__/mcp-config-secret-boundary.test.ts +78 -136
  59. package/src/__tests__/mcp-health-check.test.ts +8 -11
  60. package/src/__tests__/mcp-list-plugin-servers.test.ts +8 -10
  61. package/src/__tests__/message-deleted-hook-dispatch.test.ts +119 -0
  62. package/src/__tests__/messages-after-tiebreaker.test.ts +91 -0
  63. package/src/__tests__/messages-read-boundary-guard.test.ts +1 -1
  64. package/src/__tests__/messaging-send-tool.test.ts +355 -548
  65. package/src/__tests__/model-intents.test.ts +3 -0
  66. package/src/__tests__/notification-vellum-adapter.test.ts +85 -2
  67. package/src/__tests__/oauth-commands-routes.test.ts +168 -0
  68. package/src/__tests__/oauth-provider-profiles.test.ts +18 -0
  69. package/src/__tests__/oauth-provider-serializer.test.ts +22 -0
  70. package/src/__tests__/oauth-providers-routes.test.ts +1 -0
  71. package/src/__tests__/openai-provider.test.ts +1 -0
  72. package/src/__tests__/outlook-messaging-provider.test.ts +6 -6
  73. package/src/__tests__/platform-callback-registration.test.ts +8 -16
  74. package/src/__tests__/platform-client-verify-credential.test.ts +2 -0
  75. package/src/__tests__/plugin-import-boundary-guard.test.ts +14 -0
  76. package/src/__tests__/qdrant-manager.test.ts +132 -0
  77. package/src/__tests__/resolve-app.test.ts +135 -0
  78. package/src/__tests__/scaffold-managed-skill-tool.test.ts +229 -6
  79. package/src/__tests__/script-proxy-certs.test.ts +35 -0
  80. package/src/__tests__/secret-routes-acp-guard.test.ts +59 -1
  81. package/src/__tests__/service-account-token.test.ts +247 -0
  82. package/src/__tests__/skill-feature-flags-integration.test.ts +1 -1
  83. package/src/__tests__/skill-feature-flags.test.ts +2 -2
  84. package/src/__tests__/skills.test.ts +9 -4
  85. package/src/__tests__/source-fingerprint.test.ts +184 -0
  86. package/src/__tests__/subagent-tool-gate-mode.test.ts +70 -3
  87. package/src/__tests__/subagent-tools.test.ts +3 -2
  88. package/src/__tests__/telephony-tts-guard.test.ts +38 -3
  89. package/src/__tests__/test-support/computer-use-skill-harness.ts +3 -2
  90. package/src/__tests__/ui-channel-variants.test.ts +1 -56
  91. package/src/__tests__/unicode.test.ts +13 -0
  92. package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +4 -0
  93. package/src/__tests__/watch-retro-tool-availability.test.ts +8 -17
  94. package/src/__tests__/workspace-git-service.test.ts +26 -0
  95. package/src/__tests__/workspace-migration-154-repair-retired-codex-gpt-5-4-model-ids.test.ts +336 -0
  96. package/src/acp/__tests__/acp-claude-oauth.test.ts +257 -6
  97. package/src/acp/__tests__/acp-credentials.test.ts +13 -0
  98. package/src/acp/__tests__/agent-process.test.ts +258 -4
  99. package/src/acp/__tests__/auth-required.test.ts +96 -0
  100. package/src/acp/__tests__/claude-token-refresh.test.ts +257 -0
  101. package/src/acp/__tests__/client-handler.test.ts +90 -2
  102. package/src/acp/__tests__/helpers/acp-model-option.ts +51 -0
  103. package/src/acp/__tests__/prepare-agent-env.test.ts +60 -1
  104. package/src/acp/__tests__/session-manager-persistence.test.ts +5 -1
  105. package/src/acp/__tests__/session-manager-resume.test.ts +270 -6
  106. package/src/acp/__tests__/session-manager-usage.test.ts +4 -2
  107. package/src/acp/__tests__/session-manager.test.ts +895 -4
  108. package/src/acp/acp-claude-oauth.ts +328 -14
  109. package/src/acp/acp-credentials.ts +19 -0
  110. package/src/acp/agent-process.test.ts +4 -1
  111. package/src/acp/agent-process.ts +96 -10
  112. package/src/acp/auth-required.ts +50 -1
  113. package/src/acp/auto-install.test.ts +9 -7
  114. package/src/acp/claude-token-refresh.ts +150 -0
  115. package/src/acp/client-handler.ts +16 -3
  116. package/src/acp/model-config.test.ts +166 -0
  117. package/src/acp/model-config.ts +138 -0
  118. package/src/acp/prepare-agent-env.ts +21 -6
  119. package/src/acp/resolve-agent.test.ts +220 -6
  120. package/src/acp/resolve-agent.ts +88 -23
  121. package/src/acp/session-manager.test.ts +196 -3
  122. package/src/acp/session-manager.ts +441 -18
  123. package/src/acp/types.ts +50 -5
  124. package/src/agent/loop.ts +1 -0
  125. package/src/api/events/acp-session-model-update.test.ts +88 -0
  126. package/src/api/events/acp-session-model-update.ts +46 -0
  127. package/src/api/events/app-files-changed.ts +4 -3
  128. package/src/api/events/notification-intent.ts +2 -0
  129. package/src/api/events/user-message-echo.ts +7 -1
  130. package/src/api/index.ts +6 -0
  131. package/src/api/responses/conversation-message.ts +5 -0
  132. package/src/apps/app-store.ts +1 -1
  133. package/src/apps/resolve-app.ts +81 -0
  134. package/src/apps/source-fingerprint.ts +266 -0
  135. package/src/avatar/identity-avatar.ts +7 -2
  136. package/src/bundler/app-compiler.ts +15 -0
  137. package/src/calls/__tests__/barge-in-guard.test.ts +81 -0
  138. package/src/{__tests__ → calls/__tests__}/call-controller.test.ts +503 -82
  139. package/src/{__tests__ → calls/__tests__}/media-stream-audio-transcode.test.ts +1 -1
  140. package/src/{__tests__ → calls/__tests__}/media-stream-output.test.ts +37 -8
  141. package/src/{__tests__ → calls/__tests__}/media-stream-parser.test.ts +1 -1
  142. package/src/{__tests__ → calls/__tests__}/media-stream-server-integration.test.ts +150 -57
  143. package/src/{__tests__ → calls/__tests__}/media-stream-stt-session.test.ts +5 -5
  144. package/src/{__tests__ → calls/__tests__}/media-turn-detector.test.ts +1 -1
  145. package/src/{live-voice → calls}/__tests__/progress-narration.test.ts +4 -4
  146. package/src/{live-voice → calls}/__tests__/progress-phrases.test.ts +1 -1
  147. package/src/calls/__tests__/voice-control-protocol.test.ts +120 -25
  148. package/src/calls/__tests__/voice-leg-coordinator.test.ts +229 -0
  149. package/src/calls/__tests__/voice-progress-cadence.test.ts +274 -0
  150. package/src/{__tests__/voice-session-bridge.test.ts → calls/__tests__/voice-session-bridge-turn-flow.test.ts} +20 -12
  151. package/src/calls/__tests__/voice-session-bridge.test.ts +56 -1
  152. package/src/calls/__tests__/voice-triage-escalate.test.ts +105 -0
  153. package/src/calls/barge-in-guard.ts +118 -0
  154. package/src/calls/call-constants.ts +24 -4
  155. package/src/calls/call-controller.ts +499 -199
  156. package/src/calls/call-transport.ts +16 -0
  157. package/src/calls/media-stream-output.ts +32 -0
  158. package/src/calls/media-stream-server.ts +82 -30
  159. package/src/calls/media-stream-stt-session.ts +15 -0
  160. package/src/{live-voice → calls}/progress-narration.ts +2 -2
  161. package/src/calls/resolve-call-tts-provider.ts +33 -2
  162. package/src/calls/tts-call-strategy.ts +9 -5
  163. package/src/calls/types.ts +2 -0
  164. package/src/calls/voice-control-protocol.ts +155 -21
  165. package/src/calls/voice-leg-coordinator.ts +189 -0
  166. package/src/calls/voice-progress-cadence.ts +423 -0
  167. package/src/calls/voice-session-bridge.ts +92 -72
  168. package/src/calls/voice-triage-escalate.ts +178 -59
  169. package/src/cli/commands/__tests__/apps.test.ts +245 -0
  170. package/src/cli/commands/__tests__/bash.test.ts +53 -0
  171. package/src/cli/commands/__tests__/roadmap.help.test.ts +19 -0
  172. package/src/cli/commands/apps.help.ts +67 -13
  173. package/src/cli/commands/apps.ts +183 -0
  174. package/src/cli/commands/bash.help.ts +8 -13
  175. package/src/cli/commands/bash.ts +7 -25
  176. package/src/cli/commands/channels/__tests__/send.test.ts +218 -0
  177. package/src/cli/commands/channels/index.help.ts +70 -2
  178. package/src/cli/commands/channels/index.ts +16 -3
  179. package/src/cli/commands/channels/send.ts +128 -0
  180. package/src/cli/commands/credentials.help.ts +6 -2
  181. package/src/cli/commands/credentials.ts +2 -2
  182. package/src/cli/commands/mcp.help.ts +8 -8
  183. package/src/cli/commands/mcp.ts +1 -1
  184. package/src/cli/commands/oauth/status.ts +5 -0
  185. package/src/cli/commands/roadmap.help.ts +5 -1
  186. package/src/cli/commands/roadmap.ts +1 -1
  187. package/src/cli/lib/bundled-marketplace.json +103 -90
  188. package/src/config/__tests__/default-profile-catalog.test.ts +22 -0
  189. package/src/config/__tests__/memory-retrospective-schema.test.ts +15 -1
  190. package/src/config/__tests__/platform-identity.test.ts +255 -0
  191. package/src/config/__tests__/platform-rehydration.test.ts +99 -9
  192. package/src/config/acp-agent-write.ts +43 -0
  193. package/src/config/acp-defaults.test.ts +13 -3
  194. package/src/config/acp-defaults.ts +23 -6
  195. package/src/config/acp-schema.test.ts +81 -0
  196. package/src/config/acp-schema.ts +30 -2
  197. package/src/config/bundled-skills/acp/SKILL.md +22 -14
  198. package/src/config/bundled-skills/acp/TOOLS.json +5 -1
  199. package/src/config/bundled-skills/app-builder/SKILL.md +12 -9
  200. package/src/config/bundled-skills/app-builder/references/CUSTOM_ROUTES.md +1 -1
  201. package/src/config/bundled-skills/computer-use/SKILL.md +29 -2
  202. package/src/config/bundled-skills/computer-use/TOOLS.json +99 -0
  203. package/src/config/bundled-skills/computer-use/tools/computer-use-sequence.ts +12 -0
  204. package/src/config/bundled-skills/media-processing/services/preprocess.ts +2 -1
  205. package/src/config/bundled-skills/media-processing/services/processing-pipeline.ts +2 -1
  206. package/src/config/bundled-skills/media-processing/tools/generate-clip.ts +2 -1
  207. package/src/config/bundled-skills/messaging/SKILL.md +3 -3
  208. package/src/config/bundled-skills/messaging/TOOLS.json +3 -3
  209. package/src/config/bundled-skills/messaging/tools/messaging-send.ts +67 -139
  210. package/src/config/bundled-skills/phone-calls/references/TRANSCRIPTS.md +1 -1
  211. package/src/config/bundled-skills/playbooks/tools/playbook-create.ts +2 -1
  212. package/src/config/bundled-skills/playbooks/tools/playbook-update.ts +2 -1
  213. package/src/config/bundled-skills/schedule/SKILL.md +3 -4
  214. package/src/config/bundled-skills/screen-annotation/SKILL.md +8 -1
  215. package/src/config/bundled-skills/screen-annotation/tools/screen-annotation.test.ts +4 -1
  216. package/src/config/bundled-skills/skill-management/TOOLS.json +6 -2
  217. package/src/config/bundled-skills/transcribe/tools/transcribe-media.ts +5 -2
  218. package/src/config/default-profile-catalog.ts +1 -1
  219. package/src/config/env.ts +2 -2
  220. package/src/config/feature-flag-registry.json +33 -13
  221. package/src/config/loader.ts +2 -0
  222. package/src/config/memory-v3-gate.test.ts +31 -0
  223. package/src/config/memory-v3-gate.ts +20 -16
  224. package/src/config/platform-identity.ts +201 -0
  225. package/src/config/platform-rehydration.ts +11 -27
  226. package/src/config/schema.ts +2 -2
  227. package/src/config/schemas/__tests__/live-voice.test.ts +8 -158
  228. package/src/config/schemas/__tests__/voice.test.ts +148 -0
  229. package/src/config/schemas/calls.ts +1 -28
  230. package/src/config/schemas/live-voice.ts +1 -173
  231. package/src/config/schemas/mcp.ts +1 -1
  232. package/src/config/schemas/memory-retrospective.ts +10 -0
  233. package/src/config/schemas/services.ts +18 -0
  234. package/src/config/schemas/skills.ts +0 -14
  235. package/src/config/schemas/voice.ts +150 -0
  236. package/src/credential-execution/process-manager.test.ts +18 -19
  237. package/src/credential-health/credential-health-service.ts +11 -17
  238. package/src/daemon/__tests__/conversation-tool-setup.test.ts +66 -121
  239. package/src/daemon/__tests__/plugin-mcp-reconcile.test.ts +4 -1
  240. package/src/daemon/__tests__/skill-memory-refresh-mtime.test.ts +133 -0
  241. package/src/daemon/app-change-notify.ts +45 -0
  242. package/src/daemon/config-watcher.ts +13 -194
  243. package/src/daemon/conversation-error.ts +3 -2
  244. package/src/daemon/conversation-media-retry.ts +2 -1
  245. package/src/daemon/conversation-process.ts +35 -64
  246. package/src/daemon/conversation-runtime-assembly.ts +20 -7
  247. package/src/daemon/conversation-skill-tools.ts +13 -31
  248. package/src/daemon/conversation-store.ts +1 -1
  249. package/src/daemon/conversation-surfaces.ts +21 -10
  250. package/src/daemon/conversation-tool-setup.ts +45 -59
  251. package/src/daemon/conversation.ts +0 -3
  252. package/src/daemon/dictation-profile-store.ts +2 -1
  253. package/src/daemon/handlers/shared.ts +2 -1
  254. package/src/daemon/handlers/skills.ts +6 -3
  255. package/src/daemon/host-bash-proxy.ts +8 -12
  256. package/src/daemon/host-browser-proxy.ts +15 -1
  257. package/src/daemon/host-cu-proxy.ts +224 -19
  258. package/src/daemon/host-file-proxy.ts +8 -10
  259. package/src/daemon/host-proxy-preactivation.ts +2 -1
  260. package/src/daemon/host-transfer-proxy.ts +14 -18
  261. package/src/daemon/lifecycle.ts +0 -5
  262. package/src/daemon/mcp-reload-service.ts +5 -5
  263. package/src/daemon/message-types/sync.ts +1 -0
  264. package/src/daemon/orphan-reaper.ts +1 -1
  265. package/src/daemon/providers-setup.ts +1 -1
  266. package/src/daemon/reaction-history-render.ts +2 -1
  267. package/src/daemon/shutdown-handlers.ts +1 -9
  268. package/src/daemon/skill-memory-refresh.ts +64 -0
  269. package/src/daemon/tool-side-effects.ts +7 -18
  270. package/src/desktop/__tests__/fake-desktop.ts +122 -0
  271. package/src/desktop/desktop-chrome-policy.test.ts +79 -0
  272. package/src/desktop/desktop-chrome-policy.ts +47 -0
  273. package/src/desktop/desktop-chrome-session.ts +37 -0
  274. package/src/desktop/desktop-dependencies.test.ts +102 -0
  275. package/src/desktop/desktop-dependencies.ts +308 -0
  276. package/src/desktop/desktop-feature.test.ts +18 -0
  277. package/src/desktop/desktop-feature.ts +19 -0
  278. package/src/desktop/desktop-panel-config.test.ts +135 -0
  279. package/src/desktop/desktop-panel-config.ts +149 -0
  280. package/src/desktop/desktop-session-manager.test.ts +730 -0
  281. package/src/desktop/desktop-session-manager.ts +850 -0
  282. package/src/desktop/desktop-stream-bridge.test.ts +395 -0
  283. package/src/desktop/desktop-stream-bridge.ts +214 -0
  284. package/src/desktop/desktop-wallpaper.test.ts +191 -0
  285. package/src/desktop/desktop-wallpaper.ts +113 -0
  286. package/src/desktop/desktop-window-drag.ts +177 -0
  287. package/src/desktop/desktop-window-manager-config.test.ts +230 -0
  288. package/src/desktop/desktop-window-manager-config.ts +238 -0
  289. package/src/desktop/desktop-window-theme.ts +170 -0
  290. package/src/heartbeat/heartbeat-service.ts +21 -3
  291. package/src/home/__tests__/feed-writer.test.ts +22 -0
  292. package/src/home/feed-writer.ts +11 -2
  293. package/src/hooks/types.ts +33 -0
  294. package/src/i18n/AGENTS.md +22 -0
  295. package/src/i18n/__tests__/i18n.test.ts +108 -0
  296. package/src/i18n/index.ts +16 -0
  297. package/src/i18n/locales.ts +93 -0
  298. package/src/i18n/messages.ts +61 -0
  299. package/src/i18n/title.ts +25 -0
  300. package/src/inbound/platform-callback-registration.ts +4 -5
  301. package/src/live-voice/__tests__/live-voice-agent-turn.test.ts +121 -0
  302. package/src/live-voice/__tests__/live-voice-events.test.ts +8 -7
  303. package/src/live-voice/__tests__/live-voice-metrics.test.ts +0 -3
  304. package/src/live-voice/__tests__/live-voice-progress.test.ts +94 -15
  305. package/src/live-voice/__tests__/live-voice-sight-frame-echo.test.ts +238 -0
  306. package/src/live-voice/__tests__/live-voice-vad.test.ts +2 -2
  307. package/src/live-voice/__tests__/protocol.test.ts +39 -0
  308. package/src/live-voice/__tests__/runtime-websocket-shell.test.ts +13 -69
  309. package/src/live-voice/__tests__/session-controls.test.ts +79 -0
  310. package/src/live-voice/live-voice-photo.ts +25 -6
  311. package/src/live-voice/live-voice-session.ts +297 -699
  312. package/src/live-voice/protocol.ts +60 -2
  313. package/src/live-voice/session-controls.ts +111 -0
  314. package/src/mcp/__tests__/effective-config.test.ts +2 -2
  315. package/src/mcp/__tests__/workspace-mcp-config.test.ts +135 -0
  316. package/src/mcp/effective-config.ts +3 -3
  317. package/src/mcp/mcp-header-store.ts +29 -45
  318. package/src/mcp/spec-schema.ts +111 -0
  319. package/src/mcp/startup.ts +8 -4
  320. package/src/mcp/workspace-mcp-config.ts +188 -0
  321. package/src/messaging/provider.ts +10 -3
  322. package/src/messaging/providers/__tests__/proactive-address.test.ts +95 -0
  323. package/src/messaging/providers/callback-routing.ts +18 -0
  324. package/src/messaging/providers/channel-transport.ts +56 -0
  325. package/src/messaging/providers/discord/transport.ts +17 -0
  326. package/src/messaging/providers/slack/__tests__/adapter-token-routing.test.ts +6 -17
  327. package/src/messaging/providers/slack/adapter.ts +7 -44
  328. package/src/messaging/providers/slack/transport.ts +16 -0
  329. package/src/messaging/providers/telegram-bot/adapter.ts +1 -48
  330. package/src/messaging/providers/telegram-bot/client.ts +0 -26
  331. package/src/messaging/providers/telegram-bot/transport.ts +20 -0
  332. package/src/messaging/providers/whatsapp/adapter.ts +1 -48
  333. package/src/messaging/providers/whatsapp/transport.ts +18 -0
  334. package/src/monitoring/__tests__/workspace-git-heartbeat.test.ts +8 -0
  335. package/src/notifications/__tests__/assistant-reply-producer.test.ts +55 -0
  336. package/src/notifications/__tests__/guardian-feed-projection.test.ts +158 -2
  337. package/src/notifications/__tests__/home-feed-side-effect.test.ts +153 -3
  338. package/src/notifications/__tests__/schedule-result-producer.test.ts +99 -3
  339. package/src/notifications/adapters/macos.ts +3 -0
  340. package/src/notifications/assistant-reply-producer.ts +8 -3
  341. package/src/notifications/conversation-pairing.ts +36 -16
  342. package/src/notifications/delivered-post-record.ts +11 -1
  343. package/src/notifications/guardian-feed-projection.ts +125 -5
  344. package/src/notifications/home-feed-side-effect.ts +55 -7
  345. package/src/notifications/schedule-result-producer.ts +66 -22
  346. package/src/oauth/AGENTS.md +2 -0
  347. package/src/oauth/__tests__/seed-providers-managed.test.ts +149 -0
  348. package/src/oauth/byo-connection.test.ts +105 -0
  349. package/src/oauth/byo-connection.ts +36 -6
  350. package/src/oauth/connection-resolver.test.ts +100 -0
  351. package/src/oauth/connection-resolver.ts +120 -3
  352. package/src/oauth/provider-serializer.ts +9 -0
  353. package/src/oauth/scope-utils.ts +24 -0
  354. package/src/oauth/seed-providers.ts +314 -27
  355. package/src/outbound-proxy/certs.ts +3 -5
  356. package/src/permissions/checker.test.ts +11 -6
  357. package/src/persistence/compaction-log-store-clickhouse.ts +3 -3
  358. package/src/persistence/conversation-crud.ts +71 -63
  359. package/src/persistence/conversation-lineage.ts +12 -4
  360. package/src/persistence/conversation-queries.ts +2 -2
  361. package/src/persistence/conversation-title-placeholders.ts +23 -0
  362. package/src/persistence/conversation-title-service.ts +9 -26
  363. package/src/persistence/embeddings/qdrant-manager.ts +163 -18
  364. package/src/persistence/llm-request-log-sink-clickhouse.ts +3 -3
  365. package/src/persistence/llm-request-log-source-clickhouse.ts +3 -3
  366. package/src/persistence/message-cursor.ts +78 -0
  367. package/src/persistence/message-reads.ts +30 -0
  368. package/src/persistence/migrations/157-invite-contact-id.ts +18 -6
  369. package/src/persistence/migrations/__tests__/157-invite-contact-id.test.ts +149 -0
  370. package/src/persistence/schema/memory-core.ts +5 -0
  371. package/src/platform/client.test.ts +4 -2
  372. package/src/platform/client.ts +2 -10
  373. package/src/plugin-api/constants.ts +2 -0
  374. package/src/plugin-api/index.ts +1 -0
  375. package/src/plugin-api/types.ts +2 -0
  376. package/src/plugins/defaults/index.ts +2 -0
  377. package/src/plugins/defaults/memory/__tests__/memory-retrospective-accounting.test.ts +46 -0
  378. package/src/plugins/defaults/memory/__tests__/memory-retrospective-cursor-backfill.test.ts +118 -0
  379. package/src/plugins/defaults/memory/__tests__/memory-retrospective-cursor-preserve.test.ts +83 -0
  380. package/src/plugins/defaults/memory/__tests__/memory-retrospective-enqueue.test.ts +9 -5
  381. package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +20 -10
  382. package/src/plugins/defaults/memory/__tests__/memory-retrospective-prompt.test.ts +5 -0
  383. package/src/plugins/defaults/memory/__tests__/memory-retrospective-state.test.ts +219 -0
  384. package/src/plugins/defaults/memory/__tests__/memory-retrospective-sweep.test.ts +31 -0
  385. package/src/plugins/defaults/memory/__tests__/memory-retrospective-trigger-check.test.ts +63 -0
  386. package/src/plugins/defaults/memory/__tests__/shutdown-hook.test.ts +4 -0
  387. package/src/plugins/defaults/memory/context-search/agent-runner.ts +3 -2
  388. package/src/plugins/defaults/memory/context-search/format.ts +3 -2
  389. package/src/plugins/defaults/memory/context-search/sources/memory-v2.ts +6 -3
  390. package/src/plugins/defaults/memory/context-search/sources/workspace.ts +3 -2
  391. package/src/plugins/defaults/memory/graph/capability-seed.ts +6 -7
  392. package/src/plugins/defaults/memory/hooks/init.ts +10 -0
  393. package/src/plugins/defaults/memory/hooks/message-deleted.ts +21 -0
  394. package/src/plugins/defaults/memory/hooks/shutdown.ts +2 -0
  395. package/src/plugins/defaults/memory/host-utils.ts +10 -0
  396. package/src/plugins/defaults/memory/jobs-worker.ts +13 -0
  397. package/src/plugins/defaults/memory/memory-retrospective-accounting.ts +34 -60
  398. package/src/plugins/defaults/memory/memory-retrospective-cursor-backfill.ts +126 -0
  399. package/src/plugins/defaults/memory/memory-retrospective-cursor-preserve.ts +79 -0
  400. package/src/plugins/defaults/memory/memory-retrospective-cursor.ts +28 -0
  401. package/src/plugins/defaults/memory/memory-retrospective-enqueue.ts +3 -5
  402. package/src/plugins/defaults/memory/memory-retrospective-job.ts +12 -3
  403. package/src/plugins/defaults/memory/memory-retrospective-prompt.ts +1 -1
  404. package/src/plugins/defaults/memory/memory-retrospective-state.ts +312 -71
  405. package/src/plugins/defaults/memory/memory-retrospective-sweep.ts +2 -1
  406. package/src/plugins/defaults/memory/memory-retrospective-trigger-check.ts +5 -3
  407. package/src/plugins/defaults/memory/skill-md-mtime-poll.ts +9 -0
  408. package/src/plugins/defaults/memory/startup.ts +28 -2
  409. package/src/plugins/defaults/memory/substrate/__tests__/skill-content.test.ts +7 -9
  410. package/src/plugins/defaults/memory/substrate/page-index.ts +6 -1
  411. package/src/plugins/defaults/memory/substrate/skill-content.ts +2 -2
  412. package/src/plugins/defaults/memory/v1/graph/consolidation.ts +4 -2
  413. package/src/plugins/defaults/memory/v1/graph/extraction.ts +4 -2
  414. package/src/plugins/defaults/memory/v1/graph/retriever.ts +4 -1
  415. package/src/plugins/defaults/memory/v2/reranker.ts +6 -1
  416. package/src/plugins/defaults/memory/v3/__tests__/card.test.ts +24 -0
  417. package/src/plugins/defaults/memory/v3/__tests__/pool-select.test.ts +125 -0
  418. package/src/plugins/defaults/memory/v3/__tests__/sections.test.ts +26 -0
  419. package/src/plugins/defaults/memory/v3/__tests__/shadow-plugin.test.ts +30 -0
  420. package/src/plugins/defaults/memory/v3/card.ts +3 -2
  421. package/src/plugins/defaults/memory/v3/pool-select.ts +5 -3
  422. package/src/plugins/defaults/memory/v3/sections.ts +9 -3
  423. package/src/plugins/defaults/memory/v3/shadow-plugin.ts +5 -2
  424. package/src/plugins/defaults/memory/worker.ts +6 -0
  425. package/src/plugins/mcp-servers.ts +15 -75
  426. package/src/providers/__tests__/connection-model-compat.test.ts +3 -3
  427. package/src/providers/__tests__/retry-callsite.test.ts +41 -0
  428. package/src/providers/__tests__/retry-outbound-sanitize.test.ts +176 -0
  429. package/src/providers/anthropic/client.ts +0 -47
  430. package/src/providers/gemini/client.ts +9 -23
  431. package/src/providers/gemini-thought-signature.test.ts +63 -0
  432. package/src/providers/gemini-thought-signature.ts +44 -0
  433. package/src/providers/inference/__tests__/endpoint-probe.test.ts +42 -3
  434. package/src/providers/inference/auth.ts +2 -3
  435. package/src/providers/inference/connection-availability.ts +27 -8
  436. package/src/providers/inference/endpoint-probe.ts +10 -1
  437. package/src/providers/inference/resolve-auth.ts +22 -4
  438. package/src/providers/inference/service-account-token.ts +248 -0
  439. package/src/providers/model-catalog.ts +34 -0
  440. package/src/providers/model-intents.ts +10 -5
  441. package/src/providers/openai/__tests__/chat-completions-output-token-limit.test.ts +141 -0
  442. package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +146 -18
  443. package/src/providers/openai/__tests__/chat-completions-provider-thought-signature.test.ts +613 -0
  444. package/src/providers/openai/__tests__/google-thought-signature.test.ts +235 -0
  445. package/src/providers/openai/__tests__/tool-choice-mapping.test.ts +83 -1
  446. package/src/providers/openai/chat-completions-provider.ts +212 -79
  447. package/src/providers/openai/codex-models.ts +0 -4
  448. package/src/providers/openai/google-thought-signature.ts +320 -0
  449. package/src/providers/opencode/client.test.ts +73 -4
  450. package/src/providers/opencode/client.ts +60 -3
  451. package/src/providers/openrouter/client.ts +20 -0
  452. package/src/providers/outbound-request-sanitize.ts +96 -0
  453. package/src/providers/retry.ts +30 -19
  454. package/src/providers/unparseable-tool-args.ts +5 -1
  455. package/src/runtime/AGENTS.md +3 -1
  456. package/src/runtime/__tests__/channel-send.test.ts +443 -0
  457. package/src/runtime/__tests__/desktop-stream-upgrade.test.ts +89 -0
  458. package/src/runtime/__tests__/host-observe.test.ts +40 -1
  459. package/src/runtime/__tests__/live-voice-upgrade.test.ts +58 -0
  460. package/src/runtime/__tests__/runtime-ws-test-utils.ts +72 -0
  461. package/src/runtime/__tests__/watch-stream-upgrade.test.ts +59 -0
  462. package/src/runtime/agent-wake.ts +2 -1
  463. package/src/runtime/assistant-event-hub.ts +21 -3
  464. package/src/runtime/auth/same-actor.ts +38 -3
  465. package/src/runtime/channel-send.ts +316 -0
  466. package/src/runtime/host-observe.ts +11 -1
  467. package/src/runtime/http-server.ts +160 -151
  468. package/src/runtime/routes/__tests__/acp-claude-auth-routes.test.ts +16 -5
  469. package/src/runtime/routes/__tests__/acp-routes.test.ts +159 -4
  470. package/src/runtime/routes/__tests__/apps-refresh-route.test.ts +275 -0
  471. package/src/runtime/routes/__tests__/channel-send-routes.test.ts +127 -0
  472. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +108 -1
  473. package/src/runtime/routes/__tests__/default-provider-routes.test.ts +2 -2
  474. package/src/runtime/routes/__tests__/dictation-cleanup-guard.test.ts +107 -0
  475. package/src/runtime/routes/__tests__/mcp-add-default-risk.test.ts +16 -12
  476. package/src/runtime/routes/acp-claude-auth-routes.ts +11 -3
  477. package/src/runtime/routes/acp-routes.test.ts +15 -0
  478. package/src/runtime/routes/acp-routes.ts +72 -9
  479. package/src/runtime/routes/app-management-routes.ts +90 -2
  480. package/src/runtime/routes/app-routes.ts +1 -1
  481. package/src/runtime/routes/channel-send-routes.ts +85 -0
  482. package/src/runtime/routes/conversation-list-routes.ts +14 -3
  483. package/src/runtime/routes/conversation-query-routes.ts +40 -0
  484. package/src/runtime/routes/conversation-routes.ts +16 -3
  485. package/src/runtime/routes/credential-routes.ts +20 -14
  486. package/src/runtime/routes/desktop-setup-routes.test.ts +74 -0
  487. package/src/runtime/routes/desktop-setup-routes.ts +35 -0
  488. package/src/runtime/routes/diagnostics-routes.ts +61 -4
  489. package/src/runtime/routes/events-routes.ts +4 -0
  490. package/src/runtime/routes/host-cu-routes.ts +6 -0
  491. package/src/runtime/routes/index.ts +4 -2
  492. package/src/runtime/routes/log-export-routes.ts +2 -0
  493. package/src/runtime/routes/mcp-auth-routes.ts +39 -47
  494. package/src/runtime/routes/migration-routes.ts +6 -20
  495. package/src/runtime/routes/oauth-commands-routes.ts +50 -0
  496. package/src/runtime/routes/oauth-providers.ts +7 -0
  497. package/src/runtime/routes/platform-routes.ts +18 -15
  498. package/src/runtime/routes/workspace-routes.test.ts +55 -26
  499. package/src/runtime/routes/workspace-routes.ts +46 -63
  500. package/src/runtime/routes/workspace-tree-walk.test.ts +244 -0
  501. package/src/runtime/routes/workspace-tree-walk.ts +240 -0
  502. package/src/runtime/routes/workspace-utils.ts +17 -0
  503. package/src/runtime/services/__tests__/conversation-serializer.test.ts +28 -0
  504. package/src/runtime/services/conversation-serializer.ts +16 -3
  505. package/src/runtime/sync/resource-sync-events.ts +2 -1
  506. package/src/schedule/run-script.ts +2 -1
  507. package/src/schedule/schedule-store.ts +9 -2
  508. package/src/schedule/worker.ts +1 -1
  509. package/src/security/__tests__/ces-http-record-backend.test.ts +137 -0
  510. package/src/security/ces-http-record-backend.ts +120 -0
  511. package/src/security/ces-rpc-record-backend.ts +7 -0
  512. package/src/security/untrusted-content.ts +3 -1
  513. package/src/skills/__tests__/workspace-skill-md-signature.test.ts +60 -0
  514. package/src/skills/workspace-skill-md-signature.ts +50 -0
  515. package/src/subagent/consult-context.ts +12 -25
  516. package/src/tools/__tests__/side-effect-abort-guard.test.ts +1 -0
  517. package/src/tools/acp/list-agents.test.ts +3 -1
  518. package/src/tools/acp/spawn.test.ts +146 -11
  519. package/src/tools/acp/spawn.ts +21 -3
  520. package/src/tools/acp/status.test.ts +94 -0
  521. package/src/tools/acp/status.ts +40 -3
  522. package/src/tools/app-control/skill-proxy-bridge.ts +2 -1
  523. package/src/tools/browser/browser-execution.ts +1 -1
  524. package/src/tools/browser/cdp-client/accessibility-snapshot.ts +9 -3
  525. package/src/tools/browser/cdp-client/cdp-inspect/discovery.ts +2 -1
  526. package/src/tools/browser/cdp-client/extension-cdp-client.ts +3 -2
  527. package/src/tools/browser/network-recorder.ts +2 -1
  528. package/src/tools/capability-offer.test.ts +22 -2
  529. package/src/tools/capability-offer.ts +16 -1
  530. package/src/tools/computer-use/definitions.ts +121 -2
  531. package/src/tools/computer-use/skill-proxy-bridge.ts +2 -1
  532. package/src/tools/credentials/metadata-store.ts +100 -0
  533. package/src/tools/filesystem/search.ts +2 -1
  534. package/src/tools/host-filesystem/edit.test.ts +2 -1
  535. package/src/tools/host-filesystem/edit.ts +2 -2
  536. package/src/tools/host-filesystem/read.test.ts +2 -1
  537. package/src/tools/host-filesystem/read.ts +2 -2
  538. package/src/tools/host-filesystem/transfer.test.ts +2 -1
  539. package/src/tools/host-filesystem/transfer.ts +2 -2
  540. package/src/tools/host-filesystem/write.test.ts +2 -1
  541. package/src/tools/host-filesystem/write.ts +2 -2
  542. package/src/tools/host-terminal/host-shell.test.ts +16 -0
  543. package/src/tools/host-terminal/host-shell.ts +4 -20
  544. package/src/tools/network/web-search.ts +6 -1
  545. package/src/tools/policy-context.ts +6 -7
  546. package/src/tools/skills/scaffold-managed.ts +61 -3
  547. package/src/tools/subagent/spawn.ts +5 -8
  548. package/src/tools/terminal/__tests__/sanitized-bash.test.ts +57 -0
  549. package/src/tools/terminal/sanitized-bash.ts +105 -0
  550. package/src/tools/ui-surface/channel-variants.ts +10 -59
  551. package/src/tools/watch/watch-retro-report.ts +0 -8
  552. package/src/types/host-capabilities.ts +5 -3
  553. package/src/util/__tests__/language-subtag.test.ts +23 -1
  554. package/src/util/ca-bundle.ts +13 -0
  555. package/src/util/language-subtag.ts +16 -0
  556. package/src/util/platform.ts +8 -0
  557. package/src/util/unicode.ts +15 -1
  558. package/src/watch/watch-retro.ts +6 -8
  559. package/src/watch/watch-timeline.ts +2 -2
  560. package/src/workflows/run-manager.ts +2 -1
  561. package/src/workspace/git-porcelain.ts +66 -0
  562. package/src/workspace/git-service.ts +6 -55
  563. package/src/workspace/migrations/154-repair-retired-codex-gpt-5-4-model-ids.ts +258 -0
  564. package/src/workspace/migrations/155-move-front-model-config-to-voice.ts +78 -0
  565. package/src/workspace/migrations/156-extract-workspace-mcp-json.ts +214 -0
  566. package/src/workspace/migrations/__tests__/155-move-front-model-config-to-voice.test.ts +102 -0
  567. package/src/workspace/migrations/__tests__/156-extract-workspace-mcp-json.test.ts +199 -0
  568. package/src/workspace/migrations/registry.ts +6 -0
  569. package/src/__tests__/app-source-watcher.test.ts +0 -218
  570. package/src/__tests__/config-watcher-skill-reseed.test.ts +0 -359
  571. package/src/__tests__/speaker-identification.test.ts +0 -56
  572. package/src/calls/speaker-identification.ts +0 -233
  573. package/src/daemon/app-source-watcher.ts +0 -218
  574. package/src/messaging/providers/whatsapp/client.ts +0 -29
  575. package/src/runtime/routes/debug-bash-routes.ts +0 -173
  576. package/src/util/fs-watcher-error.ts +0 -36
  577. /package/src/{live-voice → calls}/progress-phrases.ts +0 -0
@@ -0,0 +1,186 @@
1
+ import assert from "node:assert/strict";
2
+ import { mkdir, mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
3
+ import { tmpdir } from "node:os";
4
+ import { join } from "node:path";
5
+
6
+ import { writeDesktopWindowTheme } from "../src/desktop/desktop-window-theme.js";
7
+
8
+ if (process.platform !== "linux") {
9
+ throw new Error(
10
+ "Run in a disposable Linux environment with Xvfb, Openbox, xterm, xdotool, xwininfo and xmllint installed",
11
+ );
12
+ }
13
+
14
+ const directory = await mkdtemp(join(tmpdir(), "window-theme-smoke-"));
15
+ const env = { ...process.env, DISPLAY: ":97" };
16
+ const children: ReturnType<typeof Bun.spawn>[] = [];
17
+ const start = (cmd: string[]) => {
18
+ const child = Bun.spawn(cmd, {
19
+ env,
20
+ stdout: "ignore",
21
+ stderr: "inherit",
22
+ windowsHide: true,
23
+ });
24
+ children.push(child);
25
+ return child;
26
+ };
27
+ const run = (...cmd: string[]) => {
28
+ const result = Bun.spawnSync(cmd, {
29
+ env,
30
+
31
+ windowsHide: true,
32
+ });
33
+ assert.equal(result.exitCode, 0, result.stderr.toString());
34
+ return result.stdout.toString();
35
+ };
36
+ const waitFor = async (predicate: () => boolean) => {
37
+ for (let attempt = 0; attempt < 100; attempt++) {
38
+ try {
39
+ if (predicate()) {
40
+ return;
41
+ }
42
+ } catch {}
43
+ await Bun.sleep(50);
44
+ }
45
+ throw new Error("Window theme smoke condition timed out");
46
+ };
47
+ const pointer = async (...args: string[]) => {
48
+ run("xdotool", ...args);
49
+ await Bun.sleep(200);
50
+ };
51
+ const geometry = () => {
52
+ const info = run("xwininfo", "-name", "Theme smoke");
53
+ return [
54
+ "Absolute upper-left X",
55
+ "Absolute upper-left Y",
56
+ "Width",
57
+ "Height",
58
+ ].map((label) =>
59
+ Number(new RegExp(`${label}:\\s+(-?\\d+)`).exec(info)?.[1]),
60
+ ) as [number, number, number, number];
61
+ };
62
+ const state = () => run("xprop", "-name", "Theme smoke", "_NET_WM_STATE");
63
+ const button = async (offset: number) => {
64
+ const [x, y, width] = geometry();
65
+ await pointer(
66
+ "mousemove",
67
+ String(x + width - offset),
68
+ String(y - 16),
69
+ "click",
70
+ "1",
71
+ );
72
+ };
73
+
74
+ try {
75
+ const home = join(directory, "home");
76
+ const sourceDir = join(home, ".config", "openbox");
77
+ await mkdir(sourceDir, { recursive: true });
78
+ const original = await readFile("/etc/xdg/openbox/rc.xml", "utf8");
79
+ const mouse = original.match(/<mouse>[^]*?<\/mouse>/)![0];
80
+ const keyboard = original.match(/<keyboard>[^]*?<\/keyboard>/)![0];
81
+ const source = original
82
+ .replace(
83
+ mouse,
84
+ `<xi:include href="bindings.xml" xpointer="xpointer(/*/*)"/>`,
85
+ )
86
+ .replace(keyboard, "");
87
+ const sourcePath = join(sourceDir, "rc.xml");
88
+ await writeFile(sourcePath, source);
89
+ await writeFile(
90
+ join(sourceDir, "bindings.xml"),
91
+ `<bindings xmlns="http://openbox.org/3.4/rc">${mouse}${keyboard}</bindings>`,
92
+ );
93
+ const configDir = join(directory, "managed & theme");
94
+ const config = writeDesktopWindowTheme(configDir, home, "#53b7aa");
95
+ const expanded = run("xmllint", "--xinclude", config);
96
+ assert(
97
+ expanded.includes("NextWindow") && expanded.includes("Move"),
98
+ "Relative includes must retain the actual keyboard and mouse bindings",
99
+ );
100
+ assert.equal(await readFile(sourcePath, "utf8"), source);
101
+ writeDesktopWindowTheme(configDir, home, "#bc7799");
102
+ writeDesktopWindowTheme(configDir, home, "#53b7aa");
103
+ assert.equal(await readFile(sourcePath, "utf8"), source);
104
+ const blocked = join(directory, "blocked");
105
+ await writeFile(blocked, "not a directory");
106
+ assert.throws(() => writeDesktopWindowTheme(blocked, home));
107
+ assert.equal(await readFile(sourcePath, "utf8"), source);
108
+ const customBase = source.replace(
109
+ "<openbox_config",
110
+ '<openbox_config xml:base="./custom/"',
111
+ );
112
+ await writeFile(sourcePath, customBase);
113
+ assert.throws(() => writeDesktopWindowTheme(configDir, home));
114
+ assert.equal(await readFile(sourcePath, "utf8"), customBase);
115
+ await writeFile(sourcePath, source);
116
+
117
+ start(["Xvfb", ":97", "-screen", "0", "1100x700x24"]);
118
+ await waitFor(
119
+ () => run("xdotool", "getdisplaygeometry").trim() === "1100 700",
120
+ );
121
+ start(["openbox", "--config-file", config]);
122
+ await waitFor(() =>
123
+ run("xprop", "-root", "_OB_THEME").includes("window-theme"),
124
+ );
125
+ start([
126
+ "xterm",
127
+ "-title",
128
+ "Theme smoke",
129
+ "-geometry",
130
+ "48x12+450+250",
131
+ "-e",
132
+ "sleep",
133
+ "60",
134
+ ]);
135
+ await waitFor(
136
+ () => run("xdotool", "search", "--name", "^Theme smoke$").trim().length > 0,
137
+ );
138
+ await Bun.sleep(300);
139
+ const id = run("xdotool", "search", "--name", "^Theme smoke$").trim();
140
+ await button(39);
141
+ assert(
142
+ state().includes("MAXIMIZED_HORZ") && state().includes("MAXIMIZED_VERT"),
143
+ );
144
+ await button(39);
145
+ assert(!state().includes("MAXIMIZED"));
146
+ await button(62);
147
+ assert(state().includes("HIDDEN"));
148
+ await pointer("windowactivate", id);
149
+ assert(!state().includes("HIDDEN"));
150
+ let [x, y, width, height] = geometry();
151
+ await pointer("mousemove", String(x + 100), String(y - 16), "mousedown", "1");
152
+ await pointer("mousemove", String(x + 90), String(y - 26));
153
+ await pointer("mousemove", String(x + 45), String(y - 65));
154
+ await pointer("mouseup", "1");
155
+ const [movedX, movedY] = geometry();
156
+ assert(Math.abs(movedX - x) >= 30 && Math.abs(movedY - y) >= 30);
157
+ [x, y, width, height] = geometry();
158
+ await pointer(
159
+ "mousemove",
160
+ String(x + width - 2),
161
+ String(y + height + 2),
162
+ "mousedown",
163
+ "1",
164
+ );
165
+ await pointer("mousemove", String(x + width + 10), String(y + height + 10));
166
+ await pointer("mousemove", String(x + width + 60), String(y + height + 40));
167
+ await pointer("mouseup", "1");
168
+ const [, , resizedWidth, resizedHeight] = geometry();
169
+ assert(resizedWidth > width && resizedHeight > height);
170
+ await pointer("key", "alt+F4");
171
+ await waitFor(
172
+ () =>
173
+ !run("xprop", "-root", "_NET_CLIENT_LIST").includes(
174
+ `0x${Number(id).toString(16)}`,
175
+ ),
176
+ );
177
+ console.log(
178
+ "PASS: relative includes, preserved source, repeated theme updates, maximize/restore, minimize/activation, dragging, resizing, and keyboard close",
179
+ );
180
+ } finally {
181
+ for (const child of children.reverse()) {
182
+ child.kill();
183
+ }
184
+ await Promise.all(children.map((child) => child.exited));
185
+ await rm(directory, { recursive: true, force: true });
186
+ }
@@ -26,7 +26,7 @@ afterAll(() => {
26
26
  });
27
27
 
28
28
  describe("always-loaded tool count", () => {
29
- test("should be exactly 11 with recall occupying the existing slot", async () => {
29
+ test("should be exactly 19 with recall occupying the existing slot", async () => {
30
30
  await initializeTools();
31
31
  const allDefs = getAllToolDefinitions();
32
32
 
@@ -44,23 +44,31 @@ describe("always-loaded tool count", () => {
44
44
  );
45
45
  const activeNames = activeTools.map((t) => t.name).sort();
46
46
 
47
- // Host tools (host_bash, host_file_*) are excluded when no client is
48
- // connected without a human in the loop, the guardian auto-approve
49
- // path would allow unchecked host command execution.
50
- //
51
- // `watch_retro_report` is here for the same reason the ui_surface tools are
52
- // NOT: a watch retrospective runs clientless, so it can only report through
53
- // a tool that survives this baseline. Its description and schema are kept
54
- // deliberately terse because that is the cost of the slot.
47
+ // `watch_retro_report` survives this baseline because a watch
48
+ // retrospective runs clientless and can only report through a tool that
49
+ // stays on this baseline. The ui_* tools stay here because background
50
+ // surfaces persist and return instead of awaiting action, so a connected
51
+ // client is not required for the definitions to be present.
52
+ // Host tool definitions stay on the wire for background turns: schemas
53
+ // are cache-stable, and the shared execution gate rejects host tools on
54
+ // explicitly non-interactive turns before any proxy dispatch.
55
55
  const expectedNames = [
56
56
  "bash",
57
57
  "file_edit",
58
58
  "file_read",
59
59
  "file_write",
60
+ "host_bash",
61
+ "host_file_edit",
62
+ "host_file_read",
63
+ "host_file_transfer",
64
+ "host_file_write",
60
65
  "recall",
61
66
  "remember",
62
67
  "skill_execute",
63
68
  "skill_load",
69
+ "ui_dismiss",
70
+ "ui_show",
71
+ "ui_update",
64
72
  "watch_retro_report",
65
73
  "web_fetch",
66
74
  "web_search",
@@ -68,6 +76,6 @@ describe("always-loaded tool count", () => {
68
76
 
69
77
  expect(activeNames).toEqual(expectedNames);
70
78
  expect(activeNames.filter((name) => name === "recall")).toHaveLength(1);
71
- expect(activeTools.length).toBe(11);
79
+ expect(activeTools.length).toBe(19);
72
80
  });
73
81
  });
@@ -3029,69 +3029,6 @@ describe("AnthropicProvider - internal attachment id", () => {
3029
3029
  });
3030
3030
  });
3031
3031
 
3032
- // ---------------------------------------------------------------------------
3033
- // Tests — Orphaned UTF-16 surrogate sanitization
3034
- // ---------------------------------------------------------------------------
3035
-
3036
- describe("AnthropicProvider — surrogate sanitization", () => {
3037
- let provider: AnthropicProvider;
3038
-
3039
- beforeEach(() => {
3040
- lastStreamParams = null;
3041
- provider = new AnthropicProvider("sk-ant-test", "claude-sonnet-4-6");
3042
- });
3043
-
3044
- test("strips orphaned high surrogate from a tool result before sending", async () => {
3045
- // An orphaned high surrogate — the exact shape that triggers Anthropic's
3046
- // "no low surrogate in string" 400. The mock's JSON.parse(JSON.stringify)
3047
- // on line ~44 would throw if sanitization didn't happen.
3048
- const LONE_HIGH = "\uD83C";
3049
- const messages: Message[] = [
3050
- toolUseMsg("tu1", "bash"),
3051
- toolResultMsg("tu1", `shell output ${LONE_HIGH} more output`),
3052
- userMsg("what happened?"),
3053
- ];
3054
-
3055
- await provider.sendMessage(messages);
3056
-
3057
- const sent = lastStreamParams!.messages as Array<{
3058
- role: string;
3059
- content: Array<{ type: string; content?: string; text?: string }>;
3060
- }>;
3061
- // Find the tool_result block in the captured payload and assert no orphans.
3062
- const toolResult = sent
3063
- .flatMap((m) => m.content)
3064
- .find((b) => b.type === "tool_result");
3065
- expect(toolResult).toBeDefined();
3066
- expect(toolResult!.content).toBeDefined();
3067
- const content = toolResult!.content as string;
3068
- for (let i = 0; i < content.length; i++) {
3069
- const code = content.charCodeAt(i);
3070
- if (code >= 0xd800 && code <= 0xdbff) {
3071
- const next = i + 1 < content.length ? content.charCodeAt(i + 1) : 0;
3072
- expect(next >= 0xdc00 && next <= 0xdfff).toBe(true);
3073
- i++;
3074
- } else {
3075
- expect(code < 0xdc00 || code > 0xdfff).toBe(true);
3076
- }
3077
- }
3078
- });
3079
-
3080
- test("clean payloads are not copied unnecessarily", async () => {
3081
- // When there are no orphans, the sanitizer should be a no-op. We can't
3082
- // easily assert reference equality through the mock boundary (the mock
3083
- // JSON-round-trips params for capture), but we can at least confirm the
3084
- // call succeeds without error on ordinary payloads containing valid
3085
- // surrogate pairs (emoji).
3086
- const EMOJI = "\uD83C\uDF89";
3087
- await provider.sendMessage([userMsg(`hello ${EMOJI} world`)]);
3088
- const sent = lastStreamParams!.messages as Array<{
3089
- content: Array<{ text?: string }>;
3090
- }>;
3091
- expect(sent[0].content[0].text).toContain(EMOJI);
3092
- });
3093
- });
3094
-
3095
3032
  // ---------------------------------------------------------------------------
3096
3033
  // Haiku model gating
3097
3034
  // ---------------------------------------------------------------------------
@@ -112,6 +112,12 @@ describe("compileApp", () => {
112
112
  const html = await readFile(join(appDir, "dist", "index.html"), "utf-8");
113
113
  expect(html).toContain('src="main.js"');
114
114
  expect(html).toContain('type="module"');
115
+
116
+ const fingerprint = JSON.parse(
117
+ await readFile(join(appDir, "dist", ".source-fingerprint.json"), "utf-8"),
118
+ ) as { algorithm: string; files: Record<string, string> };
119
+ expect(fingerprint.algorithm).toBe("sha256");
120
+ expect(fingerprint.files["src/main.tsx"]).toMatch(/^[0-9a-f]{64}$/);
115
121
  });
116
122
 
117
123
  test("compiles preact JSX correctly", async () => {
@@ -591,8 +591,11 @@ describe("forwardAppControlProxyTool", () => {
591
591
  ctx,
592
592
  );
593
593
  expect(result.isError).toBe(true);
594
- expect(result.content).toContain("no proxy resolver available");
595
- expect(result.content).toContain("app_control_click");
594
+ expect(result.content).toContain(
595
+ "The Vellum desktop app is needed to control apps on your computer",
596
+ );
597
+ expect(result.content).toContain("https://www.vellum.ai/downloads");
598
+ expect(result.content).not.toContain("app_control_click");
596
599
  });
597
600
 
598
601
  test("delegates to proxy resolver when available", async () => {
@@ -9,15 +9,13 @@ import { describe, expect, test } from "bun:test";
9
9
  * This prevents regressions where new code bypasses the dirName-based path
10
10
  * resolution and constructs UUID-based paths directly.
11
11
  *
12
- * Allowlist: only app-store.ts itself, app-source-watcher.ts (uses getAppsDir
13
- * for the fs.watch root, not for per-app paths), and workspace migrations
12
+ * Allowlist: only app-store.ts itself and workspace migrations
14
13
  * (self-contained, don't import from app-store).
15
14
  */
16
15
 
17
16
  /** Files that are permitted to import getAppsDir. */
18
17
  const ALLOWLIST = new Set([
19
18
  "assistant/src/apps/app-store.ts", // defines getAppsDir
20
- "assistant/src/daemon/app-source-watcher.ts", // uses getAppsDir for recursive fs.watch root, not per-app paths
21
19
  "assistant/src/tools/filesystem/write.ts", // uses getAppsDir as an exemption root for the artifact-HTML guard, not per-app paths
22
20
  ]);
23
21
 
@@ -125,7 +125,10 @@ describe("AssistantEventHub — machineName", () => {
125
125
  });
126
126
  });
127
127
 
128
- describe("window capture negotiation", () => {
128
+ describe.each([
129
+ ["x-vellum-cu-window-capture", "host_cu_window_capture"],
130
+ ["x-vellum-cu-sequence", "host_cu_sequence"],
131
+ ] as const)("%s negotiation", (header, capability) => {
129
132
  test.each([
130
133
  ["macos", undefined, false],
131
134
  ["macos", "0", false],
@@ -145,18 +148,14 @@ describe("window capture negotiation", () => {
145
148
  headers: {
146
149
  "x-vellum-client-id": "client-1",
147
150
  "x-vellum-interface-id": interfaceId,
148
- ...(advertised
149
- ? { "x-vellum-cu-window-capture": advertised }
150
- : {}),
151
+ ...(advertised ? { [header]: advertised } : {}),
151
152
  },
152
153
  abortSignal: ac.signal,
153
154
  },
154
155
  { hub },
155
156
  );
156
157
  expect(
157
- hub
158
- .getClientById("client-1")
159
- ?.capabilities.includes("host_cu_window_capture"),
158
+ hub.getClientById("client-1")?.capabilities.includes(capability),
160
159
  ).toBe(supported);
161
160
  } finally {
162
161
  ac.abort();
@@ -690,3 +690,47 @@ test("window requests never reach an older overlapping connection with the same
690
690
  supported.dispose();
691
691
  }
692
692
  });
693
+
694
+ test("batched action requests never reach an older overlapping connection with the same device ID", async () => {
695
+ const receivedLegacy: unknown[] = [];
696
+ const receivedSupported: unknown[] = [];
697
+ const legacy = assistantEventHub.subscribe({
698
+ type: "client",
699
+ clientId: "sequence-client",
700
+ interfaceId: "macos",
701
+ capabilities: ["host_cu"],
702
+ callback: (event) => {
703
+ receivedLegacy.push(event);
704
+ },
705
+ });
706
+ const supported = assistantEventHub.subscribe({
707
+ type: "client",
708
+ clientId: "sequence-client",
709
+ interfaceId: "macos",
710
+ capabilities: ["host_cu", "host_cu_sequence"],
711
+ callback: (event) => {
712
+ receivedSupported.push(event);
713
+ },
714
+ });
715
+ try {
716
+ broadcastMessage(
717
+ {
718
+ type: "host_cu_request",
719
+ requestId: "sequence-request",
720
+ conversationId: "sequence-session",
721
+ toolName: "computer_use_sequence",
722
+ input: { actions: [{ action: "key", key: "cmd+n" }] },
723
+ stepNumber: 1,
724
+ targetClientId: "sequence-client",
725
+ },
726
+ "sequence-session",
727
+ { targetClientId: "sequence-client" },
728
+ );
729
+ await new Promise((resolve) => setTimeout(resolve, 0));
730
+ expect(receivedLegacy).toHaveLength(0);
731
+ expect(receivedSupported).toHaveLength(1);
732
+ } finally {
733
+ legacy.dispose();
734
+ supported.dispose();
735
+ }
736
+ });
@@ -29,7 +29,7 @@ const manifestPath = resolve(
29
29
  const manifest = JSON.parse(readFileSync(manifestPath, "utf-8"));
30
30
 
31
31
  describe("computer-use skill manifest regression", () => {
32
- test("manifest has exactly 11 tools", () => {
32
+ test("manifest has exactly 12 tools", () => {
33
33
  expect(manifest.tools).toHaveLength(COMPUTER_USE_TOOL_COUNT);
34
34
  });
35
35
 
@@ -13,8 +13,11 @@ describe("forwardComputerUseProxyTool", () => {
13
13
  );
14
14
 
15
15
  expect(result.isError).toBe(true);
16
- expect(result.content).toContain("no proxy resolver available");
17
- expect(result.content).toContain("computer_use_click");
16
+ expect(result.content).toContain(
17
+ "The Vellum desktop app is needed to view or control your screen",
18
+ );
19
+ expect(result.content).toContain("https://www.vellum.ai/downloads");
20
+ expect(result.content).not.toContain("computer_use_click");
18
21
  });
19
22
 
20
23
  test("forwards to proxyToolResolver when present", async () => {
@@ -37,8 +37,8 @@ const ctx: ToolContext = {
37
37
  // ── Tool definitions ────────────────────────────────────────────────
38
38
 
39
39
  describe("computer-use tool definitions", () => {
40
- test("allComputerUseTools contains 11 tools", () => {
41
- expect(allComputerUseTools.length).toBe(11);
40
+ test("allComputerUseTools contains 12 tools", () => {
41
+ expect(allComputerUseTools.length).toBe(12);
42
42
  });
43
43
 
44
44
  test("all tools belong to computer-use category", () => {
@@ -104,7 +104,10 @@ describe("computer_use_click (unified)", () => {
104
104
  test("execute returns isError when no proxy resolver is configured", async () => {
105
105
  const result = await computerUseClickTool.execute({}, ctx);
106
106
  expect(result.isError).toBe(true);
107
- expect(result.content).toMatch(/No proxy resolver/);
107
+ expect(result.content).toContain(
108
+ "The Vellum desktop app is needed to view or control your screen",
109
+ );
110
+ expect(result.content).toContain("https://www.vellum.ai/downloads");
108
111
  });
109
112
  });
110
113
 
@@ -119,7 +122,10 @@ describe("computer_use_type_text", () => {
119
122
  test("execute returns isError when no proxy resolver is configured", async () => {
120
123
  const result = await computerUseTypeTextTool.execute({}, ctx);
121
124
  expect(result.isError).toBe(true);
122
- expect(result.content).toMatch(/No proxy resolver/);
125
+ expect(result.content).toContain(
126
+ "The Vellum desktop app is needed to view or control your screen",
127
+ );
128
+ expect(result.content).toContain("https://www.vellum.ai/downloads");
123
129
  });
124
130
  });
125
131
 
@@ -134,7 +140,10 @@ describe("computer_use_key", () => {
134
140
  test("execute returns isError when no proxy resolver is configured", async () => {
135
141
  const result = await computerUseKeyTool.execute({}, ctx);
136
142
  expect(result.isError).toBe(true);
137
- expect(result.content).toMatch(/No proxy resolver/);
143
+ expect(result.content).toContain(
144
+ "The Vellum desktop app is needed to view or control your screen",
145
+ );
146
+ expect(result.content).toContain("https://www.vellum.ai/downloads");
138
147
  });
139
148
  });
140
149
 
@@ -241,8 +250,11 @@ describe("forwardComputerUseProxyTool", () => {
241
250
  );
242
251
 
243
252
  expect(result.isError).toBe(true);
244
- expect(result.content).toContain("no proxy resolver available");
245
- expect(result.content).toContain("computer_use_click");
253
+ expect(result.content).toContain(
254
+ "The Vellum desktop app is needed to view or control your screen",
255
+ );
256
+ expect(result.content).toContain("https://www.vellum.ai/downloads");
257
+ expect(result.content).not.toContain("computer_use_click");
246
258
  });
247
259
 
248
260
  test("delegates to proxy resolver when available", async () => {
@@ -130,7 +130,7 @@ describe("getSchemaAtPath", () => {
130
130
  expect(properties).toBeDefined();
131
131
  expect(properties.enabled).toBeDefined();
132
132
  expect(properties.voice).toBeDefined();
133
- expect(properties.safety).toBeDefined();
133
+ expect(properties.disclosure).toBeDefined();
134
134
  });
135
135
 
136
136
  test("navigates through .transform() wrappers (ingress → object schema)", () => {
@@ -230,7 +230,7 @@ describe("z.toJSONSchema integration", () => {
230
230
  expect(properties).toBeDefined();
231
231
  expect(properties!.enabled).toBeDefined();
232
232
  expect(properties!.voice).toBeDefined();
233
- expect(properties!.safety).toBeDefined();
233
+ expect(properties!.disclosure).toBeDefined();
234
234
  });
235
235
 
236
236
  test("sub-schema at a leaf like llm.profileSession.defaultTtlSeconds produces integer schema", () => {