@vellumai/assistant 0.12.1 → 0.12.2-staging.1

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 (548) 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/openapi.yaml +327 -52
  6. package/package.json +3 -1
  7. package/scripts/smoke-desktop-window-theme.ts +186 -0
  8. package/src/__tests__/always-loaded-tools-guard.test.ts +18 -10
  9. package/src/__tests__/anthropic-provider.test.ts +0 -63
  10. package/src/__tests__/app-compiler.test.ts +6 -0
  11. package/src/__tests__/app-control-tool-schemas.test.ts +5 -2
  12. package/src/__tests__/app-dir-path-guard.test.ts +1 -3
  13. package/src/__tests__/assistant-event-hub-machine-name.test.ts +6 -7
  14. package/src/__tests__/assistant-event-hub.test.ts +44 -0
  15. package/src/__tests__/computer-use-skill-manifest-regression.test.ts +1 -1
  16. package/src/__tests__/computer-use-skill-proxy-bridge.test.ts +5 -2
  17. package/src/__tests__/computer-use-tools.test.ts +19 -7
  18. package/src/__tests__/config-schema-cmd.test.ts +2 -2
  19. package/src/__tests__/config-schema.test.ts +28 -29
  20. package/src/__tests__/config-watcher.test.ts +23 -8
  21. package/src/__tests__/connection-model-compat.test.ts +2 -2
  22. package/src/__tests__/conversation-key-store-disk-view.test.ts +1 -1
  23. package/src/__tests__/conversation-pairing.test.ts +26 -0
  24. package/src/__tests__/conversation-process-app-control-preactivation.test.ts +4 -10
  25. package/src/__tests__/conversation-queue.test.ts +48 -207
  26. package/src/__tests__/conversation-retry-discard.test.ts +54 -1
  27. package/src/__tests__/conversation-skill-tools.test.ts +27 -0
  28. package/src/__tests__/conversation-surfaces-app-control.test.ts +8 -3
  29. package/src/__tests__/conversation-surfaces-task-progress.test.ts +67 -0
  30. package/src/__tests__/conversation-title-service.test.ts +14 -10
  31. package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +3 -5
  32. package/src/__tests__/conversation-tool-setup-attribution.test.ts +51 -0
  33. package/src/__tests__/credential-record-retire.test.ts +171 -1
  34. package/src/__tests__/credential-routes.test.ts +212 -3
  35. package/src/__tests__/credential-security-invariants.test.ts +4 -2
  36. package/src/__tests__/cu-unified-flow.test.ts +8 -2
  37. package/src/__tests__/document-sync-tags.test.ts +25 -0
  38. package/src/__tests__/drain-kick-guard.test.ts +0 -2
  39. package/src/__tests__/drain-requeue-on-contention.test.ts +0 -6
  40. package/src/__tests__/evict-conversations-for-reload.test.ts +1 -1
  41. package/src/__tests__/git-porcelain.test.ts +47 -0
  42. package/src/__tests__/heartbeat-service.test.ts +56 -40
  43. package/src/__tests__/helpers/set-workspace-mcp.ts +11 -0
  44. package/src/__tests__/host-bash-proxy.test.ts +26 -45
  45. package/src/__tests__/host-browser-proxy.test.ts +6 -17
  46. package/src/__tests__/host-cu-proxy.test.ts +539 -0
  47. package/src/__tests__/host-file-proxy-targeted.test.ts +23 -0
  48. package/src/__tests__/host-file-proxy.test.ts +11 -23
  49. package/src/__tests__/host-transfer-proxy-targeted.test.ts +30 -9
  50. package/src/__tests__/list-messages-camera-frame.test.ts +121 -0
  51. package/src/__tests__/llm-catalog-parity.test.ts +25 -0
  52. package/src/__tests__/mcp-auth-routes.test.ts +6 -9
  53. package/src/__tests__/mcp-config-secret-boundary.test.ts +78 -136
  54. package/src/__tests__/mcp-health-check.test.ts +8 -11
  55. package/src/__tests__/mcp-list-plugin-servers.test.ts +8 -10
  56. package/src/__tests__/message-deleted-hook-dispatch.test.ts +119 -0
  57. package/src/__tests__/messages-after-tiebreaker.test.ts +91 -0
  58. package/src/__tests__/messages-read-boundary-guard.test.ts +1 -1
  59. package/src/__tests__/messaging-send-tool.test.ts +355 -548
  60. package/src/__tests__/model-intents.test.ts +3 -0
  61. package/src/__tests__/notification-vellum-adapter.test.ts +85 -2
  62. package/src/__tests__/oauth-commands-routes.test.ts +113 -0
  63. package/src/__tests__/oauth-provider-profiles.test.ts +18 -0
  64. package/src/__tests__/openai-provider.test.ts +1 -0
  65. package/src/__tests__/outlook-messaging-provider.test.ts +6 -6
  66. package/src/__tests__/platform-callback-registration.test.ts +8 -16
  67. package/src/__tests__/platform-client-verify-credential.test.ts +2 -0
  68. package/src/__tests__/plugin-import-boundary-guard.test.ts +14 -0
  69. package/src/__tests__/qdrant-manager.test.ts +132 -0
  70. package/src/__tests__/resolve-app.test.ts +135 -0
  71. package/src/__tests__/scaffold-managed-skill-tool.test.ts +229 -6
  72. package/src/__tests__/script-proxy-certs.test.ts +35 -0
  73. package/src/__tests__/service-account-token.test.ts +247 -0
  74. package/src/__tests__/skill-feature-flags-integration.test.ts +1 -1
  75. package/src/__tests__/skill-feature-flags.test.ts +2 -2
  76. package/src/__tests__/skills.test.ts +9 -4
  77. package/src/__tests__/source-fingerprint.test.ts +184 -0
  78. package/src/__tests__/subagent-tool-gate-mode.test.ts +19 -3
  79. package/src/__tests__/subagent-tools.test.ts +3 -2
  80. package/src/__tests__/telephony-tts-guard.test.ts +38 -3
  81. package/src/__tests__/test-support/computer-use-skill-harness.ts +3 -2
  82. package/src/__tests__/unicode.test.ts +13 -0
  83. package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +4 -0
  84. package/src/__tests__/watch-retro-tool-availability.test.ts +8 -17
  85. package/src/__tests__/workspace-git-service.test.ts +26 -0
  86. package/src/__tests__/workspace-migration-154-repair-retired-codex-gpt-5-4-model-ids.test.ts +336 -0
  87. package/src/acp/__tests__/agent-process.test.ts +258 -4
  88. package/src/acp/__tests__/auth-required.test.ts +96 -0
  89. package/src/acp/__tests__/client-handler.test.ts +90 -2
  90. package/src/acp/__tests__/helpers/acp-model-option.ts +51 -0
  91. package/src/acp/__tests__/session-manager-persistence.test.ts +5 -1
  92. package/src/acp/__tests__/session-manager-resume.test.ts +270 -6
  93. package/src/acp/__tests__/session-manager-usage.test.ts +4 -2
  94. package/src/acp/__tests__/session-manager.test.ts +895 -4
  95. package/src/acp/agent-process.test.ts +4 -1
  96. package/src/acp/agent-process.ts +96 -10
  97. package/src/acp/auth-required.ts +50 -1
  98. package/src/acp/auto-install.test.ts +9 -7
  99. package/src/acp/client-handler.ts +16 -3
  100. package/src/acp/model-config.test.ts +166 -0
  101. package/src/acp/model-config.ts +138 -0
  102. package/src/acp/resolve-agent.test.ts +220 -6
  103. package/src/acp/resolve-agent.ts +88 -23
  104. package/src/acp/session-manager.test.ts +196 -3
  105. package/src/acp/session-manager.ts +441 -18
  106. package/src/acp/types.ts +50 -5
  107. package/src/agent/loop.ts +1 -0
  108. package/src/api/events/acp-session-model-update.test.ts +88 -0
  109. package/src/api/events/acp-session-model-update.ts +46 -0
  110. package/src/api/events/app-files-changed.ts +4 -3
  111. package/src/api/events/notification-intent.ts +2 -0
  112. package/src/api/events/user-message-echo.ts +7 -1
  113. package/src/api/index.ts +6 -0
  114. package/src/api/responses/conversation-message.ts +5 -0
  115. package/src/apps/app-store.ts +1 -1
  116. package/src/apps/resolve-app.ts +81 -0
  117. package/src/apps/source-fingerprint.ts +266 -0
  118. package/src/avatar/identity-avatar.ts +7 -2
  119. package/src/bundler/app-compiler.ts +15 -0
  120. package/src/calls/__tests__/barge-in-guard.test.ts +81 -0
  121. package/src/{__tests__ → calls/__tests__}/call-controller.test.ts +503 -82
  122. package/src/{__tests__ → calls/__tests__}/media-stream-audio-transcode.test.ts +1 -1
  123. package/src/{__tests__ → calls/__tests__}/media-stream-output.test.ts +37 -8
  124. package/src/{__tests__ → calls/__tests__}/media-stream-parser.test.ts +1 -1
  125. package/src/{__tests__ → calls/__tests__}/media-stream-server-integration.test.ts +150 -57
  126. package/src/{__tests__ → calls/__tests__}/media-stream-stt-session.test.ts +5 -5
  127. package/src/{__tests__ → calls/__tests__}/media-turn-detector.test.ts +1 -1
  128. package/src/{live-voice → calls}/__tests__/progress-narration.test.ts +4 -4
  129. package/src/{live-voice → calls}/__tests__/progress-phrases.test.ts +1 -1
  130. package/src/calls/__tests__/voice-control-protocol.test.ts +58 -25
  131. package/src/calls/__tests__/voice-leg-coordinator.test.ts +229 -0
  132. package/src/calls/__tests__/voice-progress-cadence.test.ts +274 -0
  133. package/src/{__tests__/voice-session-bridge.test.ts → calls/__tests__/voice-session-bridge-turn-flow.test.ts} +20 -12
  134. package/src/calls/__tests__/voice-session-bridge.test.ts +37 -1
  135. package/src/calls/__tests__/voice-triage-escalate.test.ts +105 -0
  136. package/src/calls/barge-in-guard.ts +118 -0
  137. package/src/calls/call-constants.ts +24 -4
  138. package/src/calls/call-controller.ts +499 -199
  139. package/src/calls/call-transport.ts +16 -0
  140. package/src/calls/media-stream-output.ts +32 -0
  141. package/src/calls/media-stream-server.ts +82 -30
  142. package/src/calls/media-stream-stt-session.ts +15 -0
  143. package/src/{live-voice → calls}/progress-narration.ts +2 -2
  144. package/src/calls/resolve-call-tts-provider.ts +33 -2
  145. package/src/calls/tts-call-strategy.ts +9 -5
  146. package/src/calls/types.ts +2 -0
  147. package/src/calls/voice-control-protocol.ts +53 -21
  148. package/src/calls/voice-leg-coordinator.ts +189 -0
  149. package/src/calls/voice-progress-cadence.ts +423 -0
  150. package/src/calls/voice-session-bridge.ts +59 -46
  151. package/src/calls/voice-triage-escalate.ts +175 -56
  152. package/src/cli/commands/__tests__/apps.test.ts +245 -0
  153. package/src/cli/commands/__tests__/bash.test.ts +53 -0
  154. package/src/cli/commands/__tests__/roadmap.help.test.ts +19 -0
  155. package/src/cli/commands/apps.help.ts +67 -13
  156. package/src/cli/commands/apps.ts +183 -0
  157. package/src/cli/commands/bash.help.ts +8 -13
  158. package/src/cli/commands/bash.ts +7 -25
  159. package/src/cli/commands/channels/__tests__/send.test.ts +218 -0
  160. package/src/cli/commands/channels/index.help.ts +70 -2
  161. package/src/cli/commands/channels/index.ts +16 -3
  162. package/src/cli/commands/channels/send.ts +128 -0
  163. package/src/cli/commands/credentials.help.ts +6 -2
  164. package/src/cli/commands/credentials.ts +2 -2
  165. package/src/cli/commands/mcp.help.ts +8 -8
  166. package/src/cli/commands/mcp.ts +1 -1
  167. package/src/cli/commands/roadmap.help.ts +5 -1
  168. package/src/cli/commands/roadmap.ts +1 -1
  169. package/src/cli/lib/bundled-marketplace.json +103 -90
  170. package/src/config/__tests__/default-profile-catalog.test.ts +22 -0
  171. package/src/config/__tests__/memory-retrospective-schema.test.ts +15 -1
  172. package/src/config/__tests__/platform-identity.test.ts +255 -0
  173. package/src/config/__tests__/platform-rehydration.test.ts +99 -9
  174. package/src/config/acp-agent-write.ts +43 -0
  175. package/src/config/acp-defaults.test.ts +13 -3
  176. package/src/config/acp-defaults.ts +23 -6
  177. package/src/config/acp-schema.test.ts +81 -0
  178. package/src/config/acp-schema.ts +30 -2
  179. package/src/config/bundled-skills/acp/SKILL.md +22 -14
  180. package/src/config/bundled-skills/acp/TOOLS.json +5 -1
  181. package/src/config/bundled-skills/app-builder/SKILL.md +12 -9
  182. package/src/config/bundled-skills/app-builder/references/CUSTOM_ROUTES.md +1 -1
  183. package/src/config/bundled-skills/computer-use/SKILL.md +20 -2
  184. package/src/config/bundled-skills/computer-use/TOOLS.json +99 -0
  185. package/src/config/bundled-skills/computer-use/tools/computer-use-sequence.ts +12 -0
  186. package/src/config/bundled-skills/media-processing/services/preprocess.ts +2 -1
  187. package/src/config/bundled-skills/media-processing/services/processing-pipeline.ts +2 -1
  188. package/src/config/bundled-skills/media-processing/tools/generate-clip.ts +2 -1
  189. package/src/config/bundled-skills/messaging/SKILL.md +3 -3
  190. package/src/config/bundled-skills/messaging/TOOLS.json +3 -3
  191. package/src/config/bundled-skills/messaging/tools/messaging-send.ts +67 -139
  192. package/src/config/bundled-skills/phone-calls/references/TRANSCRIPTS.md +1 -1
  193. package/src/config/bundled-skills/playbooks/tools/playbook-create.ts +2 -1
  194. package/src/config/bundled-skills/playbooks/tools/playbook-update.ts +2 -1
  195. package/src/config/bundled-skills/schedule/SKILL.md +3 -4
  196. package/src/config/bundled-skills/screen-annotation/SKILL.md +8 -1
  197. package/src/config/bundled-skills/screen-annotation/tools/screen-annotation.test.ts +4 -1
  198. package/src/config/bundled-skills/skill-management/TOOLS.json +6 -2
  199. package/src/config/bundled-skills/transcribe/tools/transcribe-media.ts +5 -2
  200. package/src/config/default-profile-catalog.ts +1 -1
  201. package/src/config/env.ts +2 -2
  202. package/src/config/feature-flag-registry.json +24 -12
  203. package/src/config/loader.ts +1 -0
  204. package/src/config/memory-v3-gate.test.ts +31 -0
  205. package/src/config/memory-v3-gate.ts +20 -16
  206. package/src/config/platform-identity.ts +201 -0
  207. package/src/config/platform-rehydration.ts +11 -27
  208. package/src/config/schema.ts +2 -2
  209. package/src/config/schemas/__tests__/live-voice.test.ts +8 -158
  210. package/src/config/schemas/__tests__/voice.test.ts +148 -0
  211. package/src/config/schemas/calls.ts +1 -28
  212. package/src/config/schemas/live-voice.ts +1 -173
  213. package/src/config/schemas/mcp.ts +1 -1
  214. package/src/config/schemas/memory-retrospective.ts +10 -0
  215. package/src/config/schemas/services.ts +8 -0
  216. package/src/config/schemas/skills.ts +0 -14
  217. package/src/config/schemas/voice.ts +150 -0
  218. package/src/credential-execution/process-manager.test.ts +18 -19
  219. package/src/credential-health/credential-health-service.ts +11 -17
  220. package/src/daemon/__tests__/conversation-tool-setup.test.ts +66 -121
  221. package/src/daemon/__tests__/plugin-mcp-reconcile.test.ts +4 -1
  222. package/src/daemon/__tests__/skill-memory-refresh-mtime.test.ts +133 -0
  223. package/src/daemon/app-change-notify.ts +45 -0
  224. package/src/daemon/config-watcher.ts +13 -194
  225. package/src/daemon/conversation-error.ts +3 -2
  226. package/src/daemon/conversation-media-retry.ts +2 -1
  227. package/src/daemon/conversation-process.ts +35 -64
  228. package/src/daemon/conversation-runtime-assembly.ts +2 -1
  229. package/src/daemon/conversation-skill-tools.ts +13 -31
  230. package/src/daemon/conversation-store.ts +1 -1
  231. package/src/daemon/conversation-surfaces.ts +15 -9
  232. package/src/daemon/conversation-tool-setup.ts +37 -43
  233. package/src/daemon/conversation.ts +0 -3
  234. package/src/daemon/dictation-profile-store.ts +2 -1
  235. package/src/daemon/handlers/shared.ts +2 -1
  236. package/src/daemon/handlers/skills.ts +6 -3
  237. package/src/daemon/host-bash-proxy.ts +8 -12
  238. package/src/daemon/host-browser-proxy.ts +15 -1
  239. package/src/daemon/host-cu-proxy.ts +186 -19
  240. package/src/daemon/host-file-proxy.ts +8 -10
  241. package/src/daemon/host-proxy-preactivation.ts +2 -1
  242. package/src/daemon/host-transfer-proxy.ts +14 -18
  243. package/src/daemon/lifecycle.ts +0 -5
  244. package/src/daemon/mcp-reload-service.ts +5 -5
  245. package/src/daemon/message-types/sync.ts +1 -0
  246. package/src/daemon/orphan-reaper.ts +1 -1
  247. package/src/daemon/providers-setup.ts +1 -1
  248. package/src/daemon/reaction-history-render.ts +2 -1
  249. package/src/daemon/shutdown-handlers.ts +1 -9
  250. package/src/daemon/skill-memory-refresh.ts +64 -0
  251. package/src/daemon/tool-side-effects.ts +7 -18
  252. package/src/desktop/__tests__/fake-desktop.ts +122 -0
  253. package/src/desktop/desktop-chrome-policy.test.ts +79 -0
  254. package/src/desktop/desktop-chrome-policy.ts +47 -0
  255. package/src/desktop/desktop-chrome-session.ts +37 -0
  256. package/src/desktop/desktop-dependencies.test.ts +102 -0
  257. package/src/desktop/desktop-dependencies.ts +308 -0
  258. package/src/desktop/desktop-feature.test.ts +18 -0
  259. package/src/desktop/desktop-feature.ts +19 -0
  260. package/src/desktop/desktop-panel-config.test.ts +135 -0
  261. package/src/desktop/desktop-panel-config.ts +149 -0
  262. package/src/desktop/desktop-session-manager.test.ts +730 -0
  263. package/src/desktop/desktop-session-manager.ts +850 -0
  264. package/src/desktop/desktop-stream-bridge.test.ts +395 -0
  265. package/src/desktop/desktop-stream-bridge.ts +214 -0
  266. package/src/desktop/desktop-wallpaper.test.ts +191 -0
  267. package/src/desktop/desktop-wallpaper.ts +113 -0
  268. package/src/desktop/desktop-window-drag.ts +177 -0
  269. package/src/desktop/desktop-window-manager-config.test.ts +230 -0
  270. package/src/desktop/desktop-window-manager-config.ts +238 -0
  271. package/src/desktop/desktop-window-theme.ts +170 -0
  272. package/src/heartbeat/heartbeat-service.ts +21 -3
  273. package/src/home/__tests__/feed-writer.test.ts +22 -0
  274. package/src/home/feed-writer.ts +11 -2
  275. package/src/hooks/types.ts +33 -0
  276. package/src/i18n/AGENTS.md +22 -0
  277. package/src/i18n/__tests__/i18n.test.ts +108 -0
  278. package/src/i18n/index.ts +16 -0
  279. package/src/i18n/locales.ts +93 -0
  280. package/src/i18n/messages.ts +61 -0
  281. package/src/i18n/title.ts +25 -0
  282. package/src/inbound/platform-callback-registration.ts +4 -5
  283. package/src/live-voice/__tests__/live-voice-metrics.test.ts +0 -3
  284. package/src/live-voice/__tests__/live-voice-progress.test.ts +15 -15
  285. package/src/live-voice/__tests__/live-voice-sight-frame-echo.test.ts +238 -0
  286. package/src/live-voice/__tests__/live-voice-vad.test.ts +2 -2
  287. package/src/live-voice/__tests__/runtime-websocket-shell.test.ts +13 -69
  288. package/src/live-voice/live-voice-photo.ts +25 -6
  289. package/src/live-voice/live-voice-session.ts +213 -693
  290. package/src/live-voice/protocol.ts +0 -2
  291. package/src/mcp/__tests__/effective-config.test.ts +2 -2
  292. package/src/mcp/__tests__/workspace-mcp-config.test.ts +135 -0
  293. package/src/mcp/effective-config.ts +3 -3
  294. package/src/mcp/mcp-header-store.ts +29 -45
  295. package/src/mcp/spec-schema.ts +111 -0
  296. package/src/mcp/startup.ts +8 -4
  297. package/src/mcp/workspace-mcp-config.ts +188 -0
  298. package/src/messaging/provider.ts +10 -3
  299. package/src/messaging/providers/__tests__/proactive-address.test.ts +95 -0
  300. package/src/messaging/providers/callback-routing.ts +18 -0
  301. package/src/messaging/providers/channel-transport.ts +56 -0
  302. package/src/messaging/providers/discord/transport.ts +17 -0
  303. package/src/messaging/providers/slack/__tests__/adapter-token-routing.test.ts +6 -17
  304. package/src/messaging/providers/slack/adapter.ts +7 -44
  305. package/src/messaging/providers/slack/transport.ts +16 -0
  306. package/src/messaging/providers/telegram-bot/adapter.ts +1 -48
  307. package/src/messaging/providers/telegram-bot/client.ts +0 -26
  308. package/src/messaging/providers/telegram-bot/transport.ts +20 -0
  309. package/src/messaging/providers/whatsapp/adapter.ts +1 -48
  310. package/src/messaging/providers/whatsapp/transport.ts +18 -0
  311. package/src/monitoring/__tests__/workspace-git-heartbeat.test.ts +8 -0
  312. package/src/notifications/__tests__/assistant-reply-producer.test.ts +55 -0
  313. package/src/notifications/__tests__/guardian-feed-projection.test.ts +158 -2
  314. package/src/notifications/__tests__/home-feed-side-effect.test.ts +153 -3
  315. package/src/notifications/__tests__/schedule-result-producer.test.ts +99 -3
  316. package/src/notifications/adapters/macos.ts +3 -0
  317. package/src/notifications/assistant-reply-producer.ts +8 -3
  318. package/src/notifications/conversation-pairing.ts +36 -16
  319. package/src/notifications/delivered-post-record.ts +11 -1
  320. package/src/notifications/guardian-feed-projection.ts +125 -5
  321. package/src/notifications/home-feed-side-effect.ts +55 -7
  322. package/src/notifications/schedule-result-producer.ts +66 -22
  323. package/src/oauth/AGENTS.md +2 -0
  324. package/src/oauth/__tests__/seed-providers-managed.test.ts +54 -0
  325. package/src/oauth/byo-connection.test.ts +105 -0
  326. package/src/oauth/byo-connection.ts +36 -6
  327. package/src/oauth/connection-resolver.test.ts +73 -0
  328. package/src/oauth/connection-resolver.ts +95 -2
  329. package/src/oauth/scope-utils.ts +24 -0
  330. package/src/oauth/seed-providers.ts +204 -25
  331. package/src/outbound-proxy/certs.ts +3 -5
  332. package/src/permissions/checker.test.ts +11 -6
  333. package/src/persistence/compaction-log-store-clickhouse.ts +3 -3
  334. package/src/persistence/conversation-crud.ts +71 -63
  335. package/src/persistence/conversation-lineage.ts +12 -4
  336. package/src/persistence/conversation-queries.ts +2 -2
  337. package/src/persistence/conversation-title-placeholders.ts +23 -0
  338. package/src/persistence/conversation-title-service.ts +9 -26
  339. package/src/persistence/embeddings/qdrant-manager.ts +163 -18
  340. package/src/persistence/llm-request-log-sink-clickhouse.ts +3 -3
  341. package/src/persistence/llm-request-log-source-clickhouse.ts +3 -3
  342. package/src/persistence/message-cursor.ts +78 -0
  343. package/src/persistence/message-reads.ts +30 -0
  344. package/src/persistence/migrations/157-invite-contact-id.ts +18 -6
  345. package/src/persistence/migrations/__tests__/157-invite-contact-id.test.ts +149 -0
  346. package/src/persistence/schema/memory-core.ts +5 -0
  347. package/src/platform/client.test.ts +4 -2
  348. package/src/platform/client.ts +2 -10
  349. package/src/plugin-api/constants.ts +2 -0
  350. package/src/plugin-api/index.ts +1 -0
  351. package/src/plugin-api/types.ts +2 -0
  352. package/src/plugins/defaults/index.ts +2 -0
  353. package/src/plugins/defaults/memory/__tests__/memory-retrospective-accounting.test.ts +46 -0
  354. package/src/plugins/defaults/memory/__tests__/memory-retrospective-cursor-backfill.test.ts +118 -0
  355. package/src/plugins/defaults/memory/__tests__/memory-retrospective-cursor-preserve.test.ts +83 -0
  356. package/src/plugins/defaults/memory/__tests__/memory-retrospective-enqueue.test.ts +9 -5
  357. package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +20 -10
  358. package/src/plugins/defaults/memory/__tests__/memory-retrospective-prompt.test.ts +5 -0
  359. package/src/plugins/defaults/memory/__tests__/memory-retrospective-state.test.ts +219 -0
  360. package/src/plugins/defaults/memory/__tests__/memory-retrospective-sweep.test.ts +31 -0
  361. package/src/plugins/defaults/memory/__tests__/memory-retrospective-trigger-check.test.ts +63 -0
  362. package/src/plugins/defaults/memory/__tests__/shutdown-hook.test.ts +4 -0
  363. package/src/plugins/defaults/memory/context-search/agent-runner.ts +3 -2
  364. package/src/plugins/defaults/memory/context-search/format.ts +3 -2
  365. package/src/plugins/defaults/memory/context-search/sources/memory-v2.ts +6 -3
  366. package/src/plugins/defaults/memory/context-search/sources/workspace.ts +3 -2
  367. package/src/plugins/defaults/memory/graph/capability-seed.ts +6 -7
  368. package/src/plugins/defaults/memory/hooks/init.ts +10 -0
  369. package/src/plugins/defaults/memory/hooks/message-deleted.ts +21 -0
  370. package/src/plugins/defaults/memory/hooks/shutdown.ts +2 -0
  371. package/src/plugins/defaults/memory/host-utils.ts +10 -0
  372. package/src/plugins/defaults/memory/jobs-worker.ts +13 -0
  373. package/src/plugins/defaults/memory/memory-retrospective-accounting.ts +34 -60
  374. package/src/plugins/defaults/memory/memory-retrospective-cursor-backfill.ts +126 -0
  375. package/src/plugins/defaults/memory/memory-retrospective-cursor-preserve.ts +79 -0
  376. package/src/plugins/defaults/memory/memory-retrospective-cursor.ts +28 -0
  377. package/src/plugins/defaults/memory/memory-retrospective-enqueue.ts +3 -5
  378. package/src/plugins/defaults/memory/memory-retrospective-job.ts +12 -3
  379. package/src/plugins/defaults/memory/memory-retrospective-prompt.ts +1 -1
  380. package/src/plugins/defaults/memory/memory-retrospective-state.ts +312 -71
  381. package/src/plugins/defaults/memory/memory-retrospective-sweep.ts +2 -1
  382. package/src/plugins/defaults/memory/memory-retrospective-trigger-check.ts +5 -3
  383. package/src/plugins/defaults/memory/skill-md-mtime-poll.ts +9 -0
  384. package/src/plugins/defaults/memory/startup.ts +28 -2
  385. package/src/plugins/defaults/memory/substrate/__tests__/skill-content.test.ts +7 -9
  386. package/src/plugins/defaults/memory/substrate/page-index.ts +6 -1
  387. package/src/plugins/defaults/memory/substrate/skill-content.ts +2 -2
  388. package/src/plugins/defaults/memory/v1/graph/consolidation.ts +4 -2
  389. package/src/plugins/defaults/memory/v1/graph/extraction.ts +4 -2
  390. package/src/plugins/defaults/memory/v1/graph/retriever.ts +4 -1
  391. package/src/plugins/defaults/memory/v2/reranker.ts +6 -1
  392. package/src/plugins/defaults/memory/v3/__tests__/card.test.ts +24 -0
  393. package/src/plugins/defaults/memory/v3/__tests__/pool-select.test.ts +125 -0
  394. package/src/plugins/defaults/memory/v3/__tests__/sections.test.ts +26 -0
  395. package/src/plugins/defaults/memory/v3/__tests__/shadow-plugin.test.ts +30 -0
  396. package/src/plugins/defaults/memory/v3/card.ts +3 -2
  397. package/src/plugins/defaults/memory/v3/pool-select.ts +5 -3
  398. package/src/plugins/defaults/memory/v3/sections.ts +9 -3
  399. package/src/plugins/defaults/memory/v3/shadow-plugin.ts +5 -2
  400. package/src/plugins/defaults/memory/worker.ts +6 -0
  401. package/src/plugins/mcp-servers.ts +15 -75
  402. package/src/providers/__tests__/connection-model-compat.test.ts +3 -3
  403. package/src/providers/__tests__/retry-callsite.test.ts +41 -0
  404. package/src/providers/__tests__/retry-outbound-sanitize.test.ts +176 -0
  405. package/src/providers/anthropic/client.ts +0 -47
  406. package/src/providers/gemini/client.ts +9 -23
  407. package/src/providers/gemini-thought-signature.test.ts +63 -0
  408. package/src/providers/gemini-thought-signature.ts +44 -0
  409. package/src/providers/inference/__tests__/endpoint-probe.test.ts +42 -3
  410. package/src/providers/inference/auth.ts +2 -3
  411. package/src/providers/inference/connection-availability.ts +27 -8
  412. package/src/providers/inference/endpoint-probe.ts +10 -1
  413. package/src/providers/inference/resolve-auth.ts +22 -4
  414. package/src/providers/inference/service-account-token.ts +248 -0
  415. package/src/providers/model-catalog.ts +34 -0
  416. package/src/providers/model-intents.ts +10 -5
  417. package/src/providers/openai/__tests__/chat-completions-output-token-limit.test.ts +141 -0
  418. package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +146 -18
  419. package/src/providers/openai/__tests__/chat-completions-provider-thought-signature.test.ts +613 -0
  420. package/src/providers/openai/__tests__/google-thought-signature.test.ts +235 -0
  421. package/src/providers/openai/__tests__/tool-choice-mapping.test.ts +83 -1
  422. package/src/providers/openai/chat-completions-provider.ts +212 -79
  423. package/src/providers/openai/codex-models.ts +0 -4
  424. package/src/providers/openai/google-thought-signature.ts +320 -0
  425. package/src/providers/opencode/client.test.ts +73 -4
  426. package/src/providers/opencode/client.ts +60 -3
  427. package/src/providers/openrouter/client.ts +20 -0
  428. package/src/providers/outbound-request-sanitize.ts +96 -0
  429. package/src/providers/retry.ts +30 -19
  430. package/src/providers/unparseable-tool-args.ts +5 -1
  431. package/src/runtime/AGENTS.md +3 -1
  432. package/src/runtime/__tests__/channel-send.test.ts +443 -0
  433. package/src/runtime/__tests__/desktop-stream-upgrade.test.ts +89 -0
  434. package/src/runtime/__tests__/host-observe.test.ts +40 -1
  435. package/src/runtime/__tests__/live-voice-upgrade.test.ts +58 -0
  436. package/src/runtime/__tests__/runtime-ws-test-utils.ts +72 -0
  437. package/src/runtime/__tests__/watch-stream-upgrade.test.ts +59 -0
  438. package/src/runtime/agent-wake.ts +2 -1
  439. package/src/runtime/assistant-event-hub.ts +21 -3
  440. package/src/runtime/auth/same-actor.ts +38 -3
  441. package/src/runtime/channel-send.ts +316 -0
  442. package/src/runtime/host-observe.ts +11 -1
  443. package/src/runtime/http-server.ts +160 -151
  444. package/src/runtime/routes/__tests__/acp-routes.test.ts +159 -4
  445. package/src/runtime/routes/__tests__/apps-refresh-route.test.ts +205 -0
  446. package/src/runtime/routes/__tests__/channel-send-routes.test.ts +127 -0
  447. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +108 -1
  448. package/src/runtime/routes/__tests__/default-provider-routes.test.ts +2 -2
  449. package/src/runtime/routes/__tests__/dictation-cleanup-guard.test.ts +107 -0
  450. package/src/runtime/routes/__tests__/mcp-add-default-risk.test.ts +16 -12
  451. package/src/runtime/routes/acp-routes.test.ts +15 -0
  452. package/src/runtime/routes/acp-routes.ts +72 -9
  453. package/src/runtime/routes/app-management-routes.ts +73 -0
  454. package/src/runtime/routes/app-routes.ts +1 -1
  455. package/src/runtime/routes/channel-send-routes.ts +85 -0
  456. package/src/runtime/routes/conversation-list-routes.ts +14 -3
  457. package/src/runtime/routes/conversation-query-routes.ts +40 -0
  458. package/src/runtime/routes/conversation-routes.ts +16 -3
  459. package/src/runtime/routes/credential-routes.ts +19 -10
  460. package/src/runtime/routes/desktop-setup-routes.test.ts +74 -0
  461. package/src/runtime/routes/desktop-setup-routes.ts +35 -0
  462. package/src/runtime/routes/diagnostics-routes.ts +61 -4
  463. package/src/runtime/routes/events-routes.ts +4 -0
  464. package/src/runtime/routes/host-cu-routes.ts +6 -0
  465. package/src/runtime/routes/index.ts +4 -2
  466. package/src/runtime/routes/log-export-routes.ts +2 -0
  467. package/src/runtime/routes/mcp-auth-routes.ts +39 -47
  468. package/src/runtime/routes/migration-routes.ts +6 -20
  469. package/src/runtime/routes/oauth-commands-routes.ts +36 -0
  470. package/src/runtime/routes/platform-routes.ts +18 -15
  471. package/src/runtime/routes/workspace-routes.test.ts +55 -26
  472. package/src/runtime/routes/workspace-routes.ts +46 -63
  473. package/src/runtime/routes/workspace-tree-walk.test.ts +244 -0
  474. package/src/runtime/routes/workspace-tree-walk.ts +240 -0
  475. package/src/runtime/routes/workspace-utils.ts +17 -0
  476. package/src/runtime/services/__tests__/conversation-serializer.test.ts +28 -0
  477. package/src/runtime/services/conversation-serializer.ts +16 -3
  478. package/src/runtime/sync/resource-sync-events.ts +2 -1
  479. package/src/schedule/run-script.ts +2 -1
  480. package/src/schedule/schedule-store.ts +9 -2
  481. package/src/schedule/worker.ts +1 -1
  482. package/src/security/__tests__/ces-http-record-backend.test.ts +137 -0
  483. package/src/security/ces-http-record-backend.ts +120 -0
  484. package/src/security/ces-rpc-record-backend.ts +7 -0
  485. package/src/security/untrusted-content.ts +3 -1
  486. package/src/skills/__tests__/workspace-skill-md-signature.test.ts +60 -0
  487. package/src/skills/workspace-skill-md-signature.ts +50 -0
  488. package/src/subagent/consult-context.ts +12 -25
  489. package/src/tools/__tests__/side-effect-abort-guard.test.ts +1 -0
  490. package/src/tools/acp/list-agents.test.ts +3 -1
  491. package/src/tools/acp/spawn.test.ts +146 -11
  492. package/src/tools/acp/spawn.ts +21 -3
  493. package/src/tools/acp/status.test.ts +94 -0
  494. package/src/tools/acp/status.ts +40 -3
  495. package/src/tools/app-control/skill-proxy-bridge.ts +2 -1
  496. package/src/tools/browser/browser-execution.ts +1 -1
  497. package/src/tools/browser/cdp-client/accessibility-snapshot.ts +9 -3
  498. package/src/tools/browser/cdp-client/cdp-inspect/discovery.ts +2 -1
  499. package/src/tools/browser/cdp-client/extension-cdp-client.ts +3 -2
  500. package/src/tools/browser/network-recorder.ts +2 -1
  501. package/src/tools/capability-offer.test.ts +22 -2
  502. package/src/tools/capability-offer.ts +16 -1
  503. package/src/tools/computer-use/definitions.ts +121 -2
  504. package/src/tools/computer-use/skill-proxy-bridge.ts +2 -1
  505. package/src/tools/credentials/metadata-store.ts +100 -0
  506. package/src/tools/filesystem/search.ts +2 -1
  507. package/src/tools/host-filesystem/edit.test.ts +2 -1
  508. package/src/tools/host-filesystem/edit.ts +2 -2
  509. package/src/tools/host-filesystem/read.test.ts +2 -1
  510. package/src/tools/host-filesystem/read.ts +2 -2
  511. package/src/tools/host-filesystem/transfer.test.ts +2 -1
  512. package/src/tools/host-filesystem/transfer.ts +2 -2
  513. package/src/tools/host-filesystem/write.test.ts +2 -1
  514. package/src/tools/host-filesystem/write.ts +2 -2
  515. package/src/tools/host-terminal/host-shell.test.ts +16 -0
  516. package/src/tools/host-terminal/host-shell.ts +4 -20
  517. package/src/tools/network/web-search.ts +6 -1
  518. package/src/tools/policy-context.ts +6 -7
  519. package/src/tools/skills/scaffold-managed.ts +61 -3
  520. package/src/tools/subagent/spawn.ts +5 -8
  521. package/src/tools/terminal/__tests__/sanitized-bash.test.ts +57 -0
  522. package/src/tools/terminal/sanitized-bash.ts +105 -0
  523. package/src/tools/watch/watch-retro-report.ts +0 -8
  524. package/src/types/host-capabilities.ts +5 -3
  525. package/src/util/__tests__/language-subtag.test.ts +23 -1
  526. package/src/util/ca-bundle.ts +13 -0
  527. package/src/util/language-subtag.ts +16 -0
  528. package/src/util/platform.ts +8 -0
  529. package/src/util/unicode.ts +15 -1
  530. package/src/watch/watch-timeline.ts +2 -2
  531. package/src/workflows/run-manager.ts +2 -1
  532. package/src/workspace/git-porcelain.ts +66 -0
  533. package/src/workspace/git-service.ts +6 -55
  534. package/src/workspace/migrations/154-repair-retired-codex-gpt-5-4-model-ids.ts +258 -0
  535. package/src/workspace/migrations/155-move-front-model-config-to-voice.ts +78 -0
  536. package/src/workspace/migrations/156-extract-workspace-mcp-json.ts +214 -0
  537. package/src/workspace/migrations/__tests__/155-move-front-model-config-to-voice.test.ts +102 -0
  538. package/src/workspace/migrations/__tests__/156-extract-workspace-mcp-json.test.ts +199 -0
  539. package/src/workspace/migrations/registry.ts +6 -0
  540. package/src/__tests__/app-source-watcher.test.ts +0 -218
  541. package/src/__tests__/config-watcher-skill-reseed.test.ts +0 -359
  542. package/src/__tests__/speaker-identification.test.ts +0 -56
  543. package/src/calls/speaker-identification.ts +0 -233
  544. package/src/daemon/app-source-watcher.ts +0 -218
  545. package/src/messaging/providers/whatsapp/client.ts +0 -29
  546. package/src/runtime/routes/debug-bash-routes.ts +0 -173
  547. package/src/util/fs-watcher-error.ts +0 -36
  548. /package/src/{live-voice → calls}/progress-phrases.ts +0 -0
@@ -4,25 +4,30 @@ import type { CliCommandHelp } from "../lib/cli-command-help.js";
4
4
 
5
5
  export const appsHelp: CliCommandHelp = {
6
6
  name: "apps",
7
- description: "Inspect apps and their on-disk source",
7
+ description: "List, inspect, and compile apps",
8
8
  helpText: `
9
9
  Apps are mini-applications the assistant can surface. Each has a name and a
10
10
  source directory holding its HTML/TSX definition, pages, and records.
11
11
 
12
12
  Apps come from two places, distinguished by their source path:
13
- workspace User-created apps under the workspace apps directory
14
- (~/.vellum/apps/<slug>/).
13
+ workspace User-created apps under the workspace apps directory.
15
14
  plugin Apps bundled by an installed plugin, each a directory under
16
- ~/.vellum/plugins/<name>/apps/<app>/. Stray directories without
17
- a plugin package.json, and disabled plugins, contribute nothing.
15
+ the plugin's apps/ folder. Stray directories without a plugin
16
+ package.json, and disabled plugins, contribute nothing.
18
17
 
19
- This surface is read-only. Workspace apps are created, edited, and deleted
20
- through the app-builder skill and its tools (app-create, app-update,
21
- app-delete); plugin apps are owned by their plugin.
18
+ Create and delete workspace apps through the app-builder skill and its tools
19
+ (app_create, app_delete). This command lists apps, inspects whether source
20
+ has changed since the last compile, and compiles an app once you are done
21
+ editing. File edits do not compile on their own.
22
+
23
+ list and inspect read the workspace directly (the assistant does not need to
24
+ be running). refresh compiles inside the running assistant so open surfaces
25
+ pick up the new build, including plugin apps with local source changes.
22
26
 
23
27
  Examples:
24
28
  $ assistant apps list
25
- $ assistant apps list --json`,
29
+ $ assistant apps inspect Budget
30
+ $ assistant apps refresh Budget`,
26
31
  subcommands: [
27
32
  {
28
33
  name: "list",
@@ -31,10 +36,10 @@ Examples:
31
36
  { flags: "--json", description: "Machine-readable JSON output" },
32
37
  ],
33
38
  helpText: `
34
- Lists every app with its name and the absolute path to its source directory
35
- the path itself shows whether the app is a workspace app or bundled by a plugin
36
- (~/.vellum/plugins/<name>/apps/...). Workspace apps are listed first, then
37
- plugin-bundled apps; both are sorted by name.
39
+ Lists every app with its name and the absolute path to its source directory.
40
+ The path itself shows whether the app is a workspace app or bundled by a
41
+ plugin. Workspace apps are listed first, then plugin-bundled apps; both are
42
+ sorted by name.
38
43
 
39
44
  Pass --json for machine-readable output.
40
45
 
@@ -42,5 +47,54 @@ Examples:
42
47
  $ assistant apps list
43
48
  $ assistant apps list --json`,
44
49
  },
50
+ {
51
+ name: "inspect",
52
+ args: "<app_name>",
53
+ description:
54
+ "Show whether an app's source has changed since the last compile",
55
+ options: [
56
+ { flags: "--json", description: "Machine-readable JSON output" },
57
+ ],
58
+ helpText: `
59
+ Arguments:
60
+ app_name App display name, directory slug, or id. Run 'assistant apps list'
61
+ to see available apps.
62
+
63
+ Compares the on-disk source against the fingerprint recorded in dist/ at the
64
+ last successful compile. Reports clean (no changes), stale (source drifted),
65
+ never compiled, or unknown baseline (compiled before fingerprints existed).
66
+
67
+ Does not compile. Use 'assistant apps refresh <app_name>' after inspect when
68
+ source has changed.
69
+
70
+ Examples:
71
+ $ assistant apps inspect Budget
72
+ $ assistant apps inspect Budget --json`,
73
+ },
74
+ {
75
+ name: "refresh",
76
+ args: "<app_name>",
77
+ description:
78
+ "Compile an app and refresh open surfaces. Requires a running assistant",
79
+ options: [
80
+ { flags: "--json", description: "Machine-readable JSON output" },
81
+ ],
82
+ helpText: `
83
+ Arguments:
84
+ app_name App display name, directory slug, or id. Run 'assistant apps list'
85
+ to see available apps.
86
+
87
+ Compiles src/ into dist/ inside the running assistant, then refreshes any
88
+ open surfaces and published deployments. Call this once after a batch of
89
+ edits, not after every file write. Workspace and plugin apps are both
90
+ accepted so local plugin source changes can be compiled without waiting
91
+ for the plugin watcher.
92
+
93
+ The assistant must be running.
94
+
95
+ Examples:
96
+ $ assistant apps refresh Budget
97
+ $ assistant apps refresh Budget --json`,
98
+ },
45
99
  ],
46
100
  };
@@ -1,8 +1,13 @@
1
1
  import type { Command } from "commander";
2
2
 
3
+ import {
4
+ cliIpcCall,
5
+ exitCodeFromIpcResult,
6
+ } from "../../ipc/cli-client.js";
3
7
  import { applyCommandHelp, subcommand } from "../lib/cli-command-help.js";
4
8
  import { registerCommand } from "../lib/register-command.js";
5
9
  import { log } from "../logger.js";
10
+ import { shouldOutputJson, writeError, writeOutput } from "../output.js";
6
11
  import { appsHelp } from "./apps.help.js";
7
12
 
8
13
  interface AppListEntry {
@@ -10,6 +15,36 @@ interface AppListEntry {
10
15
  source: string;
11
16
  }
12
17
 
18
+ interface AppsRefreshResponse {
19
+ ok: true;
20
+ appId: string;
21
+ name: string;
22
+ compiled: boolean;
23
+ compile_duration_ms: number;
24
+ compile_errors?: Array<{
25
+ text: string;
26
+ location?: { file: string; line: number; column: number };
27
+ }>;
28
+ compile_warnings?: Array<{
29
+ text: string;
30
+ location?: { file: string; line: number; column: number };
31
+ }>;
32
+ }
33
+
34
+ function refreshHint(appId: string): string {
35
+ return `Run 'assistant apps refresh ${appId}' to compile.`;
36
+ }
37
+
38
+ function formatDiagnostic(diag: {
39
+ text: string;
40
+ location?: { file: string; line: number; column: number };
41
+ }): string {
42
+ if (!diag.location) {
43
+ return diag.text;
44
+ }
45
+ return `${diag.location.file}:${diag.location.line}: ${diag.text}`;
46
+ }
47
+
13
48
  export function registerAppsCommand(program: Command): void {
14
49
  registerCommand(program, {
15
50
  name: appsHelp.name,
@@ -46,6 +81,154 @@ export function registerAppsCommand(program: Command): void {
46
81
  log.info(` ${e.name.padEnd(nameWidth)} ${e.source}`);
47
82
  }
48
83
  });
84
+
85
+ subcommand(apps, "inspect").action(
86
+ async (appName: string, opts: { json?: boolean }, cmd: Command) => {
87
+ const { resolveAppQuery, appNotFoundMessage, appAmbiguousMessage } =
88
+ await import("../../apps/resolve-app.js");
89
+ const { inspectAppSource } = await import(
90
+ "../../apps/source-fingerprint.js"
91
+ );
92
+
93
+ const resolved = resolveAppQuery(appName);
94
+ if (!resolved.ok) {
95
+ const message =
96
+ resolved.reason === "ambiguous"
97
+ ? appAmbiguousMessage(resolved.query, resolved.matches)
98
+ : appNotFoundMessage(resolved.query);
99
+ writeError(cmd, message);
100
+ process.exitCode = 1;
101
+ return;
102
+ }
103
+
104
+ const { app } = resolved;
105
+ const inspect = inspectAppSource(app.sourcePath);
106
+ const origin =
107
+ app.origin.kind === "plugin"
108
+ ? { kind: "plugin" as const, plugin: app.origin.pluginName }
109
+ : { kind: "workspace" as const };
110
+
111
+ if (opts.json || shouldOutputJson(cmd)) {
112
+ writeOutput(cmd, {
113
+ ok: true,
114
+ app: {
115
+ id: app.id,
116
+ name: app.name,
117
+ source: app.sourcePath,
118
+ origin,
119
+ },
120
+ compile: inspect,
121
+ });
122
+ return;
123
+ }
124
+
125
+ const originLabel =
126
+ origin.kind === "plugin"
127
+ ? `plugin ${origin.plugin}`
128
+ : "workspace";
129
+ log.info(`App: ${app.name} (${originLabel})`);
130
+ log.info(`Id: ${app.id}`);
131
+ log.info(`Source: ${app.sourcePath}`);
132
+
133
+ if (inspect.status === "clean") {
134
+ const when = inspect.compiledAt
135
+ ? ` (compiled ${inspect.compiledAt})`
136
+ : "";
137
+ log.info(`Compile: up to date${when}`);
138
+ return;
139
+ }
140
+ if (inspect.status === "never_compiled") {
141
+ log.info("Compile: never compiled");
142
+ log.info(refreshHint(app.id));
143
+ return;
144
+ }
145
+ if (inspect.status === "unknown_baseline") {
146
+ log.info(
147
+ "Compile: compiled, but no source fingerprint is recorded.",
148
+ );
149
+ log.info(
150
+ `Run 'assistant apps refresh ${app.id}' to record one and rebuild.`,
151
+ );
152
+ return;
153
+ }
154
+
155
+ const when = inspect.compiledAt
156
+ ? ` (last compiled ${inspect.compiledAt})`
157
+ : "";
158
+ log.info(`Compile: source changed since last compile${when}`);
159
+ if (inspect.modified.length > 0) {
160
+ log.info("Modified:");
161
+ for (const path of inspect.modified) {
162
+ log.info(` ${path}`);
163
+ }
164
+ }
165
+ if (inspect.added.length > 0) {
166
+ log.info("Added:");
167
+ for (const path of inspect.added) {
168
+ log.info(` ${path}`);
169
+ }
170
+ }
171
+ if (inspect.removed.length > 0) {
172
+ log.info("Removed:");
173
+ for (const path of inspect.removed) {
174
+ log.info(` ${path}`);
175
+ }
176
+ }
177
+ log.info(refreshHint(app.id));
178
+ },
179
+ );
180
+
181
+ subcommand(apps, "refresh").action(
182
+ async (appName: string, opts: { json?: boolean }, cmd: Command) => {
183
+ const { resolveAppQuery, appNotFoundMessage, appAmbiguousMessage } =
184
+ await import("../../apps/resolve-app.js");
185
+
186
+ const resolved = resolveAppQuery(appName);
187
+ if (!resolved.ok) {
188
+ const message =
189
+ resolved.reason === "ambiguous"
190
+ ? appAmbiguousMessage(resolved.query, resolved.matches)
191
+ : appNotFoundMessage(resolved.query);
192
+ writeError(cmd, message);
193
+ process.exitCode = 1;
194
+ return;
195
+ }
196
+
197
+ const result = await cliIpcCall<AppsRefreshResponse>("apps_refresh", {
198
+ pathParams: { id: resolved.app.id },
199
+ });
200
+
201
+ if (!result.ok || !result.result) {
202
+ writeError(cmd, result.error ?? "Refresh failed");
203
+ process.exitCode = exitCodeFromIpcResult(result);
204
+ return;
205
+ }
206
+
207
+ const payload = result.result;
208
+ if (opts.json || shouldOutputJson(cmd)) {
209
+ writeOutput(cmd, payload);
210
+ if (!payload.compiled) {
211
+ process.exitCode = 1;
212
+ }
213
+ return;
214
+ }
215
+
216
+ if (!payload.compiled) {
217
+ log.error(
218
+ `Compile failed for "${payload.name}" (${payload.compile_duration_ms}ms).`,
219
+ );
220
+ for (const diag of payload.compile_errors ?? []) {
221
+ log.error(` ${formatDiagnostic(diag)}`);
222
+ }
223
+ process.exitCode = 1;
224
+ return;
225
+ }
226
+
227
+ log.info(
228
+ `Compiled "${payload.name}" in ${payload.compile_duration_ms}ms.`,
229
+ );
230
+ },
231
+ );
49
232
  },
50
233
  });
51
234
  }
@@ -6,7 +6,7 @@ export const bashHelp: CliCommandHelp = {
6
6
  name: "bash",
7
7
  args: "<command>",
8
8
  description:
9
- "Execute a shell command through the assistant process for debugging",
9
+ "Execute a shell command with the same sanitized environment as the bash tool",
10
10
  options: [
11
11
  {
12
12
  flags: "-t, --timeout <ms>",
@@ -15,24 +15,19 @@ export const bashHelp: CliCommandHelp = {
15
15
  },
16
16
  ],
17
17
  helpText: `
18
- Sends a shell command to the running assistant for execution via the IPC
19
- socket. The assistant spawns the command in its own process environment and
20
- returns stdout, stderr, and the exit code.
21
-
22
- This is a developer debugging tool for inspecting how the assistant invokes and
23
- observes shell commands. The command runs with the assistant's environment, working
24
- directory, and process context — not the caller's shell.
25
-
26
- Requires the assistant to be running with VELLUM_DEBUG=1. When debug mode is off
27
- (the default), the assistant returns an error immediately.
18
+ Spawns the command with the same sanitized environment, working directory,
19
+ and platform shell the bash tool uses for tool-call subprocesses. Vault
20
+ bearers such as CES_SERVICE_TOKEN are stripped; CES_LOCAL_SOCKET and workspace
21
+ paths are forwarded. The command does not go through the assistant HTTP or IPC
22
+ API, and does not require a running assistant process.
28
23
 
29
24
  Arguments:
30
25
  command The shell command string to execute (e.g. "echo hello", "ls -la").
31
- Runs in bash via \`bash -c\` in the assistant's process environment.
26
+ Runs via the same platform shell invocation the bash tool uses.
32
27
 
33
28
  Examples:
34
29
  $ assistant bash "echo hello"
35
30
  $ assistant bash "which node"
36
31
  $ assistant bash "env | grep PATH" --timeout 10000
37
- $ assistant bash "ls -la"`,
32
+ $ assistant bash "assistant oauth request --provider outlook --json https://graph.microsoft.com/v1.0/me"`,
38
33
  };
@@ -1,28 +1,19 @@
1
1
  /**
2
- * `assistant bash` run a shell command in the assistant's process
3
- * environment (debug tool, requires VELLUM_DEBUG=1 on the daemon).
2
+ * `assistant bash` runs a shell command with the same sanitized environment
3
+ * the bash tool forwards to tool-call subprocesses.
4
4
  */
5
5
 
6
6
  import type { Command } from "commander";
7
7
 
8
- import { cliIpcCall } from "../../ipc/cli-client.js";
9
8
  import { applyCommandHelp, commandSpec } from "../lib/cli-command-help.js";
10
9
  import { registerCommand } from "../lib/register-command.js";
11
10
  import { log } from "../logger.js";
12
11
  import { bashHelp } from "./bash.help.js";
13
12
 
14
- interface DebugBashResult {
15
- stdout: string;
16
- stderr: string;
17
- exitCode: number | null;
18
- timedOut: boolean;
19
- error?: string;
20
- }
21
-
22
13
  export function registerBashCommand(program: Command): void {
23
14
  registerCommand(program, {
24
15
  name: commandSpec(bashHelp),
25
- transport: "ipc",
16
+ transport: "local",
26
17
  description: bashHelp.description,
27
18
  build: (cmd) => {
28
19
  applyCommandHelp(cmd, bashHelp);
@@ -34,19 +25,10 @@ export function registerBashCommand(program: Command): void {
34
25
  return;
35
26
  }
36
27
 
37
- const result = await cliIpcCall<DebugBashResult>(
38
- "debug_bash",
39
- { body: { command, timeoutMs } },
40
- { timeoutMs: timeoutMs + 10_000 },
28
+ const { runSanitizedBash } = await import(
29
+ "../../tools/terminal/sanitized-bash.js"
41
30
  );
42
-
43
- if (!result.ok) {
44
- log.error(result.error ?? "Failed to reach the assistant.");
45
- process.exitCode = 1;
46
- return;
47
- }
48
-
49
- const data = result.result!;
31
+ const data = await runSanitizedBash(command, timeoutMs);
50
32
 
51
33
  if (data.error) {
52
34
  log.error(data.error);
@@ -69,7 +51,7 @@ export function registerBashCommand(program: Command): void {
69
51
  }
70
52
 
71
53
  if (data.timedOut) {
72
- log.info(`Command timed out in assistant.`);
54
+ log.info("Command timed out.");
73
55
  }
74
56
 
75
57
  if (data.exitCode != null && data.exitCode !== 0) {
@@ -0,0 +1,218 @@
1
+ import { beforeEach, describe, expect, mock, test } from "bun:test";
2
+
3
+ // The command is a door onto the daemon's one send implementation, so what
4
+ // matters is the request it hands the route and what it does with the
5
+ // answer. IPC is stubbed to capture that request; the exit-code helper
6
+ // stays real, so the tests assert the mapping that ships.
7
+
8
+ const ipcCalls: Array<{
9
+ method: string;
10
+ params: Record<string, unknown>;
11
+ opts?: Record<string, unknown>;
12
+ }> = [];
13
+ let ipcResult: Record<string, unknown> = {
14
+ ok: true,
15
+ result: {
16
+ channel: "slack",
17
+ chatId: "C0123456789",
18
+ messageIds: ["1700000000.000100"],
19
+ lastMessageId: "1700000000.000100",
20
+ recordedIn: "conv-home",
21
+ },
22
+ };
23
+
24
+ const actualCliClient = await import("../../../../ipc/cli-client.js");
25
+ mock.module("../../../../ipc/cli-client.js", () => ({
26
+ ...actualCliClient,
27
+ cliIpcCall: async (
28
+ method: string,
29
+ params: Record<string, unknown>,
30
+ opts?: Record<string, unknown>,
31
+ ) => {
32
+ ipcCalls.push({ method, params, ...(opts ? { opts } : {}) });
33
+ return ipcResult;
34
+ },
35
+ }));
36
+
37
+ // Imported after the mock is installed, so the command module under test
38
+ // binds the stubbed IPC call rather than the real one.
39
+ const { runCliCommand } = await import("../../__tests__/cli-test-harness.js");
40
+ const { registerChannelsCommand } = await import("../index.js");
41
+
42
+ beforeEach(() => {
43
+ ipcCalls.length = 0;
44
+ ipcResult = {
45
+ ok: true,
46
+ result: {
47
+ channel: "slack",
48
+ chatId: "C0123456789",
49
+ messageIds: ["1700000000.000100"],
50
+ lastMessageId: "1700000000.000100",
51
+ recordedIn: "conv-home",
52
+ },
53
+ };
54
+ });
55
+
56
+ // The shipped registration as-is: `send` declares its own `--json`, which is
57
+ // why the program's global leaf-option pass skips it.
58
+ function runSend(args: string[]) {
59
+ return runCliCommand(registerChannelsCommand, ["channels", "send", ...args]);
60
+ }
61
+
62
+ /** The body the command handed the route on its one call. */
63
+ function sentBody(): Record<string, unknown> {
64
+ expect(ipcCalls).toHaveLength(1);
65
+ expect(ipcCalls[0]!.method).toBe("channels_send_post");
66
+ return ipcCalls[0]!.params.body as Record<string, unknown>;
67
+ }
68
+
69
+ describe("the request the command makes", () => {
70
+ test("names the chat and asks for the channel's rich rendering", async () => {
71
+ const r = await runSend([
72
+ "slack",
73
+ "C0123456789",
74
+ "--text",
75
+ "deploy is green",
76
+ ]);
77
+ expect(r.exitCode).toBe(0);
78
+ expect(sentBody()).toEqual({
79
+ channel: "slack",
80
+ target: { kind: "chat", chatId: "C0123456789" },
81
+ text: "deploy is green",
82
+ renderRichly: true,
83
+ });
84
+ });
85
+
86
+ test("carries a named thread as the target's thread", async () => {
87
+ await runSend([
88
+ "slack",
89
+ "C0123456789",
90
+ "--thread",
91
+ "1700000000.000001",
92
+ "--text",
93
+ "and the smoke tests passed",
94
+ ]);
95
+ expect(sentBody().target).toEqual({
96
+ kind: "chat",
97
+ chatId: "C0123456789",
98
+ threadId: "1700000000.000001",
99
+ });
100
+ });
101
+
102
+ test("--plain asks for the text verbatim", async () => {
103
+ await runSend(["telegram", "123456789", "--text", "morning", "--plain"]);
104
+ const body = sentBody();
105
+ expect(body.renderRichly).toBeUndefined();
106
+ expect(body.channel).toBe("telegram");
107
+ });
108
+
109
+ test("sends the text as the caller wrote it, whitespace included", async () => {
110
+ await runSend([
111
+ "slack",
112
+ "C0123456789",
113
+ "--text",
114
+ " indented ",
115
+ "--plain",
116
+ ]);
117
+ expect(sentBody().text).toBe(" indented ");
118
+ });
119
+
120
+ test("waits longer than the IPC default, since the send itself retries", async () => {
121
+ await runSend(["slack", "C0123456789", "--text", "hi"]);
122
+ expect(ipcCalls[0]!.opts).toMatchObject({ timeoutMs: 120_000 });
123
+ });
124
+
125
+ test("refuses an empty text before it sends anything", async () => {
126
+ for (const args of [
127
+ ["slack", "C0123456789"],
128
+ ["slack", "C0123456789", "--text", " "],
129
+ ]) {
130
+ ipcCalls.length = 0;
131
+ const r = await runSend(args);
132
+ expect(r.exitCode).toBe(1);
133
+ expect(r.stderr).toContain("--text is required");
134
+ expect(ipcCalls).toEqual([]);
135
+ }
136
+ });
137
+ });
138
+
139
+ describe("what the command reports", () => {
140
+ test("names where the post landed and the conversation it was recorded in", async () => {
141
+ const r = await runSend(["slack", "C0123456789", "--text", "hello"]);
142
+ expect(r.stdout).toContain("C0123456789");
143
+ expect(r.stdout).toContain("1700000000.000100");
144
+ expect(r.stdout).toContain("conv-home");
145
+ });
146
+
147
+ test("says so when the channel split the text", async () => {
148
+ ipcResult = {
149
+ ok: true,
150
+ result: {
151
+ channel: "telegram",
152
+ chatId: "123456789",
153
+ messageIds: ["10", "11", "12"],
154
+ lastMessageId: "12",
155
+ },
156
+ };
157
+ const r = await runSend(["telegram", "123456789", "--text", "a long one"]);
158
+ expect(r.stdout).toContain("3 posts");
159
+ });
160
+
161
+ test("--json answers with the route's own result", async () => {
162
+ const r = await runSend([
163
+ "slack",
164
+ "C0123456789",
165
+ "--text",
166
+ "hello",
167
+ "--json",
168
+ ]);
169
+ expect(JSON.parse(r.stdout)).toEqual({
170
+ channel: "slack",
171
+ chatId: "C0123456789",
172
+ messageIds: ["1700000000.000100"],
173
+ lastMessageId: "1700000000.000100",
174
+ recordedIn: "conv-home",
175
+ });
176
+ });
177
+
178
+ test("a refused send reports the route's reason and its exit code", async () => {
179
+ ipcResult = {
180
+ ok: false,
181
+ error: 'Channel "email" is not addressable',
182
+ statusCode: 400,
183
+ };
184
+ const r = await runSend(["email", "someone", "--text", "hello"]);
185
+ expect(r.exitCode).toBe(
186
+ actualCliClient.exitCodeFromIpcResult({ statusCode: 400 }),
187
+ );
188
+ expect(r.stderr).toContain("not addressable");
189
+ });
190
+
191
+ test("a timeout is reported as an unknown outcome, not a failure to retry", async () => {
192
+ ipcResult = { ok: false, error: "Request timed out", timedOut: true };
193
+ const r = await runSend(["slack", "C0123456789", "--text", "hello"]);
194
+ expect(r.stderr).toContain("may still be in flight");
195
+ expect(r.stderr).toContain("before sending again");
196
+ expect(r.stderr).not.toContain("The send failed");
197
+ });
198
+
199
+ test("a refusal in --json mode is a JSON error envelope", async () => {
200
+ ipcResult = {
201
+ ok: false,
202
+ error: 'Channel "slack" did not acknowledge the send',
203
+ statusCode: 502,
204
+ };
205
+ const r = await runSend([
206
+ "slack",
207
+ "C0123456789",
208
+ "--text",
209
+ "hello",
210
+ "--json",
211
+ ]);
212
+ expect(JSON.parse(r.stdout)).toEqual({
213
+ ok: false,
214
+ error: 'Channel "slack" did not acknowledge the send',
215
+ });
216
+ expect(r.exitCode).toBe(3);
217
+ });
218
+ });