@vellumai/assistant 0.9.0 → 0.10.0-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 (572) hide show
  1. package/ARCHITECTURE.md +18 -34
  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 +976 -63
  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__/always-loaded-tools-guard.test.ts +2 -3
  28. package/src/__tests__/app-compiler.test.ts +15 -1
  29. package/src/__tests__/app-dir-path-guard.test.ts +0 -1
  30. package/src/__tests__/assistant-feature-flag-guard.test.ts +1 -4
  31. package/src/__tests__/assistant-feature-flag-guardrails.test.ts +0 -2
  32. package/src/__tests__/auth-fallback-events-store.test.ts +6 -14
  33. package/src/__tests__/avatar-identity-sync.test.ts +2 -27
  34. package/src/__tests__/btw-routes.test.ts +6 -8
  35. package/src/__tests__/call-pointer-messages.test.ts +28 -0
  36. package/src/__tests__/cancel-clears-processing.test.ts +89 -0
  37. package/src/__tests__/channel-approval-routes.test.ts +0 -4
  38. package/src/__tests__/channel-inbound-disk-pressure.test.ts +5 -15
  39. package/src/__tests__/checker.test.ts +0 -3
  40. package/src/__tests__/cli-memory-v2-reembed-skills.test.ts +3 -4
  41. package/src/__tests__/compactor-image-manifest-trust.test.ts +21 -1
  42. package/src/__tests__/compactor-summary-call-truncation.test.ts +223 -0
  43. package/src/__tests__/config-loader-backfill.test.ts +268 -27
  44. package/src/__tests__/config-schema.test.ts +35 -0
  45. package/src/__tests__/config-watcher.test.ts +0 -18
  46. package/src/__tests__/confirmation-request-guardian-bridge.test.ts +2 -2
  47. package/src/__tests__/contact-store-user-file.test.ts +0 -6
  48. package/src/__tests__/contacts-tools.test.ts +29 -0
  49. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +22 -0
  50. package/src/__tests__/conversation-agent-loop-overflow.test.ts +1 -0
  51. package/src/__tests__/conversation-agent-loop.test.ts +58 -0
  52. package/src/__tests__/conversation-attention-telegram.test.ts +0 -1
  53. package/src/__tests__/conversation-lifecycle.test.ts +7 -9
  54. package/src/__tests__/conversation-load-history-repair.test.ts +101 -0
  55. package/src/__tests__/conversation-routes-guardian-reply.test.ts +15 -12
  56. package/src/__tests__/conversation-surfaces-activation-emit.test.ts +6 -3
  57. package/src/__tests__/conversation-title-service.test.ts +62 -0
  58. package/src/__tests__/credential-broker.test.ts +449 -1
  59. package/src/__tests__/credential-execution-shell-lockdown.test.ts +18 -11
  60. package/src/__tests__/credential-execution-tools.test.ts +0 -1
  61. package/src/__tests__/credential-prompt-route.test.ts +4 -4
  62. package/src/__tests__/credential-routes.test.ts +360 -0
  63. package/src/__tests__/credential-security-invariants.test.ts +4 -13
  64. package/src/__tests__/disk-pressure-policy.test.ts +12 -0
  65. package/src/__tests__/disk-usage.test.ts +65 -0
  66. package/src/__tests__/dynamic-page-surface.test.ts +152 -1
  67. package/src/__tests__/fixtures/credential-security-fixtures.ts +2 -33
  68. package/src/__tests__/gateway-flag-listener.test.ts +110 -1
  69. package/src/__tests__/gateway-only-guard.test.ts +3 -7
  70. package/src/__tests__/guardian-binding-drift-heal.test.ts +1 -1
  71. package/src/__tests__/guardian-card-withdrawal.test.ts +403 -0
  72. package/src/__tests__/guardian-decision-primitive-canonical.test.ts +5 -3
  73. package/src/__tests__/guardian-grant-minting.test.ts +3 -35
  74. package/src/__tests__/guardian-routing-invariants.test.ts +64 -26
  75. package/src/__tests__/guardian-routing-state.test.ts +0 -1
  76. package/src/__tests__/headless-browser-mode.test.ts +10 -0
  77. package/src/__tests__/headless-browser-navigate.test.ts +8 -3
  78. package/src/__tests__/helpers/create-guardian-binding.ts +0 -1
  79. package/src/__tests__/host-browser-proxy.test.ts +87 -0
  80. package/src/__tests__/identity-routes.test.ts +0 -189
  81. package/src/__tests__/inbound-invite-redemption.test.ts +4 -4
  82. package/src/__tests__/injector-v3-suppression.test.ts +27 -20
  83. package/src/__tests__/internal-telemetry-routes.test.ts +6 -14
  84. package/src/__tests__/invite-redemption-service.test.ts +4 -7
  85. package/src/__tests__/llm-callsite-catalog.test.ts +5 -6
  86. package/src/__tests__/llm-catalog-parity.test.ts +30 -23
  87. package/src/__tests__/llm-resolver.test.ts +70 -24
  88. package/src/__tests__/llm-schema.test.ts +1 -0
  89. package/src/__tests__/managed-profile-guard.test.ts +163 -4
  90. package/src/__tests__/mcp-health-check.test.ts +6 -7
  91. package/src/__tests__/media-stream-server-integration.test.ts +317 -13
  92. package/src/__tests__/oauth-provider-seed-logos.test.ts +4 -6
  93. package/src/__tests__/onboarding-persona-write.test.ts +1 -1
  94. package/src/__tests__/path-policy.test.ts +34 -0
  95. package/src/__tests__/persona-resolver.test.ts +49 -14
  96. package/src/__tests__/plugin-api-model-profiles.test.ts +178 -0
  97. package/src/__tests__/plugin-api-provider.test.ts +24 -0
  98. package/src/__tests__/plugin-tool-contribution.test.ts +6 -3
  99. package/src/__tests__/post-compaction-reinjection-idempotency.test.ts +214 -0
  100. package/src/__tests__/provider-send-message-override-profile.test.ts +76 -0
  101. package/src/__tests__/reaction-persistence.test.ts +150 -29
  102. package/src/__tests__/registry.test.ts +2 -7
  103. package/src/__tests__/relay-server.test.ts +285 -0
  104. package/src/__tests__/runtime-attachment-metadata.test.ts +0 -1
  105. package/src/__tests__/schedule-routes-workflow-validation.test.ts +1 -10
  106. package/src/__tests__/schedule-routes.test.ts +0 -30
  107. package/src/__tests__/schedule-tools.test.ts +2 -18
  108. package/src/__tests__/scheduler-reuse-conversation.test.ts +8 -5
  109. package/src/__tests__/skill-execute-input.test.ts +51 -1
  110. package/src/__tests__/skill-runtime-path.test.ts +2 -3
  111. package/src/__tests__/skills.test.ts +51 -0
  112. package/src/__tests__/slack-notification-approval-card.test.ts +176 -0
  113. package/src/__tests__/slack-reaction-canonical-approval.test.ts +285 -0
  114. package/src/__tests__/subagent-tools.test.ts +266 -0
  115. package/src/__tests__/surface-completion-nudge-hook.test.ts +367 -0
  116. package/src/__tests__/task-progress-nudge-hook.test.ts +1 -1
  117. package/src/__tests__/title-generate-hook.test.ts +100 -3
  118. package/src/__tests__/token-estimator-accuracy.benchmark.test.ts +1 -29
  119. package/src/__tests__/token-manager.test.ts +519 -0
  120. package/src/__tests__/tool-approval-seed-content-blocks.test.ts +1 -1
  121. package/src/__tests__/tool-audit-listener.test.ts +7 -7
  122. package/src/__tests__/tool-executor-lifecycle-events.test.ts +6 -3
  123. package/src/__tests__/tool-executor.test.ts +0 -79
  124. package/src/__tests__/trusted-contact-approval-notifier.test.ts +4 -2
  125. package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +220 -3
  126. package/src/__tests__/trusted-contact-multichannel.test.ts +3 -3
  127. package/src/__tests__/trusted-contact-verification.test.ts +8 -10
  128. package/src/__tests__/twilio-routes.test.ts +81 -1
  129. package/src/__tests__/voice-invite-redemption.test.ts +2 -3
  130. package/src/__tests__/weak-open-model.test.ts +30 -0
  131. package/src/__tests__/web-search-catalog-parity.test.ts +6 -25
  132. package/src/__tests__/workspace-greetings.test.ts +152 -0
  133. package/src/__tests__/workspace-migration-105-enable-memory-v3-live-for-new-workspaces.test.ts +149 -0
  134. package/src/__tests__/workspace-migration-108-drop-balanced-economy-profile.test.ts +285 -0
  135. package/src/__tests__/workspace-migration-add-send-diagnostics.test.ts +1 -1
  136. package/src/__tests__/workspace-migration-drop-collect-usage-data.test.ts +118 -0
  137. package/src/__tests__/workspace-migration-drop-send-diagnostics.test.ts +118 -0
  138. package/src/a2a/__tests__/e2e-a2a-channel.test.ts +0 -4
  139. package/src/agent/loop.ts +49 -29
  140. package/src/api/README.md +6 -6
  141. package/src/api/events/tool-result.ts +6 -0
  142. package/src/api/events/workflow-completed.ts +53 -0
  143. package/src/api/events/workflow-leaf-finished.ts +38 -0
  144. package/src/api/events/workflow-leaf-started.ts +35 -0
  145. package/src/api/events/workflow-progress.ts +32 -0
  146. package/src/api/events/workflow-started.ts +31 -0
  147. package/src/api/index.ts +40 -0
  148. package/src/api/responses/conversation-message.ts +28 -4
  149. package/src/api/responses/home.ts +26 -4
  150. package/src/api/responses/workflow-journal.ts +53 -0
  151. package/src/approvals/guardian-card-withdrawal.ts +145 -0
  152. package/src/approvals/guardian-decision-primitive.ts +26 -3
  153. package/src/approvals/guardian-request-resolvers.ts +183 -80
  154. package/src/calls/__tests__/channel-admission-reader.test.ts +132 -0
  155. package/src/calls/__tests__/relay-setup-router.test.ts +350 -0
  156. package/src/calls/call-pointer-messages.ts +10 -4
  157. package/src/calls/channel-admission-reader.ts +104 -0
  158. package/src/calls/guardian-dispatch.ts +17 -45
  159. package/src/calls/media-stream-server.ts +84 -2
  160. package/src/calls/relay-access-wait.ts +1 -1
  161. package/src/calls/relay-server.ts +66 -0
  162. package/src/calls/relay-setup-router.ts +82 -1
  163. package/src/calls/twilio-routes.ts +17 -8
  164. package/src/calls/voice-session-bridge.ts +2 -2
  165. package/src/cli/commands/clients.ts +3 -0
  166. package/src/cli/commands/{__tests__ → memory/__tests__}/memory-v2-compare-render.test.ts +1 -1
  167. package/src/cli/commands/{__tests__ → memory/__tests__}/memory-v2.test.ts +8 -7
  168. package/src/cli/commands/{__tests__ → memory/__tests__}/memory-v3.test.ts +5 -4
  169. package/src/cli/commands/memory/index.ts +30 -0
  170. package/src/cli/commands/{memory-v2-compare-render.ts → memory/memory-v2-compare-render.ts} +1 -1
  171. package/src/cli/commands/{memory-v2.ts → memory/memory-v2.ts} +6 -15
  172. package/src/cli/commands/{memory-v3.ts → memory/memory-v3.ts} +97 -11
  173. package/src/cli/commands/oauth/status.test.ts +36 -0
  174. package/src/cli/commands/oauth/status.ts +23 -3
  175. package/src/cli/commands/plugins.ts +197 -4
  176. package/src/cli/lib/__tests__/diff-plugin.test.ts +443 -0
  177. package/src/cli/lib/__tests__/inspect-plugin.test.ts +54 -0
  178. package/src/cli/lib/__tests__/merge-plugin-tree.test.ts +443 -0
  179. package/src/cli/lib/__tests__/plugin-surfaces.test.ts +111 -0
  180. package/src/cli/lib/__tests__/upgrade-plugin.test.ts +295 -2
  181. package/src/cli/lib/diff-plugin.ts +346 -0
  182. package/src/cli/lib/inspect-plugin.ts +12 -1
  183. package/src/cli/lib/install-from-github.ts +105 -17
  184. package/src/cli/lib/merge-plugin-tree.ts +328 -0
  185. package/src/cli/lib/plugin-fingerprint.ts +14 -0
  186. package/src/cli/lib/plugin-surfaces.ts +104 -0
  187. package/src/cli/lib/upgrade-plugin.ts +298 -10
  188. package/src/cli/program.ts +2 -6
  189. package/src/config/__tests__/sync-gated-profiles.test.ts +368 -0
  190. package/src/config/assistant-feature-flags.ts +22 -7
  191. package/src/config/bundled-skills/contacts/tools/contact-search.ts +0 -1
  192. package/src/config/bundled-skills/messaging/SKILL.md +6 -4
  193. package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +9 -8
  194. package/src/config/bundled-skills/subagent/SKILL.md +4 -0
  195. package/src/config/bundled-skills/subagent/TOOLS.json +4 -0
  196. package/src/config/bundled-skills/workflows/SKILL.md +14 -8
  197. package/src/config/bundled-tool-registry.ts +2 -7
  198. package/src/config/call-site-defaults.ts +15 -2
  199. package/src/config/feature-flag-registry.json +46 -31
  200. package/src/config/inference-profile-validation.ts +26 -0
  201. package/src/config/llm-resolver.ts +3 -0
  202. package/src/config/loader.ts +4 -0
  203. package/src/config/memory-v3-gate.ts +11 -0
  204. package/src/config/profile-order.ts +28 -0
  205. package/src/config/schema.ts +8 -6
  206. package/src/config/schemas/__tests__/memory-v3.test.ts +1 -0
  207. package/src/config/schemas/call-site-catalog.ts +7 -0
  208. package/src/config/schemas/channels.ts +11 -0
  209. package/src/config/schemas/elevenlabs.ts +0 -1
  210. package/src/config/schemas/llm.ts +31 -0
  211. package/src/config/schemas/memory-lifecycle.ts +3 -7
  212. package/src/config/schemas/memory-v3.ts +6 -0
  213. package/src/config/schemas/platform.ts +0 -8
  214. package/src/config/schemas/services.ts +18 -0
  215. package/src/config/seed-inference-profiles.ts +109 -44
  216. package/src/config/skills.ts +21 -0
  217. package/src/config/sync-gated-profiles.ts +220 -0
  218. package/src/contacts/contact-store.ts +89 -106
  219. package/src/contacts/contacts-write.ts +5 -22
  220. package/src/contacts/types.ts +0 -1
  221. package/src/context/compactor.ts +88 -54
  222. package/src/context/strip-injections.ts +58 -10
  223. package/src/context/token-estimator.ts +1 -1
  224. package/src/credential-execution/process-manager.ts +55 -14
  225. package/src/credential-execution/prompted-credential.ts +2 -3
  226. package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +3 -2
  227. package/src/daemon/config-watcher.ts +0 -4
  228. package/src/daemon/conversation-agent-loop-handlers.ts +2 -0
  229. package/src/daemon/conversation-agent-loop.ts +114 -22
  230. package/src/daemon/conversation-history.ts +1 -1
  231. package/src/daemon/conversation-lifecycle.ts +3 -5
  232. package/src/daemon/conversation-process.ts +13 -5
  233. package/src/daemon/conversation-runtime-assembly.ts +13 -15
  234. package/src/daemon/conversation-slash.ts +2 -23
  235. package/src/daemon/conversation-surfaces.ts +26 -0
  236. package/src/daemon/conversation-tool-setup.ts +27 -14
  237. package/src/daemon/conversation.ts +66 -14
  238. package/src/daemon/disk-pressure-policy.ts +5 -3
  239. package/src/daemon/handlers/__tests__/config-a2a-complete.test.ts +0 -1
  240. package/src/daemon/handlers/__tests__/config-a2a-redeem.test.ts +0 -1
  241. package/src/daemon/handlers/config-a2a.ts +0 -2
  242. package/src/daemon/handlers/config-channels.ts +15 -16
  243. package/src/daemon/handlers/config-slack-channel.ts +22 -3
  244. package/src/daemon/handlers/conversations.ts +107 -0
  245. package/src/daemon/host-browser-proxy.ts +41 -0
  246. package/src/daemon/lifecycle.ts +55 -27
  247. package/src/daemon/message-provenance.ts +2 -0
  248. package/src/daemon/message-types/contacts.ts +0 -1
  249. package/src/daemon/message-types/conversations.ts +3 -3
  250. package/src/daemon/message-types/sync.ts +0 -1
  251. package/src/daemon/message-types/web-activity.ts +7 -1
  252. package/src/daemon/message-types/workflows.ts +83 -1
  253. package/src/daemon/orphan-reaper.test.ts +0 -19
  254. package/src/daemon/orphan-reaper.ts +2 -24
  255. package/src/daemon/server.ts +0 -10
  256. package/src/daemon/tool-setup-types.ts +4 -0
  257. package/src/daemon/trust-context.ts +1 -1
  258. package/src/events/tool-audit-listener.ts +2 -2
  259. package/src/home/feed-source-enrichment.test.ts +151 -0
  260. package/src/home/feed-source-enrichment.ts +176 -0
  261. package/src/home/relationship-state.ts +2 -4
  262. package/src/instrument.ts +18 -6
  263. package/src/ipc/__tests__/binary-result-ipc.test.ts +81 -0
  264. package/src/ipc/__tests__/clients-list-ipc.test.ts +20 -0
  265. package/src/ipc/assistant-server.ts +37 -4
  266. package/src/ipc/gateway-flag-listener.ts +18 -2
  267. package/src/memory/__tests__/auto-analysis-enqueue.test.ts +5 -16
  268. package/src/memory/__tests__/jobs-store-enqueue-gate.test.ts +7 -11
  269. package/src/memory/__tests__/memory-retrospective-enqueue.test.ts +37 -7
  270. package/src/memory/__tests__/memory-retrospective-job.test.ts +229 -401
  271. package/src/memory/__tests__/onboarding-events-store.test.ts +7 -7
  272. package/src/memory/auth-fallback-events-store.ts +2 -2
  273. package/src/memory/auto-analysis-enqueue.ts +3 -5
  274. package/src/memory/bookmark-crud.ts +1 -2
  275. package/src/memory/canonical-guardian-store.ts +39 -1
  276. package/src/memory/conversation-crud.ts +9 -4
  277. package/src/memory/conversation-key-store.ts +17 -2
  278. package/src/memory/conversation-title-service.ts +64 -7
  279. package/src/memory/db-init.ts +17 -17
  280. package/src/memory/embedding-backend.ts +38 -1
  281. package/src/memory/embedding-billing-breaker.ts +96 -0
  282. package/src/memory/jobs-store.ts +25 -13
  283. package/src/memory/jobs-worker.ts +54 -1
  284. package/src/memory/lifecycle-events-store.ts +2 -2
  285. package/src/memory/memory-retrospective-constants.ts +4 -4
  286. package/src/memory/memory-retrospective-enqueue.ts +31 -6
  287. package/src/memory/memory-retrospective-job.ts +28 -227
  288. package/src/memory/migrations/129-contact-channels-access-fields.ts +18 -9
  289. package/src/memory/migrations/131-drop-legacy-member-guardian-tables.ts +14 -2
  290. package/src/memory/migrations/289-contact-channels-unique-ext-user.ts +10 -0
  291. package/src/memory/migrations/291-contact-channels-renormalize-addresses.ts +72 -0
  292. package/src/memory/migrations/292-schedule-default-no-reuse-conversation.test.ts +67 -0
  293. package/src/memory/migrations/292-schedule-default-no-reuse-conversation.ts +25 -0
  294. package/src/memory/migrations/293-workflow-journal-leaf-tokens.ts +32 -0
  295. package/src/memory/migrations/294-drop-external-user-id.ts +31 -0
  296. package/src/memory/migrations/295-drop-approval-prompt-ts-tracker.ts +20 -0
  297. package/src/memory/migrations/296-rewrite-balanced-economy-profile-pins.test.ts +110 -0
  298. package/src/memory/migrations/296-rewrite-balanced-economy-profile-pins.ts +68 -0
  299. package/src/memory/migrations/__tests__/131-drop-legacy-member-guardian-tables.test.ts +154 -0
  300. package/src/memory/migrations/__tests__/289-contact-channels-unique-ext-user.test.ts +31 -0
  301. package/src/memory/migrations/__tests__/291-contact-channels-renormalize-addresses.test.ts +341 -0
  302. package/src/memory/migrations/__tests__/run-migrations.test.ts +52 -0
  303. package/src/memory/migrations/index.ts +6 -0
  304. package/src/memory/migrations/run-migrations.ts +41 -0
  305. package/src/memory/migrations/validate-migration-state.ts +1 -1
  306. package/src/memory/onboarding-events-store.ts +3 -3
  307. package/src/memory/schema/contacts.ts +0 -5
  308. package/src/memory/skill-loaded-events-store.test.ts +7 -15
  309. package/src/memory/skill-loaded-events-store.ts +2 -2
  310. package/src/memory/tool-executed-events-store.test.ts +7 -7
  311. package/src/memory/turn-trace-store.test.ts +736 -0
  312. package/src/memory/turn-trace-store.ts +364 -0
  313. package/src/memory/v2/__tests__/consolidation-job.test.ts +8 -0
  314. package/src/memory/v2/__tests__/skill-content.test.ts +30 -0
  315. package/src/memory/v2/consolidation-job.ts +2 -2
  316. package/src/memory/v2/skill-content.ts +25 -7
  317. package/src/memory/v2/skill-store.ts +7 -1
  318. package/src/memory/v3-eval/__tests__/eval-packets.test.ts +248 -0
  319. package/src/memory/v3-eval/eval-packets.ts +546 -0
  320. package/src/messaging/providers/slack/adapter.ts +1 -1
  321. package/src/messaging/providers/slack/api.ts +31 -0
  322. package/src/messaging/providers/slack/send.test.ts +114 -2
  323. package/src/messaging/providers/slack/send.ts +30 -7
  324. package/src/messaging/providers/slack/withdraw.test.ts +200 -0
  325. package/src/messaging/providers/slack/withdraw.ts +161 -0
  326. package/src/notifications/AGENTS.md +2 -0
  327. package/src/notifications/access-request-copy.ts +72 -59
  328. package/src/notifications/adapters/shared.ts +29 -0
  329. package/src/notifications/adapters/slack.ts +58 -103
  330. package/src/notifications/adapters/telegram.ts +2 -20
  331. package/src/notifications/approval-card-data.ts +333 -0
  332. package/src/notifications/broadcaster.ts +16 -3
  333. package/src/notifications/canonical-delivery-recorder.ts +139 -0
  334. package/src/notifications/copy-composer.ts +3 -3
  335. package/src/notifications/decision-engine.ts +4 -2
  336. package/src/notifications/destination-resolver.ts +4 -6
  337. package/src/notifications/guardian-question-mode.ts +10 -0
  338. package/src/notifications/home-feed-side-effect.ts +7 -16
  339. package/src/notifications/notification-utils.ts +19 -20
  340. package/src/notifications/signal.ts +79 -43
  341. package/src/notifications/types.ts +98 -121
  342. package/src/oauth/AGENTS.md +5 -24
  343. package/src/permissions/checker.test.ts +51 -0
  344. package/src/permissions/checker.ts +185 -26
  345. package/src/permissions/ipc-risk-types.ts +24 -0
  346. package/src/permissions/question-prompter.test.ts +27 -0
  347. package/src/permissions/question-prompter.ts +4 -0
  348. package/src/platform/client.test.ts +119 -0
  349. package/src/platform/client.ts +66 -0
  350. package/src/platform/consent-cache.test.ts +267 -0
  351. package/src/platform/consent-cache.ts +174 -0
  352. package/src/plugin-api/constants.ts +1 -1
  353. package/src/plugin-api/index.ts +33 -1
  354. package/src/plugin-api/model-profiles.ts +33 -0
  355. package/src/plugin-api/types.ts +50 -2
  356. package/src/plugins/defaults/advisor/__tests__/advisor-gate.test.ts +56 -0
  357. package/src/plugins/defaults/advisor/__tests__/advisor-state-store.test.ts +43 -0
  358. package/src/plugins/defaults/advisor/__tests__/agent-loop-integration.test.ts +137 -0
  359. package/src/plugins/defaults/advisor/__tests__/consult.test.ts +153 -0
  360. package/src/plugins/defaults/advisor/__tests__/hooks.test.ts +138 -0
  361. package/src/plugins/defaults/advisor/__tests__/transcript.test.ts +147 -0
  362. package/src/plugins/defaults/advisor/advisor-gate.ts +29 -0
  363. package/src/plugins/defaults/advisor/advisor-state-store.ts +94 -0
  364. package/src/plugins/defaults/advisor/config.ts +21 -0
  365. package/src/plugins/defaults/advisor/consult.ts +93 -0
  366. package/src/plugins/defaults/advisor/hooks/post-model-call.ts +34 -0
  367. package/src/plugins/defaults/advisor/hooks/pre-model-call.ts +30 -0
  368. package/src/plugins/defaults/advisor/hooks/user-prompt-submit.ts +19 -0
  369. package/src/plugins/defaults/advisor/package.json +14 -0
  370. package/src/plugins/defaults/advisor/steering.ts +67 -0
  371. package/src/plugins/defaults/advisor/tools/advisor.ts +65 -0
  372. package/src/plugins/defaults/advisor/transcript.ts +76 -0
  373. package/src/plugins/defaults/index.ts +60 -0
  374. package/src/plugins/defaults/memory-retrieval/hooks/post-compact.ts +22 -9
  375. package/src/plugins/defaults/memory-retrieval/hooks/user-prompt-submit.ts +2 -2
  376. package/src/plugins/defaults/memory-retrieval/tail-reinjection-strip.ts +64 -0
  377. package/src/plugins/defaults/memory-retrieval/unified-turn-context.ts +29 -21
  378. package/src/plugins/defaults/memory-v3-shadow/__tests__/carry-integration.test.ts +1 -0
  379. package/src/plugins/defaults/memory-v3-shadow/__tests__/injection.test.ts +1 -0
  380. package/src/plugins/defaults/memory-v3-shadow/__tests__/maintain-job.test.ts +129 -9
  381. package/src/plugins/defaults/memory-v3-shadow/__tests__/orchestrate.test.ts +31 -4
  382. package/src/plugins/defaults/memory-v3-shadow/__tests__/selection-log-store.test.ts +77 -2
  383. package/src/plugins/defaults/memory-v3-shadow/__tests__/shadow-plugin.test.ts +1 -0
  384. package/src/plugins/defaults/memory-v3-shadow/injector.ts +7 -10
  385. package/src/plugins/defaults/memory-v3-shadow/maintain-job.ts +144 -11
  386. package/src/plugins/defaults/memory-v3-shadow/orchestrate.ts +32 -20
  387. package/src/plugins/defaults/memory-v3-shadow/selection-log-store.ts +56 -3
  388. package/src/plugins/defaults/memory-v3-shadow/shadow-plugin.ts +23 -2
  389. package/src/plugins/defaults/surface-completion-nudge/hooks/post-model-call.ts +276 -0
  390. package/src/plugins/defaults/surface-completion-nudge/hooks/stop.ts +22 -0
  391. package/src/plugins/defaults/surface-completion-nudge/nudge-state-store.ts +46 -0
  392. package/src/plugins/defaults/surface-completion-nudge/package.json +14 -0
  393. package/src/plugins/defaults/task-progress-nudge/hooks/post-tool-use.ts +3 -13
  394. package/src/plugins/defaults/title-generate/hooks/stop.ts +56 -21
  395. package/src/prompts/persona-resolver.ts +14 -4
  396. package/src/prompts/templates/system-sections.ts +7 -2
  397. package/src/providers/__tests__/provider-env-vars.test.ts +6 -0
  398. package/src/providers/__tests__/provider-secret-catalog.test.ts +1 -0
  399. package/src/providers/__tests__/retry-callsite.test.ts +176 -0
  400. package/src/providers/atlascloud/client.ts +85 -0
  401. package/src/providers/fetch-provider-catalog.ts +85 -0
  402. package/src/providers/inference/adapter-factory.ts +3 -0
  403. package/src/providers/model-catalog.ts +58 -0
  404. package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +33 -0
  405. package/src/providers/openai/chat-completions-provider.ts +7 -0
  406. package/src/providers/openai/responses-provider.ts +10 -0
  407. package/src/providers/provider-send-message.ts +11 -3
  408. package/src/providers/retry.ts +53 -12
  409. package/src/providers/search-provider-catalog.ts +10 -0
  410. package/src/providers/weak-open-model.ts +22 -0
  411. package/src/runtime/AGENTS.md +0 -1
  412. package/src/runtime/__tests__/agent-wake.test.ts +181 -0
  413. package/src/runtime/__tests__/client-health.test.ts +44 -0
  414. package/src/runtime/access-request-helper.ts +21 -53
  415. package/src/runtime/actor-trust-resolver.ts +59 -63
  416. package/src/runtime/agent-wake.ts +52 -0
  417. package/src/runtime/assistant-event-hub.ts +18 -4
  418. package/src/runtime/auth/__tests__/route-policy.test.ts +12 -0
  419. package/src/runtime/auth/require-bound-guardian.ts +1 -4
  420. package/src/runtime/btw-sidechain.ts +3 -6
  421. package/src/runtime/capabilities.test.ts +120 -0
  422. package/src/runtime/capabilities.ts +197 -0
  423. package/src/runtime/channel-approval-types.ts +22 -45
  424. package/src/runtime/channel-invite-transports/telegram.ts +4 -4
  425. package/src/runtime/channel-retry-sweep.ts +1 -0
  426. package/src/runtime/channel-verification-service.ts +3 -3
  427. package/src/runtime/client-health.ts +26 -0
  428. package/src/runtime/confirmation-request-guardian-bridge.ts +38 -29
  429. package/src/runtime/effective-capabilities.test.ts +128 -0
  430. package/src/runtime/effective-capabilities.ts +84 -0
  431. package/src/runtime/guardian-reply-router.ts +106 -21
  432. package/src/runtime/invite-redemption-service.ts +9 -25
  433. package/src/runtime/migrations/__tests__/vbundle-builder-fd-leak.test.ts +123 -0
  434. package/src/runtime/migrations/vbundle-builder.ts +49 -20
  435. package/src/runtime/pending-interactions.ts +15 -0
  436. package/src/runtime/routes/__tests__/client-routes.test.ts +13 -0
  437. package/src/runtime/routes/__tests__/conversation-management-routes.test.ts +67 -0
  438. package/src/runtime/routes/__tests__/plugins-routes.test.ts +240 -1
  439. package/src/runtime/routes/app-routes.ts +1 -1
  440. package/src/runtime/routes/approval-strategies/guardian-callback-strategy.ts +2 -2
  441. package/src/runtime/routes/assets/vellum-design-system.css +1959 -0
  442. package/src/runtime/routes/browser-tabs-routes.ts +9 -0
  443. package/src/runtime/routes/btw-routes.ts +1 -27
  444. package/src/runtime/routes/canonical-guardian-expiry-sweep.ts +17 -8
  445. package/src/runtime/routes/client-routes.ts +10 -0
  446. package/src/runtime/routes/contact-routes.ts +31 -8
  447. package/src/runtime/routes/conversation-compaction-routes.ts +1 -1
  448. package/src/runtime/routes/conversation-management-routes.ts +80 -1
  449. package/src/runtime/routes/conversation-query-routes.ts +68 -22
  450. package/src/runtime/routes/conversation-routes.ts +39 -14
  451. package/src/runtime/routes/credential-routes.ts +40 -16
  452. package/src/runtime/routes/empty-state-greeting-cache.ts +1 -2
  453. package/src/runtime/routes/events-routes.ts +1 -3
  454. package/src/runtime/routes/guardian-approval-interception.ts +14 -73
  455. package/src/runtime/routes/guardian-approval-prompt.ts +22 -4
  456. package/src/runtime/routes/home-feed-routes.ts +8 -3
  457. package/src/runtime/routes/identity-routes.ts +1 -296
  458. package/src/runtime/routes/inbound-message-handler.ts +214 -228
  459. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +89 -7
  460. package/src/runtime/routes/inbound-stages/admission-policy.test.ts +154 -0
  461. package/src/runtime/routes/inbound-stages/admission-policy.ts +140 -0
  462. package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +3 -3
  463. package/src/runtime/routes/inbound-stages/background-dispatch.ts +11 -6
  464. package/src/runtime/routes/inbound-stages/escalation-intercept.ts +1 -2
  465. package/src/runtime/routes/inbound-stages/guardian-activation-intercept.ts +1 -2
  466. package/src/runtime/routes/inbound-stages/guardian-reply-intercept.test.ts +7 -7
  467. package/src/runtime/routes/inbound-stages/guardian-reply-intercept.ts +47 -28
  468. package/src/runtime/routes/inbound-stages/reaction-intercept.ts +358 -0
  469. package/src/runtime/routes/index.ts +2 -0
  470. package/src/runtime/routes/integrations/slack/__tests__/channel.test.ts +8 -0
  471. package/src/runtime/routes/integrations/slack/channel.ts +36 -0
  472. package/src/runtime/routes/internal-telemetry-routes.ts +1 -1
  473. package/src/runtime/routes/mcp-auth-routes.ts +233 -41
  474. package/src/runtime/routes/memory-eval-routes.ts +87 -0
  475. package/src/runtime/routes/notification-routes.ts +122 -133
  476. package/src/runtime/routes/platform-routes.ts +2 -2
  477. package/src/runtime/routes/plugins-routes.ts +202 -3
  478. package/src/runtime/routes/schedule-routes.ts +0 -22
  479. package/src/runtime/routes/secret-routes.ts +10 -0
  480. package/src/runtime/routes/surface-action-routes.ts +2 -1
  481. package/src/runtime/routes/tool-call-question-enrichment.test.ts +146 -0
  482. package/src/runtime/routes/tool-call-question-enrichment.ts +66 -0
  483. package/src/runtime/routes/workflow-routes.test.ts +229 -44
  484. package/src/runtime/routes/workflow-routes.ts +131 -29
  485. package/src/runtime/routes/workspace-greetings.ts +55 -0
  486. package/src/runtime/sync/resource-sync-events.ts +1 -11
  487. package/src/runtime/tool-grant-request-helper.ts +18 -16
  488. package/src/runtime/trust-context-resolver.ts +8 -5
  489. package/src/schedule/inference-profile.ts +2 -14
  490. package/src/schedule/schedule-store.ts +1 -1
  491. package/src/schedule/scheduler-types.ts +5 -1
  492. package/src/security/__tests__/provider-key-env-fallback.test.ts +6 -0
  493. package/src/security/secret-patterns.ts +3 -0
  494. package/src/subagent/manager.ts +17 -4
  495. package/src/subagent/types.ts +6 -0
  496. package/src/telemetry/trace-collection-policy.test.ts +28 -0
  497. package/src/telemetry/trace-collection-policy.ts +30 -0
  498. package/src/telemetry/types.ts +89 -0
  499. package/src/telemetry/usage-telemetry-reporter.test.ts +586 -36
  500. package/src/telemetry/usage-telemetry-reporter.ts +148 -41
  501. package/src/tools/AGENTS.md +3 -3
  502. package/src/tools/browser/__tests__/browser-execution-acquire.test.ts +31 -0
  503. package/src/tools/browser/browser-execution.ts +30 -19
  504. package/src/tools/document/document-tool.ts +2 -3
  505. package/src/tools/executor.ts +5 -3
  506. package/src/tools/host-terminal/host-shell.ts +5 -4
  507. package/src/tools/memory/register.ts +2 -2
  508. package/src/tools/network/__tests__/web-fetch-firecrawl.test.ts +360 -0
  509. package/src/tools/network/__tests__/web-search.test.ts +143 -0
  510. package/src/tools/network/web-fetch.ts +372 -1
  511. package/src/tools/network/web-search-error.ts +1 -1
  512. package/src/tools/network/web-search.ts +213 -10
  513. package/src/tools/permission-checker.ts +4 -3
  514. package/src/tools/registry.ts +20 -0
  515. package/src/tools/schedule/create.ts +7 -12
  516. package/src/tools/schedule/update.ts +4 -11
  517. package/src/tools/shared/filesystem/path-policy.ts +39 -13
  518. package/src/tools/side-effects.ts +2 -17
  519. package/src/tools/skills/execute.ts +33 -0
  520. package/src/tools/subagent/spawn.ts +61 -12
  521. package/src/tools/terminal/shell.ts +10 -4
  522. package/src/tools/tool-approval-handler.ts +18 -13
  523. package/src/tools/tool-manifest.ts +0 -2
  524. package/src/tools/types.ts +9 -0
  525. package/src/tools/ui-surface/definitions.ts +64 -3
  526. package/src/tools/verification-control-plane-policy.ts +3 -1
  527. package/src/tools/workflows/run-workflow.test.ts +8 -18
  528. package/src/tools/workflows/run-workflow.ts +1 -0
  529. package/src/util/disk-usage.ts +78 -23
  530. package/src/util/platform.ts +10 -3
  531. package/src/watcher/telemetry.ts +2 -2
  532. package/src/workflows/capabilities.ts +2 -3
  533. package/src/workflows/engine.test.ts +175 -1
  534. package/src/workflows/engine.ts +82 -0
  535. package/src/workflows/journal-store.test.ts +70 -0
  536. package/src/workflows/journal-store.ts +18 -3
  537. package/src/workflows/run-manager.test.ts +171 -28
  538. package/src/workflows/run-manager.ts +66 -24
  539. package/src/workspace/migrations/105-enable-memory-v3-live-for-new-workspaces.ts +63 -0
  540. package/src/workspace/migrations/106-drop-collect-usage-data.ts +47 -0
  541. package/src/workspace/migrations/107-drop-send-diagnostics.ts +47 -0
  542. package/src/workspace/migrations/108-drop-balanced-economy-profile.ts +129 -0
  543. package/src/workspace/migrations/registry.ts +8 -0
  544. package/src/__tests__/app-control-no-global-cgevent.test.ts +0 -98
  545. package/src/__tests__/credential-security-e2e.test.ts +0 -362
  546. package/src/__tests__/credential-vault-unit.test.ts +0 -1528
  547. package/src/__tests__/credential-vault.test.ts +0 -1706
  548. package/src/__tests__/identity-intro-cache.test.ts +0 -315
  549. package/src/__tests__/secret-onetime-send.test.ts +0 -182
  550. package/src/cli/commands/__tests__/task.test.ts +0 -914
  551. package/src/cli/commands/task.ts +0 -771
  552. package/src/config/bundled-skills/personal-page/SKILL.md +0 -57
  553. package/src/config/bundled-skills/personal-page/TOOLS.json +0 -27
  554. package/src/config/bundled-skills/personal-page/tools/app-refresh.ts +0 -17
  555. package/src/config/preloaded-apps/personal-page/src/components/About.tsx +0 -22
  556. package/src/config/preloaded-apps/personal-page/src/components/App.tsx +0 -16
  557. package/src/config/preloaded-apps/personal-page/src/components/Features.tsx +0 -77
  558. package/src/config/preloaded-apps/personal-page/src/components/Hero.tsx +0 -57
  559. package/src/config/preloaded-apps/personal-page/src/components/Pending.tsx +0 -28
  560. package/src/config/preloaded-apps/personal-page/src/components/animations.tsx +0 -234
  561. package/src/config/preloaded-apps/personal-page/src/components/icons.tsx +0 -48
  562. package/src/config/preloaded-apps/personal-page/src/components/media.ts +0 -16
  563. package/src/config/preloaded-apps/personal-page/src/index.html +0 -20
  564. package/src/config/preloaded-apps/personal-page/src/main.tsx +0 -7
  565. package/src/config/preloaded-apps/personal-page/src/profile-data.ts +0 -82
  566. package/src/config/preloaded-apps/personal-page/src/styles.css +0 -759
  567. package/src/memory/__tests__/preloaded-apps.test.ts +0 -85
  568. package/src/memory/preloaded-apps.ts +0 -116
  569. package/src/notifications/tool-approval-copy.ts +0 -142
  570. package/src/runtime/routes/approval-prompt-ts-tracker.ts +0 -78
  571. package/src/runtime/routes/identity-intro-cache.ts +0 -172
  572. package/src/tools/credentials/vault.ts +0 -712
@@ -0,0 +1,129 @@
1
+ import { existsSync, readFileSync, writeFileSync } from "node:fs";
2
+ import { join } from "node:path";
3
+
4
+ import type { WorkspaceMigration } from "./types.js";
5
+
6
+ // Reclaim the managed `balanced-economy` inference profile. Its
7
+ // MiniMax-M3-on-Fireworks config lives on `balanced`, whose content the seeder
8
+ // reconciles from the templates on every boot; the seeder never deletes a
9
+ // profile, so this migration deletes the managed `balanced-economy` object and
10
+ // repoints every reference to it — its `profileOrder` entry, the `activeProfile`
11
+ // and `advisorProfile` selections, call-site `profile` overrides, and mix-profile
12
+ // arms — onto `balanced`, which resolves to the same MiniMax M3 route. A
13
+ // `balanced-economy` profile that the user owns (`source !== "managed"`) is left
14
+ // fully intact, references included.
15
+
16
+ const ECONOMY = "balanced-economy";
17
+ const REPLACEMENT = "balanced";
18
+
19
+ export const dropBalancedEconomyProfileMigration: WorkspaceMigration = {
20
+ id: "108-drop-balanced-economy-profile",
21
+ description:
22
+ "Remove the managed Balanced Economy profile and repoint its references to Balanced",
23
+ run(workspaceDir: string): void {
24
+ const configPath = join(workspaceDir, "config.json");
25
+ if (!existsSync(configPath)) return;
26
+
27
+ let config: Record<string, unknown>;
28
+ try {
29
+ const raw = JSON.parse(readFileSync(configPath, "utf-8"));
30
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) return;
31
+ config = raw as Record<string, unknown>;
32
+ } catch {
33
+ return;
34
+ }
35
+
36
+ const llm = readObject(config.llm);
37
+ if (llm === null) return;
38
+
39
+ const profiles = readObject(llm.profiles);
40
+ const economy = profiles !== null ? readObject(profiles[ECONOMY]) : null;
41
+
42
+ // A user-owned profile that happens to use this name keeps everything,
43
+ // references included — only the managed profile is reclaimed.
44
+ if (economy !== null && economy.source !== "managed") return;
45
+
46
+ let changed = false;
47
+
48
+ if (economy !== null && profiles !== null) {
49
+ delete profiles[ECONOMY];
50
+ changed = true;
51
+ }
52
+
53
+ if (Array.isArray(llm.profileOrder)) {
54
+ const order = llm.profileOrder as unknown[];
55
+ const pruned = order.filter((name) => name !== ECONOMY);
56
+ if (pruned.length !== order.length) {
57
+ llm.profileOrder = pruned;
58
+ changed = true;
59
+ }
60
+ }
61
+
62
+ // Repoint call-site overrides — LLMSchema strips a profile name absent from
63
+ // `llm.profiles` at load, which would drop the equivalent MiniMax route.
64
+ const callSites = readObject(llm.callSites);
65
+ if (callSites !== null) {
66
+ for (const value of Object.values(callSites)) {
67
+ const site = readObject(value);
68
+ if (site !== null && site.profile === ECONOMY) {
69
+ site.profile = REPLACEMENT;
70
+ changed = true;
71
+ }
72
+ }
73
+ }
74
+
75
+ // Repoint mix-profile arms — LLMSchema.superRefine rejects a mix arm whose
76
+ // referenced profile is absent, failing config validation at load.
77
+ if (profiles !== null) {
78
+ for (const value of Object.values(profiles)) {
79
+ const entry = readObject(value);
80
+ if (entry === null || !Array.isArray(entry.mix)) continue;
81
+ for (const arm of entry.mix) {
82
+ const armObj = readObject(arm);
83
+ if (armObj !== null && armObj.profile === ECONOMY) {
84
+ armObj.profile = REPLACEMENT;
85
+ changed = true;
86
+ }
87
+ }
88
+ }
89
+ }
90
+
91
+ if (llm.activeProfile === ECONOMY) {
92
+ llm.activeProfile = REPLACEMENT;
93
+ changed = true;
94
+
95
+ // The replaced selection was an enabled profile, so `balanced` must be
96
+ // usable: a disabled profile is skipped by the resolver and rejected by
97
+ // validation. Clearing the status sticks because the seeder preserves
98
+ // whatever status is on disk.
99
+ const balanced =
100
+ profiles !== null ? readObject(profiles[REPLACEMENT]) : null;
101
+ if (balanced !== null && balanced.status === "disabled") {
102
+ delete balanced.status;
103
+ }
104
+ }
105
+
106
+ // The advisor selection is the other top-level profile reference
107
+ // `LLMSchema.superRefine` validates against `llm.profiles`; an unresolvable
108
+ // value invalidates the config and is stripped at load.
109
+ if (llm.advisorProfile === ECONOMY) {
110
+ llm.advisorProfile = REPLACEMENT;
111
+ changed = true;
112
+ }
113
+
114
+ if (!changed) return;
115
+
116
+ config.llm = llm;
117
+ writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n");
118
+ },
119
+ down(_workspaceDir: string): void {
120
+ // Forward-only.
121
+ },
122
+ };
123
+
124
+ function readObject(value: unknown): Record<string, unknown> | null {
125
+ if (value === null || typeof value !== "object" || Array.isArray(value)) {
126
+ return null;
127
+ }
128
+ return value as Record<string, unknown>;
129
+ }
@@ -102,6 +102,10 @@ import { upgradeBalancedEconomyToMinimaxM3Migration } from "./101-upgrade-balanc
102
102
  import { preserveHeartbeatEnabledForExistingWorkspacesMigration } from "./102-preserve-heartbeat-enabled-for-existing-workspaces.js";
103
103
  import { upgradeQualityProfileToOpus48Migration } from "./103-upgrade-quality-profile-to-opus-4-8.js";
104
104
  import { recheckAdaptiveThinkingModelImpliedAnthropicMigration } from "./104-recheck-adaptive-thinking-model-implied-anthropic.js";
105
+ import { enableMemoryV3LiveForNewWorkspacesMigration } from "./105-enable-memory-v3-live-for-new-workspaces.js";
106
+ import { dropCollectUsageDataMigration } from "./106-drop-collect-usage-data.js";
107
+ import { dropSendDiagnosticsMigration } from "./107-drop-send-diagnostics.js";
108
+ import { dropBalancedEconomyProfileMigration } from "./108-drop-balanced-economy-profile.js";
105
109
  import { migrateToWorkspaceVolumeMigration } from "./migrate-to-workspace-volume.js";
106
110
  import type { WorkspaceMigration } from "./types.js";
107
111
 
@@ -215,4 +219,8 @@ export const WORKSPACE_MIGRATIONS: WorkspaceMigration[] = [
215
219
  preserveHeartbeatEnabledForExistingWorkspacesMigration,
216
220
  upgradeQualityProfileToOpus48Migration,
217
221
  recheckAdaptiveThinkingModelImpliedAnthropicMigration,
222
+ enableMemoryV3LiveForNewWorkspacesMigration,
223
+ dropCollectUsageDataMigration,
224
+ dropSendDiagnosticsMigration,
225
+ dropBalancedEconomyProfileMigration,
218
226
  ];
@@ -1,98 +0,0 @@
1
- /**
2
- * Static-analysis guard for the AppControl Swift sources.
3
- *
4
- * The app-control surface targets a *specific* host process — events must
5
- * be delivered with `CGEvent.postToPid(_:)` (Swift-bridged) or its C-symbol
6
- * equivalent `CGEventPostToPid(...)`. The deprecated global form
7
- * `CGEventPost(...)` posts to the system-wide event tap, which would leak
8
- * input to whichever app currently has user focus. That defeats the whole
9
- * point of per-process app control and is a security hazard, so we keep
10
- * it out of `clients/macos/vellum-assistant/AppControl/` entirely.
11
- *
12
- * The guard flags any standalone `CGEventPost(...)` call (i.e. the parens
13
- * follow the symbol directly, not preceded by `.`). Allowed forms:
14
- * - `CGEvent.postToPid(_:)` (Swift-bridged, modern idiom)
15
- * - `CGEventPostToPid(...)` (C-symbol, process-scoped)
16
- * - any line carrying a `// allow: CGEventPost` suppression comment
17
- *
18
- * If a real call site ever needs the global form, the suppression comment
19
- * makes the intent explicit.
20
- */
21
- import { readdirSync, readFileSync } from "node:fs";
22
- import { join } from "node:path";
23
- import { describe, expect, test } from "bun:test";
24
-
25
- const APP_CONTROL_DIR = join(
26
- process.cwd(),
27
- "..",
28
- "clients",
29
- "macos",
30
- "vellum-assistant",
31
- "AppControl",
32
- );
33
-
34
- /** Recursively collect `.swift` files under `dir`. */
35
- function collectSwiftFiles(dir: string): string[] {
36
- const out: string[] = [];
37
- for (const entry of readdirSync(dir, { withFileTypes: true })) {
38
- const full = join(dir, entry.name);
39
- if (entry.isDirectory()) {
40
- out.push(...collectSwiftFiles(full));
41
- } else if (entry.isFile() && entry.name.endsWith(".swift")) {
42
- out.push(full);
43
- }
44
- }
45
- return out;
46
- }
47
-
48
- /**
49
- * Match a global `CGEventPost(` call: the literal symbol followed
50
- * immediately by `(`. We use a negative lookbehind to exclude:
51
- * - `.CGEventPost(` (member access, not a real Swift form but harmless)
52
- * - `CGEventPostToPid(` (process-scoped C symbol — allowed)
53
- * - `CGEvent.postToPid(` (Swift-bridged form — does not match anyway,
54
- * the symbol there is `postToPid`).
55
- *
56
- * The regex is intentionally narrow: `\bCGEventPost\(` matches only
57
- * `CGEventPost(`. `CGEventPostToPid(` does not match because the substring
58
- * after `CGEventPost` is `T`, not `(`.
59
- */
60
- const GLOBAL_CGEVENT_POST = /\bCGEventPost\(/;
61
-
62
- /** Suppression comment that whitelists a single line. */
63
- const ALLOW_COMMENT = /\/\/\s*allow:\s*CGEventPost/i;
64
-
65
- describe("app-control: no global CGEventPost in Swift sources", () => {
66
- test("CGEventPost(...) is forbidden in clients/macos/vellum-assistant/AppControl/", () => {
67
- const files = collectSwiftFiles(APP_CONTROL_DIR);
68
- expect(files.length).toBeGreaterThan(0);
69
-
70
- const violations: string[] = [];
71
- for (const file of files) {
72
- const content = readFileSync(file, "utf-8");
73
- const lines = content.split("\n");
74
- for (let i = 0; i < lines.length; i++) {
75
- const line = lines[i]!;
76
- if (!GLOBAL_CGEVENT_POST.test(line)) continue;
77
- if (ALLOW_COMMENT.test(line)) continue;
78
- violations.push(`${file}:${i + 1}: ${line.trim()}`);
79
- }
80
- }
81
-
82
- if (violations.length > 0) {
83
- const message = [
84
- "Found global CGEventPost(...) calls in AppControl Swift sources.",
85
- "App-control input must be process-scoped — use CGEvent.postToPid(_:)",
86
- "(Swift-bridged form) or CGEventPostToPid(...) (C-symbol form). The",
87
- "global form leaks events to whichever app currently has user focus.",
88
- "",
89
- "If a specific call site genuinely needs the global form, append a",
90
- "`// allow: CGEventPost` comment to that line to suppress this guard.",
91
- "",
92
- "Violations:",
93
- ...violations.map((v) => ` - ${v}`),
94
- ].join("\n");
95
- expect(violations, message).toEqual([]);
96
- }
97
- });
98
- });
@@ -1,362 +0,0 @@
1
- import { beforeEach, describe, expect, mock, test } from "bun:test";
2
-
3
- // ---------------------------------------------------------------------------
4
- // Mocks — declared before importing modules under test
5
- // ---------------------------------------------------------------------------
6
-
7
- const mockConfig = {
8
- secretDetection: {
9
- enabled: true,
10
- allowOneTimeSend: false,
11
- },
12
- timeouts: { permissionTimeoutSec: 300 },
13
- };
14
-
15
- function setMockNestedValue(
16
- obj: Record<string, unknown>,
17
- path: string,
18
- value: unknown,
19
- ): void {
20
- const keys = path.split(".");
21
- let current = obj;
22
- for (let i = 0; i < keys.length - 1; i++) {
23
- const key = keys[i];
24
- if (current[key] == null || typeof current[key] !== "object") {
25
- current[key] = {};
26
- }
27
- current = current[key] as Record<string, unknown>;
28
- }
29
- current[keys[keys.length - 1]] = value;
30
- }
31
-
32
- mock.module("../config/loader.js", () => ({
33
- getConfig: () => mockConfig,
34
- loadConfig: () => mockConfig,
35
- loadRawConfig: () => ({}),
36
- saveRawConfig: () => {},
37
- setNestedValue: setMockNestedValue,
38
- invalidateConfigCache: () => {},
39
- }));
40
-
41
- mock.module("../util/logger.js", () => ({
42
- getLogger: () =>
43
- new Proxy({} as Record<string, unknown>, {
44
- get: () => () => {},
45
- }),
46
- }));
47
-
48
- // Track credential store writes
49
- const storedKeys = new Map<string, string>();
50
- mock.module("../security/secure-keys.js", () => {
51
- const syncSet = (key: string, value: string) => {
52
- storedKeys.set(key, value);
53
- return true;
54
- };
55
- const syncDelete = (key: string) => {
56
- if (storedKeys.has(key)) {
57
- storedKeys.delete(key);
58
- return "deleted" as const;
59
- }
60
- return "not-found" as const;
61
- };
62
- return {
63
- getSecureKeyAsync: async (key: string) => storedKeys.get(key) ?? undefined,
64
- getSecureKeyResultAsync: async (account: string) => ({
65
- value: storedKeys.get(account),
66
- unreachable: false,
67
- }),
68
- setSecureKeyAsync: async (key: string, value: string) =>
69
- syncSet(key, value),
70
- deleteSecureKeyAsync: async (key: string) => syncDelete(key),
71
- listSecureKeysAsync: async () => ({
72
- accounts: [...storedKeys.keys()],
73
- unreachable: false,
74
- }),
75
- getProviderKeyAsync: async () => undefined,
76
- getMaskedProviderKey: async () => null,
77
- };
78
- });
79
-
80
- // In-memory metadata store that mirrors storedKeys for list/get operations
81
- const metadataStore = new Map<
82
- string,
83
- { credentialId: string; service: string; field: string }
84
- >();
85
-
86
- mock.module("../tools/credentials/metadata-store.js", () => ({
87
- upsertCredentialMetadata: (
88
- service: string,
89
- field: string,
90
- _policy?: Record<string, unknown>,
91
- ) => {
92
- const key = `${service}:${field}`;
93
- metadataStore.set(key, {
94
- credentialId: `cred-${service}-${field}`,
95
- service,
96
- field,
97
- });
98
- },
99
- deleteCredentialMetadata: (service: string, field: string) => {
100
- metadataStore.delete(`${service}:${field}`);
101
- },
102
- getCredentialMetadata: (service: string, field: string) => {
103
- return metadataStore.get(`${service}:${field}`) ?? null;
104
- },
105
- getCredentialMetadataById: (id: string) => {
106
- for (const m of metadataStore.values()) {
107
- if (m.credentialId === id) return m;
108
- }
109
- return undefined;
110
- },
111
- listCredentialMetadata: () => [...metadataStore.values()],
112
- assertMetadataWritable: () => {},
113
- _setMetadataPath: () => {},
114
- }));
115
-
116
- mock.module("../tools/credentials/policy-validate.js", () => ({
117
- validatePolicyInput: () => ({ valid: true, errors: [] }),
118
- toPolicyFromInput: (input: Record<string, unknown>) => ({
119
- allowedTools: input.allowed_tools ?? [],
120
- allowedDomains: input.allowed_domains ?? [],
121
- usageDescription: input.usage_description,
122
- }),
123
- }));
124
-
125
- // Import modules under test
126
- const { credentialStoreTool } = await import("../tools/credentials/vault.js");
127
- const { isToolAllowed } = await import("../tools/credentials/tool-policy.js");
128
- const { isDomainAllowed } =
129
- await import("../tools/credentials/domain-policy.js");
130
-
131
- // ---------------------------------------------------------------------------
132
- // Helpers
133
- // ---------------------------------------------------------------------------
134
-
135
- function makeContext(overrides: Record<string, unknown> = {}) {
136
- return {
137
- workingDir: "/tmp",
138
- conversationId: "c1",
139
- trustClass: "guardian" as const,
140
- ...overrides,
141
- };
142
- }
143
-
144
- // ---------------------------------------------------------------------------
145
- // E2E Scenario 1 — Normal secure store + list
146
- // ---------------------------------------------------------------------------
147
-
148
- describe("E2E: secure store and list lifecycle", () => {
149
- beforeEach(() => {
150
- storedKeys.clear();
151
- metadataStore.clear();
152
- });
153
-
154
- test("store persists credential and returns metadata-only confirmation", async () => {
155
- const result = await credentialStoreTool.execute(
156
- {
157
- action: "store",
158
- service: "github",
159
- field: "token",
160
- value: "ghp_abc123",
161
- },
162
- makeContext(),
163
- );
164
- expect(result.isError).toBe(false);
165
- expect(result.content).toContain("github");
166
- // Value must NOT appear in tool output (invariant 1)
167
- expect(result.content).not.toContain("ghp_abc123");
168
- // Value must be in credential store
169
- expect(storedKeys.get("credential/github/token")).toBe("ghp_abc123");
170
- });
171
-
172
- test("list returns service/field pairs without secret values", async () => {
173
- storedKeys.set("credential/github/token", "secret1");
174
- storedKeys.set("credential/aws/access_key", "secret2");
175
- metadataStore.set("github:token", {
176
- credentialId: "cred-github-token",
177
- service: "github",
178
- field: "token",
179
- });
180
- metadataStore.set("aws:access_key", {
181
- credentialId: "cred-aws-access_key",
182
- service: "aws",
183
- field: "access_key",
184
- });
185
-
186
- const result = await credentialStoreTool.execute(
187
- { action: "list" },
188
- makeContext(),
189
- );
190
- expect(result.isError).toBe(false);
191
- expect(result.content).toContain("github");
192
- expect(result.content).toContain("token");
193
- // Secret values must NOT appear
194
- expect(result.content).not.toContain("secret1");
195
- expect(result.content).not.toContain("secret2");
196
- });
197
-
198
- test("delete removes credential from credential store", async () => {
199
- storedKeys.set("credential/github/token", "secret1");
200
-
201
- const result = await credentialStoreTool.execute(
202
- { action: "delete", service: "github", field: "token" },
203
- makeContext(),
204
- );
205
- expect(result.isError).toBe(false);
206
- expect(storedKeys.has("credential/github/token")).toBe(false);
207
- });
208
- });
209
-
210
- // ---------------------------------------------------------------------------
211
- // E2E Scenario 3 — One-time send override path
212
- // ---------------------------------------------------------------------------
213
-
214
- describe("E2E: one-time send override", () => {
215
- beforeEach(() => {
216
- storedKeys.clear();
217
- metadataStore.clear();
218
- mockConfig.secretDetection.allowOneTimeSend = false;
219
- });
220
-
221
- test("rejects transient_send when config gate is off", async () => {
222
- const ctx = makeContext({
223
- requestSecret: async () => ({
224
- value: "tmp1",
225
- delivery: "transient_send" as const,
226
- }),
227
- });
228
- const result = await credentialStoreTool.execute(
229
- { action: "prompt", service: "svc", field: "key", label: "Key" },
230
- ctx,
231
- );
232
- expect(result.isError).toBe(true);
233
- expect(result.content).toContain("not enabled");
234
- expect(storedKeys.has("credential/svc/key")).toBe(false);
235
- });
236
-
237
- test("accepts transient_send when config gate is on", async () => {
238
- mockConfig.secretDetection.allowOneTimeSend = true;
239
- const ctx = makeContext({
240
- requestSecret: async () => ({
241
- value: "tmp1",
242
- delivery: "transient_send" as const,
243
- }),
244
- });
245
- const result = await credentialStoreTool.execute(
246
- { action: "prompt", service: "svc", field: "key", label: "Key" },
247
- ctx,
248
- );
249
- expect(result.isError).toBe(false);
250
- expect(result.content).toContain("NOT saved");
251
- // Value must NOT be in credential store
252
- expect(storedKeys.has("credential/svc/key")).toBe(false);
253
- // Value must NOT appear in output
254
- expect(result.content).not.toContain("tmp1");
255
- });
256
-
257
- test("store delivery always persists regardless of config gate", async () => {
258
- mockConfig.secretDetection.allowOneTimeSend = true;
259
- const ctx = makeContext({
260
- requestSecret: async () => ({
261
- value: "perm1",
262
- delivery: "store" as const,
263
- }),
264
- });
265
- const result = await credentialStoreTool.execute(
266
- { action: "prompt", service: "svc", field: "key", label: "Key" },
267
- ctx,
268
- );
269
- expect(result.isError).toBe(false);
270
- expect(storedKeys.has("credential/svc/key")).toBe(true);
271
- });
272
- });
273
-
274
- // ---------------------------------------------------------------------------
275
- // E2E Scenario 4 — Tool policy enforcement
276
- // ---------------------------------------------------------------------------
277
-
278
- describe("E2E: tool policy enforcement", () => {
279
- test("allows tool when listed in allowedTools", () => {
280
- expect(
281
- isToolAllowed("browser_fill_credential", ["browser_fill_credential"]),
282
- ).toBe(true);
283
- });
284
-
285
- test("denies tool when not listed", () => {
286
- expect(isToolAllowed("browser_fill_credential", ["other_tool"])).toBe(
287
- false,
288
- );
289
- });
290
-
291
- test("denies all tools when allowedTools is empty (fail-closed)", () => {
292
- expect(isToolAllowed("browser_fill_credential", [])).toBe(false);
293
- });
294
-
295
- test("denies when toolName is empty", () => {
296
- expect(isToolAllowed("", ["browser_fill_credential"])).toBe(false);
297
- });
298
- });
299
-
300
- // ---------------------------------------------------------------------------
301
- // E2E Scenario 5 — Domain policy enforcement
302
- // ---------------------------------------------------------------------------
303
-
304
- describe("E2E: domain policy enforcement", () => {
305
- test("allows exact domain match", () => {
306
- expect(isDomainAllowed("github.com", ["github.com"])).toBe(true);
307
- });
308
-
309
- test("allows subdomain of registrable domain", () => {
310
- expect(isDomainAllowed("login.github.com", ["github.com"])).toBe(true);
311
- });
312
-
313
- test("denies mismatched domain", () => {
314
- expect(isDomainAllowed("evil.com", ["github.com"])).toBe(false);
315
- });
316
-
317
- test("denies when allowedDomains is empty (fail-closed)", () => {
318
- expect(isDomainAllowed("github.com", [])).toBe(false);
319
- });
320
-
321
- test("denies localhost and IP addresses", () => {
322
- expect(isDomainAllowed("localhost", ["localhost"])).toBe(false);
323
- expect(isDomainAllowed("127.0.0.1", ["127.0.0.1"])).toBe(false);
324
- });
325
- });
326
-
327
- // ---------------------------------------------------------------------------
328
- // Cross-cutting — output never leaks secrets
329
- // ---------------------------------------------------------------------------
330
-
331
- describe("E2E: cross-cutting secret leak prevention", () => {
332
- beforeEach(() => {
333
- storedKeys.clear();
334
- mockConfig.secretDetection.enabled = true;
335
- mockConfig.secretDetection.allowOneTimeSend = false;
336
- });
337
-
338
- test("store output never contains the stored value", async () => {
339
- const secret = ["sk", "-proj-", "abc123xyz"].join("");
340
- const result = await credentialStoreTool.execute(
341
- { action: "store", service: "openai", field: "api_key", value: secret },
342
- makeContext(),
343
- );
344
- expect(result.content).not.toContain(secret);
345
- });
346
-
347
- test("prompt output never contains the secret value", async () => {
348
- mockConfig.secretDetection.allowOneTimeSend = true;
349
- const secret = ["tok", "_", "sensitive99"].join("");
350
- const ctx = makeContext({
351
- requestSecret: async () => ({
352
- value: secret,
353
- delivery: "transient_send" as const,
354
- }),
355
- });
356
- const result = await credentialStoreTool.execute(
357
- { action: "prompt", service: "svc", field: "key", label: "Key" },
358
- ctx,
359
- );
360
- expect(result.content).not.toContain(secret);
361
- });
362
- });