@vellumai/assistant 0.9.0 → 0.10.0-dev.202606192226.8ed8a6a

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 (624) hide show
  1. package/ARCHITECTURE.md +19 -35
  2. package/bun.lock +7 -8
  3. package/docs/activation-funnel-telemetry.md +28 -22
  4. package/docs/architecture/security.md +29 -28
  5. package/docs/stt-provider-onboarding.md +3 -5
  6. package/docs/workflows-testing.md +13 -44
  7. package/docs/workflows.md +3 -5
  8. package/node_modules/@vellumai/ces-client/src/__tests__/ces-client.test.ts +47 -0
  9. package/node_modules/@vellumai/ces-client/src/rpc-client.ts +28 -5
  10. package/node_modules/@vellumai/environments/src/seeds.ts +2 -5
  11. package/node_modules/@vellumai/gateway-client/src/admission-policy-contract.ts +97 -0
  12. package/node_modules/@vellumai/gateway-client/src/inbound-contract.ts +10 -0
  13. package/node_modules/@vellumai/gateway-client/src/index.ts +32 -6
  14. package/node_modules/@vellumai/gateway-client/src/outbound-contract.ts +119 -0
  15. package/node_modules/@vellumai/gateway-client/src/types.ts +15 -84
  16. package/openapi.yaml +1128 -119
  17. package/package.json +2 -1
  18. package/scripts/sync-llm-catalog.ts +6 -15
  19. package/scripts/sync-web-search-catalog.ts +3 -11
  20. package/src/__tests__/access-request-card-view.test.ts +98 -0
  21. package/src/__tests__/access-request-seed-content-blocks.test.ts +2 -4
  22. package/src/__tests__/actor-trust-resolver-address-fallback.test.ts +72 -32
  23. package/src/__tests__/agent-loop-compaction-strip.test.ts +241 -0
  24. package/src/__tests__/agent-loop-mutable-latest-user-message.test.ts +16 -13
  25. package/src/__tests__/agent-loop-output-hooks.test.ts +69 -0
  26. package/src/__tests__/agent-loop-override-profile.test.ts +25 -0
  27. package/src/__tests__/agent-loop-pushes-post-hook-prompt.test.ts +306 -0
  28. package/src/__tests__/always-loaded-tools-guard.test.ts +2 -3
  29. package/src/__tests__/app-compiler.test.ts +15 -1
  30. package/src/__tests__/app-dir-path-guard.test.ts +0 -1
  31. package/src/__tests__/approval-cascade.test.ts +6 -0
  32. package/src/__tests__/approval-routes-http.test.ts +128 -0
  33. package/src/__tests__/assistant-feature-flag-guard.test.ts +1 -4
  34. package/src/__tests__/assistant-feature-flag-guardrails.test.ts +0 -2
  35. package/src/__tests__/auth-fallback-events-store.test.ts +6 -14
  36. package/src/__tests__/avatar-identity-sync.test.ts +2 -27
  37. package/src/__tests__/btw-routes.test.ts +6 -8
  38. package/src/__tests__/call-pointer-messages.test.ts +28 -0
  39. package/src/__tests__/cancel-clears-processing.test.ts +89 -0
  40. package/src/__tests__/channel-approval-routes.test.ts +0 -4
  41. package/src/__tests__/channel-inbound-disk-pressure.test.ts +5 -15
  42. package/src/__tests__/checker.test.ts +0 -3
  43. package/src/__tests__/cli-memory-v2-reembed-skills.test.ts +3 -4
  44. package/src/__tests__/compaction-events.test.ts +6 -0
  45. package/src/__tests__/compactor-image-manifest-trust.test.ts +21 -1
  46. package/src/__tests__/compactor-summary-call-truncation.test.ts +223 -0
  47. package/src/__tests__/config-loader-backfill.test.ts +268 -27
  48. package/src/__tests__/config-schema.test.ts +35 -0
  49. package/src/__tests__/config-watcher.test.ts +0 -18
  50. package/src/__tests__/confirmation-request-guardian-bridge.test.ts +2 -2
  51. package/src/__tests__/contact-store-user-file.test.ts +0 -6
  52. package/src/__tests__/contacts-tools.test.ts +29 -0
  53. package/src/__tests__/conversation-abort-tool-results.test.ts +6 -0
  54. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +22 -0
  55. package/src/__tests__/conversation-agent-loop-overflow.test.ts +1 -0
  56. package/src/__tests__/conversation-agent-loop.test.ts +58 -0
  57. package/src/__tests__/conversation-attention-telegram.test.ts +0 -1
  58. package/src/__tests__/conversation-confirmation-signals.test.ts +6 -0
  59. package/src/__tests__/conversation-lifecycle.test.ts +7 -9
  60. package/src/__tests__/conversation-load-history-repair.test.ts +101 -0
  61. package/src/__tests__/conversation-process-callsite.test.ts +6 -0
  62. package/src/__tests__/conversation-provider-retry-repair.test.ts +6 -0
  63. package/src/__tests__/conversation-queue.test.ts +6 -0
  64. package/src/__tests__/conversation-routes-guardian-reply.test.ts +15 -12
  65. package/src/__tests__/conversation-slash-queue.test.ts +6 -0
  66. package/src/__tests__/conversation-slash-unknown.test.ts +6 -0
  67. package/src/__tests__/conversation-speed-override.test.ts +6 -0
  68. package/src/__tests__/conversation-surfaces-activation-emit.test.ts +6 -3
  69. package/src/__tests__/conversation-title-service.test.ts +62 -0
  70. package/src/__tests__/conversation-workspace-cache-state.test.ts +6 -0
  71. package/src/__tests__/conversation-workspace-injection.test.ts +6 -0
  72. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +6 -0
  73. package/src/__tests__/credential-broker.test.ts +449 -1
  74. package/src/__tests__/credential-execution-shell-lockdown.test.ts +18 -11
  75. package/src/__tests__/credential-execution-tools.test.ts +0 -1
  76. package/src/__tests__/credential-prompt-route.test.ts +4 -4
  77. package/src/__tests__/credential-routes.test.ts +360 -0
  78. package/src/__tests__/credential-security-invariants.test.ts +4 -13
  79. package/src/__tests__/disk-pressure-policy.test.ts +12 -0
  80. package/src/__tests__/disk-pressure-tools.test.ts +41 -1
  81. package/src/__tests__/disk-usage.test.ts +65 -0
  82. package/src/__tests__/document-tool-security.test.ts +9 -6
  83. package/src/__tests__/document-update-default-surface.test.ts +202 -0
  84. package/src/__tests__/dynamic-page-surface.test.ts +152 -1
  85. package/src/__tests__/fixtures/credential-security-fixtures.ts +2 -33
  86. package/src/__tests__/gateway-flag-listener.test.ts +110 -1
  87. package/src/__tests__/gateway-only-guard.test.ts +3 -7
  88. package/src/__tests__/gemini-count-tokens.test.ts +70 -0
  89. package/src/__tests__/guardian-binding-drift-heal.test.ts +1 -1
  90. package/src/__tests__/guardian-card-withdrawal.test.ts +403 -0
  91. package/src/__tests__/guardian-decision-primitive-canonical.test.ts +5 -3
  92. package/src/__tests__/guardian-grant-minting.test.ts +3 -35
  93. package/src/__tests__/guardian-routing-invariants.test.ts +64 -26
  94. package/src/__tests__/guardian-routing-state.test.ts +0 -1
  95. package/src/__tests__/headless-browser-mode.test.ts +10 -0
  96. package/src/__tests__/headless-browser-navigate.test.ts +8 -3
  97. package/src/__tests__/helpers/create-guardian-binding.ts +0 -1
  98. package/src/__tests__/host-browser-proxy.test.ts +87 -0
  99. package/src/__tests__/identity-routes.test.ts +0 -189
  100. package/src/__tests__/inbound-invite-redemption.test.ts +4 -4
  101. package/src/__tests__/injector-disk-pressure.test.ts +10 -5
  102. package/src/__tests__/injector-v3-suppression.test.ts +27 -20
  103. package/src/__tests__/internal-telemetry-routes.test.ts +6 -14
  104. package/src/__tests__/invite-redemption-service.test.ts +4 -7
  105. package/src/__tests__/llm-callsite-catalog.test.ts +5 -6
  106. package/src/__tests__/llm-catalog-parity.test.ts +30 -23
  107. package/src/__tests__/llm-resolver.test.ts +70 -24
  108. package/src/__tests__/llm-schema.test.ts +1 -0
  109. package/src/__tests__/managed-profile-guard.test.ts +163 -4
  110. package/src/__tests__/mcp-health-check.test.ts +6 -7
  111. package/src/__tests__/media-stream-server-integration.test.ts +317 -13
  112. package/src/__tests__/oauth-provider-seed-logos.test.ts +4 -6
  113. package/src/__tests__/onboarding-persona-write.test.ts +1 -1
  114. package/src/__tests__/path-policy.test.ts +34 -0
  115. package/src/__tests__/persona-resolver.test.ts +49 -14
  116. package/src/__tests__/plugin-api-model-profiles.test.ts +178 -0
  117. package/src/__tests__/plugin-api-provider.test.ts +24 -0
  118. package/src/__tests__/plugin-tool-contribution.test.ts +6 -3
  119. package/src/__tests__/post-compaction-reinjection-idempotency.test.ts +214 -0
  120. package/src/__tests__/provider-send-message-override-profile.test.ts +76 -0
  121. package/src/__tests__/reaction-persistence.test.ts +150 -29
  122. package/src/__tests__/registry.test.ts +2 -7
  123. package/src/__tests__/relay-server.test.ts +285 -0
  124. package/src/__tests__/runtime-attachment-metadata.test.ts +0 -1
  125. package/src/__tests__/schedule-routes-workflow-validation.test.ts +1 -10
  126. package/src/__tests__/schedule-routes.test.ts +0 -30
  127. package/src/__tests__/schedule-tools.test.ts +2 -18
  128. package/src/__tests__/scheduler-reuse-conversation.test.ts +8 -5
  129. package/src/__tests__/secret-response-routing.test.ts +35 -0
  130. package/src/__tests__/secret-routes-platform-proxy.test.ts +16 -2
  131. package/src/__tests__/skill-execute-input.test.ts +177 -1
  132. package/src/__tests__/skill-load-tool.test.ts +72 -0
  133. package/src/__tests__/skill-runtime-path.test.ts +2 -3
  134. package/src/__tests__/skills.test.ts +51 -0
  135. package/src/__tests__/slack-notification-approval-card.test.ts +176 -0
  136. package/src/__tests__/slack-reaction-canonical-approval.test.ts +285 -0
  137. package/src/__tests__/subagent-tools.test.ts +266 -0
  138. package/src/__tests__/surface-completion-nudge-hook.test.ts +367 -0
  139. package/src/__tests__/system-storage-cleanup-skill.test.ts +56 -0
  140. package/src/__tests__/task-progress-nudge-hook.test.ts +1 -1
  141. package/src/__tests__/title-generate-hook.test.ts +100 -3
  142. package/src/__tests__/token-estimator-accuracy.benchmark.test.ts +1 -29
  143. package/src/__tests__/token-manager.test.ts +519 -0
  144. package/src/__tests__/tool-approval-seed-content-blocks.test.ts +1 -1
  145. package/src/__tests__/tool-audit-listener.test.ts +7 -7
  146. package/src/__tests__/tool-executor-lifecycle-events.test.ts +6 -3
  147. package/src/__tests__/tool-executor.test.ts +0 -79
  148. package/src/__tests__/trusted-contact-approval-notifier.test.ts +4 -2
  149. package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +220 -3
  150. package/src/__tests__/trusted-contact-multichannel.test.ts +3 -3
  151. package/src/__tests__/trusted-contact-verification.test.ts +8 -10
  152. package/src/__tests__/twilio-routes.test.ts +81 -1
  153. package/src/__tests__/voice-invite-redemption.test.ts +2 -3
  154. package/src/__tests__/weak-open-model.test.ts +30 -0
  155. package/src/__tests__/web-search-catalog-parity.test.ts +6 -25
  156. package/src/__tests__/workspace-greetings.test.ts +152 -0
  157. package/src/__tests__/workspace-migration-105-enable-memory-v3-live-for-new-workspaces.test.ts +149 -0
  158. package/src/__tests__/workspace-migration-108-drop-balanced-economy-profile.test.ts +285 -0
  159. package/src/__tests__/workspace-migration-add-send-diagnostics.test.ts +1 -1
  160. package/src/__tests__/workspace-migration-drop-collect-usage-data.test.ts +118 -0
  161. package/src/__tests__/workspace-migration-drop-send-diagnostics.test.ts +118 -0
  162. package/src/a2a/__tests__/e2e-a2a-channel.test.ts +0 -4
  163. package/src/agent/loop.ts +75 -29
  164. package/src/api/README.md +6 -6
  165. package/src/api/events/tool-result.ts +6 -0
  166. package/src/api/events/workflow-completed.ts +53 -0
  167. package/src/api/events/workflow-leaf-finished.ts +38 -0
  168. package/src/api/events/workflow-leaf-started.ts +35 -0
  169. package/src/api/events/workflow-progress.ts +32 -0
  170. package/src/api/events/workflow-started.ts +31 -0
  171. package/src/api/index.ts +40 -0
  172. package/src/api/responses/conversation-message.ts +28 -4
  173. package/src/api/responses/home.ts +26 -4
  174. package/src/api/responses/workflow-journal.ts +53 -0
  175. package/src/approvals/guardian-card-withdrawal.ts +145 -0
  176. package/src/approvals/guardian-decision-primitive.ts +26 -3
  177. package/src/approvals/guardian-request-resolvers.ts +183 -80
  178. package/src/calls/__tests__/channel-admission-reader.test.ts +132 -0
  179. package/src/calls/__tests__/relay-setup-router.test.ts +350 -0
  180. package/src/calls/call-pointer-messages.ts +10 -4
  181. package/src/calls/channel-admission-reader.ts +104 -0
  182. package/src/calls/guardian-dispatch.ts +17 -45
  183. package/src/calls/media-stream-server.ts +84 -2
  184. package/src/calls/relay-access-wait.ts +1 -1
  185. package/src/calls/relay-server.ts +66 -0
  186. package/src/calls/relay-setup-router.ts +82 -1
  187. package/src/calls/twilio-routes.ts +17 -8
  188. package/src/calls/voice-session-bridge.ts +2 -2
  189. package/src/cli/commands/clients.ts +3 -0
  190. package/src/cli/commands/db/status.ts +37 -3
  191. package/src/cli/commands/{__tests__ → memory/__tests__}/memory-v2-compare-render.test.ts +1 -1
  192. package/src/cli/commands/{__tests__ → memory/__tests__}/memory-v2.test.ts +8 -7
  193. package/src/cli/commands/{__tests__ → memory/__tests__}/memory-v3.test.ts +5 -4
  194. package/src/cli/commands/memory/index.ts +30 -0
  195. package/src/cli/commands/{memory-v2-compare-render.ts → memory/memory-v2-compare-render.ts} +1 -1
  196. package/src/cli/commands/{memory-v2.ts → memory/memory-v2.ts} +6 -15
  197. package/src/cli/commands/{memory-v3.ts → memory/memory-v3.ts} +97 -11
  198. package/src/cli/commands/oauth/status.test.ts +36 -0
  199. package/src/cli/commands/oauth/status.ts +23 -3
  200. package/src/cli/commands/plugins.ts +400 -14
  201. package/src/cli/lib/__tests__/diff-plugin.test.ts +443 -0
  202. package/src/cli/lib/__tests__/inspect-plugin.test.ts +54 -0
  203. package/src/cli/lib/__tests__/install-from-github.test.ts +31 -0
  204. package/src/cli/lib/__tests__/merge-plugin-tree.test.ts +443 -0
  205. package/src/cli/lib/__tests__/plugin-pin-history.test.ts +162 -0
  206. package/src/cli/lib/__tests__/plugin-surfaces.test.ts +111 -0
  207. package/src/cli/lib/__tests__/upgrade-plugin.test.ts +295 -2
  208. package/src/cli/lib/diff-plugin.ts +346 -0
  209. package/src/cli/lib/inspect-plugin.ts +12 -1
  210. package/src/cli/lib/install-from-github.ts +128 -19
  211. package/src/cli/lib/merge-plugin-tree.ts +328 -0
  212. package/src/cli/lib/plugin-fingerprint.ts +14 -0
  213. package/src/cli/lib/plugin-marketplace.ts +11 -0
  214. package/src/cli/lib/plugin-pin-history.ts +257 -0
  215. package/src/cli/lib/plugin-surfaces.ts +104 -0
  216. package/src/cli/lib/upgrade-plugin.ts +298 -10
  217. package/src/cli/program.ts +2 -6
  218. package/src/config/__tests__/sync-gated-profiles.test.ts +368 -0
  219. package/src/config/assistant-feature-flags.ts +22 -7
  220. package/src/config/bundled-skills/contacts/tools/contact-search.ts +0 -1
  221. package/src/config/bundled-skills/document-editor/SKILL.md +3 -3
  222. package/src/config/bundled-skills/document-editor/TOOLS.json +2 -2
  223. package/src/config/bundled-skills/messaging/SKILL.md +6 -4
  224. package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +9 -8
  225. package/src/config/bundled-skills/subagent/SKILL.md +4 -0
  226. package/src/config/bundled-skills/subagent/TOOLS.json +4 -0
  227. package/src/config/bundled-skills/system-storage-cleanup/SKILL.md +74 -0
  228. package/src/config/bundled-skills/workflows/SKILL.md +14 -8
  229. package/src/config/bundled-tool-registry.ts +2 -7
  230. package/src/config/call-site-defaults.ts +15 -2
  231. package/src/config/feature-flag-registry.json +46 -31
  232. package/src/config/inference-profile-validation.ts +26 -0
  233. package/src/config/llm-resolver.ts +3 -0
  234. package/src/config/loader.ts +4 -0
  235. package/src/config/memory-v3-gate.ts +11 -0
  236. package/src/config/profile-order.ts +28 -0
  237. package/src/config/schema.ts +8 -6
  238. package/src/config/schemas/__tests__/memory-v3.test.ts +1 -0
  239. package/src/config/schemas/call-site-catalog.ts +7 -0
  240. package/src/config/schemas/channels.ts +11 -0
  241. package/src/config/schemas/elevenlabs.ts +0 -1
  242. package/src/config/schemas/llm.ts +31 -0
  243. package/src/config/schemas/memory-lifecycle.ts +3 -7
  244. package/src/config/schemas/memory-v3.ts +6 -0
  245. package/src/config/schemas/platform.ts +0 -8
  246. package/src/config/schemas/services.ts +18 -0
  247. package/src/config/seed-inference-profiles.ts +109 -44
  248. package/src/config/skills.ts +21 -0
  249. package/src/config/sync-gated-profiles.ts +220 -0
  250. package/src/contacts/contact-store.ts +89 -106
  251. package/src/contacts/contacts-write.ts +5 -22
  252. package/src/contacts/types.ts +0 -1
  253. package/src/context/compactor.ts +88 -54
  254. package/src/context/strip-injections.ts +58 -10
  255. package/src/context/token-estimator.ts +1 -1
  256. package/src/credential-execution/process-manager.ts +55 -14
  257. package/src/credential-execution/prompted-credential.ts +2 -3
  258. package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +3 -2
  259. package/src/daemon/__tests__/conversation-tool-setup.test.ts +44 -0
  260. package/src/daemon/config-watcher.ts +0 -4
  261. package/src/daemon/conversation-agent-loop-handlers.ts +2 -0
  262. package/src/daemon/conversation-agent-loop.ts +114 -22
  263. package/src/daemon/conversation-history.ts +1 -1
  264. package/src/daemon/conversation-lifecycle.ts +3 -5
  265. package/src/daemon/conversation-process.ts +13 -5
  266. package/src/daemon/conversation-runtime-assembly.ts +13 -15
  267. package/src/daemon/conversation-slash.ts +2 -23
  268. package/src/daemon/conversation-surfaces.ts +26 -0
  269. package/src/daemon/conversation-tool-setup.ts +53 -19
  270. package/src/daemon/conversation.ts +131 -20
  271. package/src/daemon/disk-pressure-policy.ts +5 -3
  272. package/src/daemon/handlers/__tests__/config-a2a-complete.test.ts +0 -1
  273. package/src/daemon/handlers/__tests__/config-a2a-redeem.test.ts +0 -1
  274. package/src/daemon/handlers/config-a2a.ts +0 -2
  275. package/src/daemon/handlers/config-channels.ts +15 -16
  276. package/src/daemon/handlers/config-slack-channel.ts +22 -3
  277. package/src/daemon/handlers/conversations.ts +107 -0
  278. package/src/daemon/host-browser-proxy.ts +41 -0
  279. package/src/daemon/lifecycle.ts +55 -27
  280. package/src/daemon/memory-v2-startup.test.ts +131 -0
  281. package/src/daemon/memory-v2-startup.ts +100 -1
  282. package/src/daemon/message-provenance.ts +2 -0
  283. package/src/daemon/message-types/contacts.ts +0 -1
  284. package/src/daemon/message-types/conversations.ts +3 -3
  285. package/src/daemon/message-types/sync.ts +0 -1
  286. package/src/daemon/message-types/web-activity.ts +7 -1
  287. package/src/daemon/message-types/workflows.ts +83 -1
  288. package/src/daemon/orphan-reaper.test.ts +0 -19
  289. package/src/daemon/orphan-reaper.ts +2 -24
  290. package/src/daemon/server.ts +0 -10
  291. package/src/daemon/tool-setup-types.ts +4 -0
  292. package/src/daemon/trust-context.ts +1 -1
  293. package/src/daemon/wake-conversation-ops.ts +1 -0
  294. package/src/events/tool-audit-listener.ts +2 -2
  295. package/src/home/feed-source-enrichment.test.ts +151 -0
  296. package/src/home/feed-source-enrichment.ts +176 -0
  297. package/src/home/relationship-state.ts +2 -4
  298. package/src/instrument.ts +18 -6
  299. package/src/ipc/__tests__/binary-result-ipc.test.ts +81 -0
  300. package/src/ipc/__tests__/clients-list-ipc.test.ts +20 -0
  301. package/src/ipc/assistant-server.ts +37 -4
  302. package/src/ipc/gateway-flag-listener.ts +18 -2
  303. package/src/memory/__tests__/auto-analysis-enqueue.test.ts +5 -16
  304. package/src/memory/__tests__/db-logs-attach.test.ts +122 -0
  305. package/src/memory/__tests__/jobs-store-enqueue-gate.test.ts +7 -11
  306. package/src/memory/__tests__/memory-retrospective-enqueue.test.ts +37 -7
  307. package/src/memory/__tests__/memory-retrospective-job.test.ts +229 -401
  308. package/src/memory/__tests__/onboarding-events-store.test.ts +7 -7
  309. package/src/memory/auth-fallback-events-store.ts +2 -2
  310. package/src/memory/auto-analysis-enqueue.ts +3 -5
  311. package/src/memory/bookmark-crud.ts +1 -2
  312. package/src/memory/canonical-guardian-store.ts +39 -1
  313. package/src/memory/conversation-crud.ts +9 -4
  314. package/src/memory/conversation-key-store.ts +17 -2
  315. package/src/memory/conversation-title-service.ts +64 -7
  316. package/src/memory/db-async-query.ts +20 -2
  317. package/src/memory/db-connection.ts +49 -5
  318. package/src/memory/db-init.ts +17 -17
  319. package/src/memory/embedding-backend.ts +38 -1
  320. package/src/memory/embedding-billing-breaker.ts +96 -0
  321. package/src/memory/jobs-store.ts +25 -13
  322. package/src/memory/jobs-worker.ts +54 -1
  323. package/src/memory/lifecycle-events-store.ts +2 -2
  324. package/src/memory/memory-retrospective-constants.ts +4 -4
  325. package/src/memory/memory-retrospective-enqueue.ts +31 -6
  326. package/src/memory/memory-retrospective-job.ts +28 -227
  327. package/src/memory/migrations/129-contact-channels-access-fields.ts +18 -9
  328. package/src/memory/migrations/131-drop-legacy-member-guardian-tables.ts +14 -2
  329. package/src/memory/migrations/289-contact-channels-unique-ext-user.ts +10 -0
  330. package/src/memory/migrations/291-contact-channels-renormalize-addresses.ts +72 -0
  331. package/src/memory/migrations/292-schedule-default-no-reuse-conversation.test.ts +67 -0
  332. package/src/memory/migrations/292-schedule-default-no-reuse-conversation.ts +25 -0
  333. package/src/memory/migrations/293-workflow-journal-leaf-tokens.ts +32 -0
  334. package/src/memory/migrations/294-drop-external-user-id.ts +31 -0
  335. package/src/memory/migrations/295-drop-approval-prompt-ts-tracker.ts +20 -0
  336. package/src/memory/migrations/296-rewrite-balanced-economy-profile-pins.test.ts +110 -0
  337. package/src/memory/migrations/296-rewrite-balanced-economy-profile-pins.ts +68 -0
  338. package/src/memory/migrations/__tests__/131-drop-legacy-member-guardian-tables.test.ts +154 -0
  339. package/src/memory/migrations/__tests__/289-contact-channels-unique-ext-user.test.ts +31 -0
  340. package/src/memory/migrations/__tests__/291-contact-channels-renormalize-addresses.test.ts +341 -0
  341. package/src/memory/migrations/__tests__/run-migrations.test.ts +52 -0
  342. package/src/memory/migrations/index.ts +6 -0
  343. package/src/memory/migrations/run-migrations.ts +41 -0
  344. package/src/memory/migrations/validate-migration-state.ts +1 -1
  345. package/src/memory/onboarding-events-store.ts +3 -3
  346. package/src/memory/schema/contacts.ts +0 -5
  347. package/src/memory/skill-loaded-events-store.test.ts +7 -15
  348. package/src/memory/skill-loaded-events-store.ts +2 -2
  349. package/src/memory/tool-executed-events-store.test.ts +7 -7
  350. package/src/memory/turn-trace-store.test.ts +736 -0
  351. package/src/memory/turn-trace-store.ts +364 -0
  352. package/src/memory/v2/__tests__/consolidation-job.test.ts +8 -0
  353. package/src/memory/v2/__tests__/skill-content.test.ts +30 -0
  354. package/src/memory/v2/consolidation-job.ts +2 -2
  355. package/src/memory/v2/skill-content.ts +25 -7
  356. package/src/memory/v2/skill-store.ts +7 -1
  357. package/src/memory/v3-eval/__tests__/eval-packets.test.ts +248 -0
  358. package/src/memory/v3-eval/eval-packets.ts +546 -0
  359. package/src/messaging/providers/slack/adapter.ts +1 -1
  360. package/src/messaging/providers/slack/api.ts +31 -0
  361. package/src/messaging/providers/slack/send.test.ts +114 -2
  362. package/src/messaging/providers/slack/send.ts +30 -7
  363. package/src/messaging/providers/slack/withdraw.test.ts +200 -0
  364. package/src/messaging/providers/slack/withdraw.ts +161 -0
  365. package/src/notifications/AGENTS.md +2 -0
  366. package/src/notifications/access-request-copy.ts +72 -59
  367. package/src/notifications/adapters/shared.ts +29 -0
  368. package/src/notifications/adapters/slack.ts +58 -103
  369. package/src/notifications/adapters/telegram.ts +2 -20
  370. package/src/notifications/approval-card-data.ts +333 -0
  371. package/src/notifications/broadcaster.ts +16 -3
  372. package/src/notifications/canonical-delivery-recorder.ts +139 -0
  373. package/src/notifications/copy-composer.ts +3 -3
  374. package/src/notifications/decision-engine.ts +4 -2
  375. package/src/notifications/destination-resolver.ts +4 -6
  376. package/src/notifications/guardian-question-mode.ts +10 -0
  377. package/src/notifications/home-feed-side-effect.ts +7 -16
  378. package/src/notifications/notification-utils.ts +19 -20
  379. package/src/notifications/signal.ts +79 -43
  380. package/src/notifications/types.ts +98 -121
  381. package/src/oauth/AGENTS.md +5 -24
  382. package/src/permissions/checker.test.ts +51 -0
  383. package/src/permissions/checker.ts +185 -26
  384. package/src/permissions/ipc-risk-types.ts +24 -0
  385. package/src/permissions/question-prompter.test.ts +27 -0
  386. package/src/permissions/question-prompter.ts +4 -0
  387. package/src/permissions/secret-prompter.ts +15 -1
  388. package/src/platform/client.test.ts +119 -0
  389. package/src/platform/client.ts +66 -0
  390. package/src/platform/consent-cache.test.ts +267 -0
  391. package/src/platform/consent-cache.ts +174 -0
  392. package/src/plugin-api/constants.ts +1 -1
  393. package/src/plugin-api/index.ts +33 -1
  394. package/src/plugin-api/model-profiles.ts +33 -0
  395. package/src/plugin-api/types.ts +50 -2
  396. package/src/plugins/defaults/advisor/__tests__/advisor-gate.test.ts +56 -0
  397. package/src/plugins/defaults/advisor/__tests__/advisor-state-store.test.ts +43 -0
  398. package/src/plugins/defaults/advisor/__tests__/agent-loop-integration.test.ts +137 -0
  399. package/src/plugins/defaults/advisor/__tests__/consult.test.ts +153 -0
  400. package/src/plugins/defaults/advisor/__tests__/hooks.test.ts +138 -0
  401. package/src/plugins/defaults/advisor/__tests__/transcript.test.ts +147 -0
  402. package/src/plugins/defaults/advisor/advisor-gate.ts +29 -0
  403. package/src/plugins/defaults/advisor/advisor-state-store.ts +94 -0
  404. package/src/plugins/defaults/advisor/config.ts +21 -0
  405. package/src/plugins/defaults/advisor/consult.ts +93 -0
  406. package/src/plugins/defaults/advisor/hooks/post-model-call.ts +34 -0
  407. package/src/plugins/defaults/advisor/hooks/pre-model-call.ts +30 -0
  408. package/src/plugins/defaults/advisor/hooks/user-prompt-submit.ts +19 -0
  409. package/src/plugins/defaults/advisor/package.json +14 -0
  410. package/src/plugins/defaults/advisor/steering.ts +67 -0
  411. package/src/plugins/defaults/advisor/tools/advisor.ts +65 -0
  412. package/src/plugins/defaults/advisor/transcript.ts +76 -0
  413. package/src/plugins/defaults/compaction/window-manager.ts +18 -0
  414. package/src/plugins/defaults/index.ts +60 -0
  415. package/src/plugins/defaults/memory-retrieval/hooks/post-compact.ts +22 -9
  416. package/src/plugins/defaults/memory-retrieval/hooks/user-prompt-submit.ts +2 -2
  417. package/src/plugins/defaults/memory-retrieval/injectors.ts +4 -4
  418. package/src/plugins/defaults/memory-retrieval/tail-reinjection-strip.ts +64 -0
  419. package/src/plugins/defaults/memory-retrieval/unified-turn-context.ts +29 -21
  420. package/src/plugins/defaults/memory-v3-shadow/__tests__/carry-integration.test.ts +1 -0
  421. package/src/plugins/defaults/memory-v3-shadow/__tests__/injection.test.ts +1 -0
  422. package/src/plugins/defaults/memory-v3-shadow/__tests__/maintain-job.test.ts +129 -9
  423. package/src/plugins/defaults/memory-v3-shadow/__tests__/orchestrate.test.ts +31 -4
  424. package/src/plugins/defaults/memory-v3-shadow/__tests__/selection-log-store.test.ts +77 -2
  425. package/src/plugins/defaults/memory-v3-shadow/__tests__/shadow-plugin.test.ts +1 -0
  426. package/src/plugins/defaults/memory-v3-shadow/injector.ts +7 -10
  427. package/src/plugins/defaults/memory-v3-shadow/maintain-job.ts +144 -11
  428. package/src/plugins/defaults/memory-v3-shadow/orchestrate.ts +32 -20
  429. package/src/plugins/defaults/memory-v3-shadow/selection-log-store.ts +56 -3
  430. package/src/plugins/defaults/memory-v3-shadow/shadow-plugin.ts +23 -2
  431. package/src/plugins/defaults/surface-completion-nudge/hooks/post-model-call.ts +276 -0
  432. package/src/plugins/defaults/surface-completion-nudge/hooks/stop.ts +22 -0
  433. package/src/plugins/defaults/surface-completion-nudge/nudge-state-store.ts +46 -0
  434. package/src/plugins/defaults/surface-completion-nudge/package.json +14 -0
  435. package/src/plugins/defaults/task-progress-nudge/hooks/post-tool-use.ts +3 -13
  436. package/src/plugins/defaults/title-generate/hooks/stop.ts +56 -21
  437. package/src/prompts/persona-resolver.ts +14 -4
  438. package/src/prompts/templates/system-sections.ts +7 -2
  439. package/src/providers/__tests__/count-tokens-forwarding.test.ts +98 -0
  440. package/src/providers/__tests__/provider-env-vars.test.ts +6 -0
  441. package/src/providers/__tests__/provider-secret-catalog.test.ts +1 -0
  442. package/src/providers/__tests__/retry-callsite.test.ts +176 -0
  443. package/src/providers/anthropic/client.ts +230 -175
  444. package/src/providers/atlascloud/client.ts +85 -0
  445. package/src/providers/call-site-routing.ts +10 -0
  446. package/src/providers/fetch-provider-catalog.ts +85 -0
  447. package/src/providers/gemini/client.ts +43 -0
  448. package/src/providers/inference/adapter-factory.ts +3 -0
  449. package/src/providers/model-catalog.ts +58 -0
  450. package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +33 -0
  451. package/src/providers/openai/chat-completions-provider.ts +7 -0
  452. package/src/providers/openai/responses-provider.ts +10 -0
  453. package/src/providers/provider-send-message.ts +11 -3
  454. package/src/providers/ratelimit.ts +9 -0
  455. package/src/providers/retry.ts +62 -12
  456. package/src/providers/search-provider-catalog.ts +10 -0
  457. package/src/providers/types.ts +16 -0
  458. package/src/providers/usage-tracking.ts +7 -0
  459. package/src/providers/weak-open-model.ts +22 -0
  460. package/src/runtime/AGENTS.md +0 -1
  461. package/src/runtime/__tests__/agent-wake.test.ts +227 -0
  462. package/src/runtime/__tests__/client-health.test.ts +44 -0
  463. package/src/runtime/access-request-helper.ts +21 -53
  464. package/src/runtime/actor-trust-resolver.ts +59 -63
  465. package/src/runtime/agent-wake.ts +71 -0
  466. package/src/runtime/assistant-event-hub.ts +18 -4
  467. package/src/runtime/auth/__tests__/route-policy.test.ts +12 -0
  468. package/src/runtime/auth/require-bound-guardian.ts +1 -4
  469. package/src/runtime/btw-sidechain.ts +3 -6
  470. package/src/runtime/capabilities.test.ts +120 -0
  471. package/src/runtime/capabilities.ts +197 -0
  472. package/src/runtime/channel-approval-types.ts +22 -45
  473. package/src/runtime/channel-invite-transports/telegram.ts +4 -4
  474. package/src/runtime/channel-retry-sweep.ts +1 -0
  475. package/src/runtime/channel-verification-service.ts +3 -3
  476. package/src/runtime/client-health.ts +26 -0
  477. package/src/runtime/confirmation-request-guardian-bridge.ts +38 -29
  478. package/src/runtime/effective-capabilities.test.ts +128 -0
  479. package/src/runtime/effective-capabilities.ts +84 -0
  480. package/src/runtime/guardian-reply-router.ts +106 -21
  481. package/src/runtime/invite-redemption-service.ts +9 -25
  482. package/src/runtime/migrations/__tests__/vbundle-builder-fd-leak.test.ts +126 -0
  483. package/src/runtime/migrations/vbundle-builder.ts +49 -20
  484. package/src/runtime/pending-interactions.ts +35 -0
  485. package/src/runtime/routes/__tests__/client-routes.test.ts +13 -0
  486. package/src/runtime/routes/__tests__/conversation-management-routes.test.ts +67 -0
  487. package/src/runtime/routes/__tests__/plugins-routes.test.ts +383 -1
  488. package/src/runtime/routes/app-routes.ts +1 -1
  489. package/src/runtime/routes/approval-routes.ts +40 -9
  490. package/src/runtime/routes/approval-strategies/guardian-callback-strategy.ts +2 -2
  491. package/src/runtime/routes/assets/vellum-design-system.css +1959 -0
  492. package/src/runtime/routes/browser-tabs-routes.ts +9 -0
  493. package/src/runtime/routes/btw-routes.ts +1 -27
  494. package/src/runtime/routes/canonical-guardian-expiry-sweep.ts +17 -8
  495. package/src/runtime/routes/client-routes.ts +10 -0
  496. package/src/runtime/routes/contact-routes.ts +31 -8
  497. package/src/runtime/routes/conversation-compaction-routes.ts +1 -1
  498. package/src/runtime/routes/conversation-management-routes.ts +80 -1
  499. package/src/runtime/routes/conversation-query-routes.ts +68 -22
  500. package/src/runtime/routes/conversation-routes.ts +39 -14
  501. package/src/runtime/routes/credential-routes.ts +40 -16
  502. package/src/runtime/routes/empty-state-greeting-cache.ts +1 -2
  503. package/src/runtime/routes/events-routes.ts +1 -3
  504. package/src/runtime/routes/guardian-approval-interception.ts +14 -73
  505. package/src/runtime/routes/guardian-approval-prompt.ts +22 -4
  506. package/src/runtime/routes/home-feed-routes.ts +8 -3
  507. package/src/runtime/routes/identity-routes.ts +1 -296
  508. package/src/runtime/routes/inbound-message-handler.ts +214 -228
  509. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +89 -7
  510. package/src/runtime/routes/inbound-stages/admission-policy.test.ts +154 -0
  511. package/src/runtime/routes/inbound-stages/admission-policy.ts +140 -0
  512. package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +3 -3
  513. package/src/runtime/routes/inbound-stages/background-dispatch.ts +11 -6
  514. package/src/runtime/routes/inbound-stages/escalation-intercept.ts +1 -2
  515. package/src/runtime/routes/inbound-stages/guardian-activation-intercept.ts +1 -2
  516. package/src/runtime/routes/inbound-stages/guardian-reply-intercept.test.ts +7 -7
  517. package/src/runtime/routes/inbound-stages/guardian-reply-intercept.ts +47 -28
  518. package/src/runtime/routes/inbound-stages/reaction-intercept.ts +358 -0
  519. package/src/runtime/routes/index.ts +2 -0
  520. package/src/runtime/routes/integrations/slack/__tests__/channel.test.ts +8 -0
  521. package/src/runtime/routes/integrations/slack/channel.ts +36 -0
  522. package/src/runtime/routes/internal-telemetry-routes.ts +1 -1
  523. package/src/runtime/routes/mcp-auth-routes.ts +233 -41
  524. package/src/runtime/routes/memory-eval-routes.ts +87 -0
  525. package/src/runtime/routes/notification-routes.ts +122 -133
  526. package/src/runtime/routes/platform-routes.ts +2 -2
  527. package/src/runtime/routes/plugins-routes.ts +366 -11
  528. package/src/runtime/routes/schedule-routes.ts +0 -22
  529. package/src/runtime/routes/secret-routes.ts +15 -0
  530. package/src/runtime/routes/surface-action-routes.ts +2 -1
  531. package/src/runtime/routes/tool-call-question-enrichment.test.ts +146 -0
  532. package/src/runtime/routes/tool-call-question-enrichment.ts +66 -0
  533. package/src/runtime/routes/workflow-routes.test.ts +229 -44
  534. package/src/runtime/routes/workflow-routes.ts +131 -29
  535. package/src/runtime/routes/workspace-greetings.ts +55 -0
  536. package/src/runtime/sync/resource-sync-events.ts +1 -11
  537. package/src/runtime/tool-grant-request-helper.ts +18 -16
  538. package/src/runtime/trust-context-resolver.ts +8 -5
  539. package/src/schedule/inference-profile.ts +2 -14
  540. package/src/schedule/schedule-store.ts +1 -1
  541. package/src/schedule/scheduler-types.ts +5 -1
  542. package/src/security/__tests__/provider-key-env-fallback.test.ts +6 -0
  543. package/src/security/secret-patterns.ts +3 -0
  544. package/src/subagent/manager.ts +17 -4
  545. package/src/subagent/types.ts +6 -0
  546. package/src/telemetry/trace-collection-policy.test.ts +28 -0
  547. package/src/telemetry/trace-collection-policy.ts +30 -0
  548. package/src/telemetry/types.ts +89 -0
  549. package/src/telemetry/usage-telemetry-reporter.test.ts +586 -36
  550. package/src/telemetry/usage-telemetry-reporter.ts +148 -41
  551. package/src/tools/AGENTS.md +3 -3
  552. package/src/tools/browser/__tests__/browser-execution-acquire.test.ts +31 -0
  553. package/src/tools/browser/browser-execution.ts +30 -19
  554. package/src/tools/document/document-tool.ts +30 -6
  555. package/src/tools/executor.ts +5 -3
  556. package/src/tools/host-terminal/host-shell.ts +5 -4
  557. package/src/tools/memory/register.ts +2 -2
  558. package/src/tools/network/__tests__/web-fetch-firecrawl.test.ts +360 -0
  559. package/src/tools/network/__tests__/web-search.test.ts +143 -0
  560. package/src/tools/network/web-fetch.ts +372 -1
  561. package/src/tools/network/web-search-error.ts +1 -1
  562. package/src/tools/network/web-search.ts +213 -10
  563. package/src/tools/permission-checker.ts +4 -3
  564. package/src/tools/registry.ts +20 -0
  565. package/src/tools/schedule/create.ts +7 -12
  566. package/src/tools/schedule/update.ts +4 -11
  567. package/src/tools/shared/filesystem/path-policy.ts +39 -13
  568. package/src/tools/side-effects.ts +2 -17
  569. package/src/tools/skills/execute.ts +99 -2
  570. package/src/tools/skills/load.ts +43 -2
  571. package/src/tools/subagent/spawn.ts +64 -15
  572. package/src/tools/terminal/shell.ts +10 -4
  573. package/src/tools/tool-approval-handler.ts +18 -13
  574. package/src/tools/tool-manifest.ts +0 -2
  575. package/src/tools/types.ts +10 -0
  576. package/src/tools/ui-surface/definitions.ts +64 -3
  577. package/src/tools/verification-control-plane-policy.ts +3 -1
  578. package/src/tools/workflows/run-workflow.test.ts +8 -18
  579. package/src/tools/workflows/run-workflow.ts +1 -0
  580. package/src/util/disk-usage.ts +78 -23
  581. package/src/util/logs-db-path.ts +22 -0
  582. package/src/util/platform.ts +10 -3
  583. package/src/watcher/telemetry.ts +2 -2
  584. package/src/workflows/capabilities.ts +2 -3
  585. package/src/workflows/engine.test.ts +175 -1
  586. package/src/workflows/engine.ts +82 -0
  587. package/src/workflows/journal-store.test.ts +70 -0
  588. package/src/workflows/journal-store.ts +18 -3
  589. package/src/workflows/run-manager.test.ts +171 -28
  590. package/src/workflows/run-manager.ts +66 -24
  591. package/src/workspace/migrations/105-enable-memory-v3-live-for-new-workspaces.ts +63 -0
  592. package/src/workspace/migrations/106-drop-collect-usage-data.ts +47 -0
  593. package/src/workspace/migrations/107-drop-send-diagnostics.ts +47 -0
  594. package/src/workspace/migrations/108-drop-balanced-economy-profile.ts +129 -0
  595. package/src/workspace/migrations/registry.ts +8 -0
  596. package/src/__tests__/app-control-no-global-cgevent.test.ts +0 -98
  597. package/src/__tests__/credential-security-e2e.test.ts +0 -362
  598. package/src/__tests__/credential-vault-unit.test.ts +0 -1528
  599. package/src/__tests__/credential-vault.test.ts +0 -1706
  600. package/src/__tests__/identity-intro-cache.test.ts +0 -315
  601. package/src/__tests__/secret-onetime-send.test.ts +0 -182
  602. package/src/cli/commands/__tests__/task.test.ts +0 -914
  603. package/src/cli/commands/task.ts +0 -771
  604. package/src/config/bundled-skills/personal-page/SKILL.md +0 -57
  605. package/src/config/bundled-skills/personal-page/TOOLS.json +0 -27
  606. package/src/config/bundled-skills/personal-page/tools/app-refresh.ts +0 -17
  607. package/src/config/preloaded-apps/personal-page/src/components/About.tsx +0 -22
  608. package/src/config/preloaded-apps/personal-page/src/components/App.tsx +0 -16
  609. package/src/config/preloaded-apps/personal-page/src/components/Features.tsx +0 -77
  610. package/src/config/preloaded-apps/personal-page/src/components/Hero.tsx +0 -57
  611. package/src/config/preloaded-apps/personal-page/src/components/Pending.tsx +0 -28
  612. package/src/config/preloaded-apps/personal-page/src/components/animations.tsx +0 -234
  613. package/src/config/preloaded-apps/personal-page/src/components/icons.tsx +0 -48
  614. package/src/config/preloaded-apps/personal-page/src/components/media.ts +0 -16
  615. package/src/config/preloaded-apps/personal-page/src/index.html +0 -20
  616. package/src/config/preloaded-apps/personal-page/src/main.tsx +0 -7
  617. package/src/config/preloaded-apps/personal-page/src/profile-data.ts +0 -82
  618. package/src/config/preloaded-apps/personal-page/src/styles.css +0 -759
  619. package/src/memory/__tests__/preloaded-apps.test.ts +0 -85
  620. package/src/memory/preloaded-apps.ts +0 -116
  621. package/src/notifications/tool-approval-copy.ts +0 -142
  622. package/src/runtime/routes/approval-prompt-ts-tracker.ts +0 -78
  623. package/src/runtime/routes/identity-intro-cache.ts +0 -172
  624. package/src/tools/credentials/vault.ts +0 -712
@@ -34,6 +34,12 @@
34
34
 
35
35
  import { beforeEach, describe, expect, mock, test } from "bun:test";
36
36
 
37
+ import {
38
+ type DiffPluginDeps,
39
+ type DiffPluginOptions,
40
+ type PluginDiffResult,
41
+ PluginDiffUnavailableError,
42
+ } from "../../../cli/lib/diff-plugin.js";
37
43
  import {
38
44
  type InspectPluginDeps,
39
45
  type InspectPluginOptions,
@@ -54,6 +60,11 @@ import {
54
60
  PluginDetailsNotFoundError,
55
61
  type PluginDetailsOptions,
56
62
  } from "../../../cli/lib/plugin-details.js";
63
+ import {
64
+ DEFAULT_PIN_HISTORY_LIMIT,
65
+ type PluginPinHistoryEntry,
66
+ PluginPinHistoryError,
67
+ } from "../../../cli/lib/plugin-pin-history.js";
57
68
  import type {
58
69
  PluginCatalog,
59
70
  PluginSearchMatch,
@@ -66,6 +77,7 @@ import {
66
77
  type UninstallPluginResult,
67
78
  } from "../../../cli/lib/uninstall-plugin.js";
68
79
  import {
80
+ PluginMergeBaselineError,
69
81
  PluginNotUpgradableError,
70
82
  type PluginUpgradeResult,
71
83
  type UpgradePluginDeps,
@@ -173,10 +185,49 @@ const upgradeSpy = mock(
173
185
  );
174
186
 
175
187
  mock.module("../../../cli/lib/upgrade-plugin.js", () => ({
188
+ PluginMergeBaselineError,
176
189
  PluginNotUpgradableError,
177
190
  upgradePlugin: upgradeSpy,
178
191
  }));
179
192
 
193
+ // Mock diffPlugin: the lib re-materializes the install commit and computes the
194
+ // per-file unified diff (covered by diff-plugin.test.ts); the route forwards
195
+ // the name and maps the lib's error taxonomy to HTTP status codes.
196
+ const diffSpy = mock(
197
+ async (
198
+ _opts: DiffPluginOptions,
199
+ _deps: DiffPluginDeps,
200
+ ): Promise<PluginDiffResult> => {
201
+ throw new Error("diffSpy default impl not configured");
202
+ },
203
+ );
204
+
205
+ mock.module("../../../cli/lib/diff-plugin.js", () => ({
206
+ PluginDiffUnavailableError,
207
+ diffPlugin: diffSpy,
208
+ }));
209
+
210
+ // Mock the pin-history lib: the GitHub commit-history walk is covered by
211
+ // plugin-pin-history.test.ts; the routes only forward the name, validate a pin
212
+ // against the resolved history, and map errors.
213
+ const listPinHistorySpy = mock(
214
+ async (..._args: unknown[]): Promise<PluginPinHistoryEntry[]> => {
215
+ throw new Error("listPinHistorySpy default impl not configured");
216
+ },
217
+ );
218
+ const resolvePinSpy = mock(
219
+ async (..._args: unknown[]): Promise<PluginPinHistoryEntry | null> => {
220
+ throw new Error("resolvePinSpy default impl not configured");
221
+ },
222
+ );
223
+
224
+ mock.module("../../../cli/lib/plugin-pin-history.js", () => ({
225
+ DEFAULT_PIN_HISTORY_LIMIT,
226
+ PluginPinHistoryError,
227
+ listPinHistory: listPinHistorySpy,
228
+ resolvePinToMarketplaceCommit: resolvePinSpy,
229
+ }));
230
+
180
231
  import {
181
232
  BadRequestError,
182
233
  ConflictError,
@@ -199,7 +250,9 @@ const uninstallHandler = findHandler("plugins_uninstall");
199
250
  const getHandler = findHandler("plugins_get");
200
251
  const installHandler = findHandler("plugins_install");
201
252
  const inspectHandler = findHandler("plugins_inspect");
253
+ const versionsHandler = findHandler("plugins_versions");
202
254
  const upgradeHandler = findHandler("plugins_upgrade");
255
+ const diffHandler = findHandler("plugins_diff");
203
256
 
204
257
  function invoke(args: RouteHandlerArgs = {}): {
205
258
  plugins: Array<Record<string, unknown>>;
@@ -802,6 +855,7 @@ async function invokeInstall(args: RouteHandlerArgs = {}): Promise<{
802
855
  describe("POST /v1/plugins/install", () => {
803
856
  beforeEach(() => {
804
857
  installSpy.mockReset();
858
+ resolvePinSpy.mockReset();
805
859
  });
806
860
 
807
861
  test("forwards name/force and shapes the result, pinning ref to the default", async () => {
@@ -928,6 +982,121 @@ describe("POST /v1/plugins/install", () => {
928
982
  expect(caught).toBeInstanceOf(InternalError);
929
983
  expect((caught as Error).message).toContain("ECONNRESET");
930
984
  });
985
+
986
+ test("a reviewed pin installs from the marketplace commit that introduced it", async () => {
987
+ // GIVEN a pin that resolves to a marketplace commit in the reviewed history
988
+ resolvePinSpy.mockImplementation(async () => ({
989
+ pin: "a".repeat(40),
990
+ marketplaceCommit: "f".repeat(40),
991
+ promotedAt: "2026-06-01T00:00:00.000Z",
992
+ current: false,
993
+ }));
994
+ installSpy.mockImplementation(async (opts) => ({
995
+ name: opts.name,
996
+ target: `/workspace/.vellum/plugins/${opts.name}`,
997
+ fileCount: 7,
998
+ ref: opts.ref ?? "main",
999
+ commit: "a".repeat(40),
1000
+ committedAt: null,
1001
+ }));
1002
+
1003
+ const result = await invokeInstall({
1004
+ body: { name: "caveman", pin: "a".repeat(40) },
1005
+ });
1006
+
1007
+ // THEN the install reads the manifest at the resolving marketplace commit,
1008
+ // not the default branch
1009
+ expect(installSpy.mock.calls[0]?.[0]).toEqual({
1010
+ name: "caveman",
1011
+ ref: "f".repeat(40),
1012
+ force: undefined,
1013
+ });
1014
+ expect(result.ref).toBe("f".repeat(40));
1015
+ });
1016
+
1017
+ test("an unreviewed pin is refused as a BadRequest before installing", async () => {
1018
+ resolvePinSpy.mockImplementation(async () => null);
1019
+
1020
+ await expect(
1021
+ invokeInstall({ body: { name: "caveman", pin: "b".repeat(40) } }),
1022
+ ).rejects.toBeInstanceOf(BadRequestError);
1023
+ expect(installSpy).not.toHaveBeenCalled();
1024
+ });
1025
+
1026
+ test("a pin-history read failure surfaces as ServiceUnavailable (503)", async () => {
1027
+ resolvePinSpy.mockImplementation(async () => {
1028
+ throw new PluginPinHistoryError("HTTP 403");
1029
+ });
1030
+
1031
+ await expect(
1032
+ invokeInstall({ body: { name: "caveman", pin: "c".repeat(40) } }),
1033
+ ).rejects.toBeInstanceOf(ServiceUnavailableError);
1034
+ expect(installSpy).not.toHaveBeenCalled();
1035
+ });
1036
+ });
1037
+
1038
+ describe("GET /v1/plugins/:name/versions", () => {
1039
+ beforeEach(() => {
1040
+ listPinHistorySpy.mockReset();
1041
+ });
1042
+
1043
+ test("returns the resolved pin history", async () => {
1044
+ const history: PluginPinHistoryEntry[] = [
1045
+ {
1046
+ pin: "c".repeat(40),
1047
+ marketplaceCommit: "3".repeat(40),
1048
+ promotedAt: "2026-06-10T00:00:00.000Z",
1049
+ current: true,
1050
+ },
1051
+ {
1052
+ pin: "a".repeat(40),
1053
+ marketplaceCommit: "1".repeat(40),
1054
+ promotedAt: "2026-06-01T00:00:00.000Z",
1055
+ current: false,
1056
+ },
1057
+ ];
1058
+ listPinHistorySpy.mockImplementation(async () => history);
1059
+
1060
+ const result = await versionsHandler({ pathParams: { name: "level-up" } });
1061
+ expect(result).toEqual(history);
1062
+ });
1063
+
1064
+ test("forwards a positive limit to the lib", async () => {
1065
+ listPinHistorySpy.mockImplementation(async () => []);
1066
+ await versionsHandler({
1067
+ pathParams: { name: "level-up" },
1068
+ queryParams: { limit: "3" },
1069
+ });
1070
+ expect(listPinHistorySpy.mock.calls[0]?.[2]).toEqual({ limit: 3 });
1071
+ });
1072
+
1073
+ test("rejects a non-positive limit as BadRequest before calling the lib", async () => {
1074
+ await expect(
1075
+ versionsHandler({
1076
+ pathParams: { name: "level-up" },
1077
+ queryParams: { limit: "0" },
1078
+ }),
1079
+ ).rejects.toBeInstanceOf(BadRequestError);
1080
+ expect(listPinHistorySpy).not.toHaveBeenCalled();
1081
+ });
1082
+
1083
+ test("InvalidPluginNameError → BadRequestError (400)", async () => {
1084
+ listPinHistorySpy.mockImplementation(async () => {
1085
+ throw new InvalidPluginNameError("../escape");
1086
+ });
1087
+ await expect(
1088
+ versionsHandler({ pathParams: { name: "../escape" } }),
1089
+ ).rejects.toBeInstanceOf(BadRequestError);
1090
+ });
1091
+
1092
+ test("PluginPinHistoryError → ServiceUnavailableError (503)", async () => {
1093
+ listPinHistorySpy.mockImplementation(async () => {
1094
+ throw new PluginPinHistoryError("HTTP 429");
1095
+ });
1096
+ await expect(
1097
+ versionsHandler({ pathParams: { name: "level-up" } }),
1098
+ ).rejects.toBeInstanceOf(ServiceUnavailableError);
1099
+ });
931
1100
  });
932
1101
 
933
1102
  function inspection(
@@ -976,6 +1145,10 @@ function inspection(
976
1145
  }
977
1146
  : overrides.remote,
978
1147
  remoteError: overrides.remoteError ?? null,
1148
+ surfaces:
1149
+ overrides.surfaces === undefined
1150
+ ? { skills: [], hooks: ["post-model-call"], tools: [] }
1151
+ : overrides.surfaces,
979
1152
  };
980
1153
  }
981
1154
 
@@ -1080,6 +1253,9 @@ function upgradeResult(
1080
1253
  target: overrides.target ?? "/workspace/.vellum/plugins/level-up",
1081
1254
  fileCount: overrides.fileCount === undefined ? 12 : overrides.fileCount,
1082
1255
  dryRun: overrides.dryRun ?? false,
1256
+ strategy: overrides.strategy ?? "overwrite",
1257
+ conflicts: overrides.conflicts ?? [],
1258
+ binaryConflicts: overrides.binaryConflicts ?? [],
1083
1259
  provenanceWasUnknown: overrides.provenanceWasUnknown ?? false,
1084
1260
  };
1085
1261
  }
@@ -1094,6 +1270,9 @@ async function invokeUpgrade(args: RouteHandlerArgs = {}): Promise<{
1094
1270
  target: string;
1095
1271
  fileCount: number | null;
1096
1272
  dryRun: boolean;
1273
+ strategy: string;
1274
+ conflicts: readonly string[];
1275
+ binaryConflicts: readonly string[];
1097
1276
  provenanceWasUnknown: boolean;
1098
1277
  }> {
1099
1278
  return (await upgradeHandler(args)) as {
@@ -1106,6 +1285,9 @@ async function invokeUpgrade(args: RouteHandlerArgs = {}): Promise<{
1106
1285
  target: string;
1107
1286
  fileCount: number | null;
1108
1287
  dryRun: boolean;
1288
+ strategy: string;
1289
+ conflicts: readonly string[];
1290
+ binaryConflicts: readonly string[];
1109
1291
  provenanceWasUnknown: boolean;
1110
1292
  };
1111
1293
  }
@@ -1136,15 +1318,85 @@ describe("POST /v1/plugins/:name/upgrade", () => {
1136
1318
  target: "/workspace/.vellum/plugins/level-up",
1137
1319
  fileCount: 12,
1138
1320
  dryRun: false,
1321
+ strategy: "overwrite",
1322
+ conflicts: [],
1323
+ binaryConflicts: [],
1139
1324
  provenanceWasUnknown: false,
1140
1325
  });
1141
- // AND the name + dryRun are forwarded to the lib
1326
+ // AND the name + dryRun are forwarded to the lib (strategy omitted)
1142
1327
  expect(upgradeSpy.mock.calls[0]?.[0]).toEqual({
1143
1328
  name: "level-up",
1144
1329
  dryRun: false,
1330
+ strategy: undefined,
1331
+ });
1332
+ });
1333
+
1334
+ test("forwards a requested strategy to the lib and projects it", async () => {
1335
+ // GIVEN upgradePlugin merges local edits forward via the `ours` strategy
1336
+ upgradeSpy.mockImplementation(async () =>
1337
+ upgradeResult({ strategy: "ours" }),
1338
+ );
1339
+
1340
+ // WHEN the handler runs with a strategy in the body
1341
+ const result = await invokeUpgrade({
1342
+ pathParams: { name: "level-up" },
1343
+ body: { strategy: "ours" },
1344
+ });
1345
+
1346
+ // THEN the strategy is forwarded to the lib and surfaced on the wire
1347
+ expect(result.strategy).toBe("ours");
1348
+ expect(upgradeSpy.mock.calls[0]?.[0]).toEqual({
1349
+ name: "level-up",
1350
+ dryRun: undefined,
1351
+ strategy: "ours",
1145
1352
  });
1146
1353
  });
1147
1354
 
1355
+ test("projects conflicts + binaryConflicts from the assistant strategy onto the wire", async () => {
1356
+ // GIVEN upgradePlugin merges with conflict markers under `assistant`
1357
+ upgradeSpy.mockImplementation(async () =>
1358
+ upgradeResult({
1359
+ strategy: "assistant",
1360
+ conflicts: ["hooks/post-model-call.ts"],
1361
+ binaryConflicts: ["assets/icon.png"],
1362
+ }),
1363
+ );
1364
+
1365
+ // WHEN the handler runs with the `assistant` strategy
1366
+ const result = await invokeUpgrade({
1367
+ pathParams: { name: "level-up" },
1368
+ body: { strategy: "assistant" },
1369
+ });
1370
+
1371
+ // THEN the conflicted paths are surfaced for the assistant to resolve
1372
+ expect(result.strategy).toBe("assistant");
1373
+ expect(result.conflicts).toEqual(["hooks/post-model-call.ts"]);
1374
+ expect(result.binaryConflicts).toEqual(["assets/icon.png"]);
1375
+ expect(upgradeSpy.mock.calls[0]?.[0]).toEqual({
1376
+ name: "level-up",
1377
+ dryRun: undefined,
1378
+ strategy: "assistant",
1379
+ });
1380
+ });
1381
+
1382
+ test("PluginMergeBaselineError \u2192 ConflictError (409)", async () => {
1383
+ // A merge strategy whose install-time baseline can't be reconstructed: a
1384
+ // well-formed request that isn't actionable in the current state.
1385
+ upgradeSpy.mockImplementation(async () => {
1386
+ throw new PluginMergeBaselineError(
1387
+ "level-up",
1388
+ "the install-time baseline could not be faithfully reconstructed",
1389
+ );
1390
+ });
1391
+
1392
+ await expect(
1393
+ invokeUpgrade({
1394
+ pathParams: { name: "level-up" },
1395
+ body: { strategy: "ours" },
1396
+ }),
1397
+ ).rejects.toBeInstanceOf(ConflictError);
1398
+ });
1399
+
1148
1400
  test("omits dryRun (passes undefined) when the body flag is absent", async () => {
1149
1401
  // GIVEN a no-op upgrade where the install already matches the pin
1150
1402
  upgradeSpy.mockImplementation(async () =>
@@ -1246,3 +1498,133 @@ describe("POST /v1/plugins/:name/upgrade", () => {
1246
1498
  expect((caught as Error).message).toContain("ECONNRESET");
1247
1499
  });
1248
1500
  });
1501
+
1502
+ function diffResult(
1503
+ overrides: Partial<PluginDiffResult> = {},
1504
+ ): PluginDiffResult {
1505
+ return {
1506
+ name: overrides.name ?? "level-up",
1507
+ target: overrides.target ?? "/workspace/.vellum/plugins/level-up",
1508
+ commit: overrides.commit ?? "60a392b0000000000000000000000000000000aa",
1509
+ committedAt: overrides.committedAt ?? "2026-06-01T12:34:56.000Z",
1510
+ clean: overrides.clean ?? false,
1511
+ files: overrides.files ?? [
1512
+ {
1513
+ path: "src/skill.ts",
1514
+ status: "modified",
1515
+ diff: "--- a/src/skill.ts\n+++ b/src/skill.ts\n@@ -1 +1 @@\n-old\n+new\n",
1516
+ binary: false,
1517
+ reconstructed: true,
1518
+ },
1519
+ ],
1520
+ };
1521
+ }
1522
+
1523
+ async function invokeDiff(
1524
+ args: RouteHandlerArgs = {},
1525
+ ): Promise<PluginDiffResult> {
1526
+ return (await diffHandler(args)) as PluginDiffResult;
1527
+ }
1528
+
1529
+ describe("POST /v1/plugins/:name/diff", () => {
1530
+ beforeEach(() => {
1531
+ diffSpy.mockReset();
1532
+ });
1533
+
1534
+ test("forwards the name to diffPlugin and returns the diff verbatim", async () => {
1535
+ // GIVEN diffPlugin reports a single modified file against the install commit
1536
+ const view = diffResult();
1537
+ diffSpy.mockImplementation(async () => view);
1538
+
1539
+ // WHEN the route handler is invoked with the path name
1540
+ const result = await invokeDiff({ pathParams: { name: "level-up" } });
1541
+
1542
+ // THEN the diff is returned unchanged
1543
+ expect(result).toEqual(view);
1544
+ // AND only the name is forwarded to the lib (ref is never caller-supplied)
1545
+ expect(diffSpy.mock.calls[0]?.[0]).toEqual({ name: "level-up" });
1546
+ });
1547
+
1548
+ test("InvalidPluginNameError → BadRequestError (400)", async () => {
1549
+ diffSpy.mockImplementation(async () => {
1550
+ throw new InvalidPluginNameError("../escape");
1551
+ });
1552
+
1553
+ await expect(
1554
+ invokeDiff({ pathParams: { name: "../escape" } }),
1555
+ ).rejects.toBeInstanceOf(BadRequestError);
1556
+ });
1557
+
1558
+ test("PluginNotInstalledError → NotFoundError (404)", async () => {
1559
+ diffSpy.mockImplementation(async () => {
1560
+ throw new PluginNotInstalledError(
1561
+ "ghost",
1562
+ "/workspace/.vellum/plugins/ghost",
1563
+ );
1564
+ });
1565
+
1566
+ await expect(
1567
+ invokeDiff({ pathParams: { name: "ghost" } }),
1568
+ ).rejects.toBeInstanceOf(NotFoundError);
1569
+ });
1570
+
1571
+ test("PluginNotFoundError → NotFoundError (404)", async () => {
1572
+ // The recorded commit no longer resolves to a tree (source/commit gone).
1573
+ diffSpy.mockImplementation(async () => {
1574
+ throw new PluginNotFoundError(
1575
+ "level-up",
1576
+ "deadbeef",
1577
+ "vellum-ai/level-up",
1578
+ );
1579
+ });
1580
+
1581
+ await expect(
1582
+ invokeDiff({ pathParams: { name: "level-up" } }),
1583
+ ).rejects.toBeInstanceOf(NotFoundError);
1584
+ });
1585
+
1586
+ test("PluginDiffUnavailableError → ConflictError (409)", async () => {
1587
+ // The install recorded no commit, so there is no baseline to diff against:
1588
+ // a well-formed request that is not actionable in the current state.
1589
+ diffSpy.mockImplementation(async () => {
1590
+ throw new PluginDiffUnavailableError(
1591
+ "level-up",
1592
+ "no install commit was recorded",
1593
+ );
1594
+ });
1595
+
1596
+ await expect(
1597
+ invokeDiff({ pathParams: { name: "level-up" } }),
1598
+ ).rejects.toBeInstanceOf(ConflictError);
1599
+ });
1600
+
1601
+ test("PluginSourceUnavailableError → ServiceUnavailableError (503)", async () => {
1602
+ // Re-materializing the baseline can hit a rate-limited/down GitHub; that is
1603
+ // retryable, so surface 503 rather than a misleading 500.
1604
+ diffSpy.mockImplementation(async () => {
1605
+ throw new PluginSourceUnavailableError(
1606
+ "git clone failed for vellum-ai/level-up: HTTP 403",
1607
+ 503,
1608
+ );
1609
+ });
1610
+
1611
+ await expect(
1612
+ invokeDiff({ pathParams: { name: "level-up" } }),
1613
+ ).rejects.toBeInstanceOf(ServiceUnavailableError);
1614
+ });
1615
+
1616
+ test("unknown errors → InternalError with original message preserved", async () => {
1617
+ diffSpy.mockImplementation(async () => {
1618
+ throw new Error("ECONNRESET");
1619
+ });
1620
+
1621
+ let caught: unknown;
1622
+ try {
1623
+ await invokeDiff({ pathParams: { name: "level-up" } });
1624
+ } catch (err) {
1625
+ caught = err;
1626
+ }
1627
+ expect(caught).toBeInstanceOf(InternalError);
1628
+ expect((caught as Error).message).toContain("ECONNRESET");
1629
+ });
1630
+ });
@@ -45,7 +45,7 @@ function loadDesignSystemCss(): string {
45
45
  try {
46
46
  const cssPath = join(
47
47
  import.meta.dirname ?? __dirname,
48
- "../../../../clients/macos/vellum-assistant/Resources/vellum-design-system.css",
48
+ "assets/vellum-design-system.css",
49
49
  );
50
50
  designSystemCssCache = readFileSync(cssPath, "utf-8");
51
51
  } catch {
@@ -116,21 +116,35 @@ function handleConfirm({ body }: RouteHandlerArgs) {
116
116
  */
117
117
  function handleSecret({ body }: RouteHandlerArgs) {
118
118
  const requestId = body?.requestId as string | undefined;
119
- const value = body?.value as string | undefined;
120
119
  const delivery = body?.delivery as string | undefined;
121
120
 
122
121
  if (!requestId || typeof requestId !== "string") {
123
122
  throw new BadRequestError("requestId is required");
124
123
  }
125
124
 
125
+ // Legacy compat shim: already-shipped web clients send `delivery: "none"` to
126
+ // cancel a secret prompt. Normalize it to the cancellation path (value
127
+ // undefined) so the request settles cleanly rather than 400-ing and stranding
128
+ // the pending interaction.
129
+ const isCancel = delivery === "none";
130
+ const value = isCancel
131
+ ? undefined
132
+ : (body?.value as string | undefined);
133
+
126
134
  if (
127
135
  delivery !== undefined &&
128
136
  delivery !== "store" &&
129
- delivery !== "transient_send"
137
+ delivery !== "transient_send" &&
138
+ delivery !== "none"
130
139
  ) {
131
140
  throw new BadRequestError('delivery must be "store" or "transient_send"');
132
141
  }
133
142
 
143
+ const effectiveDelivery =
144
+ isCancel || delivery === undefined
145
+ ? undefined
146
+ : (delivery as "store" | "transient_send");
147
+
134
148
  const interaction = pendingInteractions.get(requestId);
135
149
  if (!interaction) {
136
150
  throw new NotFoundError("No pending interaction found for this requestId");
@@ -153,11 +167,7 @@ function handleSecret({ body }: RouteHandlerArgs) {
153
167
  ? findConversation(interaction.conversationId)
154
168
  : undefined;
155
169
  if (conversation?.hasPendingSecret(requestId)) {
156
- conversation.handleSecretResponse(
157
- requestId,
158
- value,
159
- delivery as "store" | "transient_send" | undefined,
160
- );
170
+ conversation.handleSecretResponse(requestId, value, effectiveDelivery);
161
171
  return { accepted: true };
162
172
  }
163
173
 
@@ -170,7 +180,7 @@ function handleSecret({ body }: RouteHandlerArgs) {
170
180
  );
171
181
  (resolved?.rpcResolve as ((r: SecretPromptResult) => void) | undefined)?.({
172
182
  value: value ?? null,
173
- delivery: (delivery as SecretDelivery) ?? "store",
183
+ delivery: (effectiveDelivery as SecretDelivery) ?? "store",
174
184
  });
175
185
  return { accepted: true };
176
186
  }
@@ -246,6 +256,15 @@ function handleListPendingInteractions({ queryParams }: RouteHandlerArgs) {
246
256
  pendingSecret: secret
247
257
  ? {
248
258
  requestId: secret.requestId,
259
+ service: secret.secretDetails?.service,
260
+ field: secret.secretDetails?.field,
261
+ label: secret.secretDetails?.label,
262
+ description: secret.secretDetails?.description,
263
+ placeholder: secret.secretDetails?.placeholder,
264
+ purpose: secret.secretDetails?.purpose,
265
+ allowedTools: secret.secretDetails?.allowedTools,
266
+ allowedDomains: secret.secretDetails?.allowedDomains,
267
+ allowOneTimeSend: secret.secretDetails?.allowOneTimeSend,
249
268
  }
250
269
  : null,
251
270
  };
@@ -340,8 +359,20 @@ export const ROUTES: RouteDefinition[] = [
340
359
  .describe("Pending confirmation details or null")
341
360
  .optional(),
342
361
  pendingSecret: z
343
- .object({})
362
+ .object({
363
+ requestId: z.string(),
364
+ service: z.string().optional(),
365
+ field: z.string().optional(),
366
+ label: z.string().optional(),
367
+ description: z.string().optional(),
368
+ placeholder: z.string().optional(),
369
+ purpose: z.string().optional(),
370
+ allowedTools: z.array(z.string()).optional(),
371
+ allowedDomains: z.array(z.string()).optional(),
372
+ allowOneTimeSend: z.boolean().optional(),
373
+ })
344
374
  .passthrough()
375
+ .nullable()
345
376
  .describe("Pending secret request or null")
346
377
  .optional(),
347
378
  interactions: z
@@ -763,7 +763,7 @@ async function handleAccessRequestApproval(
763
763
  const requesterContactResult = approval.requesterExternalUserId
764
764
  ? findContactChannel({
765
765
  channelType: approval.channel,
766
- externalUserId: approval.requesterExternalUserId,
766
+ address: approval.requesterExternalUserId,
767
767
  })
768
768
  : null;
769
769
  const requesterDisplayName =
@@ -772,7 +772,7 @@ async function handleAccessRequestApproval(
772
772
  const decidedByContactResult = decidedByExternalUserId
773
773
  ? findContactChannel({
774
774
  channelType: approval.channel,
775
- externalUserId: decidedByExternalUserId,
775
+ address: decidedByExternalUserId,
776
776
  })
777
777
  : null;
778
778
  const decidedByDisplayName =