@vellumai/assistant 0.6.4 → 0.6.5

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 (717) hide show
  1. package/.prettierignore +5 -0
  2. package/ARCHITECTURE.md +32 -36
  3. package/Dockerfile +12 -0
  4. package/README.md +3 -4
  5. package/bun.lock +8 -3
  6. package/docs/architecture/integrations.md +1 -20
  7. package/docs/architecture/security.md +16 -16
  8. package/docs/error-handling.md +111 -0
  9. package/docs/skills.md +10 -10
  10. package/docs/stt-provider-onboarding.md +2 -1
  11. package/knip.json +9 -2
  12. package/node_modules/@vellumai/ces-contracts/package.json +2 -1
  13. package/node_modules/@vellumai/ces-contracts/src/__tests__/trust-rules.test.ts +471 -0
  14. package/node_modules/@vellumai/ces-contracts/src/trust-rules.ts +398 -4
  15. package/node_modules/@vellumai/credential-storage/bun.lock +2 -2
  16. package/node_modules/@vellumai/credential-storage/package.json +2 -2
  17. package/node_modules/@vellumai/credential-storage/src/oauth-runtime.ts +20 -2
  18. package/node_modules/@vellumai/egress-proxy/bun.lock +2 -2
  19. package/node_modules/@vellumai/egress-proxy/package.json +2 -2
  20. package/openapi.yaml +123 -11
  21. package/package.json +6 -3
  22. package/scripts/generate-openapi.ts +50 -11
  23. package/src/__tests__/agent-loop-callsite-precedence.test.ts +318 -0
  24. package/src/__tests__/agent-loop-sentry-hygiene.test.ts +137 -0
  25. package/src/__tests__/agent-loop.test.ts +112 -1
  26. package/src/__tests__/anthropic-error-formatting.test.ts +98 -0
  27. package/src/__tests__/anthropic-provider.test.ts +171 -2
  28. package/src/__tests__/approval-cascade.test.ts +31 -10
  29. package/src/__tests__/approval-routes-http.test.ts +134 -10
  30. package/src/__tests__/assistant-attachments.test.ts +44 -0
  31. package/src/__tests__/assistant-feature-flags-integration.test.ts +29 -0
  32. package/src/__tests__/browser-fill-credential.test.ts +1 -1
  33. package/src/__tests__/browser-identifier-parity-guard.test.ts +53 -0
  34. package/src/__tests__/browser-skill-baseline-tool-payload.test.ts +23 -33
  35. package/src/__tests__/browser-skill-endstate.test.ts +51 -182
  36. package/src/__tests__/btw-routes.test.ts +47 -1
  37. package/src/__tests__/call-controller.test.ts +1 -2
  38. package/src/__tests__/call-site-routing-provider.test.ts +214 -0
  39. package/src/__tests__/catalog-cache.test.ts +27 -4
  40. package/src/__tests__/channel-approval-routes.test.ts +4 -4
  41. package/src/__tests__/channel-reply-delivery.test.ts +300 -2
  42. package/src/__tests__/checker.test.ts +428 -501
  43. package/src/__tests__/cli-command-risk-guard.test.ts +30 -33
  44. package/src/__tests__/compaction-circuit-breaker.test.ts +336 -0
  45. package/src/__tests__/compaction.benchmark.test.ts +1 -1
  46. package/src/__tests__/config-analysis.test.ts +11 -28
  47. package/src/__tests__/config-loader-backfill.test.ts +174 -0
  48. package/src/__tests__/config-loader-corrupt.test.ts +183 -0
  49. package/src/__tests__/config-loader-quarantine-bulletin.test.ts +202 -0
  50. package/src/__tests__/config-schema-cmd.test.ts +11 -5
  51. package/src/__tests__/config-schema.test.ts +427 -114
  52. package/src/__tests__/config-watcher.test.ts +2 -2
  53. package/src/__tests__/contact-store-user-file.test.ts +72 -73
  54. package/src/__tests__/contacts-write.test.ts +4 -4
  55. package/src/__tests__/context-token-estimator.test.ts +191 -1
  56. package/src/__tests__/context-window-manager.test.ts +530 -2
  57. package/src/__tests__/conversation-abort-tool-results.test.ts +30 -16
  58. package/src/__tests__/conversation-agent-loop-overflow.test.ts +61 -17
  59. package/src/__tests__/conversation-agent-loop.test.ts +412 -82
  60. package/src/__tests__/conversation-attachments.test.ts +1 -1
  61. package/src/__tests__/conversation-confirmation-signals.test.ts +30 -9
  62. package/src/__tests__/conversation-error.test.ts +37 -6
  63. package/src/__tests__/conversation-history-web-search.test.ts +6 -0
  64. package/src/__tests__/conversation-init.benchmark.test.ts +36 -0
  65. package/src/__tests__/conversation-lifecycle.test.ts +336 -0
  66. package/src/__tests__/conversation-load-history-repair.test.ts +27 -10
  67. package/src/__tests__/conversation-pre-run-repair.test.ts +30 -16
  68. package/src/__tests__/conversation-process-callsite.test.ts +306 -0
  69. package/src/__tests__/conversation-provider-retry-repair.test.ts +30 -16
  70. package/src/__tests__/conversation-queue.test.ts +41 -26
  71. package/src/__tests__/conversation-routes-disk-view.test.ts +29 -1
  72. package/src/__tests__/conversation-routes-slash-commands.test.ts +31 -3
  73. package/src/__tests__/conversation-runtime-assembly.test.ts +2735 -55
  74. package/src/__tests__/conversation-runtime-workspace.test.ts +12 -12
  75. package/src/__tests__/conversation-skill-tools.test.ts +12 -146
  76. package/src/__tests__/conversation-slash-queue.test.ts +34 -19
  77. package/src/__tests__/conversation-slash-unknown.test.ts +30 -16
  78. package/src/__tests__/conversation-speed-override.test.ts +30 -11
  79. package/src/__tests__/conversation-surfaces-standalone-payloads.test.ts +1035 -0
  80. package/src/__tests__/conversation-surfaces-standalone.test.ts +630 -0
  81. package/src/__tests__/conversation-title-service.test.ts +2 -2
  82. package/src/__tests__/conversation-tool-setup-batch-authorized.test.ts +1 -1
  83. package/src/__tests__/conversation-unread-route.test.ts +2 -2
  84. package/src/__tests__/conversation-usage.test.ts +3 -1
  85. package/src/__tests__/conversation-workspace-cache-state.test.ts +31 -10
  86. package/src/__tests__/conversation-workspace-injection.test.ts +43 -15
  87. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +44 -16
  88. package/src/__tests__/credential-broker-browser-fill.test.ts +110 -0
  89. package/src/__tests__/credential-security-invariants.test.ts +3 -0
  90. package/src/__tests__/credential-storage-oauth-compat.test.ts +18 -0
  91. package/src/__tests__/credential-storage-static-compat.test.ts +28 -0
  92. package/src/__tests__/credential-vault-unit.test.ts +135 -19
  93. package/src/__tests__/credentials-cli.test.ts +1 -9
  94. package/src/__tests__/cross-provider-web-search.test.ts +84 -0
  95. package/src/__tests__/daemon-server-persist-and-process-callsite.test.ts +92 -0
  96. package/src/__tests__/delete-propagation.test.ts +437 -0
  97. package/src/__tests__/dm-backfill.test.ts +417 -0
  98. package/src/__tests__/dm-persistence.test.ts +227 -0
  99. package/src/__tests__/edit-propagation.test.ts +280 -0
  100. package/src/__tests__/ephemeral-permissions.test.ts +93 -3
  101. package/src/__tests__/estimator-calibration-integration.test.ts +208 -0
  102. package/src/__tests__/estimator-calibration.test.ts +213 -0
  103. package/src/__tests__/extension-id-sync-guard.test.ts +26 -7
  104. package/src/__tests__/file-write-tool.test.ts +151 -1
  105. package/src/__tests__/filing-service.test.ts +255 -0
  106. package/src/__tests__/gemini-provider.test.ts +0 -3
  107. package/src/__tests__/guardian-grant-minting.test.ts +8 -0
  108. package/src/__tests__/headless-browser-interactions.test.ts +1 -1
  109. package/src/__tests__/heartbeat-service.test.ts +96 -15
  110. package/src/__tests__/host-shell-tool.test.ts +124 -18
  111. package/src/__tests__/http-user-message-parity.test.ts +29 -1
  112. package/src/__tests__/inbound-slack-persistence.test.ts +340 -0
  113. package/src/__tests__/intent-routing.test.ts +1 -40
  114. package/src/__tests__/llm-catalog-parity.test.ts +174 -0
  115. package/src/__tests__/llm-context-normalization.test.ts +121 -0
  116. package/src/__tests__/llm-resolver.test.ts +214 -0
  117. package/src/__tests__/llm-schema.test.ts +223 -0
  118. package/src/__tests__/managed-proxy-context.test.ts +6 -2
  119. package/src/__tests__/messaging-skill-split.test.ts +3 -34
  120. package/src/__tests__/migration-import-from-url.test.ts +684 -0
  121. package/src/__tests__/model-intents.test.ts +9 -83
  122. package/src/__tests__/notification-decision-fallback.test.ts +0 -10
  123. package/src/__tests__/notification-decision-identity.test.ts +0 -9
  124. package/src/__tests__/notification-decision-recipient-context.test.ts +0 -9
  125. package/src/__tests__/oauth-store.test.ts +10 -7
  126. package/src/__tests__/oauth2-gateway-transport.test.ts +8 -3
  127. package/src/__tests__/oauth2-refresh-retry.test.ts +279 -0
  128. package/src/__tests__/openai-provider.test.ts +7 -0
  129. package/src/__tests__/openai-responses-provider.test.ts +396 -0
  130. package/src/__tests__/openrouter-provider-only.test.ts +135 -0
  131. package/src/__tests__/outbound-slack-persistence.test.ts +293 -0
  132. package/src/__tests__/permission-checker-host-gate.test.ts +1 -1
  133. package/src/__tests__/permission-mode.test.ts +16 -0
  134. package/src/__tests__/permission-types.test.ts +0 -1
  135. package/src/__tests__/persona-resolver.test.ts +13 -13
  136. package/src/__tests__/pkb-autoinject.test.ts +37 -1
  137. package/src/__tests__/platform-bash-auto-approve.test.ts +1 -1
  138. package/src/__tests__/pricing.test.ts +50 -3
  139. package/src/__tests__/profiler-routes.test.ts +1 -1
  140. package/src/__tests__/provider-commit-message-generator.test.ts +14 -84
  141. package/src/__tests__/provider-env-vars-scope.test.ts +52 -0
  142. package/src/__tests__/provider-error-scenarios.test.ts +135 -6
  143. package/src/__tests__/provider-managed-proxy-integration.test.ts +42 -11
  144. package/src/__tests__/provider-registry-ollama.test.ts +1 -2
  145. package/src/__tests__/proxy-approval-callback.test.ts +0 -1
  146. package/src/__tests__/reaction-persistence.test.ts +560 -0
  147. package/src/__tests__/relay-server.test.ts +1 -1
  148. package/src/__tests__/require-fresh-approval.test.ts +1 -1
  149. package/src/__tests__/retry-openrouter-only-normalization.test.ts +136 -0
  150. package/src/__tests__/retry-thinking-tool-choice.test.ts +226 -0
  151. package/src/__tests__/risk-classifier-parity.test.ts +230 -0
  152. package/src/__tests__/sanitize-config-for-transfer.test.ts +78 -1
  153. package/src/__tests__/secret-ingress-http.test.ts +28 -0
  154. package/src/__tests__/secret-prompter-channel-fallback.test.ts +125 -0
  155. package/src/__tests__/secret-routes-managed-proxy.test.ts +2 -3
  156. package/src/__tests__/secret-scanner-executor.test.ts +1 -1
  157. package/src/__tests__/send-endpoint-busy.test.ts +29 -1
  158. package/src/__tests__/server-history-render.test.ts +31 -0
  159. package/src/__tests__/shell-parser-property.test.ts +13 -13
  160. package/src/__tests__/skill-cache-store.test.ts +182 -0
  161. package/src/__tests__/skills.test.ts +19 -33
  162. package/src/__tests__/slack-app-setup-skill-regression.test.ts +3 -1
  163. package/src/__tests__/slack-skill.test.ts +3 -8
  164. package/src/__tests__/starter-bundle.test.ts +35 -0
  165. package/src/__tests__/subagent-call-site-routing.test.ts +280 -0
  166. package/src/__tests__/suggestion-routes.test.ts +160 -3
  167. package/src/__tests__/system-prompt.test.ts +22 -35
  168. package/src/__tests__/task-runner.test.ts +3 -1
  169. package/src/__tests__/tcc-sandbox-deny.test.ts +198 -0
  170. package/src/__tests__/terminal-tools.test.ts +8 -0
  171. package/src/__tests__/test-support/browser-skill-harness.ts +2 -52
  172. package/src/__tests__/thread-backfill.test.ts +941 -0
  173. package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +2 -2
  174. package/src/__tests__/tool-executor-lifecycle-events.test.ts +2 -2
  175. package/src/__tests__/tool-executor.test.ts +60 -94
  176. package/src/__tests__/trust-store.test.ts +442 -109
  177. package/src/__tests__/update-bulletin-job.test.ts +389 -0
  178. package/src/__tests__/usage-cache-backfill-migration.test.ts +3 -1
  179. package/src/__tests__/verification-control-plane-policy.test.ts +1 -22
  180. package/src/__tests__/voice-session-bridge.test.ts +39 -0
  181. package/src/__tests__/volume-security-guard.test.ts +3 -2
  182. package/src/__tests__/web-search-history.test.ts +337 -0
  183. package/src/__tests__/workspace-migration-039-drop-legacy-llm-keys.test.ts +343 -0
  184. package/src/__tests__/workspace-migration-043-release-notes-latex-rendering.test.ts +202 -0
  185. package/src/__tests__/workspace-migration-045-release-notes-meet-avatar.test.ts +210 -0
  186. package/src/__tests__/workspace-migration-drop-user-md.test.ts +11 -11
  187. package/src/__tests__/workspace-migration-unify-llm-callsite-configs.test.ts +841 -0
  188. package/src/__tests__/workspace-policy.test.ts +1 -13
  189. package/src/acp/client-handler.ts +1 -2
  190. package/src/agent/loop.ts +209 -17
  191. package/src/avatar/resvg-lazy.test.ts +136 -0
  192. package/src/avatar/resvg-lazy.ts +82 -9
  193. package/src/avatar/traits-png-sync.ts +21 -1
  194. package/src/browser/__tests__/operations.test.ts +163 -0
  195. package/src/browser/identifiers.ts +51 -0
  196. package/src/browser/operations.ts +660 -0
  197. package/src/browser/types.ts +81 -0
  198. package/src/calls/guardian-question-copy.ts +2 -2
  199. package/src/calls/telephony-stt-routing.ts +1 -1
  200. package/src/calls/voice-session-bridge.ts +1 -0
  201. package/src/cli/AGENTS.md +1 -1
  202. package/src/cli/commands/__tests__/attachment.test.ts +438 -0
  203. package/src/cli/commands/__tests__/browser.test.ts +554 -0
  204. package/src/cli/commands/__tests__/cache.test.ts +623 -0
  205. package/src/cli/commands/__tests__/email-list.test.ts +6 -0
  206. package/src/cli/commands/__tests__/email-send.test.ts +93 -1
  207. package/src/cli/commands/__tests__/image-generation.test.ts +666 -0
  208. package/src/cli/commands/__tests__/inference-send.test.ts +451 -0
  209. package/src/cli/commands/__tests__/stt-transcribe.test.ts +454 -0
  210. package/src/cli/commands/__tests__/task.test.ts +913 -0
  211. package/src/cli/commands/__tests__/tts-synthesize.test.ts +594 -0
  212. package/src/cli/commands/__tests__/ui-confirm.test.ts +650 -0
  213. package/src/cli/commands/__tests__/ui.test.ts +1215 -0
  214. package/src/cli/commands/__tests__/watchers.test.ts +716 -0
  215. package/src/cli/commands/attachment.ts +182 -0
  216. package/src/cli/commands/browser.ts +350 -0
  217. package/src/cli/commands/cache.ts +341 -0
  218. package/src/cli/commands/completions.ts +0 -3
  219. package/src/cli/commands/config.ts +6 -6
  220. package/src/cli/commands/conversations-import.ts +347 -0
  221. package/src/cli/commands/conversations.ts +14 -1
  222. package/src/cli/commands/email.ts +234 -194
  223. package/src/cli/commands/image-generation.ts +300 -0
  224. package/src/cli/commands/inference.ts +200 -0
  225. package/src/cli/commands/memory.ts +127 -17
  226. package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +0 -1
  227. package/src/cli/commands/platform/__tests__/connect.test.ts +0 -1
  228. package/src/cli/commands/platform/__tests__/disconnect.test.ts +0 -1
  229. package/src/cli/commands/platform/__tests__/status.test.ts +0 -1
  230. package/src/cli/commands/stt.ts +339 -0
  231. package/src/cli/commands/task.ts +795 -0
  232. package/src/cli/commands/trust.ts +50 -19
  233. package/src/cli/commands/tts.ts +273 -0
  234. package/src/cli/commands/ui.ts +670 -0
  235. package/src/cli/commands/watchers.ts +509 -0
  236. package/src/cli/lib/daemon-credential-client.ts +0 -19
  237. package/src/cli/program.ts +23 -4
  238. package/src/cli.ts +0 -37
  239. package/src/config/bundled-skills/conversations/tools/rename-conversation.ts +23 -1
  240. package/src/config/bundled-skills/media-processing/services/reduce.ts +1 -1
  241. package/src/config/bundled-skills/messaging/SKILL.md +2 -2
  242. package/src/config/bundled-skills/messaging/TOOLS.json +4 -0
  243. package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +8 -1
  244. package/src/config/bundled-skills/messaging/tools/messaging-read.ts +15 -1
  245. package/src/config/bundled-skills/messaging/tools/messaging-search.ts +21 -1
  246. package/src/config/bundled-skills/messaging/tools/messaging-send.ts +11 -12
  247. package/src/config/bundled-skills/phone-calls/references/CONFIG.md +9 -8
  248. package/src/config/bundled-skills/settings/TOOLS.json +3 -3
  249. package/src/config/bundled-tool-registry.ts +0 -175
  250. package/src/config/env.ts +7 -2
  251. package/src/config/feature-flag-registry.json +25 -9
  252. package/src/config/llm-resolver.ts +128 -0
  253. package/src/config/loader.ts +194 -10
  254. package/src/config/raw-config-utils.ts +30 -2
  255. package/src/config/sanitize-for-transfer.ts +35 -0
  256. package/src/config/schema.ts +30 -41
  257. package/src/config/schemas/analysis.ts +3 -22
  258. package/src/config/schemas/calls.ts +0 -4
  259. package/src/config/schemas/filing.ts +2 -7
  260. package/src/config/schemas/heartbeat.ts +0 -5
  261. package/src/config/schemas/inference.ts +3 -23
  262. package/src/config/schemas/llm.ts +318 -0
  263. package/src/config/schemas/memory-processing.ts +1 -9
  264. package/src/config/schemas/notifications.ts +4 -11
  265. package/src/config/schemas/platform.ts +3 -9
  266. package/src/config/schemas/security.ts +33 -0
  267. package/src/config/schemas/services.ts +9 -4
  268. package/src/config/schemas/stt.ts +1 -0
  269. package/src/config/schemas/tts.ts +53 -0
  270. package/src/config/schemas/updates.ts +1 -1
  271. package/src/config/schemas/workspace-git.ts +3 -40
  272. package/src/config/skills.ts +2 -2
  273. package/src/context/__tests__/compact-prompt.test.ts +45 -0
  274. package/src/context/__tests__/microcompact.test.ts +805 -0
  275. package/src/context/estimator-calibration.ts +136 -0
  276. package/src/context/microcompact.ts +443 -0
  277. package/src/context/prompts/compact.md +12 -0
  278. package/src/context/token-estimator.ts +61 -3
  279. package/src/context/window-manager.ts +229 -25
  280. package/src/credential-execution/approval-bridge.ts +0 -1
  281. package/src/credential-execution/executable-discovery.ts +19 -8
  282. package/src/credential-execution/process-manager.test.ts +109 -0
  283. package/src/credential-execution/process-manager.ts +65 -2
  284. package/src/daemon/approval-generators.ts +29 -4
  285. package/src/daemon/assistant-attachments.ts +24 -13
  286. package/src/daemon/classifier.ts +2 -2
  287. package/src/daemon/config-watcher.ts +0 -1
  288. package/src/daemon/context-overflow-reducer.ts +4 -1
  289. package/src/daemon/conversation-agent-loop-handlers.ts +79 -12
  290. package/src/daemon/conversation-agent-loop.ts +462 -80
  291. package/src/daemon/conversation-attachments.ts +2 -6
  292. package/src/daemon/conversation-error.ts +36 -1
  293. package/src/daemon/conversation-lifecycle.ts +30 -6
  294. package/src/daemon/conversation-messaging.ts +73 -4
  295. package/src/daemon/conversation-process.ts +10 -4
  296. package/src/daemon/conversation-queue-manager.ts +3 -0
  297. package/src/daemon/conversation-runtime-assembly.ts +760 -29
  298. package/src/daemon/conversation-slash.ts +2 -2
  299. package/src/daemon/conversation-surfaces.ts +389 -1
  300. package/src/daemon/conversation-tool-setup.ts +10 -5
  301. package/src/daemon/conversation-usage.ts +1 -1
  302. package/src/daemon/conversation.ts +118 -30
  303. package/src/daemon/external-skills-bootstrap.ts +41 -0
  304. package/src/daemon/guardian-action-generators.ts +34 -14
  305. package/src/daemon/handlers/config-model.test.ts +86 -0
  306. package/src/daemon/handlers/config-model.ts +54 -12
  307. package/src/daemon/handlers/conversations.ts +9 -2
  308. package/src/daemon/handlers/shared.ts +39 -11
  309. package/src/daemon/handlers/skills.ts +2 -2
  310. package/src/daemon/handlers/slack-channel-oauth-install.ts +197 -0
  311. package/src/daemon/lifecycle.ts +76 -14
  312. package/src/daemon/message-types/conversations.ts +14 -0
  313. package/src/daemon/message-types/messages.ts +9 -1
  314. package/src/daemon/message-types/trust.ts +0 -2
  315. package/src/daemon/parse-actual-tokens-from-error.test.ts +57 -1
  316. package/src/daemon/parse-actual-tokens-from-error.ts +66 -0
  317. package/src/daemon/pkb-context-tracker.test.ts +169 -0
  318. package/src/daemon/pkb-context-tracker.ts +125 -0
  319. package/src/daemon/pkb-reminder-builder.test.ts +70 -0
  320. package/src/daemon/pkb-reminder-builder.ts +31 -0
  321. package/src/daemon/providers-setup.ts +6 -0
  322. package/src/daemon/server.ts +117 -9
  323. package/src/daemon/tool-side-effects.ts +0 -9
  324. package/src/daemon/watch-handler.ts +4 -4
  325. package/src/daemon/web-search-history.ts +126 -0
  326. package/src/events/domain-events.ts +0 -1
  327. package/src/filing/filing-service.ts +9 -10
  328. package/src/heartbeat/heartbeat-service.ts +76 -28
  329. package/src/home/__tests__/feed-scheduler.test.ts +39 -11
  330. package/src/home/__tests__/rollup-producer.test.ts +44 -0
  331. package/src/home/assistant-feed-authoring.ts +4 -0
  332. package/src/home/emit-feed-event.ts +4 -0
  333. package/src/home/feed-scheduler.ts +20 -4
  334. package/src/home/feed-types.ts +56 -2
  335. package/src/home/relationship-state-writer.ts +2 -2
  336. package/src/home/rollup-producer.ts +34 -5
  337. package/src/home/suggested-prompts.ts +101 -0
  338. package/src/ipc/__tests__/attachment-ipc.test.ts +213 -0
  339. package/src/ipc/__tests__/browser-ipc.test.ts +339 -0
  340. package/src/ipc/__tests__/cache-ipc.test.ts +266 -0
  341. package/src/ipc/__tests__/socket-path.test.ts +73 -0
  342. package/src/ipc/__tests__/task-ipc.test.ts +577 -0
  343. package/src/ipc/__tests__/ui-request-route.test.ts +495 -0
  344. package/src/ipc/__tests__/watcher-ipc.test.ts +295 -0
  345. package/src/ipc/cli-client.ts +2 -1
  346. package/src/ipc/cli-server.ts +26 -8
  347. package/src/ipc/gateway-client.ts +4 -4
  348. package/src/ipc/routes/attachment.ts +114 -0
  349. package/src/ipc/routes/browser-context.ts +61 -0
  350. package/src/ipc/routes/browser.ts +96 -0
  351. package/src/ipc/routes/cache.ts +96 -0
  352. package/src/ipc/routes/index.ts +17 -1
  353. package/src/ipc/routes/task-queue.ts +226 -0
  354. package/src/ipc/routes/task.ts +173 -0
  355. package/src/ipc/routes/ui-request.ts +50 -0
  356. package/src/ipc/routes/watcher.ts +203 -0
  357. package/src/ipc/socket-path.ts +100 -0
  358. package/src/memory/__tests__/conversation-analyze-job.test.ts +9 -8
  359. package/src/memory/__tests__/conversation-group-migration.test.ts +99 -0
  360. package/src/memory/admin.ts +18 -0
  361. package/src/memory/conversation-analyze-job.ts +14 -13
  362. package/src/memory/conversation-attention-store.ts +13 -6
  363. package/src/memory/conversation-crud.ts +103 -3
  364. package/src/memory/conversation-group-migration.ts +38 -6
  365. package/src/memory/conversation-title-service.ts +7 -4
  366. package/src/memory/db-init.ts +2 -0
  367. package/src/memory/embedding-backend.ts +1 -1
  368. package/src/memory/graph/compaction.ts +299 -0
  369. package/src/memory/graph/consolidation.ts +4 -4
  370. package/src/memory/graph/conversation-graph-memory.ts +89 -29
  371. package/src/memory/graph/extraction.test.ts +272 -2
  372. package/src/memory/graph/extraction.ts +173 -51
  373. package/src/memory/graph/graph-search.test.ts +92 -0
  374. package/src/memory/graph/graph-search.ts +4 -1
  375. package/src/memory/graph/narrative.ts +2 -2
  376. package/src/memory/graph/pattern-scan.ts +2 -2
  377. package/src/memory/graph/retriever.test.ts +459 -0
  378. package/src/memory/graph/retriever.ts +230 -48
  379. package/src/memory/graph/store.ts +41 -0
  380. package/src/memory/graph/tool-handlers.ts +27 -0
  381. package/src/memory/graph/tools.ts +6 -1
  382. package/src/memory/indexer.ts +5 -5
  383. package/src/memory/job-handlers/conversation-starters.ts +23 -20
  384. package/src/memory/job-handlers/summarization.ts +2 -2
  385. package/src/memory/job-utils.ts +7 -1
  386. package/src/memory/jobs/embed-pkb-file.test.ts +168 -0
  387. package/src/memory/jobs/embed-pkb-file.ts +54 -0
  388. package/src/memory/jobs-store.ts +44 -3
  389. package/src/memory/jobs-worker.ts +4 -0
  390. package/src/memory/migrations/140-backfill-usage-cache-accounting.ts +1 -1
  391. package/src/memory/migrations/220-normalize-user-file-by-principal.ts +2 -2
  392. package/src/memory/migrations/222-strip-placeholder-sentinels-from-messages.ts +82 -0
  393. package/src/memory/migrations/index.ts +1 -0
  394. package/src/memory/pkb/pkb-index.test.ts +368 -0
  395. package/src/memory/pkb/pkb-index.ts +255 -0
  396. package/src/memory/pkb/pkb-reconcile.test.ts +251 -0
  397. package/src/memory/pkb/pkb-reconcile.ts +148 -0
  398. package/src/memory/pkb/pkb-search.test.ts +438 -0
  399. package/src/memory/pkb/pkb-search.ts +137 -0
  400. package/src/memory/pkb/types.ts +53 -0
  401. package/src/memory/qdrant-client.ts +122 -1
  402. package/src/memory/slack-thread-store.ts +37 -0
  403. package/src/messaging/providers/gmail/adapter.ts +6 -16
  404. package/src/messaging/providers/gmail/client.ts +22 -0
  405. package/src/messaging/providers/gmail/types.ts +7 -0
  406. package/src/messaging/providers/slack/adapter.ts +14 -2
  407. package/src/messaging/providers/slack/backfill.test.ts +257 -0
  408. package/src/messaging/providers/slack/backfill.ts +101 -0
  409. package/src/messaging/providers/slack/message-metadata.test.ts +316 -0
  410. package/src/messaging/providers/slack/message-metadata.ts +123 -0
  411. package/src/messaging/providers/slack/render-transcript.test.ts +1373 -0
  412. package/src/messaging/providers/slack/render-transcript.ts +443 -0
  413. package/src/messaging/style-analyzer.ts +5 -2
  414. package/src/notifications/README.md +9 -5
  415. package/src/notifications/decision-engine.ts +3 -9
  416. package/src/notifications/preference-extractor.ts +2 -6
  417. package/src/oauth/oauth-store.ts +1 -0
  418. package/src/oauth/platform-connection.test.ts +47 -0
  419. package/src/oauth/platform-connection.ts +15 -5
  420. package/src/oauth/seed-providers.ts +4 -2
  421. package/src/permissions/approval-policy.test.ts +948 -0
  422. package/src/permissions/approval-policy.ts +257 -0
  423. package/src/permissions/bash-risk-classifier.test.ts +1208 -0
  424. package/src/permissions/bash-risk-classifier.ts +707 -0
  425. package/src/permissions/checker.ts +217 -708
  426. package/src/permissions/command-registry.test.ts +535 -0
  427. package/src/permissions/command-registry.ts +825 -0
  428. package/src/permissions/defaults.ts +26 -78
  429. package/src/permissions/file-risk-classifier.test.ts +535 -0
  430. package/src/permissions/file-risk-classifier.ts +274 -0
  431. package/src/permissions/risk-types.ts +205 -0
  432. package/src/permissions/secret-prompter.ts +53 -2
  433. package/src/permissions/skill-risk-classifier.test.ts +311 -0
  434. package/src/permissions/skill-risk-classifier.ts +214 -0
  435. package/src/permissions/trust-client.ts +52 -25
  436. package/src/permissions/trust-store-interface.ts +1 -6
  437. package/src/permissions/trust-store.ts +161 -62
  438. package/src/permissions/types.ts +23 -14
  439. package/src/permissions/web-risk-classifier.test.ts +170 -0
  440. package/src/permissions/web-risk-classifier.ts +89 -0
  441. package/src/permissions/workspace-policy.ts +1 -16
  442. package/src/platform/client.ts +19 -1
  443. package/src/prompts/persona-resolver.ts +3 -3
  444. package/src/prompts/system-prompt.ts +19 -20
  445. package/src/prompts/templates/SOUL.md +2 -2
  446. package/src/prompts/update-bulletin-job.ts +190 -0
  447. package/src/providers/__tests__/context-overflow-error.test.ts +328 -0
  448. package/src/providers/__tests__/provider-env-vars.test.ts +102 -0
  449. package/src/providers/__tests__/retry-callsite.test.ts +424 -0
  450. package/src/providers/anthropic/client.ts +183 -14
  451. package/src/providers/call-site-routing.ts +71 -0
  452. package/src/providers/gemini/client.ts +65 -2
  453. package/src/providers/managed-proxy/constants.ts +2 -1
  454. package/src/providers/model-catalog.ts +501 -33
  455. package/src/providers/model-intents.ts +4 -4
  456. package/src/providers/openai/chat-completions-provider.ts +57 -1
  457. package/src/providers/openai/responses-provider.ts +86 -9
  458. package/src/providers/openrouter/client.ts +76 -9
  459. package/src/providers/provider-env-vars.ts +56 -0
  460. package/src/providers/provider-send-message.ts +22 -5
  461. package/src/providers/ratelimit.ts +4 -0
  462. package/src/providers/registry.ts +19 -8
  463. package/src/providers/retry.ts +174 -39
  464. package/src/providers/speech-to-text/__tests__/resolve.test.ts +55 -0
  465. package/src/providers/speech-to-text/google-gemini-live-stream.ts +4 -4
  466. package/src/providers/speech-to-text/provider-catalog.ts +17 -0
  467. package/src/providers/speech-to-text/resolve.ts +7 -0
  468. package/src/providers/speech-to-text/xai-realtime.test.ts +578 -0
  469. package/src/providers/speech-to-text/xai-realtime.ts +796 -0
  470. package/src/providers/speech-to-text/xai.test.ts +155 -0
  471. package/src/providers/speech-to-text/xai.ts +97 -0
  472. package/src/providers/types.ts +93 -3
  473. package/src/runtime/AGENTS.md +2 -2
  474. package/src/runtime/__tests__/agent-wake.test.ts +43 -2
  475. package/src/runtime/__tests__/interactive-ui.test.ts +673 -0
  476. package/src/runtime/agent-wake.ts +63 -22
  477. package/src/runtime/auth/route-policy.ts +4 -0
  478. package/src/runtime/btw-sidechain.ts +13 -3
  479. package/src/runtime/channel-reply-delivery.ts +106 -2
  480. package/src/runtime/decision-token.ts +116 -0
  481. package/src/runtime/gateway-client.ts +2 -2
  482. package/src/runtime/http-router.ts +32 -0
  483. package/src/runtime/http-server.ts +52 -1
  484. package/src/runtime/http-types.ts +23 -1
  485. package/src/runtime/interactive-ui.ts +362 -0
  486. package/src/runtime/invite-instruction-generator.ts +2 -2
  487. package/src/runtime/migrations/__tests__/gcs-signed-url.test.ts +176 -0
  488. package/src/runtime/migrations/__tests__/vbundle-metadata-merge-integration.test.ts +390 -0
  489. package/src/runtime/migrations/__tests__/vbundle-metadata-merge.test.ts +221 -0
  490. package/src/runtime/migrations/__tests__/vbundle-streaming-importer.test.ts +1540 -0
  491. package/src/runtime/migrations/__tests__/vbundle-streaming-validator.test.ts +453 -0
  492. package/src/runtime/migrations/__tests__/vbundle-tar-stream.test.ts +222 -0
  493. package/src/runtime/migrations/gcs-signed-url.ts +162 -0
  494. package/src/runtime/migrations/vbundle-importer.ts +154 -9
  495. package/src/runtime/migrations/vbundle-metadata-merge.ts +124 -0
  496. package/src/runtime/migrations/vbundle-streaming-importer.ts +2522 -0
  497. package/src/runtime/migrations/vbundle-streaming-validator.ts +244 -0
  498. package/src/runtime/migrations/vbundle-tar-stream.ts +217 -0
  499. package/src/runtime/migrations/vbundle-validator.ts +15 -6
  500. package/src/runtime/routes/__tests__/home-feed-routes.test.ts +111 -0
  501. package/src/runtime/routes/__tests__/migration-import-credential-filter.test.ts +114 -75
  502. package/src/runtime/routes/__tests__/migration-vellum-metadata-reconcile.test.ts +246 -0
  503. package/src/runtime/routes/approval-prompt-ts-tracker.ts +58 -0
  504. package/src/runtime/routes/approval-routes.ts +12 -17
  505. package/src/runtime/routes/approval-strategies/guardian-callback-strategy.ts +9 -0
  506. package/src/runtime/routes/avatar-routes.ts +20 -4
  507. package/src/runtime/routes/btw-routes.ts +1 -4
  508. package/src/runtime/routes/conversation-management-routes.ts +20 -2
  509. package/src/runtime/routes/conversation-routes.ts +133 -27
  510. package/src/runtime/routes/debug-routes.ts +1 -1
  511. package/src/runtime/routes/diagnostics-routes.ts +6 -4
  512. package/src/runtime/routes/events-routes.ts +16 -0
  513. package/src/runtime/routes/guardian-approval-interception.ts +33 -3
  514. package/src/runtime/routes/guardian-approval-prompt.ts +13 -3
  515. package/src/runtime/routes/home-feed-routes.ts +120 -2
  516. package/src/runtime/routes/inbound-message-handler.ts +912 -2
  517. package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +113 -2
  518. package/src/runtime/routes/inbound-stages/background-dispatch.ts +61 -3
  519. package/src/runtime/routes/inbound-stages/edit-intercept.ts +129 -6
  520. package/src/runtime/routes/integrations/slack/channel.ts +25 -3
  521. package/src/runtime/routes/llm-context-normalization.ts +23 -1
  522. package/src/runtime/routes/migration-routes.ts +720 -124
  523. package/src/runtime/routes/settings-routes.ts +4 -2
  524. package/src/runtime/routes/trust-rules-routes.ts +30 -14
  525. package/src/runtime/routes/work-items-routes.test.ts +1 -1
  526. package/src/runtime/routes/work-items-routes.ts +3 -2
  527. package/src/runtime/services/__tests__/analyze-conversation.test.ts +25 -43
  528. package/src/runtime/services/analyze-conversation.ts +12 -16
  529. package/src/runtime/skill-route-registry.ts +28 -6
  530. package/src/schedule/scheduler.ts +8 -0
  531. package/src/security/__tests__/provider-key-env-fallback.test.ts +119 -0
  532. package/src/security/__tests__/untrusted-content.test.ts +109 -0
  533. package/src/security/oauth2.ts +98 -35
  534. package/src/security/secure-keys.ts +7 -8
  535. package/src/security/token-manager.ts +27 -13
  536. package/src/security/untrusted-content.ts +102 -0
  537. package/src/skills/catalog-cache.ts +26 -7
  538. package/src/skills/catalog-install.ts +31 -3
  539. package/src/skills/skill-cache-store.ts +97 -0
  540. package/src/stt/__tests__/daemon-batch-transcriber.test.ts +76 -0
  541. package/src/stt/daemon-batch-transcriber.ts +33 -0
  542. package/src/stt/stt-stream-session.ts +8 -1
  543. package/src/stt/types.ts +5 -1
  544. package/src/subagent/manager.ts +41 -13
  545. package/src/tasks/ephemeral-permissions.ts +9 -4
  546. package/src/telemetry/usage-telemetry-reporter.ts +27 -5
  547. package/src/tools/browser/__tests__/browser-status.test.ts +45 -2
  548. package/src/tools/browser/browser-execution.ts +65 -38
  549. package/src/tools/browser/cdp-client/cdp-inspect/discovery.ts +22 -0
  550. package/src/tools/credentials/tool-policy.ts +39 -5
  551. package/src/tools/credentials/vault.ts +9 -4
  552. package/src/tools/executor.ts +4 -0
  553. package/src/tools/filesystem/write.ts +52 -0
  554. package/src/tools/host-terminal/host-shell.ts +45 -5
  555. package/src/tools/memory/register.test.ts +185 -0
  556. package/src/tools/memory/register.ts +3 -1
  557. package/src/tools/network/web-fetch.ts +20 -10
  558. package/src/tools/network/web-search.ts +19 -4
  559. package/src/tools/permission-checker.ts +36 -15
  560. package/src/tools/policy-context.ts +25 -8
  561. package/src/tools/registry.ts +55 -3
  562. package/src/tools/side-effects.ts +0 -11
  563. package/src/tools/skills/execute.ts +2 -2
  564. package/src/tools/skills/sandbox-runner.ts +5 -2
  565. package/src/tools/terminal/backends/native.ts +51 -2
  566. package/src/tools/terminal/safe-env.ts +3 -2
  567. package/src/tools/terminal/shell.ts +1 -0
  568. package/src/tools/tool-manifest.ts +6 -21
  569. package/src/tools/types.ts +12 -3
  570. package/src/tools/verification-control-plane-policy.ts +1 -1
  571. package/src/tts/__tests__/provider-adapters.test.ts +240 -13
  572. package/src/tts/provider-catalog.ts +18 -0
  573. package/src/tts/providers/index.ts +2 -0
  574. package/src/tts/providers/xai-provider.ts +224 -0
  575. package/src/tts/types.ts +46 -0
  576. package/src/types/tar-stream.d.ts +66 -0
  577. package/src/util/json.ts +17 -0
  578. package/src/util/platform.ts +2 -2
  579. package/src/util/pricing.ts +15 -5
  580. package/src/watcher/engine.ts +1 -1
  581. package/src/watcher/providers/google-calendar.ts +134 -8
  582. package/src/watcher/providers/outlook-calendar.ts +42 -2
  583. package/src/workspace/git-service.ts +23 -4
  584. package/src/workspace/migrations/038-unify-llm-callsite-configs.ts +516 -0
  585. package/src/workspace/migrations/039-drop-legacy-llm-keys.ts +171 -0
  586. package/src/workspace/migrations/040-seed-latency-callsite-defaults.ts +154 -0
  587. package/src/workspace/migrations/041-backfill-google-gmail-settings-scope.ts +57 -0
  588. package/src/workspace/migrations/042-fix-backfill-google-gmail-settings-scope.ts +70 -0
  589. package/src/workspace/migrations/043-release-notes-latex-rendering.ts +75 -0
  590. package/src/workspace/migrations/044-bump-stale-provider-stream-timeout.ts +51 -0
  591. package/src/workspace/migrations/045-release-notes-meet-avatar.ts +130 -0
  592. package/src/workspace/migrations/AGENTS.md +1 -1
  593. package/src/workspace/migrations/registry.ts +16 -0
  594. package/src/workspace/provider-commit-message-generator.ts +19 -38
  595. package/src/__tests__/gmail-archive-fallback.test.ts +0 -193
  596. package/src/__tests__/gmail-archive-gate.test.ts +0 -246
  597. package/src/__tests__/gmail-preferences.test.ts +0 -117
  598. package/src/__tests__/outlook-attachments.test.ts +0 -301
  599. package/src/__tests__/outlook-automation-tools.test.ts +0 -425
  600. package/src/__tests__/outlook-categories.test.ts +0 -212
  601. package/src/__tests__/outlook-compose-tools.test.ts +0 -325
  602. package/src/__tests__/outlook-declutter-tools.test.ts +0 -585
  603. package/src/__tests__/outlook-follow-up.test.ts +0 -196
  604. package/src/__tests__/outlook-trash.test.ts +0 -77
  605. package/src/__tests__/outlook-unsubscribe.test.ts +0 -279
  606. package/src/__tests__/update-bulletin-format.test.ts +0 -181
  607. package/src/__tests__/update-bulletin-state.test.ts +0 -135
  608. package/src/__tests__/update-bulletin.test.ts +0 -478
  609. package/src/__tests__/update-template-contract.test.ts +0 -29
  610. package/src/cli/commands/doctor.ts +0 -341
  611. package/src/config/bundled-skills/browser/SKILL.md +0 -88
  612. package/src/config/bundled-skills/browser/TOOLS.json +0 -516
  613. package/src/config/bundled-skills/browser/tools/browser-attach.ts +0 -12
  614. package/src/config/bundled-skills/browser/tools/browser-click.ts +0 -12
  615. package/src/config/bundled-skills/browser/tools/browser-close.ts +0 -12
  616. package/src/config/bundled-skills/browser/tools/browser-detach.ts +0 -12
  617. package/src/config/bundled-skills/browser/tools/browser-extract.ts +0 -12
  618. package/src/config/bundled-skills/browser/tools/browser-fill-credential.ts +0 -12
  619. package/src/config/bundled-skills/browser/tools/browser-hover.ts +0 -12
  620. package/src/config/bundled-skills/browser/tools/browser-navigate.ts +0 -12
  621. package/src/config/bundled-skills/browser/tools/browser-press-key.ts +0 -12
  622. package/src/config/bundled-skills/browser/tools/browser-screenshot.ts +0 -12
  623. package/src/config/bundled-skills/browser/tools/browser-scroll.ts +0 -12
  624. package/src/config/bundled-skills/browser/tools/browser-select-option.ts +0 -12
  625. package/src/config/bundled-skills/browser/tools/browser-snapshot.ts +0 -12
  626. package/src/config/bundled-skills/browser/tools/browser-status.ts +0 -12
  627. package/src/config/bundled-skills/browser/tools/browser-type.ts +0 -12
  628. package/src/config/bundled-skills/browser/tools/browser-wait-for-download.ts +0 -49
  629. package/src/config/bundled-skills/browser/tools/browser-wait-for.ts +0 -12
  630. package/src/config/bundled-skills/chatgpt-import/SKILL.md +0 -27
  631. package/src/config/bundled-skills/chatgpt-import/TOOLS.json +0 -27
  632. package/src/config/bundled-skills/chatgpt-import/tools/chatgpt-import.ts +0 -378
  633. package/src/config/bundled-skills/gmail/SKILL.md +0 -221
  634. package/src/config/bundled-skills/gmail/TOOLS.json +0 -588
  635. package/src/config/bundled-skills/gmail/tools/gmail-archive.ts +0 -256
  636. package/src/config/bundled-skills/gmail/tools/gmail-attachments.ts +0 -112
  637. package/src/config/bundled-skills/gmail/tools/gmail-draft.ts +0 -44
  638. package/src/config/bundled-skills/gmail/tools/gmail-filters.ts +0 -81
  639. package/src/config/bundled-skills/gmail/tools/gmail-follow-up.ts +0 -108
  640. package/src/config/bundled-skills/gmail/tools/gmail-forward.ts +0 -146
  641. package/src/config/bundled-skills/gmail/tools/gmail-label.ts +0 -53
  642. package/src/config/bundled-skills/gmail/tools/gmail-outreach-scan.ts +0 -347
  643. package/src/config/bundled-skills/gmail/tools/gmail-preferences-tool.ts +0 -59
  644. package/src/config/bundled-skills/gmail/tools/gmail-preferences.ts +0 -82
  645. package/src/config/bundled-skills/gmail/tools/gmail-send-draft.ts +0 -26
  646. package/src/config/bundled-skills/gmail/tools/gmail-sender-digest.ts +0 -347
  647. package/src/config/bundled-skills/gmail/tools/gmail-trash.ts +0 -29
  648. package/src/config/bundled-skills/gmail/tools/gmail-unsubscribe.ts +0 -122
  649. package/src/config/bundled-skills/gmail/tools/gmail-vacation.ts +0 -67
  650. package/src/config/bundled-skills/gmail/tools/scan-result-store.ts +0 -100
  651. package/src/config/bundled-skills/gmail/tools/shared.ts +0 -47
  652. package/src/config/bundled-skills/google-calendar/SKILL.md +0 -51
  653. package/src/config/bundled-skills/google-calendar/TOOLS.json +0 -226
  654. package/src/config/bundled-skills/google-calendar/calendar-client.ts +0 -223
  655. package/src/config/bundled-skills/google-calendar/tools/calendar-check-availability.ts +0 -27
  656. package/src/config/bundled-skills/google-calendar/tools/calendar-create-event.ts +0 -48
  657. package/src/config/bundled-skills/google-calendar/tools/calendar-get-event.ts +0 -19
  658. package/src/config/bundled-skills/google-calendar/tools/calendar-list-events.ts +0 -36
  659. package/src/config/bundled-skills/google-calendar/tools/calendar-rsvp.ts +0 -58
  660. package/src/config/bundled-skills/google-calendar/tools/shared.ts +0 -17
  661. package/src/config/bundled-skills/google-calendar/types.ts +0 -97
  662. package/src/config/bundled-skills/outlook/SKILL.md +0 -196
  663. package/src/config/bundled-skills/outlook/TOOLS.json +0 -530
  664. package/src/config/bundled-skills/outlook/tools/outlook-attachments.ts +0 -85
  665. package/src/config/bundled-skills/outlook/tools/outlook-categories.ts +0 -77
  666. package/src/config/bundled-skills/outlook/tools/outlook-draft.ts +0 -84
  667. package/src/config/bundled-skills/outlook/tools/outlook-follow-up.ts +0 -94
  668. package/src/config/bundled-skills/outlook/tools/outlook-forward.ts +0 -49
  669. package/src/config/bundled-skills/outlook/tools/outlook-outreach-scan.ts +0 -237
  670. package/src/config/bundled-skills/outlook/tools/outlook-rules.ts +0 -161
  671. package/src/config/bundled-skills/outlook/tools/outlook-send-draft.ts +0 -32
  672. package/src/config/bundled-skills/outlook/tools/outlook-sender-digest.ts +0 -272
  673. package/src/config/bundled-skills/outlook/tools/outlook-trash.ts +0 -29
  674. package/src/config/bundled-skills/outlook/tools/outlook-unsubscribe.ts +0 -129
  675. package/src/config/bundled-skills/outlook/tools/outlook-vacation.ts +0 -87
  676. package/src/config/bundled-skills/outlook/tools/shared.ts +0 -20
  677. package/src/config/bundled-skills/outlook-calendar/SKILL.md +0 -51
  678. package/src/config/bundled-skills/outlook-calendar/TOOLS.json +0 -221
  679. package/src/config/bundled-skills/outlook-calendar/calendar-client.ts +0 -252
  680. package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-check-availability.ts +0 -53
  681. package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-create-event.ts +0 -74
  682. package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-get-event.ts +0 -18
  683. package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-list-events.ts +0 -46
  684. package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-rsvp.ts +0 -36
  685. package/src/config/bundled-skills/outlook-calendar/tools/shared.ts +0 -17
  686. package/src/config/bundled-skills/outlook-calendar/types.ts +0 -120
  687. package/src/config/bundled-skills/slack/SKILL.md +0 -108
  688. package/src/config/bundled-skills/tasks/SKILL.md +0 -37
  689. package/src/config/bundled-skills/tasks/TOOLS.json +0 -353
  690. package/src/config/bundled-skills/tasks/icon.svg +0 -34
  691. package/src/config/bundled-skills/tasks/tools/task-delete.ts +0 -12
  692. package/src/config/bundled-skills/tasks/tools/task-list-add.ts +0 -12
  693. package/src/config/bundled-skills/tasks/tools/task-list-remove.ts +0 -12
  694. package/src/config/bundled-skills/tasks/tools/task-list-show.ts +0 -12
  695. package/src/config/bundled-skills/tasks/tools/task-list-update.ts +0 -12
  696. package/src/config/bundled-skills/tasks/tools/task-list.ts +0 -12
  697. package/src/config/bundled-skills/tasks/tools/task-queue-run.ts +0 -12
  698. package/src/config/bundled-skills/tasks/tools/task-run.ts +0 -12
  699. package/src/config/bundled-skills/tasks/tools/task-save.ts +0 -12
  700. package/src/config/bundled-skills/watcher/SKILL.md +0 -31
  701. package/src/config/bundled-skills/watcher/TOOLS.json +0 -167
  702. package/src/config/bundled-skills/watcher/tools/watcher-create.ts +0 -12
  703. package/src/config/bundled-skills/watcher/tools/watcher-delete.ts +0 -12
  704. package/src/config/bundled-skills/watcher/tools/watcher-digest.ts +0 -12
  705. package/src/config/bundled-skills/watcher/tools/watcher-list.ts +0 -12
  706. package/src/config/bundled-skills/watcher/tools/watcher-update.ts +0 -12
  707. package/src/prompts/templates/UPDATES.md +0 -50
  708. package/src/prompts/update-bulletin-format.ts +0 -85
  709. package/src/prompts/update-bulletin-state.ts +0 -58
  710. package/src/prompts/update-bulletin-template-path.ts +0 -13
  711. package/src/prompts/update-bulletin.ts +0 -139
  712. package/src/shared/provider-env-vars.ts +0 -19
  713. package/src/tools/watcher/create.ts +0 -86
  714. package/src/tools/watcher/delete.ts +0 -36
  715. package/src/tools/watcher/digest.ts +0 -54
  716. package/src/tools/watcher/list.ts +0 -83
  717. package/src/tools/watcher/update.ts +0 -71
@@ -1,22 +1,32 @@
1
1
  /**
2
2
  * Tests for platform credential filtering during bundle import.
3
3
  *
4
- * The filtering logic in migration-routes.ts uses the PLATFORM_CREDENTIAL_PREFIX
5
- * constant ("vellum:") to exclude platform-identity credentials from being
6
- * written to the credential store during import. Since the filtering is a simple
7
- * array filter, we test the logic directly using the same prefix constant and
8
- * extractCredentialsFromBundle function without needing to drive the full
9
- * HTTP handler (which has heavy transitive dependencies).
4
+ * `migration-routes.ts` pushes every bundle credential through a filter that
5
+ * must exclude platform-identity (`vellum:*`) entries so they can't overwrite
6
+ * the target's own Django-provisioned identity. The filter runs against the
7
+ * raw CES account format `credential/{service}/{field}` produced by
8
+ * `credentialKey()`, which is what `listSecureKeysAsync()` returns and what
9
+ * `extractCredentialsFromBundle` surfaces back as `account`.
10
10
  *
11
- * Covers:
12
- * - vellum:* credentials are excluded when filtering with the prefix
13
- * - User credentials (without vellum: prefix) pass through unchanged
14
- * - Mixed bundles correctly split platform vs user credentials
15
- * - skippedPlatform count is accurate
11
+ * The constant is duplicated here (rather than imported) because
12
+ * `migration-routes.ts` has heavy transitive imports that are expensive to
13
+ * resolve in a test and would require wide mocking. Instead we bind the two
14
+ * copies with a regression assertion: if `credentialKey()`'s output format
15
+ * changes, the `startsWith(...)` prefix must change in lockstep. That
16
+ * regression is explicit at the bottom of this file.
17
+ *
18
+ * Covered:
19
+ * - Platform (vellum:*) credentials stored under the real `credential/vellum/...`
20
+ * key format are excluded.
21
+ * - User credentials (any other prefix) pass through unchanged.
22
+ * - Mixed bundles correctly split platform vs user credentials.
23
+ * - skippedPlatform count matches the number of excluded entries.
24
+ * - Regression: the prefix constant matches `credentialKey("vellum", "")`.
16
25
  */
17
26
 
18
27
  import { describe, expect, test } from "bun:test";
19
28
 
29
+ import { credentialKey } from "../../../security/credential-key.js";
20
30
  import { extractCredentialsFromBundle } from "../../migrations/vbundle-importer.js";
21
31
  import type {
22
32
  ManifestType,
@@ -24,10 +34,11 @@ import type {
24
34
  } from "../../migrations/vbundle-validator.js";
25
35
 
26
36
  // ---------------------------------------------------------------------------
27
- // The same constant used by migration-routes.ts
37
+ // The same constant used by migration-routes.ts — kept in sync via the
38
+ // regression assertion at the bottom of this file.
28
39
  // ---------------------------------------------------------------------------
29
40
 
30
- const PLATFORM_CREDENTIAL_PREFIX = "vellum:";
41
+ const PLATFORM_CREDENTIAL_PREFIX = credentialKey("vellum", "");
31
42
 
32
43
  // ---------------------------------------------------------------------------
33
44
  // Helpers (same pattern as vbundle-import-credentials.test.ts)
@@ -52,6 +63,15 @@ function makeManifest(paths: string[]): ManifestType {
52
63
  } as ManifestType;
53
64
  }
54
65
 
66
+ /**
67
+ * Build a bundle archive entry path for a credential whose CES account is
68
+ * `account`. `vbundle-builder.ts` stores credentials under
69
+ * `credentials/<account>`; the importer reverses that split.
70
+ */
71
+ function bundlePathFor(account: string): string {
72
+ return `credentials/${account}`;
73
+ }
74
+
55
75
  /**
56
76
  * Simulate the filtering logic from migration-routes.ts:
57
77
  *
@@ -74,49 +94,45 @@ function filterCredentials(
74
94
  // ---------------------------------------------------------------------------
75
95
 
76
96
  describe("migration import credential filtering", () => {
77
- test("vellum:-prefixed credentials are excluded", () => {
78
- const entries = new Map<string, VBundleTarEntry>();
79
- entries.set("credentials/vellum:assistant_api_key", makeTarEntry("key-1"));
80
- entries.set(
81
- "credentials/vellum:platform_assistant_id",
82
- makeTarEntry("asst-2"),
83
- );
84
- entries.set(
85
- "credentials/vellum:platform_base_url",
86
- makeTarEntry("https://example.com"),
87
- );
88
- entries.set(
89
- "credentials/vellum:platform_organization_id",
90
- makeTarEntry("org-3"),
97
+ test("platform (vellum:*) credentials are excluded", () => {
98
+ const vellumFields = [
99
+ "assistant_api_key",
100
+ "platform_assistant_id",
101
+ "platform_base_url",
102
+ "platform_organization_id",
103
+ "platform_user_id",
104
+ "webhook_secret",
105
+ ] as const;
106
+ const vellumPaths = vellumFields.map((f) =>
107
+ bundlePathFor(credentialKey("vellum", f)),
91
108
  );
92
- entries.set("credentials/vellum:platform_user_id", makeTarEntry("user-4"));
93
- entries.set("credentials/vellum:webhook_secret", makeTarEntry("whsec-5"));
94
109
 
95
- const manifest = makeManifest([
96
- "credentials/vellum:assistant_api_key",
97
- "credentials/vellum:platform_assistant_id",
98
- "credentials/vellum:platform_base_url",
99
- "credentials/vellum:platform_organization_id",
100
- "credentials/vellum:platform_user_id",
101
- "credentials/vellum:webhook_secret",
102
- ]);
110
+ const entries = new Map<string, VBundleTarEntry>();
111
+ for (const path of vellumPaths) {
112
+ entries.set(path, makeTarEntry(`value-for-${path}`));
113
+ }
114
+
115
+ const manifest = makeManifest(vellumPaths);
103
116
 
104
117
  const bundleCredentials = extractCredentialsFromBundle(entries, manifest);
105
118
  const { userCredentials, skippedPlatform } =
106
119
  filterCredentials(bundleCredentials);
107
120
 
108
121
  expect(userCredentials).toHaveLength(0);
109
- expect(skippedPlatform).toBe(6);
122
+ expect(skippedPlatform).toBe(vellumFields.length);
110
123
  });
111
124
 
112
- test("user credentials without vellum: prefix pass through unchanged", () => {
125
+ test("user credentials pass through unchanged", () => {
126
+ const openaiAccount = credentialKey("openai", "api_key");
127
+ const anthropicAccount = credentialKey("anthropic", "api_key");
128
+
113
129
  const entries = new Map<string, VBundleTarEntry>();
114
- entries.set("credentials/openai-key", makeTarEntry("sk-user-123"));
115
- entries.set("credentials/anthropic-key", makeTarEntry("sk-ant-456"));
130
+ entries.set(bundlePathFor(openaiAccount), makeTarEntry("sk-user-123"));
131
+ entries.set(bundlePathFor(anthropicAccount), makeTarEntry("sk-ant-456"));
116
132
 
117
133
  const manifest = makeManifest([
118
- "credentials/openai-key",
119
- "credentials/anthropic-key",
134
+ bundlePathFor(openaiAccount),
135
+ bundlePathFor(anthropicAccount),
120
136
  ]);
121
137
 
122
138
  const bundleCredentials = extractCredentialsFromBundle(entries, manifest);
@@ -125,50 +141,50 @@ describe("migration import credential filtering", () => {
125
141
 
126
142
  expect(userCredentials).toHaveLength(2);
127
143
  expect(userCredentials).toContainEqual({
128
- account: "openai-key",
144
+ account: openaiAccount,
129
145
  value: "sk-user-123",
130
146
  });
131
147
  expect(userCredentials).toContainEqual({
132
- account: "anthropic-key",
148
+ account: anthropicAccount,
133
149
  value: "sk-ant-456",
134
150
  });
135
151
  expect(skippedPlatform).toBe(0);
136
152
  });
137
153
 
138
- test("mixed bundle with both vellum:* and user credentials correctly splits", () => {
154
+ test("mixed bundle with both platform and user credentials correctly splits", () => {
155
+ const vellumApiKey = credentialKey("vellum", "assistant_api_key");
156
+ const vellumUserId = credentialKey("vellum", "platform_user_id");
157
+ const openaiKey = credentialKey("openai", "api_key");
158
+ const anthropicKey = credentialKey("anthropic", "api_key");
159
+ const githubToken = credentialKey("github", "api_token");
160
+
139
161
  const entries = new Map<string, VBundleTarEntry>();
140
- entries.set(
141
- "credentials/vellum:assistant_api_key",
142
- makeTarEntry("platform-key"),
143
- );
144
- entries.set(
145
- "credentials/vellum:platform_user_id",
146
- makeTarEntry("platform-user"),
147
- );
148
- entries.set("credentials/openai-key", makeTarEntry("sk-user-123"));
149
- entries.set("credentials/anthropic-key", makeTarEntry("sk-ant-456"));
150
- entries.set("credentials/github-token", makeTarEntry("ghp-789"));
162
+ entries.set(bundlePathFor(vellumApiKey), makeTarEntry("platform-key"));
163
+ entries.set(bundlePathFor(vellumUserId), makeTarEntry("platform-user"));
164
+ entries.set(bundlePathFor(openaiKey), makeTarEntry("sk-user-123"));
165
+ entries.set(bundlePathFor(anthropicKey), makeTarEntry("sk-ant-456"));
166
+ entries.set(bundlePathFor(githubToken), makeTarEntry("ghp-789"));
151
167
 
152
168
  const manifest = makeManifest([
153
- "credentials/vellum:assistant_api_key",
154
- "credentials/vellum:platform_user_id",
155
- "credentials/openai-key",
156
- "credentials/anthropic-key",
157
- "credentials/github-token",
169
+ bundlePathFor(vellumApiKey),
170
+ bundlePathFor(vellumUserId),
171
+ bundlePathFor(openaiKey),
172
+ bundlePathFor(anthropicKey),
173
+ bundlePathFor(githubToken),
158
174
  ]);
159
175
 
160
176
  const bundleCredentials = extractCredentialsFromBundle(entries, manifest);
161
177
  const { userCredentials, skippedPlatform } =
162
178
  filterCredentials(bundleCredentials);
163
179
 
164
- // Only user credentials should pass through
180
+ // Only user credentials should pass through.
165
181
  expect(userCredentials).toHaveLength(3);
166
182
  const accounts = userCredentials.map((c) => c.account).sort();
167
- expect(accounts).toEqual(["anthropic-key", "github-token", "openai-key"]);
183
+ expect(accounts).toEqual([anthropicKey, githubToken, openaiKey].sort());
168
184
 
169
- // No vellum: credentials in the filtered output
185
+ // No platform credentials in the filtered output.
170
186
  const vellumCreds = userCredentials.filter((c) =>
171
- c.account.startsWith("vellum:"),
187
+ c.account.startsWith(PLATFORM_CREDENTIAL_PREFIX),
172
188
  );
173
189
  expect(vellumCreds).toHaveLength(0);
174
190
 
@@ -176,17 +192,22 @@ describe("migration import credential filtering", () => {
176
192
  });
177
193
 
178
194
  test("skippedPlatform count is accurate with mixed credentials", () => {
195
+ const vellumApiKey = credentialKey("vellum", "assistant_api_key");
196
+ const vellumBaseUrl = credentialKey("vellum", "platform_base_url");
197
+ const vellumWebhook = credentialKey("vellum", "webhook_secret");
198
+ const userKey = credentialKey("github", "api_token");
199
+
179
200
  const entries = new Map<string, VBundleTarEntry>();
180
- entries.set("credentials/vellum:assistant_api_key", makeTarEntry("v1"));
181
- entries.set("credentials/vellum:platform_base_url", makeTarEntry("v2"));
182
- entries.set("credentials/vellum:webhook_secret", makeTarEntry("v3"));
183
- entries.set("credentials/user-key", makeTarEntry("user-val"));
201
+ entries.set(bundlePathFor(vellumApiKey), makeTarEntry("v1"));
202
+ entries.set(bundlePathFor(vellumBaseUrl), makeTarEntry("v2"));
203
+ entries.set(bundlePathFor(vellumWebhook), makeTarEntry("v3"));
204
+ entries.set(bundlePathFor(userKey), makeTarEntry("user-val"));
184
205
 
185
206
  const manifest = makeManifest([
186
- "credentials/vellum:assistant_api_key",
187
- "credentials/vellum:platform_base_url",
188
- "credentials/vellum:webhook_secret",
189
- "credentials/user-key",
207
+ bundlePathFor(vellumApiKey),
208
+ bundlePathFor(vellumBaseUrl),
209
+ bundlePathFor(vellumWebhook),
210
+ bundlePathFor(userKey),
190
211
  ]);
191
212
 
192
213
  const bundleCredentials = extractCredentialsFromBundle(entries, manifest);
@@ -196,7 +217,7 @@ describe("migration import credential filtering", () => {
196
217
  expect(skippedPlatform).toBe(3);
197
218
  expect(userCredentials).toHaveLength(1);
198
219
  expect(userCredentials[0]).toEqual({
199
- account: "user-key",
220
+ account: userKey,
200
221
  value: "user-val",
201
222
  });
202
223
 
@@ -205,4 +226,22 @@ describe("migration import credential filtering", () => {
205
226
  userCredentials.length + skippedPlatform,
206
227
  );
207
228
  });
229
+
230
+ test("regression: the prefix matches credentialKey('vellum', '') so format changes propagate", () => {
231
+ // If credentialKey()'s format ever changes (e.g. slash → something else),
232
+ // this assertion will fail and the duplicated constant in
233
+ // migration-routes.ts must be updated to stay in sync.
234
+ expect(PLATFORM_CREDENTIAL_PREFIX).toBe("credential/vellum/");
235
+ expect(
236
+ credentialKey("vellum", "assistant_api_key").startsWith(
237
+ PLATFORM_CREDENTIAL_PREFIX,
238
+ ),
239
+ ).toBe(true);
240
+
241
+ // The raw "vellum:" string is not a valid CES account prefix — only
242
+ // the full "credential/vellum/" format from credentialKey() is correct.
243
+ expect(
244
+ credentialKey("vellum", "assistant_api_key").startsWith("vellum:"),
245
+ ).toBe(false);
246
+ });
208
247
  });
@@ -0,0 +1,246 @@
1
+ /**
2
+ * Tests for the post-import vellum metadata reconciliation helper.
3
+ *
4
+ * After every bundle import, `reconcileVellumMetadataFromCes` walks the
5
+ * platform-identity fields the gateway requires and, for each one that
6
+ * CES already holds a value for, ensures `metadata.json` lists a
7
+ * matching entry. This closes the race where a provisioning write to
8
+ * CES completes successfully but its metadata upsert gets clobbered by
9
+ * the import's in-place clear or atomic swap. The reconciled set covers
10
+ * both the Django-provisioned fields (assistant_api_key,
11
+ * platform_assistant_id, platform_base_url, webhook_secret) and the
12
+ * client-injected identity fields (platform_organization_id,
13
+ * platform_user_id).
14
+ *
15
+ * We test the reconcile logic in isolation by mocking the secure-keys
16
+ * and metadata-store modules — the real migration handler wires the
17
+ * same imports, so the behavior under test matches production.
18
+ *
19
+ * Covered:
20
+ * - CES has all 6 fields + metadata empty → all 6 upserted.
21
+ * - CES has all 6 + metadata has 2 → only the missing 4 upserted.
22
+ * - CES has no values → nothing upserted.
23
+ * - CES has values + metadata already has them → no-op (no duplicate
24
+ * upserts).
25
+ * - upsert throws for one field → warning recorded, loop continues.
26
+ */
27
+
28
+ import { afterEach, beforeEach, describe, expect, mock, test } from "bun:test";
29
+
30
+ import { credentialKey } from "../../../security/credential-key.js";
31
+
32
+ type MetadataRecord = {
33
+ credentialId: string;
34
+ service: string;
35
+ field: string;
36
+ allowedTools: string[];
37
+ allowedDomains: string[];
38
+ createdAt: number;
39
+ updatedAt: number;
40
+ };
41
+
42
+ const VELLUM_FIELDS = [
43
+ "platform_base_url",
44
+ "assistant_api_key",
45
+ "platform_assistant_id",
46
+ "platform_organization_id",
47
+ "platform_user_id",
48
+ "webhook_secret",
49
+ ] as const;
50
+
51
+ const upsertCalls: Array<{ service: string; field: string }> = [];
52
+ let metadataStore: Map<string, MetadataRecord> = new Map();
53
+ let cesValues: Map<string, string> = new Map();
54
+ let upsertImpl: (service: string, field: string) => void = (service, field) => {
55
+ const key = `${service}:${field}`;
56
+ metadataStore.set(key, {
57
+ credentialId: `id-${key}`,
58
+ service,
59
+ field,
60
+ allowedTools: [],
61
+ allowedDomains: [],
62
+ createdAt: Date.now(),
63
+ updatedAt: Date.now(),
64
+ });
65
+ };
66
+
67
+ mock.module("../../../security/secure-keys.js", () => ({
68
+ bulkSetSecureKeysAsync: async () => [],
69
+ deleteSecureKeyAsync: async () => "ok",
70
+ getActiveBackendName: () => "test",
71
+ getMaskedProviderKey: async () => null,
72
+ getProviderKeyAsync: async () => null,
73
+ getSecureKeyAsync: async (key: string) => cesValues.get(key) ?? null,
74
+ getSecureKeyResultAsync: async () => ({ ok: true, value: null }),
75
+ listSecureKeysAsync: async () => [],
76
+ onCesClientChanged: () => {},
77
+ setCesClient: () => {},
78
+ setCesReconnect: () => {},
79
+ setSecureKeyAsync: async () => true,
80
+ _resetBackend: () => {},
81
+ }));
82
+
83
+ mock.module("../../../tools/credentials/metadata-store.js", () => ({
84
+ getCredentialMetadata: (service: string, field: string) =>
85
+ metadataStore.get(`${service}:${field}`),
86
+ upsertCredentialMetadata: (
87
+ service: string,
88
+ field: string,
89
+ _policy?: unknown,
90
+ ) => {
91
+ upsertCalls.push({ service, field });
92
+ upsertImpl(service, field);
93
+ return metadataStore.get(`${service}:${field}`);
94
+ },
95
+ }));
96
+
97
+ // Import under test AFTER the mocks are set up.
98
+ const { reconcileVellumMetadataFromCes } =
99
+ (await import("../migration-routes.js")) as unknown as {
100
+ reconcileVellumMetadataFromCes: (sink: {
101
+ warnings: string[];
102
+ }) => Promise<void>;
103
+ };
104
+
105
+ beforeEach(() => {
106
+ upsertCalls.length = 0;
107
+ metadataStore = new Map();
108
+ cesValues = new Map();
109
+ upsertImpl = (service, field) => {
110
+ const key = `${service}:${field}`;
111
+ metadataStore.set(key, {
112
+ credentialId: `id-${key}`,
113
+ service,
114
+ field,
115
+ allowedTools: [],
116
+ allowedDomains: [],
117
+ createdAt: Date.now(),
118
+ updatedAt: Date.now(),
119
+ });
120
+ };
121
+ });
122
+
123
+ afterEach(() => {
124
+ upsertCalls.length = 0;
125
+ });
126
+
127
+ function seedAllInCes(): void {
128
+ for (const field of VELLUM_FIELDS) {
129
+ cesValues.set(credentialKey("vellum", field), `value-for-${field}`);
130
+ }
131
+ }
132
+
133
+ describe("reconcileVellumMetadataFromCes", () => {
134
+ test("CES holds all fields, metadata empty → all upserted", async () => {
135
+ seedAllInCes();
136
+ const sink = { warnings: [] as string[] };
137
+
138
+ await reconcileVellumMetadataFromCes(sink);
139
+
140
+ expect(upsertCalls).toHaveLength(VELLUM_FIELDS.length);
141
+ expect(new Set(upsertCalls.map((c) => c.field))).toEqual(
142
+ new Set(VELLUM_FIELDS),
143
+ );
144
+ expect(sink.warnings).toHaveLength(0);
145
+ });
146
+
147
+ test("CES holds all, metadata has 2 → only the missing ones upserted", async () => {
148
+ seedAllInCes();
149
+ // Pre-populate metadata for 2 of the fields.
150
+ const prepopulated = ["platform_base_url", "assistant_api_key"] as const;
151
+ for (const field of prepopulated) {
152
+ metadataStore.set(`vellum:${field}`, {
153
+ credentialId: `id-vellum:${field}`,
154
+ service: "vellum",
155
+ field,
156
+ allowedTools: [],
157
+ allowedDomains: [],
158
+ createdAt: 1,
159
+ updatedAt: 1,
160
+ });
161
+ }
162
+
163
+ const sink = { warnings: [] as string[] };
164
+ await reconcileVellumMetadataFromCes(sink);
165
+
166
+ const expectedMissing = VELLUM_FIELDS.filter(
167
+ (f) => !(prepopulated as readonly string[]).includes(f),
168
+ );
169
+ expect(upsertCalls).toHaveLength(expectedMissing.length);
170
+ expect(new Set(upsertCalls.map((c) => c.field))).toEqual(
171
+ new Set(expectedMissing),
172
+ );
173
+ });
174
+
175
+ test("covers both Django-provisioned and client-injected identity fields", async () => {
176
+ seedAllInCes();
177
+ const sink = { warnings: [] as string[] };
178
+ await reconcileVellumMetadataFromCes(sink);
179
+
180
+ const reconciled = new Set(upsertCalls.map((c) => c.field));
181
+ // Django-provisioned quartet.
182
+ expect(reconciled).toContain("platform_base_url");
183
+ expect(reconciled).toContain("assistant_api_key");
184
+ expect(reconciled).toContain("platform_assistant_id");
185
+ expect(reconciled).toContain("webhook_secret");
186
+ // Client-injected identity fields (onboarding / teleport / transfer).
187
+ expect(reconciled).toContain("platform_organization_id");
188
+ expect(reconciled).toContain("platform_user_id");
189
+ });
190
+
191
+ test("CES empty → nothing upserted", async () => {
192
+ const sink = { warnings: [] as string[] };
193
+ await reconcileVellumMetadataFromCes(sink);
194
+ expect(upsertCalls).toHaveLength(0);
195
+ expect(sink.warnings).toHaveLength(0);
196
+ });
197
+
198
+ test("CES has values, metadata already has entries → no duplicate upserts", async () => {
199
+ seedAllInCes();
200
+ for (const field of VELLUM_FIELDS) {
201
+ metadataStore.set(`vellum:${field}`, {
202
+ credentialId: `id-vellum:${field}`,
203
+ service: "vellum",
204
+ field,
205
+ allowedTools: [],
206
+ allowedDomains: [],
207
+ createdAt: 1,
208
+ updatedAt: 1,
209
+ });
210
+ }
211
+
212
+ const sink = { warnings: [] as string[] };
213
+ await reconcileVellumMetadataFromCes(sink);
214
+
215
+ expect(upsertCalls).toHaveLength(0);
216
+ });
217
+
218
+ test("upsert throws for one field → warning recorded, loop continues", async () => {
219
+ seedAllInCes();
220
+ let calls = 0;
221
+ upsertImpl = (service, field) => {
222
+ calls += 1;
223
+ if (field === "assistant_api_key") {
224
+ throw new Error("simulated metadata write failure");
225
+ }
226
+ const key = `${service}:${field}`;
227
+ metadataStore.set(key, {
228
+ credentialId: `id-${key}`,
229
+ service,
230
+ field,
231
+ allowedTools: [],
232
+ allowedDomains: [],
233
+ createdAt: Date.now(),
234
+ updatedAt: Date.now(),
235
+ });
236
+ };
237
+
238
+ const sink = { warnings: [] as string[] };
239
+ await reconcileVellumMetadataFromCes(sink);
240
+
241
+ // Every field was attempted (loop did not abort).
242
+ expect(calls).toBe(VELLUM_FIELDS.length);
243
+ expect(sink.warnings).toHaveLength(1);
244
+ expect(sink.warnings[0]).toContain("vellum:assistant_api_key");
245
+ });
246
+ });
@@ -0,0 +1,58 @@
1
+ /**
2
+ * In-memory tracker for approval prompt message timestamps.
3
+ *
4
+ * Scopes guardian reaction approvals so only reactions on a known
5
+ * approval prompt can resolve a pending request. Without this, a stray
6
+ * 👍/✅ on any message in the guardian chat could approve a pending
7
+ * request (since reactions are now admitted from any subscribed channel,
8
+ * not just tracked bot threads).
9
+ *
10
+ * Entries expire after `APPROVAL_PROMPT_TS_TTL_MS` (matches the guardian
11
+ * approval TTL of 30 minutes, plus grace). Populated when an approval
12
+ * prompt is successfully delivered; consulted before applying a guardian
13
+ * reaction decision.
14
+ */
15
+
16
+ const APPROVAL_PROMPT_TS_TTL_MS = 35 * 60 * 1000;
17
+
18
+ const tracked = new Map<string, number>();
19
+
20
+ function key(channel: string, chatId: string, ts: string): string {
21
+ return `${channel}\u0000${chatId}\u0000${ts}`;
22
+ }
23
+
24
+ function pruneExpired(now: number): void {
25
+ for (const [k, expiresAt] of tracked) {
26
+ if (expiresAt <= now) tracked.delete(k);
27
+ }
28
+ }
29
+
30
+ export function trackApprovalPromptTs(
31
+ channel: string,
32
+ chatId: string,
33
+ ts: string,
34
+ ): void {
35
+ const now = Date.now();
36
+ pruneExpired(now);
37
+ tracked.set(key(channel, chatId, ts), now + APPROVAL_PROMPT_TS_TTL_MS);
38
+ }
39
+
40
+ export function isTrackedApprovalPromptTs(
41
+ channel: string,
42
+ chatId: string,
43
+ ts: string,
44
+ ): boolean {
45
+ const k = key(channel, chatId, ts);
46
+ const expiresAt = tracked.get(k);
47
+ if (expiresAt === undefined) return false;
48
+ if (expiresAt <= Date.now()) {
49
+ tracked.delete(k);
50
+ return false;
51
+ }
52
+ return true;
53
+ }
54
+
55
+ /** @internal Test-only — clear all tracked entries. */
56
+ export function _clearApprovalPromptTsTrackerForTesting(): void {
57
+ tracked.clear();
58
+ }
@@ -50,9 +50,7 @@ function canonicalizeV2ConfirmDecision(params: {
50
50
  }
51
51
 
52
52
  if (
53
- (decision === "always_allow" ||
54
- decision === "always_allow_high_risk" ||
55
- decision === "always_deny") &&
53
+ (decision === "always_allow" || decision === "always_deny") &&
56
54
  details.persistentDecisionsAllowed
57
55
  ) {
58
56
  return decision === "always_deny" ? "deny" : "allow";
@@ -79,7 +77,11 @@ export async function handleConfirm(
79
77
  selectedScope?: string;
80
78
  };
81
79
 
82
- const { requestId, decision, selectedPattern, selectedScope } = body;
80
+ const { requestId, selectedPattern, selectedScope } = body;
81
+ // Normalize legacy decision: older clients may still send
82
+ // "always_allow_high_risk" for high-risk prompts.
83
+ const decision =
84
+ body.decision === "always_allow_high_risk" ? "always_allow" : body.decision;
83
85
 
84
86
  if (!requestId || typeof requestId !== "string") {
85
87
  return httpError("BAD_REQUEST", "requestId is required", 400);
@@ -111,7 +113,6 @@ export async function handleConfirm(
111
113
  "deny",
112
114
  "always_allow",
113
115
  "always_deny",
114
- "always_allow_high_risk",
115
116
  ];
116
117
  if (
117
118
  (v2Enabled && effectiveDecision == null) ||
@@ -152,9 +153,7 @@ export async function handleConfirm(
152
153
  // and selectedScope are among the options the server actually offered.
153
154
  // This prevents a crafted request from injecting overly-broad rules.
154
155
  const persistsRule =
155
- decision === "always_allow" ||
156
- decision === "always_deny" ||
157
- decision === "always_allow_high_risk";
156
+ decision === "always_allow" || decision === "always_deny";
158
157
  if (persistsRule && (selectedPattern || selectedScope)) {
159
158
  const confirmation = peeked.confirmationDetails;
160
159
  if (!confirmation) {
@@ -312,10 +311,9 @@ export async function handleTrustRule(
312
311
  pattern?: string;
313
312
  scope?: string;
314
313
  decision?: string;
315
- allowHighRisk?: boolean;
316
314
  };
317
315
 
318
- const { requestId, pattern, scope, decision, allowHighRisk } = body;
316
+ const { requestId, pattern, scope, decision } = body;
319
317
 
320
318
  if (!requestId || typeof requestId !== "string") {
321
319
  return httpError("BAD_REQUEST", "requestId is required", 400);
@@ -396,9 +394,10 @@ export async function handleTrustRule(
396
394
  const tool = getTool(confirmation.toolName);
397
395
  const executionTarget =
398
396
  tool?.origin === "skill" ? confirmation.executionTarget : undefined;
397
+
398
+ // Canonicalization is handled inside addRule — no need to pre-parse here.
399
399
  addRule(confirmation.toolName, pattern, scope, decision, undefined, {
400
- allowHighRisk: allowHighRisk || undefined,
401
- executionTarget,
400
+ ...(executionTarget != null ? { executionTarget } : {}),
402
401
  });
403
402
  log.info(
404
403
  { tool: confirmation.toolName, pattern, scope, decision, requestId },
@@ -504,7 +503,7 @@ export function approvalRouteDefinitions(): RouteDefinition[] {
504
503
  decision: z
505
504
  .string()
506
505
  .describe(
507
- "One of: allow, allow_10m, allow_conversation, deny, always_allow, always_deny, always_allow_high_risk",
506
+ "One of: allow, allow_10m, allow_conversation, deny, always_allow, always_deny",
508
507
  ),
509
508
  selectedPattern: z
510
509
  .string()
@@ -551,10 +550,6 @@ export function approvalRouteDefinitions(): RouteDefinition[] {
551
550
  pattern: z.string().describe("Allowlist pattern"),
552
551
  scope: z.string().describe("Scope for the rule"),
553
552
  decision: z.string().describe("allow or deny"),
554
- allowHighRisk: z
555
- .boolean()
556
- .describe("Allow high-risk invocations")
557
- .optional(),
558
553
  }),
559
554
  responseBody: z.object({
560
555
  accepted: z.boolean(),