@vellumai/assistant 0.6.3 → 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 (1114) hide show
  1. package/.prettierignore +5 -0
  2. package/ARCHITECTURE.md +298 -39
  3. package/Dockerfile +14 -3
  4. package/README.md +3 -4
  5. package/bun.lock +13 -16
  6. package/docs/architecture/integrations.md +1 -20
  7. package/docs/architecture/security.md +16 -16
  8. package/docs/backup-troubleshooting.md +52 -0
  9. package/docs/browser-use-architecture-phase2.md +174 -0
  10. package/docs/error-handling.md +111 -0
  11. package/docs/skills.md +10 -10
  12. package/docs/stt-provider-onboarding.md +121 -0
  13. package/knip.json +20 -3
  14. package/node_modules/@vellumai/ces-contracts/bun.lock +8 -6
  15. package/node_modules/@vellumai/ces-contracts/package.json +5 -4
  16. package/node_modules/@vellumai/ces-contracts/src/__tests__/trust-rules.test.ts +471 -0
  17. package/node_modules/@vellumai/ces-contracts/src/trust-rules.ts +398 -4
  18. package/node_modules/@vellumai/credential-storage/bun.lock +2 -2
  19. package/node_modules/@vellumai/credential-storage/package.json +2 -2
  20. package/node_modules/@vellumai/credential-storage/src/oauth-runtime.ts +20 -2
  21. package/node_modules/@vellumai/egress-proxy/bun.lock +2 -2
  22. package/node_modules/@vellumai/egress-proxy/package.json +2 -2
  23. package/openapi.yaml +1094 -72
  24. package/package.json +9 -8
  25. package/scripts/generate-openapi.ts +50 -12
  26. package/scripts/test.sh +73 -18
  27. package/src/__tests__/agent-image-optimize.test.ts +28 -0
  28. package/src/__tests__/agent-loop-callsite-precedence.test.ts +318 -0
  29. package/src/__tests__/agent-loop-sentry-hygiene.test.ts +137 -0
  30. package/src/__tests__/agent-loop.test.ts +235 -1
  31. package/src/__tests__/anthropic-error-formatting.test.ts +98 -0
  32. package/src/__tests__/anthropic-provider.test.ts +434 -12
  33. package/src/__tests__/approval-cascade.test.ts +31 -10
  34. package/src/__tests__/approval-routes-http.test.ts +134 -10
  35. package/src/__tests__/assistant-attachments.test.ts +44 -0
  36. package/src/__tests__/assistant-feature-flags-integration.test.ts +29 -0
  37. package/src/__tests__/auto-analysis-end-to-end.test.ts +550 -0
  38. package/src/__tests__/auto-analysis-prompt.test.ts +50 -0
  39. package/src/__tests__/browser-fill-credential.test.ts +12 -1
  40. package/src/__tests__/browser-identifier-parity-guard.test.ts +53 -0
  41. package/src/__tests__/browser-skill-baseline-tool-payload.test.ts +23 -33
  42. package/src/__tests__/browser-skill-endstate.test.ts +52 -159
  43. package/src/__tests__/btw-routes.test.ts +54 -1
  44. package/src/__tests__/call-controller.test.ts +582 -22
  45. package/src/__tests__/call-site-routing-provider.test.ts +214 -0
  46. package/src/__tests__/catalog-cache.test.ts +27 -4
  47. package/src/__tests__/catalog-files.test.ts +138 -0
  48. package/src/__tests__/channel-approval-routes.test.ts +4 -4
  49. package/src/__tests__/channel-invite-transport.test.ts +2 -2
  50. package/src/__tests__/channel-readiness-routes.test.ts +16 -20
  51. package/src/__tests__/channel-readiness-service.test.ts +12 -7
  52. package/src/__tests__/channel-reply-delivery.test.ts +300 -2
  53. package/src/__tests__/checker.test.ts +576 -502
  54. package/src/__tests__/clawhub-files.test.ts +347 -0
  55. package/src/__tests__/cli-command-risk-guard.test.ts +30 -33
  56. package/src/__tests__/commit-message-enrichment-service.test.ts +36 -19
  57. package/src/__tests__/compaction-circuit-breaker.test.ts +336 -0
  58. package/src/__tests__/compaction.benchmark.test.ts +1 -1
  59. package/src/__tests__/config-analysis.test.ts +83 -0
  60. package/src/__tests__/config-loader-backfill.test.ts +174 -0
  61. package/src/__tests__/config-loader-corrupt.test.ts +183 -0
  62. package/src/__tests__/config-loader-quarantine-bulletin.test.ts +202 -0
  63. package/src/__tests__/config-schema-cmd.test.ts +11 -5
  64. package/src/__tests__/config-schema.test.ts +1458 -198
  65. package/src/__tests__/config-watcher-cleanup-throttle.test.ts +339 -0
  66. package/src/__tests__/config-watcher.test.ts +45 -10
  67. package/src/__tests__/contact-store-user-file.test.ts +511 -0
  68. package/src/__tests__/contacts-write.test.ts +197 -0
  69. package/src/__tests__/context-token-estimator.test.ts +191 -1
  70. package/src/__tests__/context-window-manager.test.ts +618 -2
  71. package/src/__tests__/conversation-abort-tool-results.test.ts +32 -16
  72. package/src/__tests__/conversation-agent-loop-overflow.test.ts +62 -17
  73. package/src/__tests__/conversation-agent-loop.test.ts +510 -84
  74. package/src/__tests__/conversation-attachments.test.ts +1 -1
  75. package/src/__tests__/conversation-confirmation-signals.test.ts +165 -9
  76. package/src/__tests__/conversation-error.test.ts +102 -1
  77. package/src/__tests__/conversation-history-web-search.test.ts +17 -4
  78. package/src/__tests__/conversation-init.benchmark.test.ts +42 -1
  79. package/src/__tests__/conversation-launcher-skill-regression.test.ts +51 -0
  80. package/src/__tests__/conversation-lifecycle.test.ts +336 -0
  81. package/src/__tests__/conversation-list-source.test.ts +145 -0
  82. package/src/__tests__/conversation-load-history-repair.test.ts +27 -10
  83. package/src/__tests__/conversation-pre-run-repair.test.ts +32 -16
  84. package/src/__tests__/conversation-process-callsite.test.ts +306 -0
  85. package/src/__tests__/conversation-provider-retry-repair.test.ts +32 -16
  86. package/src/__tests__/conversation-queue.test.ts +932 -76
  87. package/src/__tests__/conversation-routes-disk-view.test.ts +299 -1
  88. package/src/__tests__/conversation-routes-slash-commands.test.ts +31 -3
  89. package/src/__tests__/conversation-runtime-assembly.test.ts +2790 -55
  90. package/src/__tests__/conversation-runtime-workspace.test.ts +12 -12
  91. package/src/__tests__/conversation-skill-tools.test.ts +12 -143
  92. package/src/__tests__/conversation-slash-commands.test.ts +33 -0
  93. package/src/__tests__/conversation-slash-queue.test.ts +120 -34
  94. package/src/__tests__/conversation-slash-unknown.test.ts +32 -16
  95. package/src/__tests__/conversation-speed-override.test.ts +30 -11
  96. package/src/__tests__/conversation-surfaces-standalone-payloads.test.ts +1035 -0
  97. package/src/__tests__/conversation-surfaces-standalone.test.ts +630 -0
  98. package/src/__tests__/conversation-title-service.test.ts +2 -2
  99. package/src/__tests__/conversation-tool-setup-batch-authorized.test.ts +226 -0
  100. package/src/__tests__/conversation-unread-route.test.ts +2 -2
  101. package/src/__tests__/conversation-usage.test.ts +3 -1
  102. package/src/__tests__/conversation-workspace-cache-state.test.ts +31 -10
  103. package/src/__tests__/conversation-workspace-injection.test.ts +45 -15
  104. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +46 -16
  105. package/src/__tests__/credential-broker-browser-fill.test.ts +110 -0
  106. package/src/__tests__/credential-health-service.test.ts +352 -0
  107. package/src/__tests__/credential-security-invariants.test.ts +8 -3
  108. package/src/__tests__/credential-storage-oauth-compat.test.ts +18 -0
  109. package/src/__tests__/credential-storage-static-compat.test.ts +28 -0
  110. package/src/__tests__/credential-vault-unit.test.ts +495 -3
  111. package/src/__tests__/credentials-cli.test.ts +32 -16
  112. package/src/__tests__/cross-provider-web-search.test.ts +230 -35
  113. package/src/__tests__/daemon-server-persist-and-process-callsite.test.ts +92 -0
  114. package/src/__tests__/delete-propagation.test.ts +437 -0
  115. package/src/__tests__/deterministic-verification-control-plane.test.ts +10 -1
  116. package/src/__tests__/device-id.test.ts +112 -0
  117. package/src/__tests__/dm-backfill.test.ts +417 -0
  118. package/src/__tests__/dm-persistence.test.ts +227 -0
  119. package/src/__tests__/docker-signing-key-bootstrap.test.ts +167 -4
  120. package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +1 -3
  121. package/src/__tests__/edit-propagation.test.ts +280 -0
  122. package/src/__tests__/email-html-renderer.test.ts +71 -0
  123. package/src/__tests__/email-invite-adapter.test.ts +36 -32
  124. package/src/__tests__/emit-event-signal.test.ts +71 -0
  125. package/src/__tests__/ephemeral-permissions.test.ts +93 -3
  126. package/src/__tests__/estimator-calibration-integration.test.ts +208 -0
  127. package/src/__tests__/estimator-calibration.test.ts +213 -0
  128. package/src/__tests__/extension-id-sync-guard.test.ts +101 -15
  129. package/src/__tests__/file-write-tool.test.ts +151 -1
  130. package/src/__tests__/filing-service.test.ts +255 -0
  131. package/src/__tests__/fixtures/mock-chrome-extension.ts +11 -0
  132. package/src/__tests__/gateway-only-enforcement.test.ts +206 -1
  133. package/src/__tests__/gateway-only-guard.test.ts +0 -1
  134. package/src/__tests__/gemini-provider.test.ts +64 -3
  135. package/src/__tests__/get-skill-detail-audit.test.ts +325 -0
  136. package/src/__tests__/guardian-grant-minting.test.ts +8 -0
  137. package/src/__tests__/headless-browser-interactions.test.ts +44 -1
  138. package/src/__tests__/headless-browser-mode.test.ts +614 -0
  139. package/src/__tests__/headless-browser-navigate.test.ts +142 -5
  140. package/src/__tests__/headless-browser-read-tools.test.ts +11 -0
  141. package/src/__tests__/headless-browser-snapshot.test.ts +10 -0
  142. package/src/__tests__/heartbeat-service.test.ts +166 -32
  143. package/src/__tests__/home-state-routes.test.ts +162 -0
  144. package/src/__tests__/host-bash-proxy.test.ts +0 -5
  145. package/src/__tests__/host-browser-e2e-cloud.test.ts +138 -4
  146. package/src/__tests__/host-browser-e2e-self-hosted.test.ts +4 -4
  147. package/src/__tests__/host-browser-ws-events-e2e.test.ts +103 -0
  148. package/src/__tests__/host-cu-proxy.test.ts +0 -5
  149. package/src/__tests__/host-shell-tool.test.ts +124 -18
  150. package/src/__tests__/http-user-message-parity.test.ts +29 -1
  151. package/src/__tests__/identity-intro-cache.test.ts +40 -10
  152. package/src/__tests__/inbound-slack-persistence.test.ts +340 -0
  153. package/src/__tests__/init-feature-flag-overrides.test.ts +38 -112
  154. package/src/__tests__/intent-routing.test.ts +1 -40
  155. package/src/__tests__/jobs-store-upsert-debounced.test.ts +141 -0
  156. package/src/__tests__/llm-catalog-parity.test.ts +174 -0
  157. package/src/__tests__/llm-context-normalization.test.ts +609 -0
  158. package/src/__tests__/llm-context-route-provider.test.ts +86 -5
  159. package/src/__tests__/llm-resolver.test.ts +214 -0
  160. package/src/__tests__/llm-schema.test.ts +223 -0
  161. package/src/__tests__/llm-usage-store.test.ts +363 -0
  162. package/src/__tests__/managed-proxy-context.test.ts +6 -2
  163. package/src/__tests__/media-stream-output.test.ts +555 -0
  164. package/src/__tests__/media-stream-parser.test.ts +374 -0
  165. package/src/__tests__/media-stream-server-integration.test.ts +1234 -0
  166. package/src/__tests__/media-stream-stt-session.test.ts +588 -0
  167. package/src/__tests__/media-turn-detector.test.ts +440 -0
  168. package/src/__tests__/message-queue.test.ts +125 -0
  169. package/src/__tests__/messaging-skill-split.test.ts +3 -34
  170. package/src/__tests__/migration-export-http.test.ts +6 -6
  171. package/src/__tests__/migration-import-commit-http.test.ts +8 -6
  172. package/src/__tests__/migration-import-from-url.test.ts +684 -0
  173. package/src/__tests__/migration-import-preflight-http.test.ts +6 -5
  174. package/src/__tests__/migration-validate-http.test.ts +3 -3
  175. package/src/__tests__/mock-gateway-ipc.ts +151 -0
  176. package/src/__tests__/model-intents.test.ts +10 -84
  177. package/src/__tests__/notification-decision-fallback.test.ts +0 -10
  178. package/src/__tests__/notification-decision-identity.test.ts +0 -9
  179. package/src/__tests__/notification-decision-recipient-context.test.ts +0 -9
  180. package/src/__tests__/oauth-apps-routes.test.ts +1 -0
  181. package/src/__tests__/oauth-cli.test.ts +2 -0
  182. package/src/__tests__/oauth-connect-orchestrator.test.ts +2 -0
  183. package/src/__tests__/oauth-provider-serializer.test.ts +1 -0
  184. package/src/__tests__/oauth-providers-routes.test.ts +2 -0
  185. package/src/__tests__/oauth-store.test.ts +95 -7
  186. package/src/__tests__/oauth2-gateway-transport.test.ts +257 -9
  187. package/src/__tests__/oauth2-refresh-retry.test.ts +279 -0
  188. package/src/__tests__/onboarding-template-contract.test.ts +6 -13
  189. package/src/__tests__/openai-provider.test.ts +183 -0
  190. package/src/__tests__/openai-responses-cutover-guard.test.ts +184 -0
  191. package/src/__tests__/openai-responses-provider.test.ts +1501 -0
  192. package/src/__tests__/openrouter-provider-only.test.ts +135 -0
  193. package/src/__tests__/openrouter-token-estimation.test.ts +100 -0
  194. package/src/__tests__/outbound-slack-persistence.test.ts +293 -0
  195. package/src/__tests__/permission-checker-host-gate.test.ts +1 -1
  196. package/src/__tests__/permission-mode.test.ts +16 -0
  197. package/src/__tests__/permission-types.test.ts +0 -1
  198. package/src/__tests__/persona-resolver.test.ts +251 -0
  199. package/src/__tests__/pkb-autoinject.test.ts +37 -1
  200. package/src/__tests__/platform-bash-auto-approve.test.ts +5 -1
  201. package/src/__tests__/platform.test.ts +92 -1
  202. package/src/__tests__/post-turn-tool-result-truncation.test.ts +47 -0
  203. package/src/__tests__/prechat-onboarding-contract.test.ts +267 -0
  204. package/src/__tests__/pricing.test.ts +224 -3
  205. package/src/__tests__/profiler-routes.test.ts +1 -1
  206. package/src/__tests__/provider-commit-message-generator.test.ts +14 -84
  207. package/src/__tests__/provider-env-vars-scope.test.ts +52 -0
  208. package/src/__tests__/provider-error-scenarios.test.ts +135 -6
  209. package/src/__tests__/provider-managed-proxy-integration.test.ts +42 -11
  210. package/src/__tests__/provider-registry-ollama.test.ts +1 -2
  211. package/src/__tests__/proxy-approval-callback.test.ts +0 -1
  212. package/src/__tests__/qdrant-manager.test.ts +29 -8
  213. package/src/__tests__/reaction-persistence.test.ts +560 -0
  214. package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +194 -0
  215. package/src/__tests__/relationship-state-contract.test.ts +175 -0
  216. package/src/__tests__/relay-server.test.ts +424 -6
  217. package/src/__tests__/require-fresh-approval.test.ts +1 -1
  218. package/src/__tests__/retry-openrouter-only-normalization.test.ts +136 -0
  219. package/src/__tests__/retry-thinking-tool-choice.test.ts +226 -0
  220. package/src/__tests__/risk-classifier-parity.test.ts +230 -0
  221. package/src/__tests__/sanitize-config-for-transfer.test.ts +78 -1
  222. package/src/__tests__/search-skills-unified.test.ts +118 -0
  223. package/src/__tests__/secret-ingress-http.test.ts +28 -0
  224. package/src/__tests__/secret-prompter-channel-fallback.test.ts +125 -0
  225. package/src/__tests__/secret-routes-managed-proxy.test.ts +2 -3
  226. package/src/__tests__/secret-scanner-executor.test.ts +5 -1
  227. package/src/__tests__/secure-keys.test.ts +107 -0
  228. package/src/__tests__/send-endpoint-busy.test.ts +34 -2
  229. package/src/__tests__/sequence-store.test.ts +1 -1
  230. package/src/__tests__/server-history-render.test.ts +80 -0
  231. package/src/__tests__/settings-routes.test.ts +201 -0
  232. package/src/__tests__/shell-parser-property.test.ts +13 -13
  233. package/src/__tests__/skill-cache-store.test.ts +182 -0
  234. package/src/__tests__/skill-load-feature-flag.test.ts +1 -0
  235. package/src/__tests__/skills-file-content-endpoint.test.ts +276 -145
  236. package/src/__tests__/skills-files-catalog-fallback.test.ts +381 -93
  237. package/src/__tests__/skills.test.ts +19 -30
  238. package/src/__tests__/skillssh-files.test.ts +446 -0
  239. package/src/__tests__/slack-app-setup-skill-regression.test.ts +3 -1
  240. package/src/__tests__/slack-block-formatting.test.ts +110 -0
  241. package/src/__tests__/slack-channel-config.test.ts +564 -1
  242. package/src/__tests__/slack-skill.test.ts +3 -8
  243. package/src/__tests__/starter-bundle.test.ts +35 -0
  244. package/src/__tests__/stt-catalog-parity.test.ts +282 -0
  245. package/src/__tests__/stt-stream-session.test.ts +535 -0
  246. package/src/__tests__/subagent-call-site-routing.test.ts +280 -0
  247. package/src/__tests__/suggestion-routes.test.ts +160 -3
  248. package/src/__tests__/system-prompt.test.ts +126 -53
  249. package/src/__tests__/task-runner.test.ts +3 -1
  250. package/src/__tests__/tcc-sandbox-deny.test.ts +198 -0
  251. package/src/__tests__/telephony-stt-routing.test.ts +329 -0
  252. package/src/__tests__/terminal-tools.test.ts +26 -7
  253. package/src/__tests__/test-preload.ts +18 -0
  254. package/src/__tests__/test-support/browser-skill-harness.ts +2 -49
  255. package/src/__tests__/thread-backfill.test.ts +941 -0
  256. package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +2 -2
  257. package/src/__tests__/tool-executor-lifecycle-events.test.ts +10 -6
  258. package/src/__tests__/tool-executor-shell-integration.test.ts +4 -0
  259. package/src/__tests__/tool-executor.test.ts +88 -113
  260. package/src/__tests__/tool-result-truncation.test.ts +36 -0
  261. package/src/__tests__/trust-store.test.ts +442 -103
  262. package/src/__tests__/trusted-contact-approval-notifier.test.ts +1 -1
  263. package/src/__tests__/tts-catalog-parity.test.ts +345 -0
  264. package/src/__tests__/twilio-routes-twiml.test.ts +512 -114
  265. package/src/__tests__/twilio-routes.test.ts +376 -0
  266. package/src/__tests__/unicode.test.ts +293 -0
  267. package/src/__tests__/update-bulletin-job.test.ts +389 -0
  268. package/src/__tests__/usage-cache-backfill-migration.test.ts +3 -1
  269. package/src/__tests__/usage-routes.test.ts +25 -4
  270. package/src/__tests__/user-reference.test.ts +46 -61
  271. package/src/__tests__/verification-control-plane-policy.test.ts +5 -22
  272. package/src/__tests__/voice-config-update.test.ts +403 -0
  273. package/src/__tests__/voice-quality.test.ts +434 -19
  274. package/src/__tests__/voice-session-bridge.test.ts +39 -0
  275. package/src/__tests__/volume-security-guard.test.ts +3 -2
  276. package/src/__tests__/web-search-history.test.ts +337 -0
  277. package/src/__tests__/workspace-heartbeat-service.test.ts +7 -0
  278. package/src/__tests__/workspace-migration-033-stt-service-explicit-config.test.ts +547 -0
  279. package/src/__tests__/workspace-migration-034-remove-calls-voice-transcription-provider.test.ts +596 -0
  280. package/src/__tests__/workspace-migration-039-drop-legacy-llm-keys.test.ts +343 -0
  281. package/src/__tests__/workspace-migration-043-release-notes-latex-rendering.test.ts +202 -0
  282. package/src/__tests__/workspace-migration-045-release-notes-meet-avatar.test.ts +210 -0
  283. package/src/__tests__/workspace-migration-drop-user-md.test.ts +368 -0
  284. package/src/__tests__/workspace-migration-meets.test.ts +244 -0
  285. package/src/__tests__/workspace-migration-seed-device-id.test.ts +14 -20
  286. package/src/__tests__/workspace-migration-unify-llm-callsite-configs.test.ts +841 -0
  287. package/src/__tests__/workspace-policy.test.ts +1 -11
  288. package/src/acp/client-handler.ts +1 -2
  289. package/src/agent/image-optimize.ts +24 -12
  290. package/src/agent/loop.ts +251 -19
  291. package/src/avatar/resvg-lazy.test.ts +136 -0
  292. package/src/avatar/resvg-lazy.ts +82 -9
  293. package/src/avatar/traits-png-sync.ts +21 -1
  294. package/src/backup/__tests__/backup-key.test.ts +152 -0
  295. package/src/backup/__tests__/backup-worker.test.ts +767 -0
  296. package/src/backup/__tests__/list-snapshots.test.ts +87 -0
  297. package/src/backup/__tests__/local-writer.test.ts +218 -0
  298. package/src/backup/__tests__/offsite-writer.test.ts +641 -0
  299. package/src/backup/__tests__/paths.test.ts +300 -0
  300. package/src/backup/__tests__/restore.test.ts +498 -0
  301. package/src/backup/__tests__/snapshot-lock.test.ts +352 -0
  302. package/src/backup/__tests__/stream-crypt.test.ts +228 -0
  303. package/src/backup/backup-key.ts +137 -0
  304. package/src/backup/backup-worker.ts +459 -0
  305. package/src/backup/list-snapshots.ts +147 -0
  306. package/src/backup/local-writer.ts +133 -0
  307. package/src/backup/offsite-writer.ts +222 -0
  308. package/src/backup/paths.ts +226 -0
  309. package/src/backup/restore.ts +322 -0
  310. package/src/backup/snapshot-lock.ts +431 -0
  311. package/src/backup/stream-crypt.ts +263 -0
  312. package/src/browser/__tests__/operations.test.ts +163 -0
  313. package/src/browser/identifiers.ts +51 -0
  314. package/src/browser/operations.ts +660 -0
  315. package/src/browser/types.ts +81 -0
  316. package/src/bundler/package-resolver.ts +4 -0
  317. package/src/calls/audio-store.ts +11 -5
  318. package/src/calls/call-controller.ts +226 -71
  319. package/src/calls/call-domain.ts +9 -0
  320. package/src/calls/call-speech-output.ts +190 -0
  321. package/src/calls/call-transport.ts +77 -0
  322. package/src/calls/guardian-question-copy.ts +2 -2
  323. package/src/calls/media-stream-audio-transcode.ts +173 -0
  324. package/src/calls/media-stream-output.ts +660 -0
  325. package/src/calls/media-stream-parser.ts +300 -0
  326. package/src/calls/media-stream-protocol.ts +166 -0
  327. package/src/calls/media-stream-server.ts +592 -0
  328. package/src/calls/media-stream-stt-session.ts +460 -0
  329. package/src/calls/media-turn-detector.ts +230 -0
  330. package/src/calls/relay-server.ts +90 -75
  331. package/src/calls/resolve-call-tts-provider.ts +136 -0
  332. package/src/calls/telephony-stt-routing.ts +145 -0
  333. package/src/calls/tts-call-strategy.ts +161 -0
  334. package/src/calls/tts-text-sanitizer.ts +32 -16
  335. package/src/calls/twilio-routes.ts +281 -17
  336. package/src/calls/voice-quality.ts +78 -35
  337. package/src/calls/voice-session-bridge.ts +9 -1
  338. package/src/channels/types.ts +16 -0
  339. package/src/cli/AGENTS.md +1 -1
  340. package/src/cli/__tests__/run-assistant-command.ts +11 -1
  341. package/src/cli/commands/__tests__/attachment.test.ts +438 -0
  342. package/src/cli/commands/__tests__/backup.test.ts +1165 -0
  343. package/src/cli/commands/__tests__/browser.test.ts +554 -0
  344. package/src/cli/commands/__tests__/cache.test.ts +623 -0
  345. package/src/cli/commands/__tests__/domain-register.test.ts +234 -0
  346. package/src/cli/commands/__tests__/domain-status.test.ts +132 -0
  347. package/src/cli/commands/__tests__/email-attachment.test.ts +422 -0
  348. package/src/cli/commands/__tests__/email-download.test.ts +16 -1
  349. package/src/cli/commands/__tests__/email-list.test.ts +28 -4
  350. package/src/cli/commands/__tests__/email-register.test.ts +4 -4
  351. package/src/cli/commands/__tests__/email-send.test.ts +130 -5
  352. package/src/cli/commands/__tests__/email-status.test.ts +5 -1
  353. package/src/cli/commands/__tests__/email-unregister.test.ts +34 -5
  354. package/src/cli/commands/__tests__/image-generation.test.ts +666 -0
  355. package/src/cli/commands/__tests__/inference-send.test.ts +451 -0
  356. package/src/cli/commands/__tests__/stt-transcribe.test.ts +454 -0
  357. package/src/cli/commands/__tests__/task.test.ts +913 -0
  358. package/src/cli/commands/__tests__/tts-synthesize.test.ts +594 -0
  359. package/src/cli/commands/__tests__/ui-confirm.test.ts +650 -0
  360. package/src/cli/commands/__tests__/ui.test.ts +1215 -0
  361. package/src/cli/commands/__tests__/watchers.test.ts +716 -0
  362. package/src/cli/commands/attachment.ts +182 -0
  363. package/src/cli/commands/backup.ts +993 -0
  364. package/src/cli/commands/browser.ts +350 -0
  365. package/src/cli/commands/cache.ts +341 -0
  366. package/src/cli/commands/completions.ts +0 -3
  367. package/src/cli/commands/config.ts +6 -6
  368. package/src/cli/commands/conversations-import.ts +347 -0
  369. package/src/cli/commands/conversations.ts +90 -0
  370. package/src/cli/commands/credentials.ts +0 -1
  371. package/src/cli/commands/domain.ts +210 -0
  372. package/src/cli/commands/email.ts +308 -16
  373. package/src/cli/commands/image-generation.ts +300 -0
  374. package/src/cli/commands/inference.ts +200 -0
  375. package/src/cli/commands/memory.ts +127 -17
  376. package/src/cli/commands/oauth/__tests__/connect.test.ts +12 -0
  377. package/src/cli/commands/oauth/__tests__/providers-delete.test.ts +1 -0
  378. package/src/cli/commands/oauth/__tests__/providers-register.test.ts +1 -0
  379. package/src/cli/commands/oauth/__tests__/providers-update.test.ts +1 -0
  380. package/src/cli/commands/oauth/mode.ts +12 -3
  381. package/src/cli/commands/oauth/providers.ts +15 -0
  382. package/src/cli/commands/oauth/shared.ts +2 -1
  383. package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +4 -10
  384. package/src/cli/commands/platform/__tests__/connect.test.ts +6 -1
  385. package/src/cli/commands/platform/__tests__/disconnect.test.ts +7 -2
  386. package/src/cli/commands/platform/__tests__/status.test.ts +6 -1
  387. package/src/cli/commands/stt.ts +339 -0
  388. package/src/cli/commands/task.ts +795 -0
  389. package/src/cli/commands/trust.ts +50 -19
  390. package/src/cli/commands/tts.ts +273 -0
  391. package/src/cli/commands/ui.ts +670 -0
  392. package/src/cli/commands/watchers.ts +509 -0
  393. package/src/cli/lib/daemon-credential-client.ts +0 -19
  394. package/src/cli/program.ts +53 -8
  395. package/src/cli.ts +0 -37
  396. package/src/config/__tests__/backup-schema.test.ts +134 -0
  397. package/src/config/assistant-feature-flags.ts +61 -62
  398. package/src/config/bundled-skills/app-builder/references/CUSTOM_ROUTES.md +37 -1
  399. package/src/config/bundled-skills/contacts/SKILL.md +2 -2
  400. package/src/config/bundled-skills/conversations/tools/rename-conversation.ts +23 -1
  401. package/src/config/bundled-skills/media-processing/SKILL.md +3 -9
  402. package/src/config/bundled-skills/media-processing/TOOLS.json +1 -6
  403. package/src/config/bundled-skills/media-processing/__tests__/audio-transcribe.test.ts +125 -0
  404. package/src/config/bundled-skills/media-processing/__tests__/extract-keyframes.test.ts +181 -0
  405. package/src/config/bundled-skills/media-processing/__tests__/preprocess-audio.test.ts +141 -0
  406. package/src/config/bundled-skills/media-processing/services/audio-transcribe.ts +32 -87
  407. package/src/config/bundled-skills/media-processing/services/preprocess.ts +8 -4
  408. package/src/config/bundled-skills/media-processing/services/reduce.ts +1 -1
  409. package/src/config/bundled-skills/media-processing/tools/extract-keyframes.ts +0 -10
  410. package/src/config/bundled-skills/messaging/SKILL.md +5 -5
  411. package/src/config/bundled-skills/messaging/TOOLS.json +4 -0
  412. package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +9 -2
  413. package/src/config/bundled-skills/messaging/tools/messaging-read.ts +15 -1
  414. package/src/config/bundled-skills/messaging/tools/messaging-search.ts +21 -1
  415. package/src/config/bundled-skills/messaging/tools/messaging-send.ts +11 -12
  416. package/src/config/bundled-skills/phone-calls/SKILL.md +2 -2
  417. package/src/config/bundled-skills/phone-calls/references/CONFIG.md +28 -18
  418. package/src/config/bundled-skills/phone-calls/references/TROUBLESHOOTING.md +3 -3
  419. package/src/config/bundled-skills/settings/TOOLS.json +3 -3
  420. package/src/config/bundled-skills/settings/tools/voice-config-update.ts +26 -22
  421. package/src/config/bundled-skills/transcribe/SKILL.md +9 -14
  422. package/src/config/bundled-skills/transcribe/TOOLS.json +2 -7
  423. package/src/config/bundled-skills/transcribe/tools/transcribe-media.test.ts +256 -0
  424. package/src/config/bundled-skills/transcribe/tools/transcribe-media.ts +38 -188
  425. package/src/config/bundled-tool-registry.ts +0 -167
  426. package/src/config/env-registry.ts +24 -0
  427. package/src/config/env.ts +39 -10
  428. package/src/config/feature-flag-registry.json +63 -15
  429. package/src/config/llm-resolver.ts +128 -0
  430. package/src/config/loader.ts +220 -22
  431. package/src/config/raw-config-utils.ts +30 -2
  432. package/src/config/sanitize-for-transfer.ts +35 -0
  433. package/src/config/schema.ts +65 -51
  434. package/src/config/schemas/__tests__/stt.test.ts +43 -0
  435. package/src/config/schemas/analysis.ts +32 -0
  436. package/src/config/schemas/backup.ts +72 -0
  437. package/src/config/schemas/calls.ts +1 -30
  438. package/src/config/schemas/elevenlabs.ts +0 -59
  439. package/src/config/schemas/filing.ts +49 -14
  440. package/src/config/schemas/heartbeat.ts +27 -10
  441. package/src/config/schemas/host-browser.ts +47 -1
  442. package/src/config/schemas/inference.ts +3 -23
  443. package/src/config/schemas/llm.ts +318 -0
  444. package/src/config/schemas/memory-lifecycle.ts +14 -2
  445. package/src/config/schemas/memory-processing.ts +1 -9
  446. package/src/config/schemas/notifications.ts +4 -11
  447. package/src/config/schemas/platform.ts +3 -9
  448. package/src/config/schemas/security.ts +33 -0
  449. package/src/config/schemas/services.ts +53 -4
  450. package/src/config/schemas/stt.ts +60 -0
  451. package/src/config/schemas/tts.ts +283 -0
  452. package/src/config/schemas/updates.ts +14 -0
  453. package/src/config/schemas/workspace-git.ts +3 -40
  454. package/src/config/skills.ts +6 -2
  455. package/src/config/types.ts +4 -0
  456. package/src/contacts/contact-store.ts +56 -11
  457. package/src/contacts/contacts-write.ts +38 -1
  458. package/src/context/__tests__/compact-prompt.test.ts +45 -0
  459. package/src/context/__tests__/microcompact.test.ts +805 -0
  460. package/src/context/estimator-calibration.ts +136 -0
  461. package/src/context/microcompact.ts +443 -0
  462. package/src/context/post-turn-tool-result-truncation.ts +3 -2
  463. package/src/context/prompts/compact.md +12 -0
  464. package/src/context/token-estimator.ts +61 -3
  465. package/src/context/tool-result-truncation.ts +2 -1
  466. package/src/context/window-manager.ts +272 -35
  467. package/src/credential-execution/approval-bridge.ts +0 -1
  468. package/src/credential-execution/executable-discovery.ts +23 -2
  469. package/src/credential-execution/process-manager.test.ts +109 -0
  470. package/src/credential-execution/process-manager.ts +96 -2
  471. package/src/credential-health/credential-health-service.ts +366 -0
  472. package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +324 -0
  473. package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +497 -0
  474. package/src/daemon/__tests__/conversation-tool-setup.test.ts +17 -8
  475. package/src/daemon/__tests__/lifecycle-startup-ordering.test.ts +127 -0
  476. package/src/daemon/approval-generators.ts +29 -4
  477. package/src/daemon/assistant-attachments.ts +24 -13
  478. package/src/daemon/classifier.ts +2 -2
  479. package/src/daemon/config-watcher.ts +99 -6
  480. package/src/daemon/context-overflow-reducer.ts +4 -1
  481. package/src/daemon/conversation-agent-loop-handlers.ts +85 -12
  482. package/src/daemon/conversation-agent-loop.ts +563 -104
  483. package/src/daemon/conversation-attachments.ts +2 -6
  484. package/src/daemon/conversation-error.ts +46 -0
  485. package/src/daemon/conversation-history.ts +40 -6
  486. package/src/daemon/conversation-launch.ts +220 -0
  487. package/src/daemon/conversation-lifecycle.ts +85 -11
  488. package/src/daemon/conversation-messaging.ts +110 -7
  489. package/src/daemon/conversation-notifiers.ts +5 -0
  490. package/src/daemon/conversation-process.ts +591 -23
  491. package/src/daemon/conversation-queue-manager.ts +27 -0
  492. package/src/daemon/conversation-runtime-assembly.ts +769 -28
  493. package/src/daemon/conversation-slash.ts +38 -2
  494. package/src/daemon/conversation-surfaces.ts +483 -5
  495. package/src/daemon/conversation-tool-setup.ts +35 -5
  496. package/src/daemon/conversation-usage.ts +8 -5
  497. package/src/daemon/conversation.ts +193 -47
  498. package/src/daemon/external-skills-bootstrap.ts +41 -0
  499. package/src/daemon/guardian-action-generators.ts +34 -14
  500. package/src/daemon/handlers/config-model.test.ts +86 -0
  501. package/src/daemon/handlers/config-model.ts +54 -12
  502. package/src/daemon/handlers/config-slack-channel.ts +269 -94
  503. package/src/daemon/handlers/conversations.ts +13 -3
  504. package/src/daemon/handlers/shared.ts +51 -1
  505. package/src/daemon/handlers/skills.ts +323 -79
  506. package/src/daemon/handlers/slack-channel-oauth-install.ts +197 -0
  507. package/src/daemon/host-browser-proxy.ts +2 -1
  508. package/src/daemon/lifecycle.ts +185 -26
  509. package/src/daemon/message-protocol.ts +6 -0
  510. package/src/daemon/message-types/conversations.ts +48 -1
  511. package/src/daemon/message-types/home.ts +40 -0
  512. package/src/daemon/message-types/meet.ts +143 -0
  513. package/src/daemon/message-types/messages.ts +23 -1
  514. package/src/daemon/message-types/schedules.ts +34 -2
  515. package/src/daemon/message-types/skills.ts +16 -0
  516. package/src/daemon/message-types/surfaces.ts +2 -0
  517. package/src/daemon/message-types/trust.ts +0 -2
  518. package/src/daemon/parse-actual-tokens-from-error.test.ts +57 -1
  519. package/src/daemon/parse-actual-tokens-from-error.ts +66 -0
  520. package/src/daemon/pkb-context-tracker.test.ts +169 -0
  521. package/src/daemon/pkb-context-tracker.ts +125 -0
  522. package/src/daemon/pkb-reminder-builder.test.ts +70 -0
  523. package/src/daemon/pkb-reminder-builder.ts +31 -0
  524. package/src/daemon/providers-setup.ts +6 -0
  525. package/src/daemon/server.ts +463 -10
  526. package/src/daemon/shutdown-handlers.ts +32 -4
  527. package/src/daemon/shutdown-registry.ts +40 -0
  528. package/src/daemon/tool-side-effects.ts +9 -9
  529. package/src/daemon/watch-handler.ts +4 -4
  530. package/src/daemon/web-search-history.ts +126 -0
  531. package/src/email/html-renderer.ts +76 -0
  532. package/src/events/domain-events.ts +0 -1
  533. package/src/filing/filing-service.ts +9 -10
  534. package/src/heartbeat/heartbeat-service.ts +156 -22
  535. package/src/home/__tests__/assistant-feed-authoring.test.ts +156 -0
  536. package/src/home/__tests__/emit-feed-event.test.ts +169 -0
  537. package/src/home/__tests__/feed-scheduler.test.ts +222 -0
  538. package/src/home/__tests__/feed-types.test.ts +275 -0
  539. package/src/home/__tests__/feed-writer.test.ts +688 -0
  540. package/src/home/__tests__/phase5-exit-criteria.test.ts +212 -0
  541. package/src/home/__tests__/platform-gmail-digest.test.ts +222 -0
  542. package/src/home/__tests__/progress-formula.test.ts +213 -0
  543. package/src/home/__tests__/relationship-state-writer.test.ts +740 -0
  544. package/src/home/__tests__/rollup-producer.test.ts +442 -0
  545. package/src/home/assistant-feed-authoring.ts +128 -0
  546. package/src/home/emit-feed-event.ts +162 -0
  547. package/src/home/feed-scheduler.ts +263 -0
  548. package/src/home/feed-types.ts +235 -0
  549. package/src/home/feed-writer.ts +469 -0
  550. package/src/home/platform-gmail-digest.ts +163 -0
  551. package/src/home/progress-formula.ts +86 -0
  552. package/src/home/relationship-state-writer.ts +824 -0
  553. package/src/home/relationship-state.ts +143 -0
  554. package/src/home/rollup-producer.ts +413 -0
  555. package/src/home/suggested-prompts.ts +101 -0
  556. package/src/hooks/runner.ts +7 -0
  557. package/src/inbound/platform-callback-registration.ts +12 -3
  558. package/src/inbound/public-ingress-urls.ts +12 -0
  559. package/src/instrument.ts +1 -1
  560. package/src/ipc/__tests__/attachment-ipc.test.ts +213 -0
  561. package/src/ipc/__tests__/browser-ipc.test.ts +339 -0
  562. package/src/ipc/__tests__/cache-ipc.test.ts +266 -0
  563. package/src/ipc/__tests__/cli-ipc.test.ts +200 -0
  564. package/src/ipc/__tests__/socket-path.test.ts +73 -0
  565. package/src/ipc/__tests__/task-ipc.test.ts +577 -0
  566. package/src/ipc/__tests__/ui-request-route.test.ts +495 -0
  567. package/src/ipc/__tests__/watcher-ipc.test.ts +295 -0
  568. package/src/ipc/cli-client.ts +152 -0
  569. package/src/ipc/cli-server.ts +252 -0
  570. package/src/ipc/gateway-client.ts +180 -0
  571. package/src/ipc/routes/attachment.ts +114 -0
  572. package/src/ipc/routes/browser-context.ts +61 -0
  573. package/src/ipc/routes/browser.ts +96 -0
  574. package/src/ipc/routes/cache.ts +96 -0
  575. package/src/ipc/routes/index.ts +21 -0
  576. package/src/ipc/routes/task-queue.ts +226 -0
  577. package/src/ipc/routes/task.ts +173 -0
  578. package/src/ipc/routes/ui-request.ts +50 -0
  579. package/src/ipc/routes/wake-conversation.ts +19 -0
  580. package/src/ipc/routes/watcher.ts +203 -0
  581. package/src/ipc/socket-path.ts +100 -0
  582. package/src/memory/__tests__/auto-analysis-enqueue.test.ts +356 -0
  583. package/src/memory/__tests__/auto-analysis-guard.test.ts +57 -0
  584. package/src/memory/__tests__/conversation-analyze-job.test.ts +233 -0
  585. package/src/memory/__tests__/conversation-group-migration.test.ts +99 -0
  586. package/src/memory/__tests__/find-analysis-conversation.test.ts +196 -0
  587. package/src/memory/admin.ts +18 -0
  588. package/src/memory/app-store.ts +1 -1
  589. package/src/memory/attachments-store.ts +70 -0
  590. package/src/memory/auto-analysis-enqueue.ts +127 -0
  591. package/src/memory/auto-analysis-guard.ts +27 -0
  592. package/src/memory/cleanup-schedule-state.ts +37 -0
  593. package/src/memory/conversation-analyze-job.ts +74 -0
  594. package/src/memory/conversation-attention-store.ts +13 -6
  595. package/src/memory/conversation-crud.ts +199 -0
  596. package/src/memory/conversation-disk-view.ts +7 -0
  597. package/src/memory/conversation-group-migration.ts +65 -1
  598. package/src/memory/conversation-queries.ts +6 -5
  599. package/src/memory/conversation-title-service.ts +7 -4
  600. package/src/memory/db-init.ts +8 -0
  601. package/src/memory/db-maintenance.ts +108 -0
  602. package/src/memory/db.ts +1 -0
  603. package/src/memory/embedding-backend.ts +1 -1
  604. package/src/memory/graph/compaction.ts +299 -0
  605. package/src/memory/graph/consolidation.ts +4 -4
  606. package/src/memory/graph/conversation-graph-memory.ts +104 -29
  607. package/src/memory/graph/extraction.test.ts +295 -2
  608. package/src/memory/graph/extraction.ts +181 -51
  609. package/src/memory/graph/graph-search.test.ts +92 -0
  610. package/src/memory/graph/graph-search.ts +4 -1
  611. package/src/memory/graph/narrative.ts +2 -2
  612. package/src/memory/graph/pattern-scan.ts +2 -2
  613. package/src/memory/graph/retriever.test.ts +459 -0
  614. package/src/memory/graph/retriever.ts +257 -66
  615. package/src/memory/graph/scoring.test.ts +186 -0
  616. package/src/memory/graph/scoring.ts +31 -1
  617. package/src/memory/graph/store.ts +41 -0
  618. package/src/memory/graph/tool-handlers.ts +27 -0
  619. package/src/memory/graph/tools.ts +6 -1
  620. package/src/memory/group-crud.ts +6 -1
  621. package/src/memory/indexer.ts +95 -16
  622. package/src/memory/job-handlers/cleanup.ts +11 -8
  623. package/src/memory/job-handlers/conversation-starters.ts +39 -30
  624. package/src/memory/job-handlers/summarization.ts +2 -2
  625. package/src/memory/job-utils.ts +7 -1
  626. package/src/memory/jobs/embed-pkb-file.test.ts +168 -0
  627. package/src/memory/jobs/embed-pkb-file.ts +54 -0
  628. package/src/memory/jobs-store.ts +106 -5
  629. package/src/memory/jobs-worker.ts +26 -9
  630. package/src/memory/llm-usage-store.ts +92 -56
  631. package/src/memory/migrations/140-backfill-usage-cache-accounting.ts +1 -1
  632. package/src/memory/migrations/219-oauth-providers-token-exchange-body-format.ts +15 -0
  633. package/src/memory/migrations/220-normalize-user-file-by-principal.ts +190 -0
  634. package/src/memory/migrations/221-conversations-archived-at.ts +16 -0
  635. package/src/memory/migrations/222-strip-placeholder-sentinels-from-messages.ts +82 -0
  636. package/src/memory/migrations/index.ts +7 -0
  637. package/src/memory/migrations/registry.ts +8 -0
  638. package/src/memory/pkb/pkb-index.test.ts +368 -0
  639. package/src/memory/pkb/pkb-index.ts +255 -0
  640. package/src/memory/pkb/pkb-reconcile.test.ts +251 -0
  641. package/src/memory/pkb/pkb-reconcile.ts +148 -0
  642. package/src/memory/pkb/pkb-search.test.ts +438 -0
  643. package/src/memory/pkb/pkb-search.ts +137 -0
  644. package/src/memory/pkb/types.ts +53 -0
  645. package/src/memory/qdrant-client.ts +122 -1
  646. package/src/memory/qdrant-manager.ts +43 -16
  647. package/src/memory/schema/conversations.ts +2 -0
  648. package/src/memory/schema/oauth.ts +3 -0
  649. package/src/memory/slack-thread-store.ts +37 -0
  650. package/src/memory/usage-buckets.ts +396 -0
  651. package/src/messaging/providers/gmail/adapter.ts +6 -16
  652. package/src/messaging/providers/gmail/client.ts +79 -6
  653. package/src/messaging/providers/gmail/types.ts +7 -0
  654. package/src/messaging/providers/slack/__tests__/adapter-token-routing.test.ts +282 -0
  655. package/src/messaging/providers/slack/adapter.ts +155 -38
  656. package/src/messaging/providers/slack/backfill.test.ts +257 -0
  657. package/src/messaging/providers/slack/backfill.ts +101 -0
  658. package/src/messaging/providers/slack/client.ts +16 -0
  659. package/src/messaging/providers/slack/message-metadata.test.ts +316 -0
  660. package/src/messaging/providers/slack/message-metadata.ts +123 -0
  661. package/src/messaging/providers/slack/render-transcript.test.ts +1373 -0
  662. package/src/messaging/providers/slack/render-transcript.ts +443 -0
  663. package/src/messaging/providers/slack/types.ts +4 -0
  664. package/src/messaging/style-analyzer.ts +5 -2
  665. package/src/notifications/README.md +9 -5
  666. package/src/notifications/decision-engine.ts +6 -12
  667. package/src/notifications/preference-extractor.ts +2 -6
  668. package/src/notifications/signal.ts +5 -0
  669. package/src/oauth/__tests__/identity-verifier.test.ts +1 -0
  670. package/src/oauth/byo-connection.test.ts +18 -1
  671. package/src/oauth/byo-connection.ts +3 -1
  672. package/src/oauth/connect-orchestrator.ts +2 -0
  673. package/src/oauth/connection-resolver.ts +6 -2
  674. package/src/oauth/connection.ts +2 -0
  675. package/src/oauth/oauth-store.ts +10 -0
  676. package/src/oauth/platform-connection.test.ts +145 -0
  677. package/src/oauth/platform-connection.ts +62 -31
  678. package/src/oauth/seed-providers.ts +10 -1
  679. package/src/permissions/approval-policy.test.ts +948 -0
  680. package/src/permissions/approval-policy.ts +257 -0
  681. package/src/permissions/bash-risk-classifier.test.ts +1208 -0
  682. package/src/permissions/bash-risk-classifier.ts +707 -0
  683. package/src/permissions/checker.ts +218 -699
  684. package/src/permissions/command-registry.test.ts +535 -0
  685. package/src/permissions/command-registry.ts +825 -0
  686. package/src/permissions/defaults.ts +71 -75
  687. package/src/permissions/file-risk-classifier.test.ts +535 -0
  688. package/src/permissions/file-risk-classifier.ts +274 -0
  689. package/src/permissions/risk-types.ts +205 -0
  690. package/src/permissions/secret-prompter.ts +53 -2
  691. package/src/permissions/skill-risk-classifier.test.ts +311 -0
  692. package/src/permissions/skill-risk-classifier.ts +214 -0
  693. package/src/permissions/trust-client.ts +52 -25
  694. package/src/permissions/trust-store-interface.ts +1 -6
  695. package/src/permissions/trust-store.ts +164 -65
  696. package/src/permissions/types.ts +23 -14
  697. package/src/permissions/web-risk-classifier.test.ts +170 -0
  698. package/src/permissions/web-risk-classifier.ts +89 -0
  699. package/src/permissions/workspace-policy.ts +1 -13
  700. package/src/platform/client.test.ts +10 -0
  701. package/src/platform/client.ts +19 -1
  702. package/src/platform/sync-identity.ts +129 -0
  703. package/src/prompts/persona-resolver.ts +127 -3
  704. package/src/prompts/system-prompt.ts +78 -38
  705. package/src/prompts/templates/BOOTSTRAP.md +5 -5
  706. package/src/prompts/templates/SOUL.md +5 -3
  707. package/src/prompts/templates/channels/slack.md +20 -0
  708. package/src/prompts/update-bulletin-job.ts +190 -0
  709. package/src/prompts/user-reference.ts +20 -17
  710. package/src/providers/__tests__/context-overflow-error.test.ts +328 -0
  711. package/src/providers/__tests__/provider-env-vars.test.ts +102 -0
  712. package/src/providers/__tests__/provider-secret-catalog.test.ts +42 -0
  713. package/src/providers/__tests__/retry-callsite.test.ts +424 -0
  714. package/src/providers/anthropic/client.ts +335 -70
  715. package/src/providers/call-site-routing.ts +71 -0
  716. package/src/providers/fireworks/client.ts +2 -2
  717. package/src/providers/gemini/client.ts +74 -3
  718. package/src/providers/managed-proxy/constants.ts +2 -1
  719. package/src/providers/model-catalog.ts +502 -28
  720. package/src/providers/model-intents.ts +8 -8
  721. package/src/providers/ollama/client.ts +2 -2
  722. package/src/providers/openai/chat-completions-provider.ts +530 -0
  723. package/src/providers/openai/client.ts +25 -440
  724. package/src/providers/openai/responses-provider.ts +579 -0
  725. package/src/providers/openrouter/client.ts +168 -4
  726. package/src/providers/provider-env-vars.ts +56 -0
  727. package/src/providers/provider-secret-catalog.ts +139 -0
  728. package/src/providers/provider-send-message.ts +22 -5
  729. package/src/providers/ratelimit.ts +4 -0
  730. package/src/providers/registry.ts +21 -10
  731. package/src/providers/retry.ts +185 -39
  732. package/src/providers/speech-to-text/__tests__/provider-catalog.test.ts +251 -0
  733. package/src/providers/speech-to-text/__tests__/resolve.test.ts +883 -0
  734. package/src/providers/speech-to-text/deepgram-realtime.test.ts +980 -0
  735. package/src/providers/speech-to-text/deepgram-realtime.ts +767 -0
  736. package/src/providers/speech-to-text/deepgram.test.ts +332 -0
  737. package/src/providers/speech-to-text/deepgram.ts +115 -0
  738. package/src/providers/speech-to-text/google-gemini-live-stream.test.ts +743 -0
  739. package/src/providers/speech-to-text/google-gemini-live-stream.ts +625 -0
  740. package/src/providers/speech-to-text/google-gemini.test.ts +226 -0
  741. package/src/providers/speech-to-text/google-gemini.ts +101 -0
  742. package/src/providers/speech-to-text/openai-whisper-stream.test.ts +564 -0
  743. package/src/providers/speech-to-text/openai-whisper-stream.ts +381 -0
  744. package/src/providers/speech-to-text/openai-whisper.test.ts +1 -37
  745. package/src/providers/speech-to-text/openai-whisper.ts +63 -33
  746. package/src/providers/speech-to-text/provider-catalog.ts +323 -0
  747. package/src/providers/speech-to-text/resolve.ts +393 -6
  748. package/src/providers/speech-to-text/xai-realtime.test.ts +578 -0
  749. package/src/providers/speech-to-text/xai-realtime.ts +796 -0
  750. package/src/providers/speech-to-text/xai.test.ts +155 -0
  751. package/src/providers/speech-to-text/xai.ts +97 -0
  752. package/src/providers/types.ts +102 -3
  753. package/src/runtime/AGENTS.md +45 -3
  754. package/src/runtime/__tests__/agent-wake.test.ts +872 -0
  755. package/src/runtime/__tests__/interactive-ui.test.ts +673 -0
  756. package/src/runtime/__tests__/runtime-mode.test.ts +62 -0
  757. package/src/runtime/__tests__/slack-block-formatting.test.ts +481 -0
  758. package/src/runtime/agent-wake.ts +553 -0
  759. package/src/runtime/auth/__tests__/route-policy.test.ts +40 -0
  760. package/src/runtime/auth/route-policy.ts +34 -5
  761. package/src/runtime/auth/token-service.ts +56 -1
  762. package/src/runtime/btw-sidechain.ts +15 -3
  763. package/src/runtime/capability-tokens.ts +10 -10
  764. package/src/runtime/channel-invite-transport.ts +1 -1
  765. package/src/runtime/channel-invite-transports/email.ts +14 -6
  766. package/src/runtime/channel-readiness-service.ts +12 -22
  767. package/src/runtime/channel-reply-delivery.ts +106 -2
  768. package/src/runtime/chrome-extension-registry.ts +38 -2
  769. package/src/runtime/decision-token.ts +116 -0
  770. package/src/runtime/gateway-client.ts +2 -2
  771. package/src/runtime/http-router.ts +32 -0
  772. package/src/runtime/http-server.ts +447 -11
  773. package/src/runtime/http-types.ts +29 -3
  774. package/src/runtime/interactive-ui.ts +362 -0
  775. package/src/runtime/invite-instruction-generator.ts +2 -2
  776. package/src/runtime/migrations/__tests__/gcs-signed-url.test.ts +176 -0
  777. package/src/runtime/migrations/__tests__/vbundle-import-credentials.test.ts +36 -0
  778. package/src/runtime/migrations/__tests__/vbundle-legacy-user-md.test.ts +360 -0
  779. package/src/runtime/migrations/__tests__/vbundle-metadata-merge-integration.test.ts +390 -0
  780. package/src/runtime/migrations/__tests__/vbundle-metadata-merge.test.ts +221 -0
  781. package/src/runtime/migrations/__tests__/vbundle-streaming-importer.test.ts +1540 -0
  782. package/src/runtime/migrations/__tests__/vbundle-streaming-validator.test.ts +453 -0
  783. package/src/runtime/migrations/__tests__/vbundle-tar-stream.test.ts +222 -0
  784. package/src/runtime/migrations/gcs-signed-url.ts +162 -0
  785. package/src/runtime/migrations/migration-transport.ts +1 -0
  786. package/src/runtime/migrations/migration-wizard.ts +1 -0
  787. package/src/runtime/migrations/vbundle-import-analyzer.ts +77 -1
  788. package/src/runtime/migrations/vbundle-importer.ts +187 -8
  789. package/src/runtime/migrations/vbundle-metadata-merge.ts +124 -0
  790. package/src/runtime/migrations/vbundle-streaming-importer.ts +2522 -0
  791. package/src/runtime/migrations/vbundle-streaming-validator.ts +244 -0
  792. package/src/runtime/migrations/vbundle-tar-stream.ts +217 -0
  793. package/src/runtime/migrations/vbundle-validator.ts +15 -6
  794. package/src/runtime/pending-interactions.ts +0 -11
  795. package/src/runtime/routes/__tests__/backup-routes.test.ts +967 -0
  796. package/src/runtime/routes/__tests__/home-feed-routes.test.ts +618 -0
  797. package/src/runtime/routes/__tests__/migration-import-credential-filter.test.ts +247 -0
  798. package/src/runtime/routes/__tests__/migration-vellum-metadata-reconcile.test.ts +246 -0
  799. package/src/runtime/routes/__tests__/stt-routes.test.ts +406 -0
  800. package/src/runtime/routes/__tests__/tts-routes.test.ts +474 -0
  801. package/src/runtime/routes/__tests__/user-route-dispatcher.test.ts +148 -17
  802. package/src/runtime/routes/app-management-routes.ts +12 -18
  803. package/src/runtime/routes/approval-prompt-ts-tracker.ts +58 -0
  804. package/src/runtime/routes/approval-routes.ts +12 -17
  805. package/src/runtime/routes/approval-strategies/guardian-callback-strategy.ts +9 -0
  806. package/src/runtime/routes/attachment-routes.test.ts +9 -3
  807. package/src/runtime/routes/attachment-routes.ts +216 -17
  808. package/src/runtime/routes/avatar-routes.ts +20 -4
  809. package/src/runtime/routes/backup-routes.ts +519 -0
  810. package/src/runtime/routes/browser-extension-pair-routes.ts +82 -23
  811. package/src/runtime/routes/btw-routes.ts +9 -10
  812. package/src/runtime/routes/contact-routes.test.ts +298 -0
  813. package/src/runtime/routes/contact-routes.ts +132 -5
  814. package/src/runtime/routes/conversation-analysis-routes.ts +22 -142
  815. package/src/runtime/routes/conversation-management-routes.ts +133 -0
  816. package/src/runtime/routes/conversation-routes.ts +487 -160
  817. package/src/runtime/routes/debug-routes.ts +1 -1
  818. package/src/runtime/routes/diagnostics-routes.ts +6 -4
  819. package/src/runtime/routes/events-routes.ts +16 -0
  820. package/src/runtime/routes/filing-routes.ts +93 -0
  821. package/src/runtime/routes/guardian-approval-interception.ts +33 -3
  822. package/src/runtime/routes/guardian-approval-prompt.ts +13 -3
  823. package/src/runtime/routes/home-feed-routes.ts +452 -0
  824. package/src/runtime/routes/home-state-routes.ts +138 -0
  825. package/src/runtime/routes/host-browser-routes.ts +3 -14
  826. package/src/runtime/routes/identity-intro-cache.ts +7 -3
  827. package/src/runtime/routes/identity-routes.ts +3 -17
  828. package/src/runtime/routes/inbound-message-handler.ts +912 -2
  829. package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +113 -2
  830. package/src/runtime/routes/inbound-stages/background-dispatch.ts +61 -3
  831. package/src/runtime/routes/inbound-stages/edit-intercept.ts +129 -6
  832. package/src/runtime/routes/inbound-stages/transcribe-audio.test.ts +46 -39
  833. package/src/runtime/routes/inbound-stages/transcribe-audio.ts +15 -15
  834. package/src/runtime/routes/integrations/slack/__tests__/channel.test.ts +137 -0
  835. package/src/runtime/routes/integrations/slack/__tests__/share.test.ts +179 -0
  836. package/src/runtime/routes/integrations/slack/channel.ts +36 -6
  837. package/src/runtime/routes/integrations/slack/share.ts +45 -7
  838. package/src/runtime/routes/llm-context-normalization.ts +325 -0
  839. package/src/runtime/routes/memory-item-routes.test.ts +3 -2
  840. package/src/runtime/routes/migration-routes.ts +722 -91
  841. package/src/runtime/routes/settings-routes.ts +26 -7
  842. package/src/runtime/routes/skills-routes.ts +76 -7
  843. package/src/runtime/routes/stt-routes.ts +233 -0
  844. package/src/runtime/routes/surface-action-routes.ts +41 -2
  845. package/src/runtime/routes/trust-rules-routes.ts +30 -14
  846. package/src/runtime/routes/tts-routes.ts +108 -24
  847. package/src/runtime/routes/usage-routes.ts +30 -2
  848. package/src/runtime/routes/user-route-dispatcher.ts +50 -5
  849. package/src/runtime/routes/user-routes.ts +13 -1
  850. package/src/runtime/routes/work-items-routes.test.ts +1 -1
  851. package/src/runtime/routes/work-items-routes.ts +11 -3
  852. package/src/runtime/runtime-mode.ts +33 -0
  853. package/src/runtime/services/__tests__/analyze-conversation.test.ts +426 -0
  854. package/src/runtime/services/__tests__/analyze-deps-singleton.test.ts +67 -0
  855. package/src/runtime/services/__tests__/auto-analysis-prompt.test.ts +53 -0
  856. package/src/runtime/services/__tests__/manual-analysis-prompt.test.ts +41 -0
  857. package/src/runtime/services/analyze-conversation.ts +340 -0
  858. package/src/runtime/services/analyze-deps-singleton.ts +32 -0
  859. package/src/runtime/services/auto-analysis-prompt.ts +55 -0
  860. package/src/runtime/skill-route-registry.ts +71 -0
  861. package/src/runtime/slack-block-formatting.ts +437 -10
  862. package/src/schedule/scheduler.ts +58 -0
  863. package/src/security/__tests__/provider-key-env-fallback.test.ts +119 -0
  864. package/src/security/__tests__/untrusted-content.test.ts +109 -0
  865. package/src/security/oauth2.ts +122 -37
  866. package/src/security/secure-keys.ts +32 -10
  867. package/src/security/token-manager.ts +35 -13
  868. package/src/security/untrusted-content.ts +102 -0
  869. package/src/sequence/engine.ts +23 -0
  870. package/src/sequence/types.ts +1 -1
  871. package/src/skills/catalog-cache.ts +26 -7
  872. package/src/skills/catalog-files.ts +64 -2
  873. package/src/skills/catalog-install.ts +31 -3
  874. package/src/skills/category-inference.ts +122 -0
  875. package/src/skills/clawhub-files.ts +213 -0
  876. package/src/skills/clawhub.ts +84 -23
  877. package/src/skills/skill-cache-store.ts +97 -0
  878. package/src/skills/skill-file-provider.ts +40 -0
  879. package/src/skills/skillssh-files.ts +395 -0
  880. package/src/skills/skillssh-registry.ts +4 -4
  881. package/src/stt/__tests__/daemon-batch-transcriber.test.ts +468 -0
  882. package/src/stt/__tests__/types.test.ts +89 -0
  883. package/src/stt/daemon-batch-transcriber.ts +228 -0
  884. package/src/stt/stt-stream-session.ts +506 -0
  885. package/src/stt/types.ts +334 -0
  886. package/src/stt/wav-encoder.test.ts +373 -0
  887. package/src/stt/wav-encoder.ts +175 -0
  888. package/src/subagent/manager.ts +79 -27
  889. package/src/tasks/ephemeral-permissions.ts +9 -4
  890. package/src/telemetry/usage-telemetry-reporter.ts +27 -5
  891. package/src/tools/browser/__tests__/browser-mode.test.ts +119 -0
  892. package/src/tools/browser/__tests__/browser-status.test.ts +166 -0
  893. package/src/tools/browser/browser-execution.ts +1208 -41
  894. package/src/tools/browser/browser-manager.ts +45 -0
  895. package/src/tools/browser/browser-mode-constants.ts +12 -0
  896. package/src/tools/browser/browser-mode.ts +92 -0
  897. package/src/tools/browser/browser-status-constants.ts +33 -0
  898. package/src/tools/browser/cdp-client/__tests__/cdp-inspect-client.test.ts +393 -0
  899. package/src/tools/browser/cdp-client/__tests__/extension-cdp-client.test.ts +29 -0
  900. package/src/tools/browser/cdp-client/__tests__/factory.test.ts +1648 -32
  901. package/src/tools/browser/cdp-client/cdp-inspect/__tests__/discovery.test.ts +264 -0
  902. package/src/tools/browser/cdp-client/cdp-inspect/discovery.ts +205 -17
  903. package/src/tools/browser/cdp-client/cdp-inspect-client.ts +254 -21
  904. package/src/tools/browser/cdp-client/errors.ts +15 -0
  905. package/src/tools/browser/cdp-client/extension-cdp-client.ts +39 -16
  906. package/src/tools/browser/cdp-client/factory.ts +797 -87
  907. package/src/tools/browser/cdp-client/index.ts +16 -2
  908. package/src/tools/browser/cdp-client/types.ts +68 -0
  909. package/src/tools/credentials/tool-policy.ts +39 -5
  910. package/src/tools/credentials/vault.ts +41 -7
  911. package/src/tools/executor.ts +4 -0
  912. package/src/tools/filesystem/write.ts +52 -0
  913. package/src/tools/host-terminal/host-shell.ts +45 -5
  914. package/src/tools/memory/register.test.ts +185 -0
  915. package/src/tools/memory/register.ts +3 -1
  916. package/src/tools/network/web-fetch.ts +25 -12
  917. package/src/tools/network/web-search.ts +20 -2
  918. package/src/tools/permission-checker.ts +36 -15
  919. package/src/tools/policy-context.ts +25 -8
  920. package/src/tools/registry.ts +55 -3
  921. package/src/tools/shared/shell-output.ts +3 -1
  922. package/src/tools/side-effects.ts +0 -9
  923. package/src/tools/skills/execute.ts +2 -2
  924. package/src/tools/skills/sandbox-runner.ts +6 -2
  925. package/src/tools/terminal/backends/native.ts +51 -2
  926. package/src/tools/terminal/safe-env.ts +11 -2
  927. package/src/tools/terminal/shell.ts +16 -4
  928. package/src/tools/tool-manifest.ts +6 -0
  929. package/src/tools/types.ts +29 -3
  930. package/src/tools/ui-surface/definitions.ts +6 -1
  931. package/src/tools/verification-control-plane-policy.ts +1 -1
  932. package/src/tts/__tests__/provider-adapters.test.ts +1061 -0
  933. package/src/tts/__tests__/provider-catalog-consistency.test.ts +196 -0
  934. package/src/tts/__tests__/provider-catalog.test.ts +183 -0
  935. package/src/tts/__tests__/provider-registry.test.ts +90 -0
  936. package/src/tts/provider-catalog.ts +219 -0
  937. package/src/tts/provider-registry.ts +73 -0
  938. package/src/tts/providers/deepgram-provider.ts +219 -0
  939. package/src/tts/providers/elevenlabs-provider.ts +211 -0
  940. package/src/tts/providers/fish-audio-provider.ts +183 -0
  941. package/src/tts/providers/index.ts +44 -0
  942. package/src/tts/providers/register-builtins.ts +130 -0
  943. package/src/tts/providers/xai-provider.ts +224 -0
  944. package/src/tts/synthesize-text.ts +110 -0
  945. package/src/tts/tts-config-resolver.ts +78 -0
  946. package/src/tts/types.ts +199 -0
  947. package/src/types/onboarding-context.ts +7 -0
  948. package/src/types/tar-stream.d.ts +66 -0
  949. package/src/util/abort-reasons.ts +58 -0
  950. package/src/util/device-id.ts +32 -16
  951. package/src/util/errors.ts +9 -1
  952. package/src/util/json.ts +17 -0
  953. package/src/util/platform.ts +56 -12
  954. package/src/util/pricing.ts +78 -5
  955. package/src/util/spawn.ts +1 -1
  956. package/src/util/truncate.ts +4 -2
  957. package/src/util/unicode.ts +201 -0
  958. package/src/version.ts +19 -24
  959. package/src/watcher/engine.ts +24 -1
  960. package/src/watcher/providers/google-calendar.ts +134 -8
  961. package/src/watcher/providers/outlook-calendar.ts +42 -2
  962. package/src/watcher/watcher-store.ts +31 -0
  963. package/src/workspace/git-service.ts +23 -4
  964. package/src/workspace/migrations/003-seed-device-id.ts +9 -3
  965. package/src/workspace/migrations/017-seed-persona-dirs.ts +68 -4
  966. package/src/workspace/migrations/029-seed-pkb.ts +1 -1
  967. package/src/workspace/migrations/031-drop-user-md.ts +317 -0
  968. package/src/workspace/migrations/031-llm-log-retention-zero-to-null.ts +73 -0
  969. package/src/workspace/migrations/032-tts-provider-unification.ts +227 -0
  970. package/src/workspace/migrations/033-stt-service-explicit-config.ts +122 -0
  971. package/src/workspace/migrations/034-remove-calls-voice-transcription-provider.ts +215 -0
  972. package/src/workspace/migrations/035-seed-slack-channel-persona.ts +50 -0
  973. package/src/workspace/migrations/036-update-pkb-index-bar.ts +37 -0
  974. package/src/workspace/migrations/037-create-meets-dir.ts +61 -0
  975. package/src/workspace/migrations/038-unify-llm-callsite-configs.ts +516 -0
  976. package/src/workspace/migrations/039-drop-legacy-llm-keys.ts +171 -0
  977. package/src/workspace/migrations/040-seed-latency-callsite-defaults.ts +154 -0
  978. package/src/workspace/migrations/041-backfill-google-gmail-settings-scope.ts +57 -0
  979. package/src/workspace/migrations/042-fix-backfill-google-gmail-settings-scope.ts +70 -0
  980. package/src/workspace/migrations/043-release-notes-latex-rendering.ts +75 -0
  981. package/src/workspace/migrations/044-bump-stale-provider-stream-timeout.ts +51 -0
  982. package/src/workspace/migrations/045-release-notes-meet-avatar.ts +130 -0
  983. package/src/workspace/migrations/AGENTS.md +1 -1
  984. package/src/workspace/migrations/registry.ts +32 -0
  985. package/src/workspace/provider-commit-message-generator.ts +19 -38
  986. package/src/workspace/top-level-renderer.ts +13 -1
  987. package/src/workspace/turn-commit.ts +31 -0
  988. package/src/__tests__/email-cli.test.ts +0 -297
  989. package/src/__tests__/email-service-config-fallback.test.ts +0 -102
  990. package/src/__tests__/outlook-attachments.test.ts +0 -301
  991. package/src/__tests__/outlook-automation-tools.test.ts +0 -425
  992. package/src/__tests__/outlook-categories.test.ts +0 -212
  993. package/src/__tests__/outlook-compose-tools.test.ts +0 -325
  994. package/src/__tests__/outlook-declutter-tools.test.ts +0 -585
  995. package/src/__tests__/outlook-follow-up.test.ts +0 -196
  996. package/src/__tests__/outlook-trash.test.ts +0 -77
  997. package/src/__tests__/outlook-unsubscribe.test.ts +0 -250
  998. package/src/__tests__/update-bulletin-format.test.ts +0 -122
  999. package/src/__tests__/update-bulletin-state.test.ts +0 -135
  1000. package/src/__tests__/update-bulletin.test.ts +0 -277
  1001. package/src/__tests__/update-template-contract.test.ts +0 -29
  1002. package/src/cli/commands/browser-relay.ts +0 -466
  1003. package/src/cli/commands/doctor.ts +0 -341
  1004. package/src/config/bundled-skills/browser/SKILL.md +0 -63
  1005. package/src/config/bundled-skills/browser/TOOLS.json +0 -393
  1006. package/src/config/bundled-skills/browser/tools/browser-click.ts +0 -12
  1007. package/src/config/bundled-skills/browser/tools/browser-close.ts +0 -12
  1008. package/src/config/bundled-skills/browser/tools/browser-extract.ts +0 -12
  1009. package/src/config/bundled-skills/browser/tools/browser-fill-credential.ts +0 -12
  1010. package/src/config/bundled-skills/browser/tools/browser-hover.ts +0 -12
  1011. package/src/config/bundled-skills/browser/tools/browser-navigate.ts +0 -12
  1012. package/src/config/bundled-skills/browser/tools/browser-press-key.ts +0 -12
  1013. package/src/config/bundled-skills/browser/tools/browser-screenshot.ts +0 -12
  1014. package/src/config/bundled-skills/browser/tools/browser-scroll.ts +0 -12
  1015. package/src/config/bundled-skills/browser/tools/browser-select-option.ts +0 -12
  1016. package/src/config/bundled-skills/browser/tools/browser-snapshot.ts +0 -12
  1017. package/src/config/bundled-skills/browser/tools/browser-type.ts +0 -12
  1018. package/src/config/bundled-skills/browser/tools/browser-wait-for-download.ts +0 -32
  1019. package/src/config/bundled-skills/browser/tools/browser-wait-for.ts +0 -12
  1020. package/src/config/bundled-skills/chatgpt-import/SKILL.md +0 -27
  1021. package/src/config/bundled-skills/chatgpt-import/TOOLS.json +0 -27
  1022. package/src/config/bundled-skills/chatgpt-import/tools/chatgpt-import.ts +0 -378
  1023. package/src/config/bundled-skills/gmail/SKILL.md +0 -175
  1024. package/src/config/bundled-skills/gmail/TOOLS.json +0 -558
  1025. package/src/config/bundled-skills/gmail/tools/gmail-archive.ts +0 -149
  1026. package/src/config/bundled-skills/gmail/tools/gmail-attachments.ts +0 -112
  1027. package/src/config/bundled-skills/gmail/tools/gmail-draft.ts +0 -44
  1028. package/src/config/bundled-skills/gmail/tools/gmail-filters.ts +0 -81
  1029. package/src/config/bundled-skills/gmail/tools/gmail-follow-up.ts +0 -108
  1030. package/src/config/bundled-skills/gmail/tools/gmail-forward.ts +0 -146
  1031. package/src/config/bundled-skills/gmail/tools/gmail-label.ts +0 -53
  1032. package/src/config/bundled-skills/gmail/tools/gmail-outreach-scan.ts +0 -220
  1033. package/src/config/bundled-skills/gmail/tools/gmail-send-draft.ts +0 -26
  1034. package/src/config/bundled-skills/gmail/tools/gmail-sender-digest.ts +0 -251
  1035. package/src/config/bundled-skills/gmail/tools/gmail-trash.ts +0 -29
  1036. package/src/config/bundled-skills/gmail/tools/gmail-unsubscribe.ts +0 -122
  1037. package/src/config/bundled-skills/gmail/tools/gmail-vacation.ts +0 -67
  1038. package/src/config/bundled-skills/gmail/tools/scan-result-store.ts +0 -100
  1039. package/src/config/bundled-skills/gmail/tools/shared.ts +0 -47
  1040. package/src/config/bundled-skills/google-calendar/SKILL.md +0 -51
  1041. package/src/config/bundled-skills/google-calendar/TOOLS.json +0 -226
  1042. package/src/config/bundled-skills/google-calendar/calendar-client.ts +0 -223
  1043. package/src/config/bundled-skills/google-calendar/tools/calendar-check-availability.ts +0 -27
  1044. package/src/config/bundled-skills/google-calendar/tools/calendar-create-event.ts +0 -48
  1045. package/src/config/bundled-skills/google-calendar/tools/calendar-get-event.ts +0 -19
  1046. package/src/config/bundled-skills/google-calendar/tools/calendar-list-events.ts +0 -36
  1047. package/src/config/bundled-skills/google-calendar/tools/calendar-rsvp.ts +0 -58
  1048. package/src/config/bundled-skills/google-calendar/tools/shared.ts +0 -17
  1049. package/src/config/bundled-skills/google-calendar/types.ts +0 -97
  1050. package/src/config/bundled-skills/outlook/SKILL.md +0 -196
  1051. package/src/config/bundled-skills/outlook/TOOLS.json +0 -530
  1052. package/src/config/bundled-skills/outlook/tools/outlook-attachments.ts +0 -85
  1053. package/src/config/bundled-skills/outlook/tools/outlook-categories.ts +0 -77
  1054. package/src/config/bundled-skills/outlook/tools/outlook-draft.ts +0 -84
  1055. package/src/config/bundled-skills/outlook/tools/outlook-follow-up.ts +0 -94
  1056. package/src/config/bundled-skills/outlook/tools/outlook-forward.ts +0 -49
  1057. package/src/config/bundled-skills/outlook/tools/outlook-outreach-scan.ts +0 -237
  1058. package/src/config/bundled-skills/outlook/tools/outlook-rules.ts +0 -161
  1059. package/src/config/bundled-skills/outlook/tools/outlook-send-draft.ts +0 -32
  1060. package/src/config/bundled-skills/outlook/tools/outlook-sender-digest.ts +0 -272
  1061. package/src/config/bundled-skills/outlook/tools/outlook-trash.ts +0 -29
  1062. package/src/config/bundled-skills/outlook/tools/outlook-unsubscribe.ts +0 -129
  1063. package/src/config/bundled-skills/outlook/tools/outlook-vacation.ts +0 -87
  1064. package/src/config/bundled-skills/outlook/tools/shared.ts +0 -20
  1065. package/src/config/bundled-skills/outlook-calendar/SKILL.md +0 -51
  1066. package/src/config/bundled-skills/outlook-calendar/TOOLS.json +0 -221
  1067. package/src/config/bundled-skills/outlook-calendar/calendar-client.ts +0 -252
  1068. package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-check-availability.ts +0 -53
  1069. package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-create-event.ts +0 -74
  1070. package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-get-event.ts +0 -18
  1071. package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-list-events.ts +0 -46
  1072. package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-rsvp.ts +0 -36
  1073. package/src/config/bundled-skills/outlook-calendar/tools/shared.ts +0 -17
  1074. package/src/config/bundled-skills/outlook-calendar/types.ts +0 -120
  1075. package/src/config/bundled-skills/slack/SKILL.md +0 -107
  1076. package/src/config/bundled-skills/tasks/SKILL.md +0 -37
  1077. package/src/config/bundled-skills/tasks/TOOLS.json +0 -353
  1078. package/src/config/bundled-skills/tasks/icon.svg +0 -34
  1079. package/src/config/bundled-skills/tasks/tools/task-delete.ts +0 -12
  1080. package/src/config/bundled-skills/tasks/tools/task-list-add.ts +0 -12
  1081. package/src/config/bundled-skills/tasks/tools/task-list-remove.ts +0 -12
  1082. package/src/config/bundled-skills/tasks/tools/task-list-show.ts +0 -12
  1083. package/src/config/bundled-skills/tasks/tools/task-list-update.ts +0 -12
  1084. package/src/config/bundled-skills/tasks/tools/task-list.ts +0 -12
  1085. package/src/config/bundled-skills/tasks/tools/task-queue-run.ts +0 -12
  1086. package/src/config/bundled-skills/tasks/tools/task-run.ts +0 -12
  1087. package/src/config/bundled-skills/tasks/tools/task-save.ts +0 -12
  1088. package/src/config/bundled-skills/watcher/SKILL.md +0 -31
  1089. package/src/config/bundled-skills/watcher/TOOLS.json +0 -167
  1090. package/src/config/bundled-skills/watcher/tools/watcher-create.ts +0 -12
  1091. package/src/config/bundled-skills/watcher/tools/watcher-delete.ts +0 -12
  1092. package/src/config/bundled-skills/watcher/tools/watcher-digest.ts +0 -12
  1093. package/src/config/bundled-skills/watcher/tools/watcher-list.ts +0 -12
  1094. package/src/config/bundled-skills/watcher/tools/watcher-update.ts +0 -12
  1095. package/src/email/guardrails.ts +0 -221
  1096. package/src/email/provider.ts +0 -117
  1097. package/src/email/providers/agentmail.ts +0 -361
  1098. package/src/email/providers/index.ts +0 -65
  1099. package/src/email/service.ts +0 -384
  1100. package/src/email/types.ts +0 -126
  1101. package/src/prompts/templates/UPDATES.md +0 -38
  1102. package/src/prompts/templates/USER.md +0 -13
  1103. package/src/prompts/update-bulletin-format.ts +0 -68
  1104. package/src/prompts/update-bulletin-state.ts +0 -58
  1105. package/src/prompts/update-bulletin-template-path.ts +0 -13
  1106. package/src/prompts/update-bulletin.ts +0 -128
  1107. package/src/providers/speech-to-text/types.ts +0 -17
  1108. package/src/runtime/routes/browser-cdp-routes.ts +0 -229
  1109. package/src/shared/provider-env-vars.ts +0 -19
  1110. package/src/tools/watcher/create.ts +0 -86
  1111. package/src/tools/watcher/delete.ts +0 -36
  1112. package/src/tools/watcher/digest.ts +0 -54
  1113. package/src/tools/watcher/list.ts +0 -83
  1114. package/src/tools/watcher/update.ts +0 -71
@@ -1,17 +1,13 @@
1
1
  import { createHash } from "node:crypto";
2
2
  import { homedir } from "node:os";
3
- import { dirname, join, resolve } from "node:path";
3
+ import { dirname, resolve } from "node:path";
4
4
 
5
5
  import { isAssistantFeatureFlagEnabled } from "../config/assistant-feature-flags.js";
6
6
  import { getIsContainerized } from "../config/env-registry.js";
7
7
  import { getConfig } from "../config/loader.js";
8
8
  import { loadSkillCatalog, resolveSkillSelector } from "../config/skills.js";
9
9
  import { indexCatalogById } from "../skills/include-graph.js";
10
- import {
11
- isSkillSourcePath,
12
- normalizeDirPath,
13
- normalizeFilePath,
14
- } from "../skills/path-classifier.js";
10
+ import { normalizeFilePath } from "../skills/path-classifier.js";
15
11
  import { computeTransitiveSkillVersionHash } from "../skills/transitive-version-hash.js";
16
12
  import { computeSkillVersionHash } from "../skills/version-hash.js";
17
13
  import type { ManifestOverride } from "../tools/execution-target.js";
@@ -20,13 +16,21 @@ import {
20
16
  looksLikePathOnlyInput,
21
17
  } from "../tools/network/url-safety.js";
22
18
  import { getTool } from "../tools/registry.js";
23
- import { getDeprecatedDir, getWorkspaceHooksDir } from "../util/platform.js";
19
+ import {
20
+ type ApprovalContext,
21
+ DefaultApprovalPolicy,
22
+ resolveThreshold,
23
+ } from "./approval-policy.js";
24
+ import { bashRiskClassifier } from "./bash-risk-classifier.js";
25
+ import { fileRiskClassifier } from "./file-risk-classifier.js";
26
+ import { type RiskAssessment, riskToRiskLevel } from "./risk-types.js";
24
27
  import {
25
28
  buildShellAllowlistOptions,
26
29
  buildShellCommandCandidates,
27
30
  cachedParse,
28
31
  type ParsedCommand,
29
32
  } from "./shell-identity.js";
33
+ import { skillLoadRiskClassifier } from "./skill-risk-classifier.js";
30
34
  import { findHighestPriorityRule, onRulesChanged } from "./trust-store.js";
31
35
  import {
32
36
  type AllowlistOption,
@@ -35,6 +39,7 @@ import {
35
39
  RiskLevel,
36
40
  type ScopeOption,
37
41
  } from "./types.js";
42
+ import { webRiskClassifier } from "./web-risk-classifier.js";
38
43
  import { isWorkspaceScopedInvocation } from "./workspace-policy.js";
39
44
 
40
45
  // ── Risk classification cache ────────────────────────────────────────────────
@@ -44,10 +49,35 @@ import { isWorkspaceScopedInvocation } from "./workspace-policy.js";
44
49
  // Invalidated when trust rules change since risk classification for file tools
45
50
  // depends on skill source path checks which reference config, but the core
46
51
  // risk logic is input-deterministic.
52
+ /** The result of classifyRisk(): a risk level with an optional human-readable reason. */
53
+ export interface RiskClassification {
54
+ level: RiskLevel;
55
+ /** Human-readable explanation of why this risk level was assigned. */
56
+ reason?: string;
57
+ }
58
+
47
59
  const RISK_CACHE_MAX = 256;
48
- const riskCache = new Map<string, RiskLevel>();
60
+ const riskCache = new Map<string, RiskClassification>();
49
61
  let riskCacheInvalidationHookRegistered = false;
50
62
 
63
+ // ── Assessment cache ─────────────────────────────────────────────────────────
64
+ // Stores the full RiskAssessment from classifier-backed tools so that
65
+ // generateAllowlistOptions() can read classifier-produced allowlistOptions
66
+ // without re-classifying. Keyed on (toolName, inputHash) — a simpler key
67
+ // than the full risk cache since generateAllowlistOptions() does not receive
68
+ // workingDir or manifestOverride. Cleared alongside the risk cache.
69
+ const assessmentCache = new Map<string, RiskAssessment>();
70
+
71
+ function assessmentCacheKey(
72
+ toolName: string,
73
+ input: Record<string, unknown>,
74
+ ): string {
75
+ const { reason: _reason, activity: _activity, ...cacheableInput } = input;
76
+ const inputJson = JSON.stringify(cacheableInput);
77
+ const hash = createHash("sha256").update(inputJson).digest("hex");
78
+ return `${toolName}\0${hash}`;
79
+ }
80
+
51
81
  function riskCacheKey(
52
82
  toolName: string,
53
83
  input: Record<string, unknown>,
@@ -72,6 +102,7 @@ function riskCacheKey(
72
102
  /** Clear the risk classification cache. Called when trust rules change. */
73
103
  function clearRiskCache(): void {
74
104
  riskCache.clear();
105
+ assessmentCache.clear();
75
106
  }
76
107
 
77
108
  function ensureRiskCacheInvalidationHook(): void {
@@ -82,319 +113,8 @@ function ensureRiskCacheInvalidationHook(): void {
82
113
  onRulesChanged(clearRiskCache);
83
114
  }
84
115
 
85
- // Low-risk shell programs that are read-only / informational
86
- const LOW_RISK_PROGRAMS = new Set([
87
- "ls",
88
- "cat",
89
- "head",
90
- "tail",
91
- "less",
92
- "more",
93
- "wc",
94
- "file",
95
- "stat",
96
- "grep",
97
- "rg",
98
- "ag",
99
- "ack",
100
- "find",
101
- "fd",
102
- "which",
103
- "where",
104
- "whereis",
105
- "type",
106
- "echo",
107
- "printf",
108
- "date",
109
- "cal",
110
- "uptime",
111
- "whoami",
112
- "hostname",
113
- "uname",
114
- "pwd",
115
- "realpath",
116
- "dirname",
117
- "basename",
118
- "git",
119
- "node",
120
- "bun",
121
- "deno",
122
- "npm",
123
- "npx",
124
- "yarn",
125
- "pnpm",
126
- "python",
127
- "python3",
128
- "pip",
129
- "pip3",
130
- "man",
131
- "help",
132
- "info",
133
- "env",
134
- "printenv",
135
- "set",
136
- "diff",
137
- "sort",
138
- "uniq",
139
- "cut",
140
- "tr",
141
- "tee",
142
- "xargs",
143
- "jq",
144
- "yq",
145
- "http",
146
- "dig",
147
- "nslookup",
148
- "ping",
149
- "tree",
150
- "du",
151
- "df",
152
- ]);
153
-
154
- // High-risk shell programs / patterns
155
- const HIGH_RISK_PROGRAMS = new Set([
156
- "sudo",
157
- "su",
158
- "doas",
159
- "dd",
160
- "mkfs",
161
- "fdisk",
162
- "parted",
163
- "mount",
164
- "umount",
165
- "systemctl",
166
- "service",
167
- "launchctl",
168
- "useradd",
169
- "userdel",
170
- "usermod",
171
- "groupadd",
172
- "groupdel",
173
- "iptables",
174
- "ufw",
175
- "firewall-cmd",
176
- "reboot",
177
- "shutdown",
178
- "halt",
179
- "poweroff",
180
- "kill",
181
- "killall",
182
- "pkill",
183
- ]);
184
-
185
- // Git subcommands that are low-risk (read-only)
186
- const LOW_RISK_GIT_SUBCOMMANDS = new Set([
187
- "status",
188
- "log",
189
- "diff",
190
- "show",
191
- "branch",
192
- "tag",
193
- "remote",
194
- "stash",
195
- "blame",
196
- "shortlog",
197
- "describe",
198
- "rev-parse",
199
- "ls-files",
200
- "ls-tree",
201
- "cat-file",
202
- "reflog",
203
- ]);
204
-
205
- /**
206
- * Classify risk for `assistant` CLI subcommands. Multi-word subcommands
207
- * (e.g. `assistant oauth token`) are matched by walking the positional args.
208
- */
209
- function classifyAssistantSubcommand(args: string[]): RiskLevel {
210
- const sub = firstPositionalArg(args);
211
- if (!sub) return RiskLevel.Low;
212
-
213
- if (sub === "oauth") {
214
- const oauthSub = firstPositionalArg(args.slice(args.indexOf(sub) + 1));
215
- if (oauthSub === "token") return RiskLevel.High;
216
- if (oauthSub === "mode") {
217
- // `oauth mode --set` is high risk; bare `oauth mode` (read) is low.
218
- // Match both `--set value` (two tokens) and `--set=value` (one token).
219
- if (args.some((a) => a === "--set" || a.startsWith("--set=")))
220
- return RiskLevel.High;
221
- return RiskLevel.Low;
222
- }
223
- if (oauthSub === "request") return RiskLevel.Medium;
224
- if (oauthSub === "connect" || oauthSub === "disconnect")
225
- return RiskLevel.Medium;
226
- return RiskLevel.Low;
227
- }
228
-
229
- if (sub === "credentials") {
230
- const credSub = firstPositionalArg(args.slice(args.indexOf(sub) + 1));
231
- if (credSub === "reveal") return RiskLevel.High;
232
- if (credSub === "set" || credSub === "delete") return RiskLevel.High;
233
- return RiskLevel.Low;
234
- }
235
-
236
- if (sub === "keys") {
237
- const keysSub = firstPositionalArg(args.slice(args.indexOf(sub) + 1));
238
- if (keysSub === "set" || keysSub === "delete") return RiskLevel.High;
239
- return RiskLevel.Low;
240
- }
241
-
242
- if (sub === "trust") {
243
- const trustSub = firstPositionalArg(args.slice(args.indexOf(sub) + 1));
244
- if (trustSub === "remove" || trustSub === "clear") return RiskLevel.High;
245
- return RiskLevel.Low;
246
- }
247
-
248
- return RiskLevel.Low;
249
- }
250
-
251
- // Commands that wrap another program — the real program appears as the first
252
- // non-flag argument. When one of these is the segment program we look through
253
- // its args to find the effective program (e.g. `env curl …` → curl).
254
- const WRAPPER_PROGRAMS = new Set([
255
- "env",
256
- "nice",
257
- "nohup",
258
- "time",
259
- "command",
260
- "exec",
261
- "strace",
262
- "ltrace",
263
- "ionice",
264
- "taskset",
265
- "timeout",
266
- ]);
267
-
268
- // `env` flags that consume the next positional argument as their value.
269
- // Without this, `env -u curl echo` would incorrectly identify `curl` (the
270
- // value of -u) as the wrapped program instead of `echo`.
271
- const ENV_VALUE_FLAGS = new Set(["-u", "--unset", "-C", "--chdir"]);
272
-
273
- // `timeout` flags that consume the next positional argument as their value.
274
- const TIMEOUT_VALUE_FLAGS = new Set(["-s", "--signal", "-k", "--kill-after"]);
275
-
276
- // Wrapper programs where the first non-flag positional argument is a
277
- // configuration value (duration, CPU mask), not the wrapped program name.
278
- // For these wrappers, the second non-flag positional is the real program.
279
- const WRAPPER_SKIP_FIRST_POSITIONAL = new Set(["timeout", "taskset"]);
280
-
281
- // `git` global flags that consume the next positional argument as their value.
282
- // Without this, `git -C status commit` would incorrectly identify `status`
283
- // (the directory path) as the subcommand instead of `commit`.
284
- const GIT_VALUE_FLAGS = new Set([
285
- "-C",
286
- "-c",
287
- "--git-dir",
288
- "--work-tree",
289
- "--namespace",
290
- "--super-prefix",
291
- "--config-env",
292
- ]);
293
-
294
- /**
295
- * Return the first non-flag argument from an argument list, optionally
296
- * skipping value-taking flags. Flags are arguments that start with `-`.
297
- * This is used to skip global options (e.g. `--verbose`, `-h`, `-C <path>`)
298
- * when extracting the subcommand from CLIs like `git`, `vellum`, and
299
- * `assistant`.
300
- *
301
- * When `valueFlags` is provided, any flag in that set causes the next
302
- * argument to be skipped as well (it is the flag's value, not a positional).
303
- */
304
- function firstPositionalArg(
305
- args: string[],
306
- valueFlags?: Set<string>,
307
- ): string | undefined {
308
- for (let i = 0; i < args.length; i++) {
309
- const arg = args[i];
310
- if (arg.startsWith("-")) {
311
- if (valueFlags?.has(arg)) i++; // skip the next arg (the flag's value)
312
- continue;
313
- }
314
- return arg;
315
- }
316
- return undefined;
317
- }
318
-
319
- // Bare filenames that `rm` is allowed to delete at Medium risk (instead of
320
- // High) so workspace-scoped allow rules can approve them without the
321
- // dangerous `allowHighRisk` flag. Only matches when the args contain no
322
- // flags and exactly one of these filenames.
323
- const RM_SAFE_BARE_FILES = new Set(["BOOTSTRAP.md", "UPDATES.md"]);
324
-
325
- function isRmOfKnownSafeFile(args: string[]): boolean {
326
- if (args.length !== 1) return false;
327
- const target = args[0];
328
- if (target.startsWith("-") || target.includes("/")) return false;
329
- return RM_SAFE_BARE_FILES.has(target);
330
- }
331
-
332
- /**
333
- * Given a segment whose program is a known wrapper, return the first
334
- * non-flag argument (i.e. the wrapped program name). Returns `undefined`
335
- * when no suitable argument is found.
336
- *
337
- * Handles `env` specially: skips `VAR=value` pairs and value-taking flags
338
- * like `-u NAME` and `-C DIR`.
339
- *
340
- * Handles `timeout` and `taskset` specially: their first non-flag positional
341
- * argument is a duration or CPU mask, not the wrapped program. The second
342
- * non-flag positional is the real program.
343
- */
344
- function getWrappedProgram(seg: {
345
- program: string;
346
- args: string[];
347
- }): string | undefined {
348
- const isEnv = seg.program === "env";
349
- const isTimeout = seg.program === "timeout";
350
- const skipFirst = WRAPPER_SKIP_FIRST_POSITIONAL.has(seg.program);
351
- let skippedFirstPositional = false;
352
- for (let i = 0; i < seg.args.length; i++) {
353
- const arg = seg.args[i];
354
- if (arg.startsWith("-")) {
355
- if (isEnv && ENV_VALUE_FLAGS.has(arg)) i++; // skip the value argument
356
- if (isTimeout && TIMEOUT_VALUE_FLAGS.has(arg)) i++; // skip the value argument
357
- continue;
358
- }
359
- if (isEnv && arg.includes("=")) continue; // skip env VAR=value pairs
360
- if (skipFirst && !skippedFirstPositional) {
361
- skippedFirstPositional = true;
362
- continue; // skip the duration/CPU mask
363
- }
364
- return arg;
365
- }
366
- return undefined;
367
- }
368
-
369
- /**
370
- * Like `getWrappedProgram`, but also returns the remaining args after the
371
- * wrapped program name. This allows callers to propagate subcommand-aware
372
- * classification (e.g. `env assistant oauth token` → classify `oauth token`).
373
- */
374
- function getWrappedProgramWithArgs(seg: {
375
- program: string;
376
- args: string[];
377
- }): { program: string; args: string[] } | undefined {
378
- const isEnv = seg.program === "env";
379
- const isTimeout = seg.program === "timeout";
380
- const skipFirst = WRAPPER_SKIP_FIRST_POSITIONAL.has(seg.program);
381
- let skippedFirstPositional = false;
382
- for (let i = 0; i < seg.args.length; i++) {
383
- const arg = seg.args[i];
384
- if (arg.startsWith("-")) {
385
- if (isEnv && ENV_VALUE_FLAGS.has(arg)) i++;
386
- if (isTimeout && TIMEOUT_VALUE_FLAGS.has(arg)) i++;
387
- continue;
388
- }
389
- if (isEnv && arg.includes("=")) continue;
390
- if (skipFirst && !skippedFirstPositional) {
391
- skippedFirstPositional = true;
392
- continue; // skip the duration/CPU mask
393
- }
394
- return { program: arg, args: seg.args.slice(i + 1) };
395
- }
396
- return undefined;
397
- }
116
+ // ── Approval policy singleton ────────────────────────────────────────────────
117
+ const defaultApprovalPolicy = new DefaultApprovalPolicy();
398
118
 
399
119
  function getStringField(
400
120
  input: Record<string, unknown>,
@@ -578,11 +298,7 @@ async function buildCommandCandidates(
578
298
  return [`${toolName}:${skillId}`];
579
299
  }
580
300
 
581
- if (
582
- toolName === "web_fetch" ||
583
- toolName === "browser_navigate" ||
584
- toolName === "network_request"
585
- ) {
301
+ if (toolName === "web_fetch" || toolName === "network_request") {
586
302
  const rawUrl = getStringField(input, "url").trim();
587
303
  const candidates: string[] = [];
588
304
 
@@ -659,7 +375,7 @@ export async function classifyRisk(
659
375
  preParsed?: ParsedCommand,
660
376
  manifestOverride?: ManifestOverride,
661
377
  signal?: AbortSignal,
662
- ): Promise<RiskLevel> {
378
+ ): Promise<RiskClassification> {
663
379
  signal?.throwIfAborted();
664
380
  ensureRiskCacheInvalidationHook();
665
381
 
@@ -678,13 +394,98 @@ export async function classifyRisk(
678
394
  }
679
395
  }
680
396
 
681
- let result = await classifyRiskUncached(
682
- toolName,
683
- input,
684
- workingDir,
685
- preParsed,
686
- manifestOverride,
687
- );
397
+ // ── Bash/host_bash: delegate to the registry-driven BashRiskClassifier ────
398
+ let result: RiskClassification;
399
+ let classifierAssessment: RiskAssessment | undefined;
400
+ if (toolName === "bash" || toolName === "host_bash") {
401
+ const command = ((input.command as string) ?? "").trim();
402
+ if (!command) {
403
+ result = { level: RiskLevel.Low };
404
+ } else {
405
+ const assessment = await bashRiskClassifier.classify({
406
+ command,
407
+ toolName: toolName as "bash" | "host_bash",
408
+ });
409
+ classifierAssessment = assessment;
410
+ result = {
411
+ level: riskToRiskLevel(assessment.riskLevel),
412
+ reason: assessment.reason,
413
+ };
414
+ }
415
+ }
416
+ // ── File tools: delegate to FileRiskClassifier ──────────────────────────
417
+ else if (
418
+ [
419
+ "file_read",
420
+ "file_write",
421
+ "file_edit",
422
+ "host_file_read",
423
+ "host_file_write",
424
+ "host_file_edit",
425
+ ].includes(toolName)
426
+ ) {
427
+ const filePath = getStringField(input, "path", "file_path");
428
+ const isHostTool = toolName.startsWith("host_");
429
+ const assessment = await fileRiskClassifier.classify({
430
+ toolName: toolName as
431
+ | "file_read"
432
+ | "file_write"
433
+ | "file_edit"
434
+ | "host_file_read"
435
+ | "host_file_write"
436
+ | "host_file_edit",
437
+ filePath,
438
+ workingDir: isHostTool ? "/" : (workingDir ?? process.cwd()),
439
+ });
440
+ classifierAssessment = assessment;
441
+ result = {
442
+ level: riskToRiskLevel(assessment.riskLevel),
443
+ reason: assessment.reason,
444
+ };
445
+ }
446
+ // ── Web tools: delegate to WebRiskClassifier ────────────────────────────
447
+ else if (["web_fetch", "network_request", "web_search"].includes(toolName)) {
448
+ const assessment = await webRiskClassifier.classify({
449
+ toolName: toolName as "web_fetch" | "network_request" | "web_search",
450
+ url: getStringField(input, "url"),
451
+ allowPrivateNetwork: input.allow_private_network === true,
452
+ });
453
+ classifierAssessment = assessment;
454
+ result = {
455
+ level: riskToRiskLevel(assessment.riskLevel),
456
+ reason: assessment.reason,
457
+ };
458
+ }
459
+ // ── Skill tools: delegate to SkillLoadRiskClassifier ────────────────────
460
+ else if (
461
+ ["skill_load", "scaffold_managed_skill", "delete_managed_skill"].includes(
462
+ toolName,
463
+ )
464
+ ) {
465
+ const assessment = await skillLoadRiskClassifier.classify({
466
+ toolName: toolName as
467
+ | "skill_load"
468
+ | "scaffold_managed_skill"
469
+ | "delete_managed_skill",
470
+ skillSelector: getStringField(input, "skill", "skill_id").trim(),
471
+ });
472
+ classifierAssessment = assessment;
473
+ result = {
474
+ level: riskToRiskLevel(assessment.riskLevel),
475
+ reason: assessment.reason,
476
+ };
477
+ }
478
+ // ── Remaining tools: fall through to registry-based classification ──────
479
+ else {
480
+ result = {
481
+ level: await classifyRiskFromRegistry(
482
+ toolName,
483
+ input,
484
+ workingDir,
485
+ manifestOverride,
486
+ ),
487
+ };
488
+ }
688
489
 
689
490
  // Proxied bash commands route through the credential proxy which handles
690
491
  // per-request approval separately. Cap the bash tool's own risk at Medium
@@ -692,9 +493,9 @@ export async function classifyRisk(
692
493
  if (
693
494
  toolName === "bash" &&
694
495
  input.network_mode === "proxied" &&
695
- result === RiskLevel.High
496
+ result.level === RiskLevel.High
696
497
  ) {
697
- result = RiskLevel.Medium;
498
+ result = { level: RiskLevel.Medium, reason: result.reason };
698
499
  }
699
500
 
700
501
  if (cacheKey) {
@@ -705,237 +506,26 @@ export async function classifyRisk(
705
506
  riskCache.set(cacheKey, result);
706
507
  }
707
508
 
509
+ // Store the full assessment in a separate cache keyed on (toolName, input)
510
+ // so generateAllowlistOptions() can retrieve classifier-produced options.
511
+ if (classifierAssessment) {
512
+ const aKey = assessmentCacheKey(toolName, input);
513
+ if (assessmentCache.size >= RISK_CACHE_MAX) {
514
+ const oldest = assessmentCache.keys().next().value;
515
+ if (oldest !== undefined) assessmentCache.delete(oldest);
516
+ }
517
+ assessmentCache.set(aKey, classifierAssessment);
518
+ }
519
+
708
520
  return result;
709
521
  }
710
522
 
711
- async function classifyRiskUncached(
523
+ async function classifyRiskFromRegistry(
712
524
  toolName: string,
713
- input: Record<string, unknown>,
714
- workingDir?: string,
715
- preParsed?: ParsedCommand,
525
+ _input: Record<string, unknown>,
526
+ _workingDir?: string,
716
527
  manifestOverride?: ManifestOverride,
717
528
  ): Promise<RiskLevel> {
718
- if (toolName === "file_read") {
719
- const filePath = getStringField(input, "path", "file_path");
720
- if (isActorTokenSigningKeyPath(filePath, workingDir)) {
721
- return RiskLevel.High;
722
- }
723
- return RiskLevel.Low;
724
- }
725
- if (toolName === "file_write" || toolName === "file_edit") {
726
- const filePath = getStringField(input, "path", "file_path");
727
- if (
728
- filePath &&
729
- isSkillSourcePath(
730
- resolve(workingDir ?? process.cwd(), filePath),
731
- getConfig().skills.load.extraDirs,
732
- )
733
- ) {
734
- return RiskLevel.High;
735
- }
736
- if (filePath) {
737
- const normalizedHooksDir = normalizeDirPath(getWorkspaceHooksDir());
738
- const normalizedPath = normalizeFilePath(
739
- resolve(workingDir ?? process.cwd(), filePath),
740
- );
741
- const hooksDirNoTrailingSlash = normalizedHooksDir.slice(0, -1);
742
- if (
743
- normalizedPath === hooksDirNoTrailingSlash ||
744
- normalizedPath.startsWith(normalizedHooksDir)
745
- ) {
746
- return RiskLevel.High;
747
- }
748
- }
749
- return RiskLevel.Low;
750
- }
751
- if (toolName === "web_search") return RiskLevel.Low;
752
- if (toolName === "web_fetch") {
753
- // Private-network fetches are High risk so that blanket allow rules
754
- // (including the starter bundle) cannot silently bypass the prompt.
755
- return input.allow_private_network === true
756
- ? RiskLevel.High
757
- : RiskLevel.Low;
758
- }
759
- if (toolName === "browser_navigate") {
760
- return input.allow_private_network === true
761
- ? RiskLevel.High
762
- : RiskLevel.Low;
763
- }
764
- // All other browser tools are low risk — the browser is sandboxed and user-visible.
765
- if (toolName.startsWith("browser_")) return RiskLevel.Low;
766
- // Proxy-authenticated network requests are Medium risk — they carry injected
767
- // credentials and the user should approve the target host/origin.
768
- if (toolName === "network_request") return RiskLevel.Medium;
769
- if (toolName === "skill_load") return RiskLevel.Low;
770
-
771
- // Skill mutation tools are always High risk — they write or delete persistent
772
- // skill source code. These tools moved from core tool registry to bundled
773
- // skills, but their security classification must remain High regardless of
774
- // whether they appear in the tool registry.
775
- if (
776
- toolName === "scaffold_managed_skill" ||
777
- toolName === "delete_managed_skill"
778
- ) {
779
- return RiskLevel.High;
780
- }
781
-
782
- // Escalate host file mutations targeting skill source paths to High risk.
783
- // The host variants fall through to the tool registry (Medium) by default,
784
- // but writing to skill source code is a privilege-escalation vector.
785
- if (toolName === "host_file_write" || toolName === "host_file_edit") {
786
- const filePath = getStringField(input, "path", "file_path");
787
- if (
788
- filePath &&
789
- isSkillSourcePath(resolve(filePath), getConfig().skills.load.extraDirs)
790
- ) {
791
- return RiskLevel.High;
792
- }
793
- if (filePath) {
794
- const normalizedHooksDir = normalizeDirPath(getWorkspaceHooksDir());
795
- const normalizedPath = normalizeFilePath(resolve(filePath));
796
- const hooksDirNoTrailingSlash = normalizedHooksDir.slice(0, -1);
797
- if (
798
- normalizedPath === hooksDirNoTrailingSlash ||
799
- normalizedPath.startsWith(normalizedHooksDir)
800
- ) {
801
- return RiskLevel.High;
802
- }
803
- }
804
- // Fall through to the tool registry default (Medium) below.
805
- }
806
-
807
- if (toolName === "bash" || toolName === "host_bash") {
808
- const command = (input.command as string) ?? "";
809
- if (!command.trim()) return RiskLevel.Low;
810
-
811
- const parsed = preParsed ?? (await cachedParse(command));
812
-
813
- // Dangerous patterns → High
814
- if (parsed.dangerousPatterns.length > 0) return RiskLevel.High;
815
-
816
- // Opaque constructs → at least Medium (never Low)
817
- if (parsed.hasOpaqueConstructs) return RiskLevel.Medium;
818
-
819
- // Check each segment
820
- let maxRisk = RiskLevel.Low;
821
-
822
- for (const seg of parsed.segments) {
823
- const prog = seg.program;
824
-
825
- if (HIGH_RISK_PROGRAMS.has(prog)) return RiskLevel.High;
826
-
827
- if (prog === "rm") {
828
- // Only downgrade rm of known safe workspace files for sandboxed bash.
829
- // host_bash has a global ask rule that would prompt Medium-risk
830
- // commands, so rm on the host must always require explicit approval.
831
- if (toolName === "bash" && isRmOfKnownSafeFile(seg.args)) {
832
- maxRisk = RiskLevel.Medium;
833
- continue;
834
- }
835
- return RiskLevel.High;
836
- }
837
-
838
- if (
839
- prog === "chmod" ||
840
- prog === "chown" ||
841
- prog === "chgrp" ||
842
- prog === "sed" ||
843
- prog === "awk"
844
- ) {
845
- maxRisk = RiskLevel.Medium;
846
- continue;
847
- }
848
-
849
- // curl/wget can download and execute arbitrary code from the internet.
850
- // Also catch wrapped invocations like `env curl …` or `nice wget …`.
851
- if (prog === "curl" || prog === "wget") {
852
- maxRisk = RiskLevel.Medium;
853
- continue;
854
- }
855
-
856
- if (WRAPPER_PROGRAMS.has(prog)) {
857
- // `command -v` and `command -V` are read-only lookups (print where
858
- // a command lives) — don't escalate to high risk for those.
859
- if (
860
- prog === "command" &&
861
- seg.args.length > 0 &&
862
- (seg.args[0] === "-v" || seg.args[0] === "-V")
863
- ) {
864
- continue;
865
- }
866
- const wrapped = getWrappedProgram(seg);
867
- if (wrapped === "rm") return RiskLevel.High;
868
- if (wrapped && HIGH_RISK_PROGRAMS.has(wrapped)) return RiskLevel.High;
869
- if (wrapped === "curl" || wrapped === "wget") {
870
- maxRisk = RiskLevel.Medium;
871
- continue;
872
- }
873
- // Propagate subcommand-aware classification for wrapped git/assistant
874
- if (wrapped === "git") {
875
- const wrappedWithArgs = getWrappedProgramWithArgs(seg);
876
- if (wrappedWithArgs) {
877
- const subcommand = firstPositionalArg(
878
- wrappedWithArgs.args,
879
- GIT_VALUE_FLAGS,
880
- );
881
- if (subcommand && LOW_RISK_GIT_SUBCOMMANDS.has(subcommand)) {
882
- continue;
883
- }
884
- maxRisk = RiskLevel.Medium;
885
- continue;
886
- }
887
- }
888
- if (wrapped === "assistant") {
889
- const wrappedWithArgs = getWrappedProgramWithArgs(seg);
890
- if (wrappedWithArgs) {
891
- const assistantRisk = classifyAssistantSubcommand(
892
- wrappedWithArgs.args,
893
- );
894
- if (assistantRisk === RiskLevel.High) return RiskLevel.High;
895
- if (assistantRisk === RiskLevel.Medium) {
896
- maxRisk = RiskLevel.Medium;
897
- }
898
- continue;
899
- }
900
- }
901
- }
902
-
903
- if (prog === "git") {
904
- const subcommand = firstPositionalArg(seg.args, GIT_VALUE_FLAGS);
905
- if (subcommand && LOW_RISK_GIT_SUBCOMMANDS.has(subcommand)) {
906
- // Stay at current risk
907
- continue;
908
- }
909
- // Non-read-only git commands are medium
910
- maxRisk = RiskLevel.Medium;
911
- continue;
912
- }
913
-
914
- if (prog === "assistant") {
915
- const assistantRisk = classifyAssistantSubcommand(seg.args);
916
- if (assistantRisk === RiskLevel.High) return RiskLevel.High;
917
- if (assistantRisk === RiskLevel.Medium) {
918
- maxRisk = RiskLevel.Medium;
919
- }
920
- continue;
921
- }
922
-
923
- if (!LOW_RISK_PROGRAMS.has(prog)) {
924
- // Unknown program → medium
925
- if (maxRisk === RiskLevel.Low) {
926
- maxRisk = RiskLevel.Medium;
927
- }
928
- }
929
- }
930
-
931
- // If no segments could be extracted, treat as opaque
932
- if (parsed.segments.length === 0) {
933
- return RiskLevel.Medium;
934
- }
935
-
936
- return maxRisk;
937
- }
938
-
939
529
  // Check the tool registry for a declared default risk level
940
530
  const tool = getTool(toolName);
941
531
  if (tool) return tool.defaultRiskLevel;
@@ -955,21 +545,6 @@ async function classifyRiskUncached(
955
545
  return RiskLevel.Medium;
956
546
  }
957
547
 
958
- function isActorTokenSigningKeyPath(
959
- filePath: string | undefined,
960
- workingDir?: string,
961
- ): boolean {
962
- if (!filePath) return false;
963
- const cwd = workingDir ?? process.cwd();
964
- const resolvedPath = resolve(cwd, filePath);
965
- const signingKeyPaths = [
966
- join(homedir(), ".vellum", "protected", "actor-token-signing-key"),
967
- join(getDeprecatedDir(), "actor-token-signing-key"),
968
- resolve(cwd, "deprecated", "actor-token-signing-key"),
969
- ];
970
- return signingKeyPaths.includes(resolvedPath);
971
- }
972
-
973
548
  export async function check(
974
549
  toolName: string,
975
550
  input: Record<string, unknown>,
@@ -989,7 +564,7 @@ export async function check(
989
564
  }
990
565
  }
991
566
 
992
- const risk = await classifyRisk(
567
+ const { level: risk, reason: riskReason } = await classifyRisk(
993
568
  toolName,
994
569
  input,
995
570
  workingDir,
@@ -1014,129 +589,55 @@ export async function check(
1014
589
  policyContext,
1015
590
  );
1016
591
 
1017
- // Deny rules apply at ALL risk levels — including proxied network mode.
1018
- // Evaluate them first so hard blocks are never downgraded to a prompt.
1019
- if (matchedRule && matchedRule.decision === "deny") {
1020
- return {
1021
- decision: "deny",
1022
- reason: `Blocked by deny rule: ${matchedRule.pattern}`,
1023
- matchedRule,
1024
- };
1025
- }
1026
-
1027
- if (matchedRule) {
1028
- if (matchedRule.decision === "ask") {
1029
- // Ask rules always prompt — never auto-allow or auto-deny
1030
- return {
1031
- decision: "prompt",
1032
- reason: `Matched ask rule: ${matchedRule.pattern}`,
1033
- matchedRule,
1034
- };
1035
- }
1036
-
1037
- // Allow rule: auto-allow for non-High risk
1038
- if (risk !== RiskLevel.High) {
1039
- return {
1040
- decision: "allow",
1041
- reason: `Matched trust rule: ${matchedRule.pattern}`,
1042
- matchedRule,
1043
- };
1044
- }
1045
- // High risk with allow rule that explicitly permits high-risk → auto-allow
1046
- if (matchedRule.allowHighRisk === true) {
1047
- return {
1048
- decision: "allow",
1049
- reason: `Matched high-risk trust rule: ${matchedRule.pattern}`,
1050
- matchedRule,
1051
- };
1052
- }
1053
- // High risk with allow rule (without allowHighRisk) → fall through to prompt
1054
- }
1055
-
1056
- // No matching rule (or High risk with allow rule) → risk-based fallback
1057
-
1058
- // Third-party skill-origin tools default to prompting when no trust rule
1059
- // matches, regardless of risk level. Bundled skill tools are first-party
1060
- // and trusted, so they fall through to the normal risk-based policy.
1061
- // When manifestOverride is present, the tool comes from a skill manifest
1062
- // but isn't registered — treat it as a third-party skill tool.
1063
- if (!matchedRule) {
1064
- const tool = getTool(toolName);
1065
- if (tool?.origin === "skill" && !tool.ownerSkillBundled) {
1066
- return {
1067
- decision: "prompt",
1068
- reason: "Skill tool: requires approval by default",
1069
- };
1070
- }
1071
- if (!tool && manifestOverride) {
1072
- return {
1073
- decision: "prompt",
1074
- reason: "Skill tool: requires approval by default",
1075
- };
1076
- }
1077
- }
1078
-
1079
- // In strict mode, every tool without an explicit matching rule must be
1080
- // prompted — there is no implicit auto-allow for any risk level.
1081
- // This explicitly covers skill_load: activating a skill can grant the
1082
- // agent new capabilities, so in strict mode users must approve each
1083
- // skill load via an exact-version or wildcard trust rule.
1084
- const permissionsMode = getConfig().permissions.mode;
1085
-
1086
- if (permissionsMode === "strict" && !matchedRule) {
1087
- return {
1088
- decision: "prompt",
1089
- reason: `Strict mode: no matching rule, requires approval`,
1090
- };
1091
- }
1092
-
1093
- // Workspace mode: auto-allow workspace-scoped operations that don't have
1094
- // an explicit rule, but only when risk is Low. Medium and High risk operations
1095
- // fall through to risk-based policy and always require approval.
1096
- if (
1097
- permissionsMode === "workspace" &&
1098
- !matchedRule &&
1099
- risk === RiskLevel.Low
1100
- ) {
1101
- // Outside a container, bash runs on the host — don't auto-allow
1102
- if (toolName === "bash" && !getIsContainerized()) {
1103
- // Fall through to risk-based policy below
1104
- } else if (isWorkspaceScopedInvocation(toolName, input, workingDir)) {
1105
- return {
1106
- decision: "allow",
1107
- reason: "Workspace mode: workspace-scoped operation auto-allowed",
1108
- };
1109
- }
1110
- }
1111
-
1112
- // Auto-allow low-risk bundled skill tools even without explicit trust rules.
1113
- // These are first-party tools with a vetted risk declaration — applying the
1114
- // same policy as the per-tool default allow rules for browser tools, but
1115
- // generically so every new bundled skill benefits automatically.
1116
- // This block must come AFTER the strict mode check so that strict mode
1117
- // still prompts for bundled skill tools without explicit rules.
1118
- if (!matchedRule && risk === RiskLevel.Low) {
1119
- const tool = getTool(toolName);
1120
- if (tool?.origin === "skill" && tool.ownerSkillBundled) {
1121
- return {
1122
- decision: "allow",
1123
- reason: "Bundled skill tool: low risk, auto-allowed",
1124
- };
592
+ // Build approval context from local variables
593
+ const tool = getTool(toolName);
594
+ const config = getConfig();
595
+ const resolvedThreshold = resolveThreshold(
596
+ config.permissions.autoApproveUpTo,
597
+ policyContext?.executionContext,
598
+ );
599
+ const approvalContext: ApprovalContext = {
600
+ riskLevel: risk,
601
+ toolName,
602
+ matchedRule: matchedRule ?? undefined,
603
+ permissionsMode: config.permissions.mode,
604
+ isContainerized: getIsContainerized(),
605
+ isWorkspaceScoped:
606
+ risk === RiskLevel.Low
607
+ ? isWorkspaceScopedInvocation(toolName, input, workingDir)
608
+ : false,
609
+ toolOrigin:
610
+ tool?.origin === "skill" ? "skill" : tool ? "builtin" : undefined,
611
+ isSkillBundled: tool?.ownerSkillBundled ?? false,
612
+ hasManifestOverride: !!manifestOverride,
613
+ autoApproveUpTo: resolvedThreshold,
614
+ };
615
+
616
+ // Delegate the allow/prompt/deny decision to the approval policy
617
+ const approvalDecision = defaultApprovalPolicy.evaluate(approvalContext);
618
+
619
+ // Enrich the reason with the classifier's explanation when available.
620
+ // For risk-based fallback decisions (prompt/deny from High/Medium risk),
621
+ // incorporate the classifier reason so the user sees *why* the command
622
+ // was classified at that level (e.g. "High risk (Recursive force delete): requires approval").
623
+ let enrichedReason = approvalDecision.reason;
624
+ if (riskReason && !approvalDecision.matchedRule) {
625
+ const riskLabelMatch = enrichedReason.match(
626
+ /^(High|Medium|Low|high|medium|low) risk(.*)/i,
627
+ );
628
+ if (riskLabelMatch) {
629
+ const capitalizedLabel =
630
+ riskLabelMatch[1].charAt(0).toUpperCase() +
631
+ riskLabelMatch[1].slice(1).toLowerCase();
632
+ enrichedReason = `${capitalizedLabel} risk (${riskReason})${riskLabelMatch[2]}`;
1125
633
  }
1126
634
  }
1127
635
 
1128
- if (risk === RiskLevel.High) {
1129
- return {
1130
- decision: "prompt",
1131
- reason: `High risk: always requires approval`,
1132
- };
1133
- }
1134
-
1135
- if (risk === RiskLevel.Low) {
1136
- return { decision: "allow", reason: "Low risk: auto-allowed" };
1137
- }
1138
-
1139
- return { decision: "prompt", reason: `${risk} risk: requires approval` };
636
+ return {
637
+ decision: approvalDecision.decision,
638
+ reason: enrichedReason,
639
+ matchedRule: approvalDecision.matchedRule,
640
+ };
1140
641
  }
1141
642
 
1142
643
  const TOOL_DISPLAY_NAMES: Record<string, string> = {
@@ -1147,7 +648,6 @@ const TOOL_DISPLAY_NAMES: Record<string, string> = {
1147
648
  host_file_write: "host file writes",
1148
649
  host_file_edit: "host file edits",
1149
650
  web_fetch: "URL fetches",
1150
- browser_navigate: "browser navigations",
1151
651
  network_request: "network requests",
1152
652
  };
1153
653
 
@@ -1175,6 +675,10 @@ function shellAllowlistStrategy(
1175
675
  input: Record<string, unknown>,
1176
676
  ): Promise<AllowlistOption[]> {
1177
677
  const command = ((input.command as string) ?? "").trim();
678
+ // TODO(phase-3): Wire RiskAssessment.scopeOptions into permission prompts
679
+ // and retire buildShellAllowlistOptions + buildShellCommandCandidates from
680
+ // shell-identity.ts. The classifier's generateScopeOptions produces the
681
+ // canonical scope ladder; this legacy path should not diverge further.
1178
682
  return buildShellAllowlistOptions(command);
1179
683
  }
1180
684
 
@@ -1356,7 +860,6 @@ const ALLOWLIST_STRATEGIES: Record<string, AllowlistStrategy> = {
1356
860
  host_file_write: fileAllowlistStrategy,
1357
861
  host_file_edit: fileAllowlistStrategy,
1358
862
  web_fetch: urlAllowlistStrategy,
1359
- browser_navigate: urlAllowlistStrategy,
1360
863
  network_request: urlAllowlistStrategy,
1361
864
  scaffold_managed_skill: managedSkillAllowlistStrategy,
1362
865
  delete_managed_skill: managedSkillAllowlistStrategy,
@@ -1370,6 +873,22 @@ export async function generateAllowlistOptions(
1370
873
  ): Promise<AllowlistOption[]> {
1371
874
  signal?.throwIfAborted();
1372
875
 
876
+ // Check if a classifier already produced allowlist options during
877
+ // classifyRisk(). If so, return those directly — avoids duplicate
878
+ // computation and keeps scope option generation unified with risk
879
+ // classification.
880
+ const aKey = assessmentCacheKey(toolName, input);
881
+ const cachedAssessment = assessmentCache.get(aKey);
882
+ if (
883
+ cachedAssessment?.allowlistOptions &&
884
+ cachedAssessment.allowlistOptions.length > 0
885
+ ) {
886
+ return cachedAssessment.allowlistOptions;
887
+ }
888
+
889
+ // Fall back to the per-tool strategy function for tools that don't have
890
+ // classifier-produced options (e.g. bash tools use the shell identity
891
+ // strategy, or when the cache was missed).
1373
892
  if (Object.hasOwn(ALLOWLIST_STRATEGIES, toolName)) {
1374
893
  return ALLOWLIST_STRATEGIES[toolName](toolName, input);
1375
894
  }