@vellumai/assistant 0.6.1 → 0.6.3

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 (463) hide show
  1. package/bun.lock +40 -40
  2. package/bunfig.toml +3 -0
  3. package/docker-entrypoint.sh +12 -2
  4. package/docs/architecture/memory.md +1 -1
  5. package/node_modules/@vellumai/ces-contracts/src/handles.ts +7 -9
  6. package/node_modules/@vellumai/ces-contracts/src/rpc.ts +42 -0
  7. package/openapi.yaml +184 -69
  8. package/package.json +41 -41
  9. package/scripts/generate-openapi.ts +1 -2
  10. package/src/__tests__/acp-session.test.ts +43 -0
  11. package/src/__tests__/app-builder-tool-scripts.test.ts +1 -0
  12. package/src/__tests__/app-executors.test.ts +1 -0
  13. package/src/__tests__/app-source-watcher.test.ts +37 -11
  14. package/src/__tests__/approval-routes-http.test.ts +178 -1
  15. package/src/__tests__/assistant-event-hub.test.ts +30 -0
  16. package/src/__tests__/browser-fill-credential.test.ts +229 -94
  17. package/src/__tests__/browser-manager.test.ts +40 -27
  18. package/src/__tests__/catalog-files.test.ts +862 -0
  19. package/src/__tests__/channel-approvals.test.ts +53 -0
  20. package/src/__tests__/checker.test.ts +104 -170
  21. package/src/__tests__/cli-command-risk-guard.test.ts +1 -1
  22. package/src/__tests__/config-managed-gemini-defaults.test.ts +326 -0
  23. package/src/__tests__/config-schema-cmd.test.ts +2 -2
  24. package/src/__tests__/config-schema.test.ts +125 -48
  25. package/src/__tests__/confirmation-request-guardian-bridge.test.ts +23 -0
  26. package/src/__tests__/context-overflow-approval.test.ts +21 -6
  27. package/src/__tests__/conversation-agent-loop-overflow.test.ts +1 -1
  28. package/src/__tests__/conversation-agent-loop.test.ts +1 -1
  29. package/src/__tests__/conversation-analysis-routes.test.ts +169 -0
  30. package/src/__tests__/conversation-attachments.test.ts +80 -4
  31. package/src/__tests__/conversation-confirmation-signals.test.ts +155 -0
  32. package/src/__tests__/conversation-directories-parse.test.ts +105 -0
  33. package/src/__tests__/conversation-fork-crud.test.ts +17 -0
  34. package/src/__tests__/conversation-history-web-search.test.ts +1 -0
  35. package/src/__tests__/conversation-host-access-routes.test.ts +229 -0
  36. package/src/__tests__/conversation-inject-context.test.ts +103 -0
  37. package/src/__tests__/conversation-queue.test.ts +45 -2
  38. package/src/__tests__/conversation-routes-disk-view.test.ts +5 -0
  39. package/src/__tests__/conversation-routes-guardian-reply.test.ts +16 -0
  40. package/src/__tests__/conversation-routes-slash-commands.test.ts +1 -0
  41. package/src/__tests__/conversation-runtime-assembly.test.ts +269 -46
  42. package/src/__tests__/conversation-starter-routes.test.ts +126 -0
  43. package/src/__tests__/conversation-starters-cadence.test.ts +161 -0
  44. package/src/__tests__/conversation-store.test.ts +195 -0
  45. package/src/__tests__/conversation-workspace-cache-state.test.ts +193 -0
  46. package/src/__tests__/credential-execution-approval-bridge.test.ts +32 -3
  47. package/src/__tests__/credential-security-invariants.test.ts +1 -0
  48. package/src/__tests__/credential-vault-unit.test.ts +4 -4
  49. package/src/__tests__/credential-vault.test.ts +152 -13
  50. package/src/__tests__/credentials-cli.test.ts +2 -2
  51. package/src/__tests__/date-context.test.ts +4 -4
  52. package/src/__tests__/embedding-managed-proxy-selection.test.ts +256 -0
  53. package/src/__tests__/extension-id-sync-guard.test.ts +155 -0
  54. package/src/__tests__/fixtures/mock-chrome-extension.ts +375 -0
  55. package/src/__tests__/gateway-only-guard.test.ts +3 -0
  56. package/src/__tests__/gemini-provider.test.ts +2 -2
  57. package/src/__tests__/guardian-routing-invariants.test.ts +70 -2
  58. package/src/__tests__/headless-browser-interactions.test.ts +707 -371
  59. package/src/__tests__/headless-browser-navigate.test.ts +389 -47
  60. package/src/__tests__/headless-browser-read-tools.test.ts +266 -103
  61. package/src/__tests__/headless-browser-snapshot.test.ts +240 -77
  62. package/src/__tests__/host-bash-proxy.test.ts +150 -1
  63. package/src/__tests__/host-browser-e2e-cloud.test.ts +462 -0
  64. package/src/__tests__/host-browser-e2e-self-hosted-capability.test.ts +286 -0
  65. package/src/__tests__/host-browser-e2e-self-hosted.test.ts +374 -0
  66. package/src/__tests__/host-browser-event-routes.test.ts +350 -0
  67. package/src/__tests__/host-browser-proxy.test.ts +444 -0
  68. package/src/__tests__/host-browser-routes.test.ts +198 -0
  69. package/src/__tests__/host-browser-ws-events-e2e.test.ts +320 -0
  70. package/src/__tests__/host-cu-proxy.test.ts +171 -1
  71. package/src/__tests__/host-file-proxy.test.ts +185 -1
  72. package/src/__tests__/host-file-read-tool.test.ts +52 -0
  73. package/src/__tests__/host-proxy-interface.test.ts +165 -0
  74. package/src/__tests__/host-shell-tool.test.ts +1 -11
  75. package/src/__tests__/http-user-message-parity.test.ts +1 -0
  76. package/src/__tests__/init-feature-flag-overrides.test.ts +167 -0
  77. package/src/__tests__/inline-command-runner.test.ts +7 -5
  78. package/src/__tests__/integration-status.test.ts +6 -7
  79. package/src/__tests__/list-messages-tool-merge.test.ts +37 -12
  80. package/src/__tests__/log-export-workspace.test.ts +190 -0
  81. package/src/__tests__/managed-credential-catalog-cli.test.ts +12 -14
  82. package/src/__tests__/mcp-client-auth.test.ts +40 -4
  83. package/src/__tests__/mcp-health-check.test.ts +10 -3
  84. package/src/__tests__/migration-cross-version-compatibility.test.ts +3 -1
  85. package/src/__tests__/migration-export-http.test.ts +61 -2
  86. package/src/__tests__/migration-export-streaming.test.ts +66 -0
  87. package/src/__tests__/migration-import-commit-http.test.ts +101 -1
  88. package/src/__tests__/native-host-marker-sync-guard.test.ts +157 -0
  89. package/src/__tests__/navigate-settings-tab.test.ts +14 -1
  90. package/src/__tests__/notification-broadcaster.test.ts +65 -0
  91. package/src/__tests__/oauth-apps-routes.test.ts +17 -12
  92. package/src/__tests__/oauth-cli.test.ts +707 -60
  93. package/src/__tests__/oauth-connect-orchestrator.test.ts +116 -24
  94. package/src/__tests__/oauth-provider-seed-logos.test.ts +23 -0
  95. package/src/__tests__/oauth-provider-serializer.test.ts +146 -10
  96. package/src/__tests__/oauth-provider-visibility.test.ts +19 -21
  97. package/src/__tests__/oauth-providers-routes.test.ts +50 -14
  98. package/src/__tests__/oauth-store.test.ts +1386 -182
  99. package/src/__tests__/oauth2-gateway-transport.test.ts +211 -20
  100. package/src/__tests__/onboarding-template-contract.test.ts +74 -55
  101. package/src/__tests__/openai-provider.test.ts +2 -2
  102. package/src/__tests__/outlook-categories.test.ts +1 -1
  103. package/src/__tests__/outlook-client-automation.test.ts +1 -1
  104. package/src/__tests__/outlook-compose-tools.test.ts +1 -1
  105. package/src/__tests__/outlook-email-watcher.test.ts +1 -1
  106. package/src/__tests__/outlook-follow-up.test.ts +1 -1
  107. package/src/__tests__/outlook-messaging-provider.test.ts +2 -2
  108. package/src/__tests__/outlook-trash.test.ts +1 -1
  109. package/src/__tests__/outlook-unsubscribe.test.ts +1 -1
  110. package/src/__tests__/permission-checker-host-gate.test.ts +74 -14
  111. package/src/__tests__/permission-mode.test.ts +28 -56
  112. package/src/__tests__/pkb-autoinject.test.ts +96 -0
  113. package/src/__tests__/platform-callback-registration.test.ts +19 -0
  114. package/src/__tests__/post-turn-tool-result-truncation.test.ts +296 -0
  115. package/src/__tests__/proxy-approval-callback.test.ts +18 -0
  116. package/src/__tests__/require-fresh-approval.test.ts +40 -3
  117. package/src/__tests__/sandbox-diagnostics.test.ts +1 -32
  118. package/src/__tests__/sanitize-config-for-transfer.test.ts +132 -0
  119. package/src/__tests__/schedule-routes.test.ts +162 -0
  120. package/src/__tests__/secret-detection-handler.test.ts +84 -0
  121. package/src/__tests__/secret-ingress-http.test.ts +1 -0
  122. package/src/__tests__/send-endpoint-busy.test.ts +3 -0
  123. package/src/__tests__/set-permission-mode.test.ts +13 -250
  124. package/src/__tests__/skills-file-content-endpoint.test.ts +670 -0
  125. package/src/__tests__/skills-files-catalog-fallback.test.ts +450 -0
  126. package/src/__tests__/slack-channel-config.test.ts +12 -15
  127. package/src/__tests__/subagent-detail.test.ts +44 -2
  128. package/src/__tests__/subagent-disposal.test.ts +1 -0
  129. package/src/__tests__/subagent-fork-notifications.test.ts +291 -0
  130. package/src/__tests__/subagent-fork-spawn.test.ts +384 -0
  131. package/src/__tests__/subagent-manager-notify.test.ts +1 -0
  132. package/src/__tests__/subagent-notify-parent.test.ts +1 -0
  133. package/src/__tests__/subagent-spawn-tool-fork.test.ts +411 -0
  134. package/src/__tests__/subagent-tools.test.ts +1 -0
  135. package/src/__tests__/subagent-types.test.ts +1 -0
  136. package/src/__tests__/system-prompt-ask-mode.test.ts +27 -71
  137. package/src/__tests__/system-prompt.test.ts +72 -1
  138. package/src/__tests__/task-scheduler.test.ts +32 -6
  139. package/src/__tests__/telegram-config.test.ts +10 -13
  140. package/src/__tests__/terminal-sandbox.test.ts +1 -1
  141. package/src/__tests__/terminal-tools.test.ts +11 -5
  142. package/src/__tests__/test-preload.ts +14 -0
  143. package/src/__tests__/tool-approval-handler.test.ts +73 -0
  144. package/src/__tests__/tool-domain-event-publisher.test.ts +0 -1
  145. package/src/__tests__/tool-executor-lifecycle-events.test.ts +1 -8
  146. package/src/__tests__/tool-executor.test.ts +0 -1
  147. package/src/__tests__/tool-side-effects-slack-dm.test.ts +22 -0
  148. package/src/__tests__/top-level-renderer.test.ts +73 -1
  149. package/src/__tests__/transport-hints-queue.test.ts +62 -0
  150. package/src/__tests__/trust-store.test.ts +4 -4
  151. package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +109 -0
  152. package/src/__tests__/v2-consent-policy.test.ts +103 -0
  153. package/src/__tests__/workspace-migration-030-seed-pkb-autoinject.test.ts +168 -0
  154. package/src/__tests__/workspace-policy.test.ts +2 -7
  155. package/src/acp/client-handler.ts +30 -4
  156. package/src/agent/loop.ts +12 -35
  157. package/src/approvals/guardian-request-resolvers.ts +21 -15
  158. package/src/browser-session/__tests__/manager.test.ts +297 -0
  159. package/src/browser-session/backends/cdp-inspect.ts +30 -0
  160. package/src/browser-session/backends/extension.ts +26 -0
  161. package/src/browser-session/backends/local.ts +24 -0
  162. package/src/browser-session/events.ts +164 -0
  163. package/src/browser-session/index.ts +27 -0
  164. package/src/browser-session/manager.ts +159 -0
  165. package/src/browser-session/types.ts +28 -0
  166. package/src/channels/__tests__/types.test.ts +134 -0
  167. package/src/channels/types.ts +55 -0
  168. package/src/cli/__tests__/run-assistant-command.ts +34 -7
  169. package/src/cli/__tests__/unknown-command.test.ts +33 -0
  170. package/src/cli/commands/browser-relay.ts +339 -409
  171. package/src/cli/commands/credentials.ts +3 -3
  172. package/src/cli/commands/default-action.ts +68 -1
  173. package/src/cli/commands/email.ts +18 -13
  174. package/src/cli/commands/mcp.ts +16 -4
  175. package/src/cli/commands/oauth/__tests__/connect.test.ts +68 -41
  176. package/src/cli/commands/oauth/__tests__/disconnect.test.ts +21 -21
  177. package/src/cli/commands/oauth/__tests__/mode.test.ts +17 -17
  178. package/src/cli/commands/oauth/__tests__/ping.test.ts +16 -16
  179. package/src/cli/commands/oauth/__tests__/providers-delete.test.ts +31 -33
  180. package/src/cli/commands/oauth/__tests__/providers-register.test.ts +329 -0
  181. package/src/cli/commands/oauth/__tests__/providers-update.test.ts +116 -12
  182. package/src/cli/commands/oauth/__tests__/status.test.ts +10 -10
  183. package/src/cli/commands/oauth/__tests__/token.test.ts +7 -7
  184. package/src/cli/commands/oauth/apps.ts +7 -4
  185. package/src/cli/commands/oauth/connect.ts +16 -2
  186. package/src/cli/commands/oauth/disconnect.ts +1 -1
  187. package/src/cli/commands/oauth/providers.ts +200 -36
  188. package/src/cli/commands/oauth/shared.ts +5 -5
  189. package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +259 -0
  190. package/src/cli/commands/platform/__tests__/connect.test.ts +1 -1
  191. package/src/cli/commands/platform/__tests__/disconnect.test.ts +1 -1
  192. package/src/cli/commands/platform/__tests__/status.test.ts +1 -1
  193. package/src/cli/commands/platform/index.ts +107 -10
  194. package/src/cli/commands/usage.ts +10 -9
  195. package/src/cli/lib/daemon-credential-client.ts +4 -0
  196. package/src/cli/program.ts +10 -3
  197. package/src/config/assistant-feature-flags.ts +59 -55
  198. package/src/config/bundled-skills/app-builder/SKILL.md +33 -173
  199. package/src/config/bundled-skills/app-builder/references/CUSTOM_ROUTES.md +105 -0
  200. package/src/config/bundled-skills/app-builder/references/INTERACTION_HOOKS.md +56 -0
  201. package/src/config/bundled-skills/app-builder/references/WIDGETS.md +125 -0
  202. package/src/config/bundled-skills/contacts/SKILL.md +3 -0
  203. package/src/config/bundled-skills/document/SKILL.md +4 -0
  204. package/src/config/bundled-skills/gmail/SKILL.md +12 -7
  205. package/src/config/bundled-skills/gmail/TOOLS.json +1 -1
  206. package/src/config/bundled-skills/gmail/tools/gmail-sender-digest.ts +2 -1
  207. package/src/config/bundled-skills/outlook/SKILL.md +7 -0
  208. package/src/config/bundled-skills/settings/TOOLS.json +1 -1
  209. package/src/config/bundled-skills/settings/tools/navigate-settings-tab.ts +8 -3
  210. package/src/config/bundled-skills/subagent/SKILL.md +21 -0
  211. package/src/config/bundled-skills/subagent/TOOLS.json +8 -4
  212. package/src/config/bundled-skills/tasks/SKILL.md +5 -0
  213. package/src/config/env-registry.ts +14 -0
  214. package/src/config/env.ts +21 -0
  215. package/src/config/feature-flag-registry.json +46 -7
  216. package/src/config/loader.ts +56 -1
  217. package/src/config/sanitize-for-transfer.ts +47 -0
  218. package/src/config/schema.ts +46 -5
  219. package/src/config/schemas/host-browser.ts +66 -0
  220. package/src/config/schemas/memory-lifecycle.ts +1 -1
  221. package/src/config/schemas/memory-retrieval.ts +103 -0
  222. package/src/config/schemas/security.ts +0 -6
  223. package/src/config/schemas/services.ts +16 -0
  224. package/src/config/types.ts +0 -1
  225. package/src/context/post-turn-tool-result-truncation.ts +176 -0
  226. package/src/context/window-manager.ts +19 -1
  227. package/src/credential-execution/approval-bridge.ts +49 -16
  228. package/src/credential-execution/managed-catalog.ts +3 -7
  229. package/src/daemon/__tests__/conversation-tool-setup.test.ts +186 -0
  230. package/src/daemon/app-source-watcher.ts +35 -0
  231. package/src/daemon/config-watcher.ts +6 -2
  232. package/src/daemon/context-overflow-approval.ts +5 -1
  233. package/src/daemon/conversation-agent-loop-handlers.ts +17 -2
  234. package/src/daemon/conversation-agent-loop.ts +74 -19
  235. package/src/daemon/conversation-attachments.ts +40 -1
  236. package/src/daemon/conversation-messaging.ts +3 -0
  237. package/src/daemon/conversation-process.ts +66 -3
  238. package/src/daemon/conversation-queue-manager.ts +8 -0
  239. package/src/daemon/conversation-runtime-assembly.ts +159 -20
  240. package/src/daemon/conversation-surfaces.ts +78 -12
  241. package/src/daemon/conversation-tool-setup.ts +74 -11
  242. package/src/daemon/conversation-workspace.ts +12 -0
  243. package/src/daemon/conversation.ts +227 -11
  244. package/src/daemon/date-context.ts +10 -10
  245. package/src/daemon/first-greeting.ts +3 -2
  246. package/src/daemon/handlers/conversations.ts +9 -139
  247. package/src/daemon/handlers/shared.ts +65 -0
  248. package/src/daemon/handlers/skills.ts +232 -37
  249. package/src/daemon/host-bash-proxy.ts +48 -13
  250. package/src/daemon/host-browser-proxy.ts +191 -0
  251. package/src/daemon/host-cu-proxy.ts +36 -11
  252. package/src/daemon/host-file-proxy.ts +57 -9
  253. package/src/daemon/lifecycle.ts +86 -12
  254. package/src/daemon/message-protocol.ts +7 -0
  255. package/src/daemon/message-types/conversations.ts +59 -13
  256. package/src/daemon/message-types/host-browser.ts +100 -0
  257. package/src/daemon/message-types/messages.ts +5 -6
  258. package/src/daemon/message-types/notifications.ts +12 -0
  259. package/src/daemon/message-types/settings.ts +12 -0
  260. package/src/daemon/message-types/skills.ts +10 -0
  261. package/src/daemon/message-types/subagents.ts +2 -0
  262. package/src/daemon/server.ts +112 -35
  263. package/src/daemon/tool-side-effects.ts +6 -0
  264. package/src/daemon/transport-hints.ts +14 -0
  265. package/src/inbound/platform-callback-registration.ts +18 -17
  266. package/src/index.ts +1 -1
  267. package/src/mcp/client.ts +59 -24
  268. package/src/memory/app-store.ts +31 -1
  269. package/src/memory/conversation-crud.ts +38 -10
  270. package/src/memory/conversation-directories.ts +39 -0
  271. package/src/memory/conversation-group-migration.ts +65 -5
  272. package/src/memory/conversation-starters-cadence.ts +76 -0
  273. package/src/memory/conversation-title-service.ts +5 -2
  274. package/src/memory/db-init.ts +12 -0
  275. package/src/memory/embedding-backend.test.ts +75 -0
  276. package/src/memory/embedding-backend.ts +131 -5
  277. package/src/memory/embedding-gemini.test.ts +54 -0
  278. package/src/memory/embedding-gemini.ts +20 -9
  279. package/src/memory/embedding-local.ts +177 -18
  280. package/src/memory/graph/capability-seed.ts +3 -5
  281. package/src/memory/graph/consolidation.ts +10 -23
  282. package/src/memory/graph/extraction-job.ts +15 -0
  283. package/src/memory/graph/retriever.ts +40 -22
  284. package/src/memory/graph/store.test.ts +7 -3
  285. package/src/memory/graph/store.ts +47 -12
  286. package/src/memory/group-crud.ts +25 -9
  287. package/src/memory/llm-usage-store.ts +45 -4
  288. package/src/memory/migrations/213-oauth-providers-scope-separator.ts +13 -0
  289. package/src/memory/migrations/214-oauth-providers-refresh-url.ts +11 -0
  290. package/src/memory/migrations/215-oauth-providers-revoke.ts +14 -0
  291. package/src/memory/migrations/216-oauth-providers-token-auth-method.ts +30 -0
  292. package/src/memory/migrations/217-conversation-host-access.ts +40 -0
  293. package/src/memory/migrations/218-oauth-providers-logo-url.ts +11 -0
  294. package/src/memory/migrations/index.ts +6 -0
  295. package/src/memory/migrations/registry.ts +8 -0
  296. package/src/memory/schema/conversations.ts +1 -0
  297. package/src/memory/schema/oauth.ts +18 -13
  298. package/src/messaging/provider.ts +1 -1
  299. package/src/notifications/broadcaster.ts +6 -0
  300. package/src/notifications/conversation-pairing.ts +12 -4
  301. package/src/notifications/emit-signal.ts +14 -0
  302. package/src/notifications/signal.ts +11 -0
  303. package/src/oauth/AGENTS.md +76 -0
  304. package/src/oauth/__tests__/identity-verifier.test.ts +24 -19
  305. package/src/oauth/__tests__/seed-providers-managed.test.ts +32 -0
  306. package/src/oauth/byo-connection.test.ts +8 -8
  307. package/src/oauth/byo-connection.ts +7 -7
  308. package/src/oauth/connect-orchestrator.ts +23 -21
  309. package/src/oauth/connect-types.ts +3 -3
  310. package/src/oauth/connection-resolver.test.ts +17 -4
  311. package/src/oauth/connection-resolver.ts +16 -16
  312. package/src/oauth/connection.ts +1 -1
  313. package/src/oauth/manual-token-connection.ts +13 -13
  314. package/src/oauth/oauth-store.ts +214 -100
  315. package/src/oauth/platform-connection.test.ts +5 -5
  316. package/src/oauth/platform-connection.ts +4 -4
  317. package/src/oauth/provider-serializer.ts +31 -5
  318. package/src/oauth/revoke.ts +76 -0
  319. package/src/oauth/seed-providers.ts +127 -87
  320. package/src/oauth/token-persistence.ts +1 -1
  321. package/src/permissions/checker.ts +3 -3
  322. package/src/permissions/defaults.ts +7 -8
  323. package/src/permissions/permission-mode.ts +4 -11
  324. package/src/permissions/prompter.ts +13 -3
  325. package/src/permissions/v2-consent-policy.ts +87 -0
  326. package/src/platform/client.ts +1 -1
  327. package/src/prompts/system-prompt.ts +18 -21
  328. package/src/prompts/templates/BOOTSTRAP-REFERENCE.md +3 -65
  329. package/src/prompts/templates/BOOTSTRAP.md +59 -96
  330. package/src/prompts/templates/SOUL.md +11 -11
  331. package/src/providers/anthropic/client.ts +1 -0
  332. package/src/providers/types.ts +1 -1
  333. package/src/runtime/AGENTS.md +23 -0
  334. package/src/runtime/__tests__/browser-extension-pair-routes.test.ts +715 -0
  335. package/src/runtime/__tests__/capability-tokens.test.ts +258 -0
  336. package/src/runtime/__tests__/chrome-extension-registry.test.ts +518 -0
  337. package/src/runtime/assistant-event-hub.ts +24 -2
  338. package/src/runtime/auth/__tests__/guard-tests.test.ts +1 -0
  339. package/src/runtime/auth/__tests__/middleware.test.ts +116 -1
  340. package/src/runtime/auth/__tests__/route-policy.test.ts +8 -0
  341. package/src/runtime/auth/middleware.ts +98 -0
  342. package/src/runtime/auth/route-policy.ts +6 -7
  343. package/src/runtime/auth/token-service.ts +8 -0
  344. package/src/runtime/capability-tokens.ts +414 -0
  345. package/src/runtime/channel-approvals.ts +18 -5
  346. package/src/runtime/chrome-extension-registry.ts +332 -0
  347. package/src/runtime/confirmation-request-guardian-bridge.ts +6 -0
  348. package/src/runtime/guardian-decision-types.ts +7 -0
  349. package/src/runtime/http-server.ts +425 -70
  350. package/src/runtime/migrations/__tests__/rebind-secrets-credentials.test.ts +172 -0
  351. package/src/runtime/migrations/__tests__/vbundle-builder-credentials.test.ts +276 -0
  352. package/src/runtime/migrations/__tests__/vbundle-import-credentials.test.ts +162 -0
  353. package/src/runtime/migrations/migration-transport.ts +6 -0
  354. package/src/runtime/migrations/migration-wizard.ts +22 -2
  355. package/src/runtime/migrations/rebind-secrets-screen.ts +76 -15
  356. package/src/runtime/migrations/vbundle-builder.ts +145 -38
  357. package/src/runtime/migrations/vbundle-import-analyzer.ts +19 -0
  358. package/src/runtime/migrations/vbundle-importer.ts +55 -5
  359. package/src/runtime/pending-interactions.ts +29 -13
  360. package/src/runtime/routes/approval-routes.ts +90 -16
  361. package/src/runtime/routes/browser-cdp-routes.ts +229 -0
  362. package/src/runtime/routes/browser-extension-pair-routes.ts +497 -0
  363. package/src/runtime/routes/conversation-analysis-routes.ts +18 -5
  364. package/src/runtime/routes/conversation-management-routes.ts +108 -0
  365. package/src/runtime/routes/conversation-routes.ts +308 -28
  366. package/src/runtime/routes/conversation-starter-routes.ts +78 -16
  367. package/src/runtime/routes/group-routes.ts +22 -8
  368. package/src/runtime/routes/guardian-action-routes.ts +24 -13
  369. package/src/runtime/routes/host-browser-routes.ts +279 -0
  370. package/src/runtime/routes/host-file-routes.ts +9 -1
  371. package/src/runtime/routes/identity-routes.ts +259 -16
  372. package/src/runtime/routes/log-export/AGENTS.md +104 -0
  373. package/src/runtime/routes/log-export/__tests__/workspace-allowlist-error-contract.test.ts +103 -0
  374. package/src/runtime/routes/log-export/__tests__/workspace-allowlist.test.ts +716 -0
  375. package/src/runtime/routes/log-export/workspace-allowlist.ts +458 -0
  376. package/src/runtime/routes/log-export-routes.ts +60 -25
  377. package/src/runtime/routes/memory-item-routes.ts +1 -7
  378. package/src/runtime/routes/migration-routes.ts +87 -2
  379. package/src/runtime/routes/oauth-apps.ts +15 -17
  380. package/src/runtime/routes/oauth-providers.ts +4 -0
  381. package/src/runtime/routes/schedule-routes.ts +24 -11
  382. package/src/runtime/routes/settings-routes.ts +9 -97
  383. package/src/runtime/routes/skills-routes.ts +52 -2
  384. package/src/runtime/routes/subagents-routes.ts +14 -10
  385. package/src/runtime/routes/usage-routes.ts +8 -7
  386. package/src/runtime/routes/workspace-routes.test.ts +22 -0
  387. package/src/runtime/routes/workspace-routes.ts +8 -1
  388. package/src/runtime/routes/workspace-utils.ts +2 -0
  389. package/src/schedule/scheduler.ts +7 -5
  390. package/src/security/ces-credential-client.ts +20 -0
  391. package/src/security/ces-rpc-credential-backend.ts +17 -0
  392. package/src/security/credential-backend.ts +5 -0
  393. package/src/security/oauth2.ts +42 -25
  394. package/src/security/secure-keys.ts +118 -25
  395. package/src/security/token-manager.ts +23 -10
  396. package/src/skills/catalog-files.ts +492 -0
  397. package/src/skills/inline-command-runner.ts +12 -14
  398. package/src/subagent/manager.ts +131 -26
  399. package/src/subagent/types.ts +19 -0
  400. package/src/tools/apps/executors.ts +11 -2
  401. package/src/tools/browser/__tests__/auth-detector.test.ts +202 -108
  402. package/src/tools/browser/auth-detector.ts +43 -12
  403. package/src/tools/browser/browser-execution.ts +645 -340
  404. package/src/tools/browser/browser-manager.ts +36 -12
  405. package/src/tools/browser/cdp-client/__tests__/accessibility-snapshot.test.ts +318 -0
  406. package/src/tools/browser/cdp-client/__tests__/cdp-dom-helpers.test.ts +1175 -0
  407. package/src/tools/browser/cdp-client/__tests__/cdp-inspect-client.test.ts +870 -0
  408. package/src/tools/browser/cdp-client/__tests__/extension-cdp-client.test.ts +330 -0
  409. package/src/tools/browser/cdp-client/__tests__/factory.test.ts +377 -0
  410. package/src/tools/browser/cdp-client/__tests__/fixtures/ax-tree-nested-frames.json +64 -0
  411. package/src/tools/browser/cdp-client/__tests__/fixtures/ax-tree-simple.json +69 -0
  412. package/src/tools/browser/cdp-client/__tests__/local-cdp-client.test.ts +310 -0
  413. package/src/tools/browser/cdp-client/__tests__/types.test.ts +96 -0
  414. package/src/tools/browser/cdp-client/accessibility-snapshot.ts +387 -0
  415. package/src/tools/browser/cdp-client/cdp-dom-helpers.ts +695 -0
  416. package/src/tools/browser/cdp-client/cdp-inspect/__tests__/discovery.test.ts +743 -0
  417. package/src/tools/browser/cdp-client/cdp-inspect/__tests__/ws-transport.test.ts +580 -0
  418. package/src/tools/browser/cdp-client/cdp-inspect/discovery.ts +578 -0
  419. package/src/tools/browser/cdp-client/cdp-inspect/ws-transport.ts +579 -0
  420. package/src/tools/browser/cdp-client/cdp-inspect-client.ts +635 -0
  421. package/src/tools/browser/cdp-client/errors.ts +34 -0
  422. package/src/tools/browser/cdp-client/extension-cdp-client.ts +125 -0
  423. package/src/tools/browser/cdp-client/factory.ts +204 -0
  424. package/src/tools/browser/cdp-client/index.ts +14 -0
  425. package/src/tools/browser/cdp-client/local-cdp-client.ts +187 -0
  426. package/src/tools/browser/cdp-client/types.ts +52 -0
  427. package/src/tools/filesystem/edit.ts +1 -1
  428. package/src/tools/filesystem/list.ts +1 -1
  429. package/src/tools/filesystem/read.ts +1 -1
  430. package/src/tools/filesystem/write.ts +2 -1
  431. package/src/tools/host-filesystem/edit.ts +1 -1
  432. package/src/tools/host-filesystem/read.ts +12 -15
  433. package/src/tools/host-filesystem/write.ts +1 -1
  434. package/src/tools/host-terminal/host-shell.ts +21 -16
  435. package/src/tools/permission-checker.ts +77 -100
  436. package/src/tools/registry.ts +0 -2
  437. package/src/tools/secret-detection-handler.ts +34 -1
  438. package/src/tools/shared/filesystem/image-read.ts +61 -40
  439. package/src/tools/skills/sandbox-runner.ts +3 -6
  440. package/src/tools/subagent/spawn.ts +47 -3
  441. package/src/tools/subagent/status.ts +2 -0
  442. package/src/tools/system/register.ts +2 -16
  443. package/src/tools/terminal/safe-env.ts +7 -0
  444. package/src/tools/terminal/sandbox-diagnostics.ts +4 -4
  445. package/src/tools/terminal/sandbox.ts +4 -1
  446. package/src/tools/terminal/shell.ts +24 -21
  447. package/src/tools/tool-approval-handler.ts +48 -2
  448. package/src/tools/types.ts +2 -3
  449. package/src/util/platform.ts +14 -19
  450. package/src/watcher/provider-types.ts +1 -1
  451. package/src/workspace/migrations/029-seed-pkb.ts +1 -0
  452. package/src/workspace/migrations/030-seed-pkb-autoinject.ts +73 -0
  453. package/src/workspace/migrations/registry.ts +2 -0
  454. package/src/workspace/top-level-renderer.ts +19 -1
  455. package/src/__tests__/chrome-cdp.test.ts +0 -419
  456. package/src/__tests__/permission-mode-sse.test.ts +0 -418
  457. package/src/__tests__/permission-mode-store.test.ts +0 -277
  458. package/src/browser-extension-relay/protocol.ts +0 -63
  459. package/src/browser-extension-relay/server.ts +0 -203
  460. package/src/config/schemas/sandbox.ts +0 -14
  461. package/src/permissions/permission-mode-store.ts +0 -180
  462. package/src/tools/browser/chrome-cdp.ts +0 -239
  463. package/src/tools/system/set-permission-mode.ts +0 -103
@@ -0,0 +1,162 @@
1
+ import { beforeEach, describe, expect, mock, test } from "bun:test";
2
+
3
+ mock.module("../util/logger.js", () => ({
4
+ getLogger: () =>
5
+ new Proxy({} as Record<string, unknown>, {
6
+ get: () => () => {},
7
+ }),
8
+ }));
9
+
10
+ import { getDb, initializeDb } from "../memory/db.js";
11
+ import { scheduleRouteDefinitions } from "../runtime/routes/schedule-routes.js";
12
+ import { createSchedule } from "../schedule/schedule-store.js";
13
+ import { scheduleTask } from "../tasks/task-scheduler.js";
14
+ import { createTask } from "../tasks/task-store.js";
15
+
16
+ initializeDb();
17
+
18
+ function clearTables(): void {
19
+ const db = getDb();
20
+ db.run("DELETE FROM cron_runs");
21
+ db.run("DELETE FROM cron_jobs");
22
+ db.run("DELETE FROM task_runs");
23
+ db.run("DELETE FROM tasks");
24
+ db.run("DELETE FROM messages");
25
+ db.run("DELETE FROM conversations");
26
+ }
27
+
28
+ function getRunNowHandler(sendMessageDeps: {
29
+ getOrCreateConversation: (
30
+ conversationId: string,
31
+ options?: Record<string, unknown>,
32
+ ) => Promise<unknown>;
33
+ }) {
34
+ const route = scheduleRouteDefinitions({
35
+ sendMessageDeps: sendMessageDeps as never,
36
+ }).find(
37
+ (candidate) =>
38
+ candidate.endpoint === "schedules/:id/run" && candidate.method === "POST",
39
+ );
40
+ if (!route) {
41
+ throw new Error("Run-now schedule route not found");
42
+ }
43
+ return route.handler;
44
+ }
45
+
46
+ describe("schedule run-now trust propagation", () => {
47
+ beforeEach(() => {
48
+ clearTables();
49
+ });
50
+
51
+ test("manual run-now executes plain schedules with guardian trust", async () => {
52
+ const schedule = createSchedule({
53
+ name: "Direct schedule",
54
+ cronExpression: "* * * * *",
55
+ message: "scan my inbox",
56
+ syntax: "cron",
57
+ });
58
+
59
+ const getOrCreateCalls: Array<{
60
+ conversationId: string;
61
+ options?: Record<string, unknown>;
62
+ }> = [];
63
+ const processCalls: Array<unknown[]> = [];
64
+ const fakeConversation: {
65
+ taskRunId?: string;
66
+ processMessage: (...args: unknown[]) => Promise<string>;
67
+ } = {
68
+ taskRunId: "stale-task-run",
69
+ async processMessage(...args: unknown[]) {
70
+ processCalls.push(args);
71
+ return "message-id";
72
+ },
73
+ };
74
+
75
+ const handler = getRunNowHandler({
76
+ getOrCreateConversation: async (conversationId, options) => {
77
+ getOrCreateCalls.push({ conversationId, options });
78
+ return fakeConversation;
79
+ },
80
+ });
81
+
82
+ const response = await handler({
83
+ req: new Request(`http://localhost/v1/schedules/${schedule.id}/run`, {
84
+ method: "POST",
85
+ }),
86
+ url: new URL(`http://localhost/v1/schedules/${schedule.id}/run`),
87
+ server: {} as never,
88
+ authContext: {} as never,
89
+ params: { id: schedule.id },
90
+ });
91
+
92
+ expect(response.status).toBe(200);
93
+ expect(getOrCreateCalls).toHaveLength(1);
94
+ expect(getOrCreateCalls[0].options?.trustContext).toEqual({
95
+ sourceChannel: "vellum",
96
+ trustClass: "guardian",
97
+ });
98
+ expect(processCalls).toHaveLength(1);
99
+ expect(processCalls[0][0]).toBe("scan my inbox");
100
+ expect(processCalls[0][6]).toEqual({ isInteractive: false });
101
+ expect(fakeConversation.taskRunId).toBeUndefined();
102
+ });
103
+
104
+ test("manual run-now executes scheduled tasks with guardian trust and taskRunId", async () => {
105
+ const task = createTask({
106
+ title: "Email triage",
107
+ template: "triage inbox in background",
108
+ });
109
+ const schedule = scheduleTask({
110
+ taskId: task.id,
111
+ name: "Scheduled task",
112
+ cronExpression: "* * * * *",
113
+ });
114
+
115
+ const getOrCreateCalls: Array<{
116
+ conversationId: string;
117
+ options?: Record<string, unknown>;
118
+ }> = [];
119
+ const observedTaskRunIds: Array<string | undefined> = [];
120
+ const processCalls: Array<unknown[]> = [];
121
+ const fakeConversation: {
122
+ taskRunId?: string;
123
+ processMessage: (...args: unknown[]) => Promise<string>;
124
+ } = {
125
+ taskRunId: undefined,
126
+ async processMessage(...args: unknown[]) {
127
+ observedTaskRunIds.push(fakeConversation.taskRunId);
128
+ processCalls.push(args);
129
+ return "message-id";
130
+ },
131
+ };
132
+
133
+ const handler = getRunNowHandler({
134
+ getOrCreateConversation: async (conversationId, options) => {
135
+ getOrCreateCalls.push({ conversationId, options });
136
+ return fakeConversation;
137
+ },
138
+ });
139
+
140
+ const response = await handler({
141
+ req: new Request(`http://localhost/v1/schedules/${schedule.id}/run`, {
142
+ method: "POST",
143
+ }),
144
+ url: new URL(`http://localhost/v1/schedules/${schedule.id}/run`),
145
+ server: {} as never,
146
+ authContext: {} as never,
147
+ params: { id: schedule.id },
148
+ });
149
+
150
+ expect(response.status).toBe(200);
151
+ expect(getOrCreateCalls).toHaveLength(1);
152
+ expect(getOrCreateCalls[0].options?.trustContext).toEqual({
153
+ sourceChannel: "vellum",
154
+ trustClass: "guardian",
155
+ });
156
+ expect(processCalls).toHaveLength(1);
157
+ expect(processCalls[0][0]).toBe("triage inbox in background");
158
+ expect(processCalls[0][6]).toEqual({ isInteractive: false });
159
+ expect(typeof observedTaskRunIds[0]).toBe("string");
160
+ expect(fakeConversation.taskRunId).toBeUndefined();
161
+ });
162
+ });
@@ -0,0 +1,84 @@
1
+ import { beforeEach, describe, expect, mock, test } from "bun:test";
2
+
3
+ import { _setOverridesForTesting } from "../config/assistant-feature-flags.js";
4
+
5
+ const triggerMock = mock(async () => {});
6
+ const scanTextMock = mock(() => [
7
+ { type: "api_key", redactedValue: "sk-***redacted***" },
8
+ ]);
9
+
10
+ mock.module("../config/loader.js", () => ({
11
+ getConfig: () => ({
12
+ secretDetection: {
13
+ enabled: true,
14
+ action: "prompt",
15
+ entropyThreshold: 4.5,
16
+ customPatterns: [],
17
+ },
18
+ }),
19
+ }));
20
+
21
+ mock.module("../hooks/manager.js", () => ({
22
+ getHookManager: () => ({
23
+ trigger: triggerMock,
24
+ }),
25
+ }));
26
+
27
+ mock.module("../security/secret-scanner.js", () => ({
28
+ compileCustomPatterns: () => [],
29
+ redactSecrets: (content: string) => content,
30
+ scanText: scanTextMock,
31
+ }));
32
+
33
+ import { SecretDetectionHandler } from "../tools/secret-detection-handler.js";
34
+
35
+ describe("SecretDetectionHandler under v2", () => {
36
+ beforeEach(() => {
37
+ _setOverridesForTesting({});
38
+ triggerMock.mockClear();
39
+ scanTextMock.mockClear();
40
+ });
41
+
42
+ test("blocks secret output without opening a deterministic approval prompt", async () => {
43
+ _setOverridesForTesting({ "permission-controls-v2": true });
44
+
45
+ const promptMock = mock(async () => ({ decision: "allow" as const }));
46
+ const handler = new SecretDetectionHandler({
47
+ prompt: promptMock,
48
+ } as never);
49
+ const emitLifecycleEvent = mock(() => {});
50
+
51
+ const result = await handler.handle(
52
+ { content: "secret output", isError: false },
53
+ "bash",
54
+ { command: "print-secret" },
55
+ {
56
+ conversationId: "conv-1",
57
+ workingDir: "/tmp",
58
+ requestId: "req-1",
59
+ isInteractive: true,
60
+ } as never,
61
+ "sandbox",
62
+ "medium",
63
+ "allow",
64
+ Date.now(),
65
+ emitLifecycleEvent,
66
+ (_toolName, input) => input,
67
+ );
68
+
69
+ expect(result.earlyReturn).toBe(true);
70
+ expect(result.result.isError).toBe(true);
71
+ expect(result.result.content).toContain(
72
+ "Secret-output approval cards are disabled under v2",
73
+ );
74
+ expect(promptMock).not.toHaveBeenCalled();
75
+ expect(emitLifecycleEvent).toHaveBeenCalledWith(
76
+ expect.anything(),
77
+ expect.objectContaining({
78
+ type: "permission_denied",
79
+ decision: "deny",
80
+ }),
81
+ );
82
+ expect(triggerMock).toHaveBeenCalled();
83
+ });
84
+ });
@@ -175,6 +175,7 @@ function makeSendMessageDeps() {
175
175
  trustContext: undefined,
176
176
  hasPendingConfirmation: () => false,
177
177
  setHostBashProxy: () => {},
178
+ setHostBrowserProxy: () => {},
178
179
  setHostFileProxy: () => {},
179
180
  setHostCuProxy: () => {},
180
181
  addPreactivatedSkillId: () => {},
@@ -115,6 +115,7 @@ function makeCompletingConversation(): Conversation {
115
115
  usageStats: { inputTokens: 0, outputTokens: 0, estimatedCost: 0 },
116
116
  updateClient: () => {},
117
117
  setHostBashProxy: () => {},
118
+ setHostBrowserProxy: () => {},
118
119
  setHostFileProxy: () => {},
119
120
  setHostCuProxy: () => {},
120
121
  addPreactivatedSkillId: () => {},
@@ -173,6 +174,7 @@ function makeHangingConversation(): Conversation {
173
174
  usageStats: { inputTokens: 0, outputTokens: 0, estimatedCost: 0 },
174
175
  updateClient: () => {},
175
176
  setHostBashProxy: () => {},
177
+ setHostBrowserProxy: () => {},
176
178
  setHostFileProxy: () => {},
177
179
  setHostCuProxy: () => {},
178
180
  addPreactivatedSkillId: () => {},
@@ -259,6 +261,7 @@ function makePendingApprovalConversation(
259
261
  usageStats: { inputTokens: 0, outputTokens: 0, estimatedCost: 0 },
260
262
  updateClient: () => {},
261
263
  setHostBashProxy: () => {},
264
+ setHostBrowserProxy: () => {},
262
265
  setHostFileProxy: () => {},
263
266
  setHostCuProxy: () => {},
264
267
  addPreactivatedSkillId: () => {},
@@ -1,274 +1,37 @@
1
- /**
2
- * Tests for the set_permission_mode system tool.
3
- *
4
- * Verifies:
5
- * - Mode transitions via askBeforeActing and hostAccess
6
- * - Partial updates (only provided fields change)
7
- * - Idempotent calls (setting same value is safe)
8
- * - Error when no fields provided
9
- * - Tool is not registered when permission-controls-v2 flag is off
10
- * - Tool is registered when permission-controls-v2 flag is on
11
- */
12
-
13
- import { existsSync, mkdirSync, writeFileSync } from "node:fs";
14
- import { join } from "node:path";
15
- import {
16
- afterAll,
17
- afterEach,
18
- beforeEach,
19
- describe,
20
- expect,
21
- mock,
22
- test,
23
- } from "bun:test";
24
-
25
- // ---------------------------------------------------------------------------
26
- // Mocks — declared before imports that depend on platform/logger
27
- // ---------------------------------------------------------------------------
28
-
29
- const WORKSPACE_DIR = process.env.VELLUM_WORKSPACE_DIR!;
30
- const CONFIG_PATH = join(WORKSPACE_DIR, "config.json");
31
-
32
- function ensureTestDir(): void {
33
- const dirs = [
34
- WORKSPACE_DIR,
35
- join(WORKSPACE_DIR, "data"),
36
- join(WORKSPACE_DIR, "data", "logs"),
37
- ];
38
- for (const dir of dirs) {
39
- if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
40
- }
41
- }
42
-
43
- function makeLoggerStub(): Record<string, unknown> {
44
- const stub: Record<string, unknown> = {};
45
- for (const m of [
46
- "info",
47
- "warn",
48
- "error",
49
- "debug",
50
- "trace",
51
- "fatal",
52
- "silent",
53
- "child",
54
- ]) {
55
- stub[m] = m === "child" ? () => makeLoggerStub() : () => {};
56
- }
57
- return stub;
58
- }
1
+ import { afterAll, beforeEach, describe, expect, mock, test } from "bun:test";
59
2
 
60
3
  mock.module("../util/logger.js", () => ({
61
- getLogger: () => makeLoggerStub(),
4
+ getLogger: () =>
5
+ new Proxy({} as Record<string, unknown>, {
6
+ get: () => () => {},
7
+ }),
62
8
  }));
63
9
 
64
- afterAll(() => {
65
- mock.restore();
66
- });
67
-
68
10
  import { _setOverridesForTesting } from "../config/assistant-feature-flags.js";
69
- import { invalidateConfigCache } from "../config/loader.js";
70
- import {
71
- getMode,
72
- resetForTesting,
73
- } from "../permissions/permission-mode-store.js";
74
11
  import { __clearRegistryForTesting, getTool } from "../tools/registry.js";
75
12
  import { registerSystemTools } from "../tools/system/register.js";
76
- import { setPermissionModeTool } from "../tools/system/set-permission-mode.js";
77
- import type { ToolContext } from "../tools/types.js";
78
-
79
- // ---------------------------------------------------------------------------
80
- // Helpers
81
- // ---------------------------------------------------------------------------
82
-
83
- function writeConfig(obj: unknown): void {
84
- ensureTestDir();
85
- writeFileSync(CONFIG_PATH, JSON.stringify(obj, null, 2) + "\n");
86
- }
87
-
88
- function makeContext(): ToolContext {
89
- return {
90
- workingDir: WORKSPACE_DIR,
91
- conversationId: "test-conversation",
92
- trustClass: "guardian",
93
- };
94
- }
95
-
96
- // ---------------------------------------------------------------------------
97
- // Setup / teardown
98
- // ---------------------------------------------------------------------------
99
13
 
100
14
  beforeEach(() => {
101
- ensureTestDir();
102
- resetForTesting();
103
- invalidateConfigCache();
104
15
  _setOverridesForTesting({});
105
16
  __clearRegistryForTesting();
106
- // Write a minimal config so the store initializes cleanly
107
- writeConfig({});
108
17
  });
109
18
 
110
- afterEach(() => {
111
- resetForTesting();
112
- invalidateConfigCache();
113
- _setOverridesForTesting({});
114
- __clearRegistryForTesting();
115
- });
116
-
117
- // ---------------------------------------------------------------------------
118
- // Tests — tool execution
119
- // ---------------------------------------------------------------------------
120
-
121
- describe("set_permission_mode tool", () => {
122
- describe("mode transitions", () => {
123
- test("sets askBeforeActing to false", async () => {
124
- const result = await setPermissionModeTool.execute(
125
- { askBeforeActing: false },
126
- makeContext(),
127
- );
128
-
129
- expect(result.isError).toBe(false);
130
- expect(result.content).toContain("askBeforeActing: false");
131
-
132
- const mode = getMode();
133
- expect(mode.askBeforeActing).toBe(false);
134
- });
135
-
136
- test("sets hostAccess to true", async () => {
137
- const result = await setPermissionModeTool.execute(
138
- { hostAccess: true },
139
- makeContext(),
140
- );
141
-
142
- expect(result.isError).toBe(false);
143
- expect(result.content).toContain("hostAccess: true");
144
-
145
- const mode = getMode();
146
- expect(mode.hostAccess).toBe(true);
147
- });
148
-
149
- test("sets both fields at once", async () => {
150
- const result = await setPermissionModeTool.execute(
151
- { askBeforeActing: false, hostAccess: true },
152
- makeContext(),
153
- );
154
-
155
- expect(result.isError).toBe(false);
156
- expect(result.content).toContain("askBeforeActing: false");
157
- expect(result.content).toContain("hostAccess: true");
158
-
159
- const mode = getMode();
160
- expect(mode.askBeforeActing).toBe(false);
161
- expect(mode.hostAccess).toBe(true);
162
- });
163
- });
164
-
165
- describe("partial updates", () => {
166
- test("only askBeforeActing changes, hostAccess unchanged", async () => {
167
- await setPermissionModeTool.execute(
168
- { askBeforeActing: false },
169
- makeContext(),
170
- );
171
-
172
- const mode = getMode();
173
- expect(mode.askBeforeActing).toBe(false);
174
- // hostAccess should remain at default (false)
175
- expect(mode.hostAccess).toBe(false);
176
- });
177
-
178
- test("only hostAccess changes, askBeforeActing unchanged", async () => {
179
- await setPermissionModeTool.execute({ hostAccess: true }, makeContext());
180
-
181
- const mode = getMode();
182
- // askBeforeActing should remain at default (true)
183
- expect(mode.askBeforeActing).toBe(true);
184
- expect(mode.hostAccess).toBe(true);
185
- });
186
- });
187
-
188
- describe("idempotent calls", () => {
189
- test("setting askBeforeActing to current value is safe", async () => {
190
- // Default is true
191
- const result = await setPermissionModeTool.execute(
192
- { askBeforeActing: true },
193
- makeContext(),
194
- );
195
-
196
- expect(result.isError).toBe(false);
197
- expect(getMode().askBeforeActing).toBe(true);
198
- });
199
-
200
- test("setting hostAccess to current value is safe", async () => {
201
- // Default is false
202
- const result = await setPermissionModeTool.execute(
203
- { hostAccess: false },
204
- makeContext(),
205
- );
206
-
207
- expect(result.isError).toBe(false);
208
- expect(getMode().hostAccess).toBe(false);
209
- });
210
-
211
- test("repeated calls produce same result", async () => {
212
- await setPermissionModeTool.execute(
213
- { askBeforeActing: false, hostAccess: true },
214
- makeContext(),
215
- );
216
- const result = await setPermissionModeTool.execute(
217
- { askBeforeActing: false, hostAccess: true },
218
- makeContext(),
219
- );
220
-
221
- expect(result.isError).toBe(false);
222
- const mode = getMode();
223
- expect(mode.askBeforeActing).toBe(false);
224
- expect(mode.hostAccess).toBe(true);
225
- });
226
- });
227
-
228
- describe("validation", () => {
229
- test("returns error when no fields provided", async () => {
230
- const result = await setPermissionModeTool.execute({}, makeContext());
231
-
232
- expect(result.isError).toBe(true);
233
- expect(result.content).toContain("at least one");
234
- });
235
- });
236
-
237
- describe("tool definition", () => {
238
- test("has correct name", () => {
239
- expect(setPermissionModeTool.name).toBe("set_permission_mode");
240
- });
241
-
242
- test("has correct category", () => {
243
- expect(setPermissionModeTool.category).toBe("system");
244
- });
245
-
246
- test("definition includes both properties", () => {
247
- const def = setPermissionModeTool.getDefinition();
248
- const schema = def.input_schema as { properties?: Record<string, unknown> };
249
- const props = schema.properties as Record<string, unknown>;
250
- expect(props).toHaveProperty("askBeforeActing");
251
- expect(props).toHaveProperty("hostAccess");
252
- });
253
- });
19
+ afterAll(() => {
20
+ mock.restore();
254
21
  });
255
22
 
256
- // ---------------------------------------------------------------------------
257
- // Tests feature flag gating
258
- // ---------------------------------------------------------------------------
259
-
260
- describe("set_permission_mode registration", () => {
261
- test("tool is NOT registered when permission-controls-v2 flag is off", () => {
262
- _setOverridesForTesting({ "permission-controls-v2": false });
23
+ describe("set_permission_mode removal", () => {
24
+ test("tool is not registered when system tools are initialized", () => {
25
+ _setOverridesForTesting({ "permission-controls-v2": true });
263
26
  registerSystemTools();
264
27
 
265
28
  expect(getTool("set_permission_mode")).toBeUndefined();
266
29
  });
267
30
 
268
- test("tool IS registered when permission-controls-v2 flag is on", () => {
269
- _setOverridesForTesting({ "permission-controls-v2": true });
31
+ test("tool stays unavailable even when the feature flag is disabled", () => {
32
+ _setOverridesForTesting({ "permission-controls-v2": false });
270
33
  registerSystemTools();
271
34
 
272
- expect(getTool("set_permission_mode")).toBeDefined();
35
+ expect(getTool("set_permission_mode")).toBeUndefined();
273
36
  });
274
37
  });