@vellumai/assistant 0.6.5 → 0.6.6

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 (443) hide show
  1. package/AGENTS.md +9 -1
  2. package/ARCHITECTURE.md +15 -17
  3. package/Dockerfile +6 -4
  4. package/__tests__/permissions/gateway-threshold-reader.test.ts +283 -0
  5. package/docs/architecture/integrations.md +32 -39
  6. package/docs/architecture/memory.md +25 -30
  7. package/docs/architecture/security.md +7 -6
  8. package/docs/browser-use-architecture-phase2.md +63 -20
  9. package/docs/plugins.md +761 -0
  10. package/examples/plugins/echo/README.md +132 -0
  11. package/examples/plugins/echo/package.json +17 -0
  12. package/examples/plugins/echo/register.ts +187 -0
  13. package/node_modules/@vellumai/egress-proxy/src/types.ts +19 -0
  14. package/openapi.yaml +212 -68
  15. package/package.json +1 -1
  16. package/src/__tests__/app-compiler.test.ts +57 -0
  17. package/src/__tests__/approval-cascade.test.ts +7 -2
  18. package/src/__tests__/auto-analysis-end-to-end.test.ts +1 -0
  19. package/src/__tests__/avatar-generator.test.ts +4 -2
  20. package/src/__tests__/bundled-asset.test.ts +6 -6
  21. package/src/__tests__/catalog-cache.test.ts +69 -0
  22. package/src/__tests__/checker.test.ts +459 -171
  23. package/src/__tests__/circuit-breaker-pipeline.test.ts +406 -0
  24. package/src/__tests__/compaction-events.test.ts +501 -0
  25. package/src/__tests__/compaction-pipeline.test.ts +210 -0
  26. package/src/__tests__/compaction-strip-metadata-clear.test.ts +181 -0
  27. package/src/__tests__/compaction-timeout-recovery.test.ts +262 -0
  28. package/src/__tests__/config-model-image-provider.test.ts +110 -0
  29. package/src/__tests__/config-schema.test.ts +22 -9
  30. package/src/__tests__/config-watcher-cleanup-throttle.test.ts +0 -4
  31. package/src/__tests__/contacts-tools.test.ts +26 -0
  32. package/src/__tests__/context-overflow-policy.test.ts +7 -7
  33. package/src/__tests__/context-window-manager.test.ts +355 -4
  34. package/src/__tests__/conversation-abort-tool-results.test.ts +4 -1
  35. package/src/__tests__/conversation-agent-loop-overflow.test.ts +26 -30
  36. package/src/__tests__/conversation-agent-loop.test.ts +30 -141
  37. package/src/__tests__/conversation-confirmation-signals.test.ts +6 -1
  38. package/src/__tests__/conversation-history-web-search.test.ts +1 -0
  39. package/src/__tests__/conversation-init.benchmark.test.ts +2 -16
  40. package/src/__tests__/conversation-pairing.test.ts +174 -10
  41. package/src/__tests__/conversation-pre-run-repair.test.ts +4 -1
  42. package/src/__tests__/conversation-process-callsite.test.ts +3 -0
  43. package/src/__tests__/conversation-provider-retry-repair.test.ts +16 -7
  44. package/src/__tests__/conversation-queue.test.ts +29 -14
  45. package/src/__tests__/conversation-routes-disk-view.test.ts +7 -6
  46. package/src/__tests__/conversation-runtime-assembly.test.ts +155 -110
  47. package/src/__tests__/conversation-runtime-workspace.test.ts +23 -38
  48. package/src/__tests__/conversation-seed-composer.test.ts +2 -2
  49. package/src/__tests__/conversation-slash-queue.test.ts +7 -2
  50. package/src/__tests__/conversation-slash-unknown.test.ts +25 -2
  51. package/src/__tests__/conversation-speed-override.test.ts +6 -1
  52. package/src/__tests__/conversation-title-service.test.ts +116 -0
  53. package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +41 -2
  54. package/src/__tests__/conversation-usage.test.ts +1 -1
  55. package/src/__tests__/conversation-workspace-cache-state.test.ts +4 -1
  56. package/src/__tests__/conversation-workspace-injection.test.ts +3 -0
  57. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +4 -1
  58. package/src/__tests__/credential-health-service.test.ts +78 -9
  59. package/src/__tests__/credential-security-invariants.test.ts +2 -2
  60. package/src/__tests__/db-schedule-syntax-migration.test.ts +1 -0
  61. package/src/__tests__/empty-response-pipeline.test.ts +305 -0
  62. package/src/__tests__/extension-id-sync-guard.test.ts +3 -3
  63. package/src/__tests__/first-greeting.test.ts +247 -5
  64. package/src/__tests__/headless-browser-mode.test.ts +57 -0
  65. package/src/__tests__/history-repair-pipeline.test.ts +399 -0
  66. package/src/__tests__/host-browser-e2e-cloud.test.ts +307 -0
  67. package/src/__tests__/host-browser-e2e-self-hosted.test.ts +3 -3
  68. package/src/__tests__/host-proxy-interface.test.ts +36 -2
  69. package/src/__tests__/image-credentials.test.ts +137 -0
  70. package/src/__tests__/image-service-dispatcher.test.ts +186 -0
  71. package/src/__tests__/injector-chain.test.ts +526 -0
  72. package/src/__tests__/intent-routing.test.ts +0 -26
  73. package/src/__tests__/llm-call-pipeline.test.ts +285 -0
  74. package/src/__tests__/llm-schema.test.ts +1 -1
  75. package/src/__tests__/media-generate-image.test.ts +119 -13
  76. package/src/__tests__/memory-retrieval-pipeline.test.ts +401 -0
  77. package/src/__tests__/memory-upsert-concurrency.test.ts +1 -0
  78. package/src/__tests__/migration-import-from-url.test.ts +5 -68
  79. package/src/__tests__/model-intents.test.ts +4 -2
  80. package/src/__tests__/notification-broadcaster.test.ts +3 -3
  81. package/src/__tests__/notification-decision-strategy.test.ts +0 -11
  82. package/src/__tests__/notification-schedule-notify-dedup.test.ts +108 -0
  83. package/src/__tests__/oauth-apps-routes.test.ts +1 -1
  84. package/src/__tests__/oauth-cli.test.ts +14 -12
  85. package/src/__tests__/oauth-connect-orchestrator.test.ts +4 -13
  86. package/src/__tests__/oauth-provider-serializer.test.ts +6 -4
  87. package/src/__tests__/oauth-provider-visibility.test.ts +3 -5
  88. package/src/__tests__/oauth-providers-routes.test.ts +3 -2
  89. package/src/__tests__/oauth-store.test.ts +41 -76
  90. package/src/__tests__/onboarding-template-contract.test.ts +16 -64
  91. package/src/__tests__/openai-image-service.test.ts +368 -0
  92. package/src/__tests__/overflow-reduce-pipeline.test.ts +676 -0
  93. package/src/__tests__/permission-checker-host-gate.test.ts +0 -24
  94. package/src/__tests__/persist-onboarding-artifacts.test.ts +266 -0
  95. package/src/__tests__/persistence-pipeline.test.ts +377 -0
  96. package/src/__tests__/pipeline-runner.test.ts +565 -0
  97. package/src/__tests__/platform.test.ts +5 -2
  98. package/src/__tests__/plugin-bootstrap.test.ts +483 -0
  99. package/src/__tests__/plugin-registry.test.ts +273 -0
  100. package/src/__tests__/plugin-route-contribution.test.ts +288 -0
  101. package/src/__tests__/plugin-skill-contribution.test.ts +367 -0
  102. package/src/__tests__/plugin-tool-contribution.test.ts +286 -0
  103. package/src/__tests__/plugin-types.test.ts +320 -0
  104. package/src/__tests__/pricing.test.ts +44 -12
  105. package/src/__tests__/proxy-approval-callback.test.ts +69 -8
  106. package/src/__tests__/reaction-persistence.test.ts +1 -0
  107. package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +1 -0
  108. package/src/__tests__/registry.test.ts +0 -2
  109. package/src/__tests__/schedule-routes.test.ts +131 -1
  110. package/src/__tests__/scheduler-recurrence.test.ts +14 -70
  111. package/src/__tests__/scheduler-reuse-conversation.test.ts +10 -50
  112. package/src/__tests__/secret-detection-handler.test.ts +0 -10
  113. package/src/__tests__/shell-identity.test.ts +0 -134
  114. package/src/__tests__/suggestion-routes.test.ts +103 -4
  115. package/src/__tests__/task-memory-cleanup.test.ts +1 -0
  116. package/src/__tests__/task-scheduler.test.ts +3 -15
  117. package/src/__tests__/test-preload.ts +11 -0
  118. package/src/__tests__/title-generate-pipeline.test.ts +224 -0
  119. package/src/__tests__/token-estimate-pipeline.test.ts +431 -0
  120. package/src/__tests__/tool-error-pipeline.test.ts +244 -0
  121. package/src/__tests__/tool-execute-pipeline.test.ts +431 -0
  122. package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +0 -6
  123. package/src/__tests__/tool-executor-shell-integration.test.ts +7 -10
  124. package/src/__tests__/tool-executor.test.ts +141 -0
  125. package/src/__tests__/tool-result-truncate-pipeline.test.ts +356 -0
  126. package/src/__tests__/tool-result-truncation.test.ts +0 -110
  127. package/src/__tests__/user-plugin-loader.test.ts +191 -0
  128. package/src/__tests__/workspace-migration-046-seed-conversation-starters-callsite.test.ts +185 -0
  129. package/src/__tests__/workspace-migration-049-release-notes-default-sonnet.test.ts +100 -0
  130. package/src/__tests__/workspace-migration-050-seed-main-agent-opus-callsite.test.ts +171 -0
  131. package/src/__tests__/workspace-migration-051-seed-conversation-summarization-callsite.test.ts +252 -0
  132. package/src/__tests__/workspace-migration-remove-hooks.test.ts +99 -0
  133. package/src/__tests__/workspace-policy.test.ts +21 -3
  134. package/src/agent/loop.ts +340 -102
  135. package/src/approvals/__tests__/guardian-feed-event.test.ts +304 -0
  136. package/src/approvals/guardian-request-resolvers.ts +80 -0
  137. package/src/backup/__tests__/backup-worker.test.ts +2 -13
  138. package/src/backup/backup-worker.ts +3 -15
  139. package/src/bundler/app-compiler.ts +84 -1
  140. package/src/calls/call-state.ts +2 -2
  141. package/src/channels/__tests__/types.test.ts +3 -3
  142. package/src/channels/types.ts +6 -4
  143. package/src/cli/__tests__/notifications.test.ts +87 -211
  144. package/src/cli/commands/__tests__/backup.test.ts +1 -1
  145. package/src/cli/commands/__tests__/image-generation.test.ts +255 -35
  146. package/src/cli/commands/__tests__/inference-send.test.ts +12 -0
  147. package/src/cli/commands/__tests__/tts-synthesize.test.ts +12 -0
  148. package/src/cli/commands/backup.ts +2 -2
  149. package/src/cli/commands/clients.ts +138 -0
  150. package/src/cli/commands/completions.ts +2 -9
  151. package/src/cli/commands/conversations.ts +55 -7
  152. package/src/cli/commands/image-generation.ts +33 -34
  153. package/src/cli/commands/notifications.ts +68 -103
  154. package/src/cli/commands/oauth/__tests__/providers-register.test.ts +1 -1
  155. package/src/cli/commands/oauth/__tests__/providers-update.test.ts +1 -1
  156. package/src/cli/commands/oauth/connect.ts +2 -2
  157. package/src/cli/commands/oauth/providers.ts +176 -8
  158. package/src/cli/commands/oauth/status.ts +46 -36
  159. package/src/cli/commands/skills.ts +3 -4
  160. package/src/cli/program.ts +25 -29
  161. package/src/config/__tests__/backup-schema.test.ts +7 -2
  162. package/src/config/bundled-skills/app-builder/SKILL.md +2 -2
  163. package/src/config/bundled-skills/app-builder/references/WIDGETS.md +10 -10
  164. package/src/config/bundled-skills/contacts/tools/contact-merge.ts +66 -87
  165. package/src/config/bundled-skills/contacts/tools/contact-search.ts +28 -51
  166. package/src/config/bundled-skills/contacts/tools/contact-upsert.ts +22 -40
  167. package/src/config/bundled-skills/image-studio/SKILL.md +2 -1
  168. package/src/config/bundled-skills/image-studio/TOOLS.json +2 -1
  169. package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +23 -39
  170. package/src/config/bundled-skills/messaging/SKILL.md +3 -3
  171. package/src/config/bundled-skills/messaging/tools/__tests__/messaging-feed-events.test.ts +207 -0
  172. package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +12 -0
  173. package/src/config/bundled-skills/messaging/tools/messaging-send.ts +58 -0
  174. package/src/config/bundled-skills/schedule/SKILL.md +8 -3
  175. package/src/config/bundled-skills/schedule/TOOLS.json +15 -7
  176. package/src/config/bundled-skills/schedule/references/SCRIPT_MODE_PATTERNS.md +59 -0
  177. package/src/config/bundled-tool-registry.ts +0 -15
  178. package/src/config/feature-flag-registry.json +17 -1
  179. package/src/config/schema.ts +19 -0
  180. package/src/config/schemas/backup.ts +1 -1
  181. package/src/config/schemas/conversations.ts +16 -0
  182. package/src/config/schemas/llm.ts +2 -3
  183. package/src/config/schemas/security.ts +6 -6
  184. package/src/config/schemas/tts.ts +11 -0
  185. package/src/config/skill-state.ts +6 -2
  186. package/src/config/skills.ts +94 -5
  187. package/src/context/__tests__/compact-prompt.test.ts +27 -9
  188. package/src/context/prompts/compact.md +26 -12
  189. package/src/context/tool-result-truncation.ts +3 -63
  190. package/src/context/window-manager.ts +190 -16
  191. package/src/credential-health/credential-health-service.ts +19 -6
  192. package/src/daemon/__tests__/conversation-feed-event.test.ts +317 -0
  193. package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +4 -12
  194. package/src/daemon/__tests__/conversation-tool-setup.test.ts +14 -15
  195. package/src/daemon/config-watcher.ts +0 -2
  196. package/src/daemon/context-overflow-policy.ts +4 -13
  197. package/src/daemon/conversation-agent-loop-handlers.ts +83 -22
  198. package/src/daemon/conversation-agent-loop.ts +984 -683
  199. package/src/daemon/conversation-history.ts +10 -19
  200. package/src/daemon/conversation-lifecycle.ts +37 -19
  201. package/src/daemon/conversation-notifiers.ts +2 -110
  202. package/src/daemon/conversation-process.ts +14 -7
  203. package/src/daemon/conversation-runtime-assembly.ts +532 -411
  204. package/src/daemon/conversation-tool-setup.ts +41 -4
  205. package/src/daemon/conversation.ts +80 -35
  206. package/src/daemon/external-plugins-bootstrap.ts +478 -0
  207. package/src/daemon/first-greeting.ts +191 -14
  208. package/src/daemon/handlers/config-model.ts +11 -0
  209. package/src/daemon/handlers/skills.ts +5 -1
  210. package/src/daemon/lifecycle.ts +33 -68
  211. package/src/daemon/message-types/computer-use.ts +2 -34
  212. package/src/daemon/message-types/conversations.ts +49 -0
  213. package/src/daemon/message-types/messages.ts +12 -0
  214. package/src/daemon/server.ts +5 -3
  215. package/src/daemon/shutdown-handlers.ts +2 -12
  216. package/src/daemon/tool-side-effects.ts +14 -56
  217. package/src/heartbeat/__tests__/heartbeat-feed-event.test.ts +160 -0
  218. package/src/heartbeat/heartbeat-service.ts +24 -1
  219. package/src/home/__tests__/feed-population-integration.test.ts +312 -0
  220. package/src/home/emit-feed-event.ts +7 -0
  221. package/src/home/feed-types.ts +41 -2
  222. package/src/home/rewrite-command-preview.ts +66 -0
  223. package/src/ipc/__tests__/socket-path.test.ts +11 -50
  224. package/src/ipc/cli-client.ts +1 -1
  225. package/src/ipc/cli-server.ts +3 -3
  226. package/src/ipc/gateway-client.ts +4 -1
  227. package/src/ipc/routes/browser-context.ts +2 -0
  228. package/src/ipc/routes/browser.ts +1 -0
  229. package/src/ipc/routes/get-contact.ts +16 -0
  230. package/src/ipc/routes/index.ts +14 -0
  231. package/src/ipc/routes/list-clients.ts +31 -0
  232. package/src/ipc/routes/merge-contacts.ts +17 -0
  233. package/src/ipc/routes/notification.ts +133 -0
  234. package/src/ipc/routes/rename-conversation.ts +59 -0
  235. package/src/ipc/routes/search-contacts.ts +19 -0
  236. package/src/ipc/routes/upsert-contact.ts +25 -0
  237. package/src/ipc/socket-path.ts +14 -38
  238. package/src/media/app-icon-generator.ts +23 -46
  239. package/src/media/avatar-router.ts +26 -41
  240. package/src/media/gemini-image-service.ts +8 -41
  241. package/src/media/image-credentials.ts +73 -0
  242. package/src/media/image-service.ts +85 -0
  243. package/src/media/openai-image-service.ts +131 -0
  244. package/src/media/types.ts +46 -0
  245. package/src/memory/conversation-crud.ts +48 -18
  246. package/src/memory/conversation-queries.ts +57 -4
  247. package/src/memory/conversation-title-service.ts +25 -0
  248. package/src/memory/db-init.ts +8 -0
  249. package/src/memory/embedding-gemini.test.ts +41 -2
  250. package/src/memory/embedding-gemini.ts +6 -1
  251. package/src/memory/graph/bootstrap.test.ts +282 -0
  252. package/src/memory/graph/bootstrap.ts +8 -5
  253. package/src/memory/graph/extraction.ts +10 -2
  254. package/src/memory/graph/graph-search.test.ts +1 -0
  255. package/src/memory/graph/inspect.ts +2 -2
  256. package/src/memory/graph/retriever.ts +10 -3
  257. package/src/memory/migrations/041-approval-prompt-ts-tracker.ts +26 -0
  258. package/src/memory/migrations/149-oauth-tables.ts +1 -0
  259. package/src/memory/migrations/223-schedule-script-column.ts +11 -0
  260. package/src/memory/migrations/224-oauth-providers-managed-service-is-paid.ts +24 -0
  261. package/src/memory/migrations/225-oauth-providers-available-scopes.ts +13 -0
  262. package/src/memory/migrations/index.ts +4 -0
  263. package/src/memory/pkb/pkb-index.test.ts +1 -0
  264. package/src/memory/pkb/pkb-reconcile.test.ts +1 -0
  265. package/src/memory/pkb/pkb-search.test.ts +65 -4
  266. package/src/memory/pkb/pkb-search.ts +40 -18
  267. package/src/memory/qdrant-client.test.ts +60 -0
  268. package/src/memory/qdrant-client.ts +25 -0
  269. package/src/memory/schema/infrastructure.ts +1 -0
  270. package/src/memory/schema/oauth.ts +4 -1
  271. package/src/messaging/providers/slack/render-transcript.test.ts +77 -29
  272. package/src/messaging/providers/slack/render-transcript.ts +58 -0
  273. package/src/notifications/conversation-pairing.ts +78 -19
  274. package/src/notifications/copy-composer.ts +0 -5
  275. package/src/notifications/emit-signal.ts +1 -1
  276. package/src/notifications/signal.ts +1 -2
  277. package/src/oauth/AGENTS.md +1 -1
  278. package/src/oauth/__tests__/identity-verifier.test.ts +2 -1
  279. package/src/oauth/connect-orchestrator.ts +8 -34
  280. package/src/oauth/connect-types.ts +6 -10
  281. package/src/oauth/manual-token-connection.ts +23 -0
  282. package/src/oauth/oauth-store.ts +30 -14
  283. package/src/oauth/provider-serializer.ts +6 -1
  284. package/src/oauth/seed-providers.ts +56 -108
  285. package/src/outbound-proxy/http-forwarder.ts +9 -0
  286. package/src/permissions/approval-policy.test.ts +293 -18
  287. package/src/permissions/approval-policy.ts +110 -58
  288. package/src/permissions/arg-parser.test.ts +161 -0
  289. package/src/permissions/arg-parser.ts +141 -0
  290. package/src/permissions/bash-risk-classifier.test.ts +414 -2
  291. package/src/permissions/bash-risk-classifier.ts +303 -60
  292. package/src/permissions/checker.ts +157 -29
  293. package/src/permissions/command-registry.test.ts +239 -0
  294. package/src/permissions/command-registry.ts +234 -54
  295. package/src/permissions/defaults.ts +5 -4
  296. package/src/permissions/gateway-threshold-reader.ts +196 -0
  297. package/src/permissions/prompter.ts +4 -0
  298. package/src/permissions/risk-types.ts +61 -4
  299. package/src/permissions/schedule-risk-classifier.test.ts +129 -0
  300. package/src/permissions/schedule-risk-classifier.ts +85 -0
  301. package/src/permissions/shell-identity.ts +2 -42
  302. package/src/permissions/types.ts +2 -0
  303. package/src/permissions/workspace-policy.ts +8 -3
  304. package/src/plugins/defaults/circuit-breaker.ts +146 -0
  305. package/src/plugins/defaults/compaction.ts +145 -0
  306. package/src/plugins/defaults/empty-response.ts +126 -0
  307. package/src/plugins/defaults/history-repair.ts +85 -0
  308. package/src/plugins/defaults/index.ts +116 -0
  309. package/src/plugins/defaults/injectors.ts +491 -0
  310. package/src/plugins/defaults/llm-call.ts +82 -0
  311. package/src/plugins/defaults/memory-retrieval.ts +226 -0
  312. package/src/plugins/defaults/overflow-reduce.ts +181 -0
  313. package/src/plugins/defaults/persistence.ts +129 -0
  314. package/src/plugins/defaults/title-generate.ts +95 -0
  315. package/src/plugins/defaults/token-estimate.ts +104 -0
  316. package/src/plugins/defaults/tool-error.ts +126 -0
  317. package/src/plugins/defaults/tool-execute.ts +89 -0
  318. package/src/plugins/defaults/tool-result-truncate.ts +88 -0
  319. package/src/plugins/pipeline.ts +316 -0
  320. package/src/plugins/plugin-skill-contributions.ts +292 -0
  321. package/src/plugins/registry.ts +241 -0
  322. package/src/plugins/types.ts +1134 -0
  323. package/src/plugins/user-loader.ts +177 -0
  324. package/src/prompts/templates/BOOTSTRAP.md +27 -77
  325. package/src/providers/model-catalog.ts +52 -29
  326. package/src/providers/model-intents.ts +1 -1
  327. package/src/providers/openrouter/client.ts +5 -1
  328. package/src/providers/speech-to-text/deepgram-realtime.test.ts +61 -0
  329. package/src/providers/speech-to-text/deepgram-realtime.ts +57 -0
  330. package/src/providers/speech-to-text/xai-realtime.test.ts +72 -4
  331. package/src/providers/speech-to-text/xai-realtime.ts +39 -14
  332. package/src/runtime/AGENTS.md +25 -16
  333. package/src/runtime/__tests__/browser-extension-pair-routes.test.ts +3 -3
  334. package/src/runtime/__tests__/client-registry.test.ts +293 -0
  335. package/src/runtime/client-registry.ts +261 -0
  336. package/src/runtime/http-server.ts +77 -8
  337. package/src/runtime/http-types.ts +0 -2
  338. package/src/runtime/migrations/vbundle-builder.ts +1 -22
  339. package/src/runtime/routes/approval-prompt-ts-tracker.ts +51 -31
  340. package/src/runtime/routes/approval-routes.ts +17 -0
  341. package/src/runtime/routes/browser-extension-pair-routes.ts +27 -8
  342. package/src/runtime/routes/conversation-routes.ts +223 -116
  343. package/src/runtime/routes/inbound-message-handler.ts +88 -13
  344. package/src/runtime/routes/memory-item-routes.test.ts +1 -0
  345. package/src/runtime/routes/migration-routes.ts +0 -3
  346. package/src/runtime/routes/playground/__tests__/force-compact.test.ts +284 -0
  347. package/src/runtime/routes/playground/__tests__/guard.test.ts +80 -0
  348. package/src/runtime/routes/playground/__tests__/inject-failures.test.ts +294 -0
  349. package/src/runtime/routes/playground/__tests__/reset-circuit.test.ts +271 -0
  350. package/src/runtime/routes/playground/__tests__/seed-conversation.test.ts +202 -0
  351. package/src/runtime/routes/playground/__tests__/seeded-conversations.test.ts +309 -0
  352. package/src/runtime/routes/playground/__tests__/state.test.ts +224 -0
  353. package/src/runtime/routes/playground/conversation-not-found.ts +29 -0
  354. package/src/runtime/routes/playground/deps.ts +56 -0
  355. package/src/runtime/routes/playground/force-compact.ts +73 -0
  356. package/src/runtime/routes/playground/guard.ts +37 -0
  357. package/src/runtime/routes/playground/index.ts +28 -0
  358. package/src/runtime/routes/playground/inject-failures.ts +159 -0
  359. package/src/runtime/routes/playground/reset-circuit.ts +115 -0
  360. package/src/runtime/routes/playground/seed-conversation.ts +139 -0
  361. package/src/runtime/routes/playground/seeded-conversations.ts +78 -0
  362. package/src/runtime/routes/playground/state.ts +78 -0
  363. package/src/runtime/routes/schedule-routes.ts +89 -8
  364. package/src/runtime/skill-route-registry.ts +75 -15
  365. package/src/schedule/run-script.ts +68 -0
  366. package/src/schedule/schedule-store.ts +7 -1
  367. package/src/schedule/scheduler.ts +48 -8
  368. package/src/skills/catalog-cache.ts +12 -5
  369. package/src/tools/browser/__tests__/browser-status.test.ts +189 -0
  370. package/src/tools/browser/browser-execution.ts +88 -19
  371. package/src/tools/browser/cdp-client/__tests__/extension-cdp-client.test.ts +230 -0
  372. package/src/tools/browser/cdp-client/__tests__/factory.test.ts +146 -3
  373. package/src/tools/browser/cdp-client/extension-cdp-client.ts +54 -3
  374. package/src/tools/browser/cdp-client/factory.ts +15 -4
  375. package/src/tools/executor.ts +126 -74
  376. package/src/tools/network/script-proxy/session-manager.ts +37 -1
  377. package/src/tools/permission-checker.ts +98 -49
  378. package/src/tools/policy-context.ts +4 -0
  379. package/src/tools/registry.ts +140 -3
  380. package/src/tools/schedule/create.ts +23 -8
  381. package/src/tools/schedule/update.ts +3 -1
  382. package/src/tools/secret-detection-handler.ts +0 -51
  383. package/src/tools/system/avatar-generator.ts +6 -2
  384. package/src/tools/types.ts +28 -2
  385. package/src/util/platform.ts +7 -2
  386. package/src/util/pricing.ts +26 -3
  387. package/src/workspace/migrations/006-services-config.ts +2 -4
  388. package/src/workspace/migrations/022-move-hooks-to-workspace.ts +2 -3
  389. package/src/workspace/migrations/041-backfill-google-gmail-settings-scope.ts +3 -4
  390. package/src/workspace/migrations/046-seed-conversation-starters-callsite.ts +108 -0
  391. package/src/workspace/migrations/047-remove-watch-callsites.ts +54 -0
  392. package/src/workspace/migrations/048-remove-workspace-hooks.ts +81 -0
  393. package/src/workspace/migrations/049-release-notes-default-sonnet.ts +80 -0
  394. package/src/workspace/migrations/050-seed-main-agent-opus-callsite.ts +86 -0
  395. package/src/workspace/migrations/051-seed-conversation-summarization-callsite.ts +128 -0
  396. package/src/workspace/migrations/registry.ts +12 -0
  397. package/tsconfig.json +1 -1
  398. package/hook-templates/debug-prompt-logger/hook.json +0 -7
  399. package/hook-templates/debug-prompt-logger/run.sh +0 -66
  400. package/src/__tests__/compaction-circuit-breaker.test.ts +0 -336
  401. package/src/__tests__/context-overflow-approval.test.ts +0 -156
  402. package/src/__tests__/hooks-blocking.test.ts +0 -178
  403. package/src/__tests__/hooks-cli.test.ts +0 -182
  404. package/src/__tests__/hooks-config.test.ts +0 -108
  405. package/src/__tests__/hooks-discovery.test.ts +0 -211
  406. package/src/__tests__/hooks-integration.test.ts +0 -196
  407. package/src/__tests__/hooks-manager.test.ts +0 -226
  408. package/src/__tests__/hooks-runner.test.ts +0 -175
  409. package/src/__tests__/hooks-settings.test.ts +0 -160
  410. package/src/__tests__/hooks-templates.test.ts +0 -169
  411. package/src/__tests__/hooks-ts-runner.test.ts +0 -170
  412. package/src/__tests__/hooks-watch.test.ts +0 -112
  413. package/src/__tests__/notification-schedule-dedup.test.ts +0 -213
  414. package/src/__tests__/oauth-scope-policy.test.ts +0 -180
  415. package/src/__tests__/send-notification-tool.test.ts +0 -83
  416. package/src/cli/commands/shotgun.ts +0 -266
  417. package/src/config/bundled-skills/conversations/SKILL.md +0 -20
  418. package/src/config/bundled-skills/conversations/TOOLS.json +0 -23
  419. package/src/config/bundled-skills/conversations/tools/rename-conversation.ts +0 -88
  420. package/src/config/bundled-skills/heartbeat/SKILL.md +0 -43
  421. package/src/config/bundled-skills/notifications/SKILL.md +0 -40
  422. package/src/config/bundled-skills/notifications/TOOLS.json +0 -80
  423. package/src/config/bundled-skills/notifications/tools/send-notification.ts +0 -152
  424. package/src/config/bundled-skills/notifications/tools/shared.ts +0 -13
  425. package/src/config/bundled-skills/screen-watch/SKILL.md +0 -27
  426. package/src/config/bundled-skills/screen-watch/TOOLS.json +0 -35
  427. package/src/config/bundled-skills/screen-watch/tools/start-screen-watch.ts +0 -12
  428. package/src/config/bundled-skills/skills-catalog/SKILL.md +0 -84
  429. package/src/daemon/context-overflow-approval.ts +0 -52
  430. package/src/daemon/watch-handler.ts +0 -399
  431. package/src/hooks/cli.ts +0 -253
  432. package/src/hooks/config.ts +0 -100
  433. package/src/hooks/discovery.ts +0 -135
  434. package/src/hooks/manager.ts +0 -179
  435. package/src/hooks/runner.ts +0 -117
  436. package/src/hooks/templates.ts +0 -77
  437. package/src/hooks/types.ts +0 -75
  438. package/src/oauth/scope-policy.ts +0 -89
  439. package/src/runtime/gateway-internal-client.ts +0 -94
  440. package/src/runtime/routes/watch-routes.ts +0 -156
  441. package/src/signals/shotgun.ts +0 -203
  442. package/src/tools/watch/screen-watch.ts +0 -144
  443. package/src/tools/watch/watch-state.ts +0 -142
@@ -0,0 +1,431 @@
1
+ /**
2
+ * Pipeline wrapper tests for `ToolExecutor.execute` (PR 16).
3
+ *
4
+ * Covers:
5
+ * - The public `execute` method routes through `runPipeline("toolExecute",
6
+ * ...)` so `getMiddlewaresFor("toolExecute")` middleware participates.
7
+ * - The default `toolExecute` plugin (passthrough) preserves the original
8
+ * execution path — result and side effects match the unwrapped executor.
9
+ * - A spy middleware observes the full tool invocation (name, input, ctx).
10
+ * - A short-circuit middleware intercepts the call and supplies a custom
11
+ * result without hitting the real tool.
12
+ *
13
+ * These tests reuse the same module mocks as `tool-executor.test.ts` so the
14
+ * permission check, risk classifier, and tool registry are stubbed; the
15
+ * focus here is the pipeline wrapper, not the internal execution body.
16
+ */
17
+
18
+ import { afterAll, beforeEach, describe, expect, mock, test } from "bun:test";
19
+
20
+ import type { ToolExecutionResult } from "../tools/types.js";
21
+
22
+ // ── Config mock ───────────────────────────────────────────────────────
23
+ const mockConfig = {
24
+ provider: "anthropic",
25
+ model: "test",
26
+ maxTokens: 4096,
27
+ dataDir: "/tmp",
28
+ timeouts: {
29
+ shellDefaultTimeoutSec: 120,
30
+ shellMaxTimeoutSec: 600,
31
+ permissionTimeoutSec: 300,
32
+ toolExecutionTimeoutSec: 120,
33
+ },
34
+ sandbox: {
35
+ enabled: false,
36
+ backend: "native" as const,
37
+ docker: {
38
+ image: "vellum-sandbox:latest",
39
+ cpus: 1,
40
+ memoryMb: 512,
41
+ pidsLimit: 256,
42
+ network: "none" as const,
43
+ },
44
+ },
45
+ rateLimit: { maxRequestsPerMinute: 0 },
46
+ secretDetection: {
47
+ enabled: false,
48
+ action: "warn" as const,
49
+ entropyThreshold: 4.0,
50
+ },
51
+ permissions: {
52
+ mode: "workspace" as const,
53
+ },
54
+ };
55
+
56
+ mock.module("../config/loader.js", () => ({
57
+ getConfig: () => mockConfig,
58
+ loadConfig: () => mockConfig,
59
+ invalidateConfigCache: () => {},
60
+ saveConfig: () => {},
61
+ loadRawConfig: () => ({}),
62
+ saveRawConfig: () => {},
63
+ getNestedValue: () => undefined,
64
+ setNestedValue: () => {},
65
+ }));
66
+
67
+ // ── Logger mock ──────────────────────────────────────────────────────
68
+ // Bun's `mock.module` persists across test files until explicitly
69
+ // restored, so this mock can leak into `plugin-bootstrap.test.ts`. That
70
+ // file inspects `ctx.logger` (populated via `log.child({ plugin })`), so
71
+ // we return a Proxy whose `.child(...)` yields another Proxy with the
72
+ // same shape — the bootstrap test's `expect(ctx.logger).toBeDefined()`
73
+ // then passes regardless of test-file ordering.
74
+ function makeFakeLoggerProxy(): object {
75
+ return new Proxy({} as Record<string, unknown>, {
76
+ get: (_target, prop) => {
77
+ if (prop === "child") return () => makeFakeLoggerProxy();
78
+ return () => {};
79
+ },
80
+ });
81
+ }
82
+ mock.module("../util/logger.js", () => ({
83
+ getLogger: (_name?: string) => makeFakeLoggerProxy(),
84
+ truncateForLog: (value: string) => value,
85
+ }));
86
+
87
+ // ── Permission checker — always allow so execution reaches the tool ──
88
+ mock.module("../permissions/checker.js", () => ({
89
+ classifyRisk: async () => ({ level: "low" }),
90
+ check: async () => ({ decision: "allow", reason: "allowed" }),
91
+ generateAllowlistOptions: () => [
92
+ { label: "exact", description: "exact", pattern: "exact" },
93
+ ],
94
+ generateScopeOptions: () => [{ label: "/tmp", scope: "/tmp" }],
95
+ }));
96
+
97
+ // ── Tool usage store stub ────────────────────────────────────────────
98
+ mock.module("../memory/tool-usage-store.js", () => ({
99
+ recordToolInvocation: () => {},
100
+ getRecentInvocations: () => [],
101
+ rotateToolInvocations: () => 0,
102
+ }));
103
+
104
+ // ── Tool registry: return a stub tool whose execute records the call ─
105
+ let lastToolCall: { name: string; input: Record<string, unknown> } | undefined;
106
+ let fakeToolResult: ToolExecutionResult = {
107
+ content: "real tool output",
108
+ isError: false,
109
+ };
110
+
111
+ mock.module("../tools/registry.js", () => ({
112
+ getTool: (name: string) => {
113
+ if (name === "unknown_tool") return undefined;
114
+ return {
115
+ name,
116
+ description: "test tool",
117
+ category: "test",
118
+ defaultRiskLevel: "low",
119
+ getDefinition: () => ({}),
120
+ execute: async (input: Record<string, unknown>) => {
121
+ lastToolCall = { name, input };
122
+ return fakeToolResult;
123
+ },
124
+ };
125
+ },
126
+ getAllTools: () => [],
127
+ }));
128
+
129
+ mock.module("../tools/shared/filesystem/path-policy.js", () => ({
130
+ sandboxPolicy: () => ({ ok: false }),
131
+ hostPolicy: () => ({ ok: false }),
132
+ }));
133
+
134
+ mock.module("../tools/terminal/sandbox.js", () => ({
135
+ wrapCommand: () => ({ command: "", sandboxed: false }),
136
+ }));
137
+
138
+ // ── Redaction + token manager so the executor's imports resolve ──────
139
+ mock.module("../security/redaction.js", () => ({
140
+ redactSensitiveFields: (input: Record<string, unknown>) => input,
141
+ }));
142
+
143
+ mock.module("../security/token-manager.js", () => ({
144
+ TokenExpiredError: class TokenExpiredError extends Error {},
145
+ }));
146
+
147
+ // ── Imports — after mock.module so the executor under test picks them up ──
148
+ import { PermissionPrompter } from "../permissions/prompter.js";
149
+ import { defaultToolExecutePlugin } from "../plugins/defaults/tool-execute.js";
150
+ import {
151
+ getMiddlewaresFor,
152
+ registerPlugin,
153
+ resetPluginRegistryForTests,
154
+ } from "../plugins/registry.js";
155
+ import type {
156
+ Middleware,
157
+ Plugin,
158
+ ToolExecuteArgs,
159
+ ToolExecuteResult,
160
+ } from "../plugins/types.js";
161
+ import { ToolExecutor } from "../tools/executor.js";
162
+ import type { ToolContext } from "../tools/types.js";
163
+
164
+ function makeContext(overrides?: Partial<ToolContext>): ToolContext {
165
+ return {
166
+ workingDir: "/tmp/project",
167
+ conversationId: "conversation-pipeline",
168
+ trustClass: "guardian",
169
+ ...overrides,
170
+ };
171
+ }
172
+
173
+ function makePrompter(): PermissionPrompter {
174
+ return {
175
+ prompt: async () => ({ decision: "allow" as const }),
176
+ resolveConfirmation: () => {},
177
+ updateSender: () => {},
178
+ dispose: () => {},
179
+ } as unknown as PermissionPrompter;
180
+ }
181
+
182
+ afterAll(() => {
183
+ mock.restore();
184
+ });
185
+
186
+ beforeEach(() => {
187
+ resetPluginRegistryForTests();
188
+ lastToolCall = undefined;
189
+ fakeToolResult = { content: "real tool output", isError: false };
190
+ });
191
+
192
+ describe("ToolExecutor.execute → toolExecute pipeline", () => {
193
+ test("default pipeline (no plugins) runs the same execution path", async () => {
194
+ // With no plugins registered, the pipeline has an empty middleware
195
+ // array and the terminal (executeInternal) runs directly. The
196
+ // observable result must match the unwrapped behavior.
197
+ const executor = new ToolExecutor(makePrompter());
198
+ const result = await executor.execute(
199
+ "file_read",
200
+ { path: "README.md" },
201
+ makeContext(),
202
+ );
203
+
204
+ expect(result.isError).toBe(false);
205
+ expect(result.content).toBe("real tool output");
206
+ expect(lastToolCall).toEqual({
207
+ name: "file_read",
208
+ input: { path: "README.md" },
209
+ });
210
+ });
211
+
212
+ test("default tool-execute plugin: registering the passthrough preserves behavior", async () => {
213
+ // The default plugin is a passthrough whose middleware forwards to
214
+ // `next`. Registering it should not change observable behavior —
215
+ // the terminal still runs and returns the real tool result.
216
+ registerPlugin(defaultToolExecutePlugin);
217
+
218
+ // Sanity: the registry now reports exactly one middleware for the
219
+ // `toolExecute` slot, named `defaultToolExecute`.
220
+ const middlewares = getMiddlewaresFor("toolExecute");
221
+ expect(middlewares).toHaveLength(1);
222
+ expect(middlewares[0]?.name).toBe("defaultToolExecute");
223
+
224
+ const executor = new ToolExecutor(makePrompter());
225
+ const result = await executor.execute(
226
+ "file_read",
227
+ { path: "README.md" },
228
+ makeContext(),
229
+ );
230
+
231
+ expect(result.isError).toBe(false);
232
+ expect(result.content).toBe("real tool output");
233
+ expect(lastToolCall).toEqual({
234
+ name: "file_read",
235
+ input: { path: "README.md" },
236
+ });
237
+ });
238
+
239
+ test("spy middleware observes the full tool invocation (name, input, ctx)", async () => {
240
+ let observedArgs: ToolExecuteArgs | undefined;
241
+ let observedTurnCtx:
242
+ | { conversationId: string; requestId: string }
243
+ | undefined;
244
+
245
+ const spyMiddleware: Middleware<ToolExecuteArgs, ToolExecuteResult> =
246
+ async function spy(args, next, ctx) {
247
+ observedArgs = args;
248
+ observedTurnCtx = {
249
+ conversationId: ctx.conversationId,
250
+ requestId: ctx.requestId,
251
+ };
252
+ return next(args);
253
+ };
254
+
255
+ const spyPlugin: Plugin = {
256
+ manifest: {
257
+ name: "spy-tool-execute",
258
+ version: "0.0.1",
259
+ requires: { pluginRuntime: "v1" },
260
+ },
261
+ middleware: { toolExecute: spyMiddleware },
262
+ };
263
+ registerPlugin(spyPlugin);
264
+
265
+ const executor = new ToolExecutor(makePrompter());
266
+ const ctx = makeContext({
267
+ conversationId: "conv-spy",
268
+ requestId: "req-spy",
269
+ });
270
+ const result = await executor.execute(
271
+ "bash",
272
+ { command: "echo hi", timeout_seconds: 10 },
273
+ ctx,
274
+ );
275
+
276
+ // Spy observed the full args
277
+ expect(observedArgs).toBeDefined();
278
+ expect(observedArgs!.name).toBe("bash");
279
+ expect(observedArgs!.input).toEqual({
280
+ command: "echo hi",
281
+ timeout_seconds: 10,
282
+ });
283
+ expect(observedArgs!.context).toBe(ctx);
284
+
285
+ // Spy observed the synthesized TurnContext carrying conversation +
286
+ // request IDs from the ToolContext.
287
+ expect(observedTurnCtx).toEqual({
288
+ conversationId: "conv-spy",
289
+ requestId: "req-spy",
290
+ });
291
+
292
+ // Terminal still ran — result reflects the real tool output.
293
+ expect(result.isError).toBe(false);
294
+ expect(result.content).toBe("real tool output");
295
+ expect(lastToolCall).toEqual({
296
+ name: "bash",
297
+ input: { command: "echo hi", timeout_seconds: 10 },
298
+ });
299
+ });
300
+
301
+ test("short-circuit middleware intercepts and supplies a custom result", async () => {
302
+ const syntheticResult: ToolExecuteResult = {
303
+ content: "synthesized by middleware",
304
+ isError: false,
305
+ };
306
+
307
+ const shortCircuit: Middleware<ToolExecuteArgs, ToolExecuteResult> =
308
+ async function shortCircuitMw(_args, _next) {
309
+ // Intentionally omit `next` — the terminal (real tool execution)
310
+ // must not run.
311
+ return syntheticResult;
312
+ };
313
+
314
+ const interceptPlugin: Plugin = {
315
+ manifest: {
316
+ name: "short-circuit-tool-execute",
317
+ version: "0.0.1",
318
+ requires: { pluginRuntime: "v1" },
319
+ },
320
+ middleware: { toolExecute: shortCircuit },
321
+ };
322
+ registerPlugin(interceptPlugin);
323
+
324
+ const executor = new ToolExecutor(makePrompter());
325
+ const result = await executor.execute(
326
+ "file_write",
327
+ { path: "dangerous.txt", content: "should not run" },
328
+ makeContext(),
329
+ );
330
+
331
+ expect(result).toEqual(syntheticResult);
332
+ // The real tool execute must NOT have been called.
333
+ expect(lastToolCall).toBeUndefined();
334
+ });
335
+
336
+ test("slow middleware does not trip a pipeline-level timeout", async () => {
337
+ // Regression: `ToolExecutor.execute` used to pass the per-tool timeout
338
+ // to `runPipeline`, which made the pipeline race everything upstream of
339
+ // the tool call (permission checks, approval waits, middleware) against
340
+ // the same budget. A slow human clicking "allow" produced a
341
+ // `PluginTimeoutError` thrown past `executeInternal`'s catch block,
342
+ // breaking the `execute()` never-throws contract. The pipeline is now
343
+ // untimed; `executeWithTimeout` inside `executeInternal` is the sole
344
+ // enforcer of the per-tool budget and only wraps the actual tool call.
345
+ const slow: Middleware<ToolExecuteArgs, ToolExecuteResult> =
346
+ async function slowMw(args, next) {
347
+ await new Promise((resolve) => setTimeout(resolve, 50));
348
+ return next(args);
349
+ };
350
+ registerPlugin({
351
+ manifest: {
352
+ name: "slow-tool-execute",
353
+ version: "0.0.1",
354
+ requires: { pluginRuntime: "v1" },
355
+ },
356
+ middleware: { toolExecute: slow },
357
+ });
358
+
359
+ const prev = mockConfig.timeouts.toolExecutionTimeoutSec;
360
+ mockConfig.timeouts.toolExecutionTimeoutSec = 0.01;
361
+ try {
362
+ const executor = new ToolExecutor(makePrompter());
363
+ const result = await executor.execute(
364
+ "file_read",
365
+ { path: "README.md" },
366
+ makeContext(),
367
+ );
368
+ // Middleware phase (50ms) exceeds the per-tool budget (10ms), but
369
+ // that budget is only enforced inside `executeWithTimeout` around
370
+ // the tool invocation itself. The terminal runs and succeeds.
371
+ expect(result.isError).toBe(false);
372
+ expect(result.content).toBe("real tool output");
373
+ } finally {
374
+ mockConfig.timeouts.toolExecutionTimeoutSec = prev;
375
+ }
376
+ });
377
+
378
+ test("multiple middlewares compose in registration order (outer-first)", async () => {
379
+ const trace: string[] = [];
380
+
381
+ const outer: Middleware<ToolExecuteArgs, ToolExecuteResult> =
382
+ async function outerMw(args, next) {
383
+ trace.push("outer:before");
384
+ const result = await next(args);
385
+ trace.push("outer:after");
386
+ return result;
387
+ };
388
+ const inner: Middleware<ToolExecuteArgs, ToolExecuteResult> =
389
+ async function innerMw(args, next) {
390
+ trace.push("inner:before");
391
+ const result = await next(args);
392
+ trace.push("inner:after");
393
+ return result;
394
+ };
395
+
396
+ registerPlugin({
397
+ manifest: {
398
+ name: "outer-tool-execute",
399
+ version: "0.0.1",
400
+ requires: { pluginRuntime: "v1" },
401
+ },
402
+ middleware: { toolExecute: outer },
403
+ });
404
+ registerPlugin({
405
+ manifest: {
406
+ name: "inner-tool-execute",
407
+ version: "0.0.1",
408
+ requires: { pluginRuntime: "v1" },
409
+ },
410
+ middleware: { toolExecute: inner },
411
+ });
412
+
413
+ const executor = new ToolExecutor(makePrompter());
414
+ const result = await executor.execute(
415
+ "file_read",
416
+ { path: "README.md" },
417
+ makeContext(),
418
+ );
419
+
420
+ expect(result.isError).toBe(false);
421
+ // Outer middleware wraps inner (registration order = onion order),
422
+ // so the trace is outer:before → inner:before → terminal →
423
+ // inner:after → outer:after.
424
+ expect(trace).toEqual([
425
+ "outer:before",
426
+ "inner:before",
427
+ "inner:after",
428
+ "outer:after",
429
+ ]);
430
+ });
431
+ });
@@ -67,12 +67,6 @@ mock.module("../tools/registry.js", () => ({
67
67
  },
68
68
  }));
69
69
 
70
- mock.module("../hooks/manager.js", () => ({
71
- getHookManager: () => ({
72
- trigger: () => Promise.resolve({ blocked: false }),
73
- }),
74
- }));
75
-
76
70
  import { check, classifyRisk } from "../permissions/checker.js";
77
71
  import { PermissionPrompter } from "../permissions/prompter.js";
78
72
  import { RiskLevel } from "../permissions/types.js";
@@ -3,9 +3,9 @@
3
3
  *
4
4
  * Unlike tool-executor.test.ts, this file does NOT mock ../permissions/checker.js,
5
5
  * so generateAllowlistOptions and generateScopeOptions run through the actual
6
- * implementation (buildShellAllowlistOptions analyzeShellCommand tree-sitter
7
- * WASM parser). This validates the full e2e chain from executor to parser-derived
8
- * allowlist options.
6
+ * implementation. With permission-controls-v3 OFF (the default), bash tools use
7
+ * the legacy shellAllowlistStrategy (buildShellAllowlistOptions action: key
8
+ * patterns). With the flag ON, they use classifier-produced scope ladder options.
9
9
  */
10
10
  import { beforeAll, describe, expect, mock, test } from "bun:test";
11
11
 
@@ -111,13 +111,6 @@ mock.module("../tools/terminal/sandbox.js", () => ({
111
111
  wrapCommand: () => ({ command: "", sandboxed: false }),
112
112
  }));
113
113
 
114
- // ── Hooks manager ──
115
- mock.module("../hooks/manager.js", () => ({
116
- getHookManager: () => ({
117
- trigger: async () => ({ blocked: false }),
118
- }),
119
- }));
120
-
121
114
  // ── Ephemeral permissions ──
122
115
  mock.module("../tasks/ephemeral-permissions.js", () => ({
123
116
  getTaskRunRules: () => [],
@@ -193,6 +186,10 @@ beforeAll(async () => {
193
186
  });
194
187
 
195
188
  describe("ToolExecutor → real shell allowlist integration", () => {
189
+ // These tests run with permission-controls-v3 OFF (default), so
190
+ // generateAllowlistOptions falls through to shellAllowlistStrategy
191
+ // which uses action: key patterns from buildShellAllowlistOptions.
192
+
196
193
  test("simple command produces parser-derived action keys", async () => {
197
194
  const { prompter, getAllowlist, getScopes } = makeCapturingPrompter();
198
195
  const executor = new ToolExecutor(prompter);