@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,245 @@
1
+ /**
2
+ * Tests for `assistant apps inspect` and `assistant apps refresh`.
3
+ */
4
+
5
+ import { mkdirSync, rmSync, writeFileSync } from "node:fs";
6
+ import { tmpdir } from "node:os";
7
+ import { join } from "node:path";
8
+ import { afterEach, beforeEach, describe, expect, mock, test } from "bun:test";
9
+
10
+ import { createApp, getAppDirPath } from "../../../apps/app-store.js";
11
+ import { writeAppSourceFingerprint } from "../../../apps/source-fingerprint.js";
12
+ import { getWorkspacePluginsDir } from "../../../util/platform.js";
13
+ import { runCliCommand } from "./cli-test-harness.js";
14
+
15
+ let lastIpcCall: {
16
+ method: string;
17
+ params?: Record<string, unknown>;
18
+ } | null = null;
19
+
20
+ let mockIpcResult: {
21
+ ok: boolean;
22
+ result?: unknown;
23
+ error?: string;
24
+ statusCode?: number;
25
+ } = { ok: true, result: { ok: true, compiled: true } };
26
+
27
+ mock.module("../../../ipc/cli-client.js", () => ({
28
+ cliIpcCall: async (method: string, params?: Record<string, unknown>) => {
29
+ lastIpcCall = { method, params };
30
+ return mockIpcResult;
31
+ },
32
+ exitCodeFromIpcResult: (r: { statusCode?: number }) => {
33
+ if (r.statusCode === undefined) {
34
+ return 10;
35
+ }
36
+ if (r.statusCode >= 500) {
37
+ return 3;
38
+ }
39
+ if (r.statusCode >= 400) {
40
+ return 2;
41
+ }
42
+ return 1;
43
+ },
44
+ }));
45
+
46
+ const { registerAppsCommand } = await import("../apps.js");
47
+
48
+ let workspaceDir: string;
49
+ let previousWorkspaceDir: string | undefined;
50
+
51
+ function freshWorkspace(): string {
52
+ return join(
53
+ tmpdir(),
54
+ `vellum-apps-cli-${Date.now()}-${Math.random().toString(36).slice(2)}`,
55
+ );
56
+ }
57
+
58
+ function uniqueAppName(prefix: string): string {
59
+ return `${prefix} ${Math.random().toString(36).slice(2, 8)}`;
60
+ }
61
+
62
+ beforeEach(() => {
63
+ previousWorkspaceDir = process.env.VELLUM_WORKSPACE_DIR;
64
+ workspaceDir = freshWorkspace();
65
+ process.env.VELLUM_WORKSPACE_DIR = workspaceDir;
66
+ lastIpcCall = null;
67
+ mockIpcResult = {
68
+ ok: true,
69
+ result: {
70
+ ok: true,
71
+ appId: "app-1",
72
+ name: "Budget",
73
+ compiled: true,
74
+ compile_duration_ms: 12,
75
+ },
76
+ };
77
+ });
78
+
79
+ afterEach(() => {
80
+ rmSync(workspaceDir, { recursive: true, force: true });
81
+ if (previousWorkspaceDir === undefined) {
82
+ delete process.env.VELLUM_WORKSPACE_DIR;
83
+ } else {
84
+ process.env.VELLUM_WORKSPACE_DIR = previousWorkspaceDir;
85
+ }
86
+ });
87
+
88
+ function parseJson(stdout: string): Record<string, unknown> {
89
+ return JSON.parse(stdout.trim()) as Record<string, unknown>;
90
+ }
91
+
92
+ describe("assistant apps inspect", () => {
93
+ test("reports never_compiled for a new workspace app", async () => {
94
+ const name = uniqueAppName("Inspect Fresh");
95
+ const created = createApp({
96
+ name,
97
+ schemaJson: "{}",
98
+ htmlDefinition: "<h1>Budget</h1>",
99
+ });
100
+
101
+ const result = await runCliCommand(registerAppsCommand, [
102
+ "apps",
103
+ "inspect",
104
+ created.id,
105
+ "--json",
106
+ ]);
107
+
108
+ expect(result.exitCode).toBe(0);
109
+ const body = parseJson(result.stdout);
110
+ expect(body.ok).toBe(true);
111
+ const compile = body.compile as { status: string };
112
+ expect(compile.status).toBe("never_compiled");
113
+ });
114
+
115
+ test("reports stale after source changes since the last fingerprint", async () => {
116
+ const name = uniqueAppName("Inspect Stale");
117
+ const created = createApp({
118
+ name,
119
+ schemaJson: "{}",
120
+ htmlDefinition: "<h1>Budget</h1>",
121
+ });
122
+ const appDir = getAppDirPath(created.id);
123
+ expect(appDir.length).toBeGreaterThan(0);
124
+ mkdirSync(join(appDir, "src"), { recursive: true });
125
+ writeFileSync(join(appDir, "src", "main.tsx"), "export const n = 1;\n");
126
+ mkdirSync(join(appDir, "dist"), { recursive: true });
127
+ writeFileSync(join(appDir, "dist", "index.html"), "<html></html>");
128
+ writeAppSourceFingerprint(appDir, join(appDir, "dist"));
129
+ writeFileSync(join(appDir, "src", "main.tsx"), "export const n = 2;\n");
130
+
131
+ const result = await runCliCommand(registerAppsCommand, [
132
+ "apps",
133
+ "inspect",
134
+ created.id,
135
+ "--json",
136
+ ]);
137
+
138
+ expect(result.exitCode).toBe(0);
139
+ const body = parseJson(result.stdout);
140
+ const app = body.app as { id: string; source: string };
141
+ expect(app.id).toBe(created.id);
142
+ expect(app.source).toBe(appDir);
143
+ const compile = body.compile as {
144
+ status: string;
145
+ modified: string[];
146
+ };
147
+ expect(compile.status).toBe("stale");
148
+ expect(compile.modified).toEqual(["src/main.tsx"]);
149
+ });
150
+
151
+ test("exits 1 for an unknown app", async () => {
152
+ const result = await runCliCommand(registerAppsCommand, [
153
+ "apps",
154
+ "inspect",
155
+ "missing",
156
+ "--json",
157
+ ]);
158
+ expect(result.exitCode).toBe(1);
159
+ const body = parseJson(result.stdout);
160
+ expect(body.ok).toBe(false);
161
+ expect(String(body.error)).toContain("assistant apps list");
162
+ });
163
+ });
164
+
165
+ describe("assistant apps refresh", () => {
166
+ test("sends apps_refresh IPC for a workspace app", async () => {
167
+ const name = uniqueAppName("Refresh");
168
+ const created = createApp({
169
+ name,
170
+ schemaJson: "{}",
171
+ htmlDefinition: "<h1>Budget</h1>",
172
+ });
173
+
174
+ const result = await runCliCommand(registerAppsCommand, [
175
+ "apps",
176
+ "refresh",
177
+ created.id,
178
+ "--json",
179
+ ]);
180
+
181
+ expect(result.exitCode).toBe(0);
182
+ expect(lastIpcCall).toEqual({
183
+ method: "apps_refresh",
184
+ params: { pathParams: { id: created.id } },
185
+ });
186
+ const body = parseJson(result.stdout);
187
+ expect(body.compiled).toBe(true);
188
+ });
189
+
190
+ test("sends apps_refresh IPC for a plugin app", async () => {
191
+ const pluginName = `charts-${Math.random().toString(36).slice(2, 8)}`;
192
+ const pluginDir = join(getWorkspacePluginsDir(), pluginName);
193
+ mkdirSync(pluginDir, { recursive: true });
194
+ writeFileSync(
195
+ join(pluginDir, "package.json"),
196
+ JSON.stringify({ name: pluginName, version: "1.0.0" }),
197
+ );
198
+ mkdirSync(join(pluginDir, "apps", "viewer"), { recursive: true });
199
+ writeFileSync(join(pluginDir, "apps", "viewer", "index.html"), "<h1></h1>");
200
+
201
+ const result = await runCliCommand(registerAppsCommand, [
202
+ "apps",
203
+ "refresh",
204
+ "viewer",
205
+ "--json",
206
+ ]);
207
+
208
+ expect(result.exitCode).toBe(0);
209
+ expect(lastIpcCall).toEqual({
210
+ method: "apps_refresh",
211
+ params: { pathParams: { id: `plugins~${pluginName}~viewer` } },
212
+ });
213
+ });
214
+
215
+ test("exits 1 when compile fails", async () => {
216
+ const name = uniqueAppName("Refresh Fail");
217
+ const created = createApp({
218
+ name,
219
+ schemaJson: "{}",
220
+ htmlDefinition: "<h1>Budget</h1>",
221
+ });
222
+ mockIpcResult = {
223
+ ok: true,
224
+ result: {
225
+ ok: true,
226
+ appId: created.id,
227
+ name,
228
+ compiled: false,
229
+ compile_duration_ms: 8,
230
+ compile_errors: [{ text: "Could not resolve foo" }],
231
+ },
232
+ };
233
+
234
+ const result = await runCliCommand(registerAppsCommand, [
235
+ "apps",
236
+ "refresh",
237
+ created.id,
238
+ "--json",
239
+ ]);
240
+
241
+ expect(result.exitCode).toBe(1);
242
+ const body = parseJson(result.stdout);
243
+ expect(body.compiled).toBe(false);
244
+ });
245
+ });
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Tests for `assistant bash`: local sanitized spawn, no IPC round-trip.
3
+ */
4
+
5
+ import { describe, expect, mock, test } from "bun:test";
6
+
7
+ import { runCliCommand } from "./cli-test-harness.js";
8
+
9
+ const ipcCalls: Array<{ method: string }> = [];
10
+
11
+ mock.module("../../../ipc/cli-client.js", () => ({
12
+ cliIpcCall: async (method: string) => {
13
+ ipcCalls.push({ method });
14
+ return { ok: false, error: "IPC should not be used" };
15
+ },
16
+ }));
17
+
18
+ mock.module("../../logger.js", () => ({
19
+ log: {
20
+ info: () => {},
21
+ warn: () => {},
22
+ error: (message: string) => {
23
+ process.stderr.write(`${message}\n`);
24
+ },
25
+ debug: () => {},
26
+ },
27
+ }));
28
+
29
+ const { registerBashCommand } = await import("../bash.js");
30
+
31
+ describe("assistant bash", () => {
32
+ test("spawns locally and prints stdout without IPC", async () => {
33
+ ipcCalls.length = 0;
34
+ const result = await runCliCommand(registerBashCommand, [
35
+ "bash",
36
+ "echo hello",
37
+ ]);
38
+ expect(ipcCalls).toEqual([]);
39
+ expect(result.stdout.trim()).toBe("hello");
40
+ expect(result.exitCode).toBe(0);
41
+ });
42
+
43
+ test("rejects a non-positive timeout", async () => {
44
+ const result = await runCliCommand(registerBashCommand, [
45
+ "bash",
46
+ "echo hello",
47
+ "--timeout",
48
+ "0",
49
+ ]);
50
+ expect(result.stderr).toContain("Invalid timeout value");
51
+ expect(result.exitCode).toBe(1);
52
+ });
53
+ });
@@ -0,0 +1,19 @@
1
+ import { describe, expect, test } from "bun:test";
2
+
3
+ import { roadmapHelp } from "../roadmap.help.js";
4
+
5
+ const DISCORD_URL = "https://vellum.ai/community";
6
+
7
+ describe("roadmap help is feature-proposal-only", () => {
8
+ test("top-level help describes feature proposals and routes bugs to Discord", () => {
9
+ const description = roadmapHelp.description;
10
+ const helpText = roadmapHelp.helpText ?? "";
11
+ const combined = `${description}\n${helpText}`.toLowerCase();
12
+
13
+ expect(combined).toMatch(/feature proposals?/);
14
+ expect(description.split(DISCORD_URL)).toHaveLength(2);
15
+ expect(helpText).toContain(DISCORD_URL);
16
+ expect(combined).toContain("instruct the user");
17
+ expect(combined).not.toMatch(/support@|github\.com|share feedback/);
18
+ });
19
+ });
@@ -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
  };