@vellumai/assistant 0.6.2 → 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 (396) hide show
  1. package/bun.lock +40 -40
  2. package/bunfig.toml +3 -0
  3. package/docs/architecture/memory.md +1 -1
  4. package/node_modules/@vellumai/ces-contracts/src/rpc.ts +42 -0
  5. package/openapi.yaml +184 -69
  6. package/package.json +41 -41
  7. package/scripts/generate-openapi.ts +1 -2
  8. package/src/__tests__/acp-session.test.ts +43 -0
  9. package/src/__tests__/app-builder-tool-scripts.test.ts +1 -0
  10. package/src/__tests__/app-executors.test.ts +1 -0
  11. package/src/__tests__/app-source-watcher.test.ts +37 -11
  12. package/src/__tests__/approval-routes-http.test.ts +178 -1
  13. package/src/__tests__/browser-fill-credential.test.ts +229 -94
  14. package/src/__tests__/browser-manager.test.ts +40 -27
  15. package/src/__tests__/catalog-files.test.ts +862 -0
  16. package/src/__tests__/channel-approvals.test.ts +53 -0
  17. package/src/__tests__/config-managed-gemini-defaults.test.ts +326 -0
  18. package/src/__tests__/config-schema-cmd.test.ts +2 -2
  19. package/src/__tests__/config-schema.test.ts +125 -48
  20. package/src/__tests__/confirmation-request-guardian-bridge.test.ts +23 -0
  21. package/src/__tests__/context-overflow-approval.test.ts +16 -1
  22. package/src/__tests__/conversation-agent-loop-overflow.test.ts +1 -1
  23. package/src/__tests__/conversation-agent-loop.test.ts +1 -1
  24. package/src/__tests__/conversation-analysis-routes.test.ts +2 -2
  25. package/src/__tests__/conversation-attachments.test.ts +80 -4
  26. package/src/__tests__/conversation-confirmation-signals.test.ts +155 -0
  27. package/src/__tests__/conversation-fork-crud.test.ts +17 -0
  28. package/src/__tests__/conversation-history-web-search.test.ts +1 -0
  29. package/src/__tests__/conversation-host-access-routes.test.ts +229 -0
  30. package/src/__tests__/conversation-inject-context.test.ts +103 -0
  31. package/src/__tests__/conversation-queue.test.ts +45 -2
  32. package/src/__tests__/conversation-routes-disk-view.test.ts +5 -0
  33. package/src/__tests__/conversation-routes-guardian-reply.test.ts +16 -0
  34. package/src/__tests__/conversation-routes-slash-commands.test.ts +1 -0
  35. package/src/__tests__/conversation-runtime-assembly.test.ts +269 -46
  36. package/src/__tests__/conversation-starter-routes.test.ts +126 -0
  37. package/src/__tests__/conversation-starters-cadence.test.ts +161 -0
  38. package/src/__tests__/conversation-store.test.ts +195 -0
  39. package/src/__tests__/conversation-workspace-cache-state.test.ts +193 -0
  40. package/src/__tests__/credential-execution-approval-bridge.test.ts +32 -1
  41. package/src/__tests__/credential-security-invariants.test.ts +1 -0
  42. package/src/__tests__/credential-vault-unit.test.ts +4 -4
  43. package/src/__tests__/credential-vault.test.ts +152 -13
  44. package/src/__tests__/credentials-cli.test.ts +2 -2
  45. package/src/__tests__/date-context.test.ts +4 -4
  46. package/src/__tests__/embedding-managed-proxy-selection.test.ts +256 -0
  47. package/src/__tests__/extension-id-sync-guard.test.ts +155 -0
  48. package/src/__tests__/fixtures/mock-chrome-extension.ts +375 -0
  49. package/src/__tests__/gateway-only-guard.test.ts +3 -0
  50. package/src/__tests__/gemini-provider.test.ts +2 -2
  51. package/src/__tests__/guardian-routing-invariants.test.ts +70 -2
  52. package/src/__tests__/headless-browser-interactions.test.ts +707 -371
  53. package/src/__tests__/headless-browser-navigate.test.ts +389 -47
  54. package/src/__tests__/headless-browser-read-tools.test.ts +266 -103
  55. package/src/__tests__/headless-browser-snapshot.test.ts +240 -77
  56. package/src/__tests__/host-bash-proxy.test.ts +150 -1
  57. package/src/__tests__/host-browser-e2e-cloud.test.ts +462 -0
  58. package/src/__tests__/host-browser-e2e-self-hosted-capability.test.ts +286 -0
  59. package/src/__tests__/host-browser-e2e-self-hosted.test.ts +374 -0
  60. package/src/__tests__/host-browser-event-routes.test.ts +350 -0
  61. package/src/__tests__/host-browser-proxy.test.ts +444 -0
  62. package/src/__tests__/host-browser-routes.test.ts +198 -0
  63. package/src/__tests__/host-browser-ws-events-e2e.test.ts +320 -0
  64. package/src/__tests__/host-cu-proxy.test.ts +171 -1
  65. package/src/__tests__/host-file-proxy.test.ts +185 -1
  66. package/src/__tests__/host-file-read-tool.test.ts +52 -0
  67. package/src/__tests__/host-proxy-interface.test.ts +165 -0
  68. package/src/__tests__/host-shell-tool.test.ts +1 -11
  69. package/src/__tests__/http-user-message-parity.test.ts +1 -0
  70. package/src/__tests__/integration-status.test.ts +6 -7
  71. package/src/__tests__/list-messages-tool-merge.test.ts +37 -12
  72. package/src/__tests__/mcp-client-auth.test.ts +40 -4
  73. package/src/__tests__/mcp-health-check.test.ts +10 -3
  74. package/src/__tests__/migration-cross-version-compatibility.test.ts +3 -1
  75. package/src/__tests__/migration-export-http.test.ts +61 -2
  76. package/src/__tests__/migration-export-streaming.test.ts +66 -0
  77. package/src/__tests__/migration-import-commit-http.test.ts +101 -1
  78. package/src/__tests__/native-host-marker-sync-guard.test.ts +157 -0
  79. package/src/__tests__/oauth-apps-routes.test.ts +17 -12
  80. package/src/__tests__/oauth-cli.test.ts +707 -60
  81. package/src/__tests__/oauth-connect-orchestrator.test.ts +116 -24
  82. package/src/__tests__/oauth-provider-seed-logos.test.ts +23 -0
  83. package/src/__tests__/oauth-provider-serializer.test.ts +146 -10
  84. package/src/__tests__/oauth-provider-visibility.test.ts +19 -21
  85. package/src/__tests__/oauth-providers-routes.test.ts +50 -14
  86. package/src/__tests__/oauth-store.test.ts +1386 -182
  87. package/src/__tests__/oauth2-gateway-transport.test.ts +211 -20
  88. package/src/__tests__/onboarding-template-contract.test.ts +75 -57
  89. package/src/__tests__/openai-provider.test.ts +2 -2
  90. package/src/__tests__/outlook-categories.test.ts +1 -1
  91. package/src/__tests__/outlook-client-automation.test.ts +1 -1
  92. package/src/__tests__/outlook-compose-tools.test.ts +1 -1
  93. package/src/__tests__/outlook-email-watcher.test.ts +1 -1
  94. package/src/__tests__/outlook-follow-up.test.ts +1 -1
  95. package/src/__tests__/outlook-messaging-provider.test.ts +2 -2
  96. package/src/__tests__/outlook-trash.test.ts +1 -1
  97. package/src/__tests__/outlook-unsubscribe.test.ts +1 -1
  98. package/src/__tests__/permission-checker-host-gate.test.ts +74 -14
  99. package/src/__tests__/permission-mode.test.ts +28 -56
  100. package/src/__tests__/platform-callback-registration.test.ts +19 -0
  101. package/src/__tests__/post-turn-tool-result-truncation.test.ts +296 -0
  102. package/src/__tests__/proxy-approval-callback.test.ts +18 -0
  103. package/src/__tests__/require-fresh-approval.test.ts +40 -1
  104. package/src/__tests__/sanitize-config-for-transfer.test.ts +132 -0
  105. package/src/__tests__/schedule-routes.test.ts +162 -0
  106. package/src/__tests__/secret-detection-handler.test.ts +84 -0
  107. package/src/__tests__/secret-ingress-http.test.ts +1 -0
  108. package/src/__tests__/send-endpoint-busy.test.ts +3 -0
  109. package/src/__tests__/set-permission-mode.test.ts +13 -250
  110. package/src/__tests__/skills-file-content-endpoint.test.ts +670 -0
  111. package/src/__tests__/skills-files-catalog-fallback.test.ts +450 -0
  112. package/src/__tests__/slack-channel-config.test.ts +12 -15
  113. package/src/__tests__/subagent-detail.test.ts +44 -2
  114. package/src/__tests__/subagent-disposal.test.ts +1 -0
  115. package/src/__tests__/subagent-fork-notifications.test.ts +291 -0
  116. package/src/__tests__/subagent-fork-spawn.test.ts +384 -0
  117. package/src/__tests__/subagent-manager-notify.test.ts +1 -0
  118. package/src/__tests__/subagent-notify-parent.test.ts +1 -0
  119. package/src/__tests__/subagent-spawn-tool-fork.test.ts +411 -0
  120. package/src/__tests__/subagent-tools.test.ts +1 -0
  121. package/src/__tests__/subagent-types.test.ts +1 -0
  122. package/src/__tests__/system-prompt-ask-mode.test.ts +27 -71
  123. package/src/__tests__/system-prompt.test.ts +72 -1
  124. package/src/__tests__/task-scheduler.test.ts +32 -6
  125. package/src/__tests__/telegram-config.test.ts +10 -13
  126. package/src/__tests__/terminal-tools.test.ts +9 -0
  127. package/src/__tests__/tool-approval-handler.test.ts +73 -0
  128. package/src/__tests__/tool-side-effects-slack-dm.test.ts +22 -0
  129. package/src/__tests__/top-level-renderer.test.ts +73 -1
  130. package/src/__tests__/transport-hints-queue.test.ts +14 -29
  131. package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +109 -0
  132. package/src/__tests__/v2-consent-policy.test.ts +103 -0
  133. package/src/acp/client-handler.ts +30 -4
  134. package/src/agent/loop.ts +12 -6
  135. package/src/approvals/guardian-request-resolvers.ts +21 -15
  136. package/src/browser-session/__tests__/manager.test.ts +297 -0
  137. package/src/browser-session/backends/cdp-inspect.ts +30 -0
  138. package/src/browser-session/backends/extension.ts +26 -0
  139. package/src/browser-session/backends/local.ts +24 -0
  140. package/src/browser-session/events.ts +164 -0
  141. package/src/browser-session/index.ts +27 -0
  142. package/src/browser-session/manager.ts +159 -0
  143. package/src/browser-session/types.ts +28 -0
  144. package/src/channels/__tests__/types.test.ts +134 -0
  145. package/src/channels/types.ts +53 -3
  146. package/src/cli/commands/browser-relay.ts +339 -409
  147. package/src/cli/commands/credentials.ts +3 -3
  148. package/src/cli/commands/email.ts +18 -13
  149. package/src/cli/commands/mcp.ts +16 -4
  150. package/src/cli/commands/oauth/__tests__/connect.test.ts +44 -44
  151. package/src/cli/commands/oauth/__tests__/disconnect.test.ts +21 -21
  152. package/src/cli/commands/oauth/__tests__/mode.test.ts +17 -17
  153. package/src/cli/commands/oauth/__tests__/ping.test.ts +16 -16
  154. package/src/cli/commands/oauth/__tests__/providers-delete.test.ts +31 -33
  155. package/src/cli/commands/oauth/__tests__/providers-register.test.ts +329 -0
  156. package/src/cli/commands/oauth/__tests__/providers-update.test.ts +116 -12
  157. package/src/cli/commands/oauth/__tests__/status.test.ts +10 -10
  158. package/src/cli/commands/oauth/__tests__/token.test.ts +7 -7
  159. package/src/cli/commands/oauth/apps.ts +7 -4
  160. package/src/cli/commands/oauth/connect.ts +6 -3
  161. package/src/cli/commands/oauth/disconnect.ts +1 -1
  162. package/src/cli/commands/oauth/providers.ts +200 -36
  163. package/src/cli/commands/oauth/shared.ts +5 -5
  164. package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +259 -0
  165. package/src/cli/commands/platform/index.ts +107 -10
  166. package/src/cli/commands/usage.ts +10 -9
  167. package/src/cli/lib/daemon-credential-client.ts +4 -0
  168. package/src/cli/program.ts +1 -1
  169. package/src/config/bundled-skills/app-builder/SKILL.md +26 -249
  170. package/src/config/bundled-skills/app-builder/references/CUSTOM_ROUTES.md +105 -0
  171. package/src/config/bundled-skills/app-builder/references/INTERACTION_HOOKS.md +56 -0
  172. package/src/config/bundled-skills/app-builder/references/WIDGETS.md +125 -0
  173. package/src/config/bundled-skills/contacts/SKILL.md +3 -0
  174. package/src/config/bundled-skills/document/SKILL.md +4 -0
  175. package/src/config/bundled-skills/gmail/SKILL.md +1 -1
  176. package/src/config/bundled-skills/outlook/SKILL.md +7 -0
  177. package/src/config/bundled-skills/subagent/SKILL.md +21 -0
  178. package/src/config/bundled-skills/subagent/TOOLS.json +8 -4
  179. package/src/config/bundled-skills/tasks/SKILL.md +5 -0
  180. package/src/config/env-registry.ts +14 -0
  181. package/src/config/env.ts +21 -0
  182. package/src/config/feature-flag-registry.json +44 -5
  183. package/src/config/loader.ts +56 -1
  184. package/src/config/sanitize-for-transfer.ts +47 -0
  185. package/src/config/schema.ts +46 -5
  186. package/src/config/schemas/host-browser.ts +66 -0
  187. package/src/config/schemas/memory-lifecycle.ts +1 -1
  188. package/src/config/schemas/memory-retrieval.ts +103 -0
  189. package/src/config/schemas/security.ts +0 -6
  190. package/src/config/schemas/services.ts +8 -0
  191. package/src/config/types.ts +0 -1
  192. package/src/context/post-turn-tool-result-truncation.ts +176 -0
  193. package/src/context/window-manager.ts +19 -1
  194. package/src/credential-execution/approval-bridge.ts +49 -15
  195. package/src/daemon/__tests__/conversation-tool-setup.test.ts +186 -0
  196. package/src/daemon/app-source-watcher.ts +35 -0
  197. package/src/daemon/context-overflow-approval.ts +5 -0
  198. package/src/daemon/conversation-agent-loop-handlers.ts +17 -2
  199. package/src/daemon/conversation-agent-loop.ts +58 -24
  200. package/src/daemon/conversation-attachments.ts +40 -0
  201. package/src/daemon/conversation-process.ts +48 -1
  202. package/src/daemon/conversation-runtime-assembly.ts +118 -36
  203. package/src/daemon/conversation-surfaces.ts +37 -36
  204. package/src/daemon/conversation-tool-setup.ts +74 -8
  205. package/src/daemon/conversation-workspace.ts +12 -0
  206. package/src/daemon/conversation.ts +226 -8
  207. package/src/daemon/date-context.ts +10 -10
  208. package/src/daemon/first-greeting.ts +3 -2
  209. package/src/daemon/handlers/conversations.ts +9 -140
  210. package/src/daemon/handlers/shared.ts +58 -0
  211. package/src/daemon/handlers/skills.ts +232 -37
  212. package/src/daemon/host-bash-proxy.ts +48 -13
  213. package/src/daemon/host-browser-proxy.ts +191 -0
  214. package/src/daemon/host-cu-proxy.ts +36 -11
  215. package/src/daemon/host-file-proxy.ts +57 -9
  216. package/src/daemon/lifecycle.ts +65 -11
  217. package/src/daemon/message-protocol.ts +7 -0
  218. package/src/daemon/message-types/conversations.ts +55 -13
  219. package/src/daemon/message-types/host-browser.ts +100 -0
  220. package/src/daemon/message-types/messages.ts +5 -5
  221. package/src/daemon/message-types/skills.ts +10 -0
  222. package/src/daemon/message-types/subagents.ts +2 -0
  223. package/src/daemon/server.ts +92 -12
  224. package/src/daemon/tool-side-effects.ts +6 -0
  225. package/src/daemon/transport-hints.ts +5 -24
  226. package/src/inbound/platform-callback-registration.ts +18 -17
  227. package/src/mcp/client.ts +59 -24
  228. package/src/memory/app-store.ts +31 -1
  229. package/src/memory/conversation-crud.ts +23 -0
  230. package/src/memory/conversation-starters-cadence.ts +76 -0
  231. package/src/memory/conversation-title-service.ts +5 -2
  232. package/src/memory/db-init.ts +12 -0
  233. package/src/memory/embedding-backend.test.ts +75 -0
  234. package/src/memory/embedding-backend.ts +131 -5
  235. package/src/memory/embedding-gemini.test.ts +54 -0
  236. package/src/memory/embedding-gemini.ts +20 -9
  237. package/src/memory/embedding-local.ts +176 -17
  238. package/src/memory/graph/consolidation.ts +10 -23
  239. package/src/memory/graph/extraction-job.ts +15 -0
  240. package/src/memory/graph/retriever.ts +40 -22
  241. package/src/memory/graph/store.test.ts +7 -3
  242. package/src/memory/graph/store.ts +47 -12
  243. package/src/memory/llm-usage-store.ts +45 -4
  244. package/src/memory/migrations/213-oauth-providers-scope-separator.ts +13 -0
  245. package/src/memory/migrations/214-oauth-providers-refresh-url.ts +11 -0
  246. package/src/memory/migrations/215-oauth-providers-revoke.ts +14 -0
  247. package/src/memory/migrations/216-oauth-providers-token-auth-method.ts +30 -0
  248. package/src/memory/migrations/217-conversation-host-access.ts +40 -0
  249. package/src/memory/migrations/218-oauth-providers-logo-url.ts +11 -0
  250. package/src/memory/migrations/index.ts +6 -0
  251. package/src/memory/migrations/registry.ts +8 -0
  252. package/src/memory/schema/conversations.ts +1 -0
  253. package/src/memory/schema/oauth.ts +18 -13
  254. package/src/oauth/AGENTS.md +76 -0
  255. package/src/oauth/__tests__/identity-verifier.test.ts +24 -19
  256. package/src/oauth/__tests__/seed-providers-managed.test.ts +32 -0
  257. package/src/oauth/byo-connection.test.ts +8 -8
  258. package/src/oauth/byo-connection.ts +7 -7
  259. package/src/oauth/connect-orchestrator.ts +23 -21
  260. package/src/oauth/connect-types.ts +3 -3
  261. package/src/oauth/connection-resolver.test.ts +17 -4
  262. package/src/oauth/connection-resolver.ts +16 -16
  263. package/src/oauth/connection.ts +1 -1
  264. package/src/oauth/manual-token-connection.ts +13 -13
  265. package/src/oauth/oauth-store.ts +214 -100
  266. package/src/oauth/platform-connection.test.ts +3 -3
  267. package/src/oauth/platform-connection.ts +4 -4
  268. package/src/oauth/provider-serializer.ts +31 -5
  269. package/src/oauth/revoke.ts +76 -0
  270. package/src/oauth/seed-providers.ts +126 -87
  271. package/src/oauth/token-persistence.ts +1 -1
  272. package/src/permissions/permission-mode.ts +4 -11
  273. package/src/permissions/prompter.ts +13 -1
  274. package/src/permissions/v2-consent-policy.ts +87 -0
  275. package/src/prompts/system-prompt.ts +18 -21
  276. package/src/prompts/templates/BOOTSTRAP-REFERENCE.md +3 -65
  277. package/src/prompts/templates/BOOTSTRAP.md +59 -105
  278. package/src/providers/anthropic/client.ts +1 -0
  279. package/src/providers/types.ts +1 -1
  280. package/src/runtime/AGENTS.md +23 -0
  281. package/src/runtime/__tests__/browser-extension-pair-routes.test.ts +715 -0
  282. package/src/runtime/__tests__/capability-tokens.test.ts +258 -0
  283. package/src/runtime/__tests__/chrome-extension-registry.test.ts +518 -0
  284. package/src/runtime/assistant-event-hub.ts +2 -2
  285. package/src/runtime/auth/__tests__/guard-tests.test.ts +1 -0
  286. package/src/runtime/auth/__tests__/middleware.test.ts +116 -1
  287. package/src/runtime/auth/__tests__/route-policy.test.ts +8 -0
  288. package/src/runtime/auth/middleware.ts +98 -0
  289. package/src/runtime/auth/route-policy.ts +6 -7
  290. package/src/runtime/capability-tokens.ts +414 -0
  291. package/src/runtime/channel-approvals.ts +18 -5
  292. package/src/runtime/chrome-extension-registry.ts +332 -0
  293. package/src/runtime/confirmation-request-guardian-bridge.ts +6 -0
  294. package/src/runtime/guardian-decision-types.ts +7 -0
  295. package/src/runtime/http-server.ts +425 -70
  296. package/src/runtime/migrations/__tests__/rebind-secrets-credentials.test.ts +172 -0
  297. package/src/runtime/migrations/__tests__/vbundle-builder-credentials.test.ts +276 -0
  298. package/src/runtime/migrations/__tests__/vbundle-import-credentials.test.ts +162 -0
  299. package/src/runtime/migrations/migration-transport.ts +6 -0
  300. package/src/runtime/migrations/migration-wizard.ts +22 -2
  301. package/src/runtime/migrations/rebind-secrets-screen.ts +76 -15
  302. package/src/runtime/migrations/vbundle-builder.ts +145 -38
  303. package/src/runtime/migrations/vbundle-import-analyzer.ts +19 -0
  304. package/src/runtime/migrations/vbundle-importer.ts +55 -5
  305. package/src/runtime/pending-interactions.ts +29 -13
  306. package/src/runtime/routes/approval-routes.ts +90 -16
  307. package/src/runtime/routes/browser-cdp-routes.ts +229 -0
  308. package/src/runtime/routes/browser-extension-pair-routes.ts +497 -0
  309. package/src/runtime/routes/conversation-analysis-routes.ts +2 -1
  310. package/src/runtime/routes/conversation-management-routes.ts +108 -0
  311. package/src/runtime/routes/conversation-routes.ts +301 -27
  312. package/src/runtime/routes/conversation-starter-routes.ts +78 -16
  313. package/src/runtime/routes/guardian-action-routes.ts +24 -13
  314. package/src/runtime/routes/host-browser-routes.ts +279 -0
  315. package/src/runtime/routes/host-file-routes.ts +9 -1
  316. package/src/runtime/routes/identity-routes.ts +259 -16
  317. package/src/runtime/routes/log-export-routes.ts +42 -22
  318. package/src/runtime/routes/memory-item-routes.ts +1 -7
  319. package/src/runtime/routes/migration-routes.ts +87 -2
  320. package/src/runtime/routes/oauth-apps.ts +15 -17
  321. package/src/runtime/routes/oauth-providers.ts +4 -0
  322. package/src/runtime/routes/schedule-routes.ts +24 -11
  323. package/src/runtime/routes/settings-routes.ts +9 -97
  324. package/src/runtime/routes/skills-routes.ts +52 -2
  325. package/src/runtime/routes/subagents-routes.ts +14 -10
  326. package/src/runtime/routes/usage-routes.ts +8 -7
  327. package/src/runtime/routes/workspace-routes.test.ts +22 -0
  328. package/src/runtime/routes/workspace-routes.ts +8 -1
  329. package/src/runtime/routes/workspace-utils.ts +2 -0
  330. package/src/schedule/scheduler.ts +7 -5
  331. package/src/security/ces-credential-client.ts +20 -0
  332. package/src/security/ces-rpc-credential-backend.ts +17 -0
  333. package/src/security/credential-backend.ts +5 -0
  334. package/src/security/oauth2.ts +42 -25
  335. package/src/security/secure-keys.ts +118 -25
  336. package/src/security/token-manager.ts +23 -10
  337. package/src/skills/catalog-files.ts +492 -0
  338. package/src/subagent/manager.ts +131 -26
  339. package/src/subagent/types.ts +19 -0
  340. package/src/tools/apps/executors.ts +11 -2
  341. package/src/tools/browser/__tests__/auth-detector.test.ts +202 -108
  342. package/src/tools/browser/auth-detector.ts +43 -12
  343. package/src/tools/browser/browser-execution.ts +645 -340
  344. package/src/tools/browser/browser-manager.ts +36 -12
  345. package/src/tools/browser/cdp-client/__tests__/accessibility-snapshot.test.ts +318 -0
  346. package/src/tools/browser/cdp-client/__tests__/cdp-dom-helpers.test.ts +1175 -0
  347. package/src/tools/browser/cdp-client/__tests__/cdp-inspect-client.test.ts +870 -0
  348. package/src/tools/browser/cdp-client/__tests__/extension-cdp-client.test.ts +330 -0
  349. package/src/tools/browser/cdp-client/__tests__/factory.test.ts +377 -0
  350. package/src/tools/browser/cdp-client/__tests__/fixtures/ax-tree-nested-frames.json +64 -0
  351. package/src/tools/browser/cdp-client/__tests__/fixtures/ax-tree-simple.json +69 -0
  352. package/src/tools/browser/cdp-client/__tests__/local-cdp-client.test.ts +310 -0
  353. package/src/tools/browser/cdp-client/__tests__/types.test.ts +96 -0
  354. package/src/tools/browser/cdp-client/accessibility-snapshot.ts +387 -0
  355. package/src/tools/browser/cdp-client/cdp-dom-helpers.ts +695 -0
  356. package/src/tools/browser/cdp-client/cdp-inspect/__tests__/discovery.test.ts +743 -0
  357. package/src/tools/browser/cdp-client/cdp-inspect/__tests__/ws-transport.test.ts +580 -0
  358. package/src/tools/browser/cdp-client/cdp-inspect/discovery.ts +578 -0
  359. package/src/tools/browser/cdp-client/cdp-inspect/ws-transport.ts +579 -0
  360. package/src/tools/browser/cdp-client/cdp-inspect-client.ts +635 -0
  361. package/src/tools/browser/cdp-client/errors.ts +34 -0
  362. package/src/tools/browser/cdp-client/extension-cdp-client.ts +125 -0
  363. package/src/tools/browser/cdp-client/factory.ts +204 -0
  364. package/src/tools/browser/cdp-client/index.ts +14 -0
  365. package/src/tools/browser/cdp-client/local-cdp-client.ts +187 -0
  366. package/src/tools/browser/cdp-client/types.ts +52 -0
  367. package/src/tools/filesystem/edit.ts +1 -1
  368. package/src/tools/filesystem/list.ts +1 -1
  369. package/src/tools/filesystem/read.ts +1 -1
  370. package/src/tools/filesystem/write.ts +2 -1
  371. package/src/tools/host-filesystem/edit.ts +1 -1
  372. package/src/tools/host-filesystem/read.ts +12 -15
  373. package/src/tools/host-filesystem/write.ts +1 -1
  374. package/src/tools/host-terminal/host-shell.ts +21 -16
  375. package/src/tools/permission-checker.ts +77 -82
  376. package/src/tools/registry.ts +0 -2
  377. package/src/tools/secret-detection-handler.ts +34 -0
  378. package/src/tools/shared/filesystem/image-read.ts +61 -40
  379. package/src/tools/subagent/spawn.ts +47 -3
  380. package/src/tools/subagent/status.ts +2 -0
  381. package/src/tools/system/register.ts +2 -16
  382. package/src/tools/terminal/safe-env.ts +7 -0
  383. package/src/tools/terminal/shell.ts +21 -16
  384. package/src/tools/tool-approval-handler.ts +48 -2
  385. package/src/tools/types.ts +2 -0
  386. package/src/util/platform.ts +14 -19
  387. package/src/workspace/top-level-renderer.ts +19 -1
  388. package/src/__tests__/chrome-cdp.test.ts +0 -419
  389. package/src/__tests__/permission-mode-sse.test.ts +0 -418
  390. package/src/__tests__/permission-mode-store.test.ts +0 -277
  391. package/src/browser-extension-relay/protocol.ts +0 -63
  392. package/src/browser-extension-relay/server.ts +0 -203
  393. package/src/config/schemas/sandbox.ts +0 -14
  394. package/src/permissions/permission-mode-store.ts +0 -180
  395. package/src/tools/browser/chrome-cdp.ts +0 -239
  396. package/src/tools/system/set-permission-mode.ts +0 -103
@@ -0,0 +1,329 @@
1
+ import { beforeEach, describe, expect, mock, test } from "bun:test";
2
+
3
+ import { Command } from "commander";
4
+
5
+ // ---------------------------------------------------------------------------
6
+ // Mock state
7
+ // ---------------------------------------------------------------------------
8
+
9
+ let mockRegisterProvider: (
10
+ params: Record<string, unknown>,
11
+ ) => Record<string, unknown> = () => ({});
12
+
13
+ let mockRegisterProviderCalls: Array<{
14
+ params: Record<string, unknown>;
15
+ }> = [];
16
+
17
+ // ---------------------------------------------------------------------------
18
+ // Mocks
19
+ // ---------------------------------------------------------------------------
20
+
21
+ mock.module("../../../../config/loader.js", () => ({
22
+ getConfig: () => ({ services: {} }),
23
+ loadConfig: () => ({ services: {} }),
24
+ API_KEY_PROVIDERS: [],
25
+ }));
26
+
27
+ mock.module("../../../../oauth/oauth-store.js", () => ({
28
+ getProvider: () => undefined,
29
+ updateProvider: () => undefined,
30
+ listProviders: () => [],
31
+ registerProvider: (params: Record<string, unknown>) => {
32
+ mockRegisterProviderCalls.push({ params });
33
+ return mockRegisterProvider(params);
34
+ },
35
+ deleteProvider: () => false,
36
+ disconnectOAuthProvider: async () => "ok",
37
+ seedProviders: () => {},
38
+ getConnection: () => undefined,
39
+ getConnectionByProvider: () => undefined,
40
+ getActiveConnection: () => undefined,
41
+ listActiveConnectionsByProvider: () => [],
42
+ isProviderConnected: () => false,
43
+ createConnection: () => ({}),
44
+ updateConnection: () => ({}),
45
+ deleteConnection: () => false,
46
+ upsertApp: async () => ({}),
47
+ getApp: () => undefined,
48
+ getAppByProviderAndClientId: () => undefined,
49
+ getMostRecentAppByProvider: () => undefined,
50
+ listApps: () => [],
51
+ deleteApp: async () => false,
52
+ listConnections: () => [],
53
+ }));
54
+
55
+ mock.module("../../../../oauth/seed-providers.js", () => ({
56
+ SEEDED_PROVIDER_KEYS: new Set<string>(["google", "slack", "github"]),
57
+ PROVIDER_SEED_DATA: {},
58
+ seedAllProviders: () => {},
59
+ }));
60
+
61
+ mock.module("../../../../inbound/public-ingress-urls.js", () => ({
62
+ getOAuthCallbackUrl: () => null,
63
+ }));
64
+
65
+ mock.module("../../../../util/logger.js", () => ({
66
+ getLogger: () => ({
67
+ info: () => {},
68
+ warn: () => {},
69
+ error: () => {},
70
+ debug: () => {},
71
+ }),
72
+ getCliLogger: () => ({
73
+ info: () => {},
74
+ warn: () => {},
75
+ error: () => {},
76
+ debug: () => {},
77
+ }),
78
+ }));
79
+
80
+ // ---------------------------------------------------------------------------
81
+ // Import module under test (after mocks are registered)
82
+ // ---------------------------------------------------------------------------
83
+
84
+ const { registerProviderCommands } = await import("../providers.js");
85
+
86
+ // ---------------------------------------------------------------------------
87
+ // Test helper
88
+ // ---------------------------------------------------------------------------
89
+
90
+ async function runCommand(
91
+ args: string[],
92
+ ): Promise<{ stdout: string; stderr: string; exitCode: number }> {
93
+ const originalStdoutWrite = process.stdout.write.bind(process.stdout);
94
+ const originalStderrWrite = process.stderr.write.bind(process.stderr);
95
+ const stdoutChunks: string[] = [];
96
+ const stderrChunks: string[] = [];
97
+
98
+ process.stdout.write = ((chunk: unknown) => {
99
+ stdoutChunks.push(typeof chunk === "string" ? chunk : String(chunk));
100
+ return true;
101
+ }) as typeof process.stdout.write;
102
+
103
+ process.stderr.write = ((chunk: unknown) => {
104
+ stderrChunks.push(typeof chunk === "string" ? chunk : String(chunk));
105
+ return true;
106
+ }) as typeof process.stderr.write;
107
+
108
+ process.exitCode = 0;
109
+
110
+ try {
111
+ const program = new Command();
112
+ program.exitOverride();
113
+ program.option("--json", "JSON output");
114
+ program.configureOutput({
115
+ writeErr: (str: string) => stderrChunks.push(str),
116
+ writeOut: (str: string) => stdoutChunks.push(str),
117
+ });
118
+ registerProviderCommands(program);
119
+ await program.parseAsync(["node", "assistant", ...args]);
120
+ } catch {
121
+ if (process.exitCode === 0) process.exitCode = 1;
122
+ } finally {
123
+ process.stdout.write = originalStdoutWrite;
124
+ process.stderr.write = originalStderrWrite;
125
+ }
126
+
127
+ const exitCode = process.exitCode ?? 0;
128
+ process.exitCode = 0;
129
+
130
+ return {
131
+ exitCode,
132
+ stdout: stdoutChunks.join(""),
133
+ stderr: stderrChunks.join(""),
134
+ };
135
+ }
136
+
137
+ // ---------------------------------------------------------------------------
138
+ // Sample provider row
139
+ // ---------------------------------------------------------------------------
140
+
141
+ const sampleProviderRow = {
142
+ provider: "custom-api",
143
+ authorizeUrl: "https://custom-api.example.com/oauth/authorize",
144
+ tokenExchangeUrl: "https://custom-api.example.com/oauth/token",
145
+ refreshUrl: null,
146
+ tokenEndpointAuthMethod: "client_secret_post",
147
+ userinfoUrl: null,
148
+ baseUrl: null,
149
+ defaultScopes: "[]",
150
+ scopePolicy: "{}",
151
+ scopeSeparator: null,
152
+ authorizeParams: null,
153
+ managedServiceConfigKey: null,
154
+ pingUrl: null,
155
+ pingMethod: null,
156
+ pingHeaders: null,
157
+ pingBody: null,
158
+ revokeUrl: null,
159
+ revokeBodyTemplate: null,
160
+ displayLabel: null,
161
+ description: null,
162
+ dashboardUrl: null,
163
+ logoUrl: null,
164
+ clientIdPlaceholder: null,
165
+ requiresClientSecret: 1,
166
+ loopbackPort: null,
167
+ injectionTemplates: null,
168
+ appType: null,
169
+ setupNotes: null,
170
+ identityUrl: null,
171
+ identityMethod: null,
172
+ identityHeaders: null,
173
+ identityBody: null,
174
+ identityResponsePaths: null,
175
+ identityFormat: null,
176
+ identityOkField: null,
177
+ featureFlag: null,
178
+ createdAt: Date.now(),
179
+ updatedAt: Date.now(),
180
+ };
181
+
182
+ // ---------------------------------------------------------------------------
183
+ // Tests
184
+ // ---------------------------------------------------------------------------
185
+
186
+ describe("assistant oauth providers register", () => {
187
+ beforeEach(() => {
188
+ mockRegisterProvider = () => ({ ...sampleProviderRow });
189
+ mockRegisterProviderCalls = [];
190
+ process.exitCode = 0;
191
+ });
192
+
193
+ // -------------------------------------------------------------------------
194
+ // --logo-url
195
+ // -------------------------------------------------------------------------
196
+
197
+ test("register accepts --logo-url and passes it to registerProvider", async () => {
198
+ mockRegisterProvider = () => ({
199
+ ...sampleProviderRow,
200
+ logoUrl: "https://example.com/logo.png",
201
+ });
202
+
203
+ const { exitCode } = await runCommand([
204
+ "providers",
205
+ "register",
206
+ "--provider-key",
207
+ "custom-api",
208
+ "--auth-url",
209
+ "https://custom-api.example.com/oauth/authorize",
210
+ "--token-url",
211
+ "https://custom-api.example.com/oauth/token",
212
+ "--logo-url",
213
+ "https://example.com/logo.png",
214
+ "--json",
215
+ ]);
216
+ expect(exitCode).toBe(0);
217
+ expect(mockRegisterProviderCalls).toHaveLength(1);
218
+ expect(mockRegisterProviderCalls[0].params.logoUrl).toBe(
219
+ "https://example.com/logo.png",
220
+ );
221
+ });
222
+
223
+ // -------------------------------------------------------------------------
224
+ // --logo-simpleicons-slug
225
+ // -------------------------------------------------------------------------
226
+
227
+ test("register accepts --logo-simpleicons-slug and expands it to the CDN URL", async () => {
228
+ mockRegisterProvider = () => ({
229
+ ...sampleProviderRow,
230
+ logoUrl: "https://cdn.simpleicons.org/notion",
231
+ });
232
+
233
+ const { exitCode } = await runCommand([
234
+ "providers",
235
+ "register",
236
+ "--provider-key",
237
+ "custom-api",
238
+ "--auth-url",
239
+ "https://custom-api.example.com/oauth/authorize",
240
+ "--token-url",
241
+ "https://custom-api.example.com/oauth/token",
242
+ "--logo-simpleicons-slug",
243
+ "notion",
244
+ "--json",
245
+ ]);
246
+ expect(exitCode).toBe(0);
247
+ expect(mockRegisterProviderCalls).toHaveLength(1);
248
+ expect(mockRegisterProviderCalls[0].params.logoUrl).toBe(
249
+ "https://cdn.simpleicons.org/notion",
250
+ );
251
+ });
252
+
253
+ // -------------------------------------------------------------------------
254
+ // Mutual exclusion
255
+ // -------------------------------------------------------------------------
256
+
257
+ test("register rejects both --logo-url and --logo-simpleicons-slug simultaneously", async () => {
258
+ const { exitCode, stdout } = await runCommand([
259
+ "providers",
260
+ "register",
261
+ "--provider-key",
262
+ "custom-api",
263
+ "--auth-url",
264
+ "https://custom-api.example.com/oauth/authorize",
265
+ "--token-url",
266
+ "https://custom-api.example.com/oauth/token",
267
+ "--logo-url",
268
+ "https://example.com/logo.png",
269
+ "--logo-simpleicons-slug",
270
+ "notion",
271
+ "--json",
272
+ ]);
273
+ expect(exitCode).toBe(1);
274
+ const parsed = JSON.parse(stdout);
275
+ expect(parsed.ok).toBe(false);
276
+ expect(parsed.error).toContain("mutually exclusive");
277
+ expect(mockRegisterProviderCalls).toHaveLength(0);
278
+ });
279
+
280
+ // -------------------------------------------------------------------------
281
+ // Empty slug rejection
282
+ // -------------------------------------------------------------------------
283
+
284
+ test("register rejects empty --logo-simpleicons-slug", async () => {
285
+ const { exitCode, stdout } = await runCommand([
286
+ "providers",
287
+ "register",
288
+ "--provider-key",
289
+ "custom-api",
290
+ "--auth-url",
291
+ "https://custom-api.example.com/oauth/authorize",
292
+ "--token-url",
293
+ "https://custom-api.example.com/oauth/token",
294
+ "--logo-simpleicons-slug",
295
+ "",
296
+ "--json",
297
+ ]);
298
+ expect(exitCode).toBe(1);
299
+ const parsed = JSON.parse(stdout);
300
+ expect(parsed.ok).toBe(false);
301
+ expect(parsed.error).toContain("cannot be empty");
302
+ expect(mockRegisterProviderCalls).toHaveLength(0);
303
+ });
304
+
305
+ // -------------------------------------------------------------------------
306
+ // Empty --logo-url rejection at registration time
307
+ // -------------------------------------------------------------------------
308
+
309
+ test("register rejects empty --logo-url (clearing is only valid at update time)", async () => {
310
+ const { exitCode, stdout } = await runCommand([
311
+ "providers",
312
+ "register",
313
+ "--provider-key",
314
+ "custom-api",
315
+ "--auth-url",
316
+ "https://custom-api.example.com/oauth/authorize",
317
+ "--token-url",
318
+ "https://custom-api.example.com/oauth/token",
319
+ "--logo-url",
320
+ "",
321
+ "--json",
322
+ ]);
323
+ expect(exitCode).toBe(1);
324
+ const parsed = JSON.parse(stdout);
325
+ expect(parsed.ok).toBe(false);
326
+ expect(parsed.error).toContain("Cannot clear logo_url");
327
+ expect(mockRegisterProviderCalls).toHaveLength(0);
328
+ });
329
+ });
@@ -40,6 +40,8 @@ mock.module("../../../../oauth/oauth-store.js", () => ({
40
40
  },
41
41
  listProviders: () => [],
42
42
  registerProvider: () => ({}),
43
+ deleteProvider: () => false,
44
+ disconnectOAuthProvider: async () => "ok",
43
45
  seedProviders: () => {},
44
46
  getConnection: () => undefined,
45
47
  getConnectionByProvider: () => undefined,
@@ -137,21 +139,25 @@ async function runCommand(
137
139
  // ---------------------------------------------------------------------------
138
140
 
139
141
  const sampleProviderRow = {
140
- providerKey: "custom-api",
141
- authUrl: "https://custom-api.example.com/oauth/authorize",
142
- tokenUrl: "https://custom-api.example.com/oauth/token",
143
- tokenEndpointAuthMethod: null,
142
+ provider: "custom-api",
143
+ authorizeUrl: "https://custom-api.example.com/oauth/authorize",
144
+ tokenExchangeUrl: "https://custom-api.example.com/oauth/token",
145
+ refreshUrl: null,
146
+ tokenEndpointAuthMethod: "client_secret_post",
144
147
  userinfoUrl: null,
145
148
  baseUrl: null,
146
149
  defaultScopes: "[]",
147
150
  scopePolicy: "{}",
148
- extraParams: null,
151
+ scopeSeparator: null,
152
+ authorizeParams: null,
149
153
  managedServiceConfigKey: null,
150
154
  pingUrl: null,
151
155
  pingMethod: null,
152
156
  pingHeaders: null,
153
157
  pingBody: null,
154
- displayName: null,
158
+ revokeUrl: null,
159
+ revokeBodyTemplate: null,
160
+ displayLabel: null,
155
161
  description: null,
156
162
  dashboardUrl: null,
157
163
  clientIdPlaceholder: null,
@@ -214,7 +220,7 @@ describe("assistant oauth providers update", () => {
214
220
  test("built-in provider returns error suggesting register", async () => {
215
221
  mockGetProvider = () => ({
216
222
  ...sampleProviderRow,
217
- providerKey: "google",
223
+ provider: "google",
218
224
  });
219
225
 
220
226
  const { exitCode, stdout } = await runCommand([
@@ -259,7 +265,7 @@ describe("assistant oauth providers update", () => {
259
265
  mockGetProvider = () => ({ ...sampleProviderRow });
260
266
  mockUpdateProvider = (_key, _params) => ({
261
267
  ...sampleProviderRow,
262
- displayName: "New Name",
268
+ displayLabel: "New Name",
263
269
  updatedAt: Date.now(),
264
270
  });
265
271
 
@@ -285,9 +291,9 @@ describe("assistant oauth providers update", () => {
285
291
  mockGetProvider = () => ({ ...sampleProviderRow });
286
292
  mockUpdateProvider = (_key, _params) => ({
287
293
  ...sampleProviderRow,
288
- displayName: "My API",
294
+ displayLabel: "My API",
289
295
  defaultScopes: '["read","write"]',
290
- authUrl: "https://new.example.com/auth",
296
+ authorizeUrl: "https://new.example.com/auth",
291
297
  updatedAt: Date.now(),
292
298
  });
293
299
 
@@ -311,9 +317,9 @@ describe("assistant oauth providers update", () => {
311
317
  expect(mockUpdateProviderCalls).toHaveLength(1);
312
318
  expect(mockUpdateProviderCalls[0].key).toBe("custom-api");
313
319
  expect(mockUpdateProviderCalls[0].params).toEqual({
314
- displayName: "My API",
320
+ displayLabel: "My API",
315
321
  defaultScopes: ["read", "write"],
316
- authUrl: "https://new.example.com/auth",
322
+ authorizeUrl: "https://new.example.com/auth",
317
323
  });
318
324
  });
319
325
 
@@ -321,6 +327,104 @@ describe("assistant oauth providers update", () => {
321
327
  // Successful update with injection templates, identity config, and setup metadata
322
328
  // -------------------------------------------------------------------------
323
329
 
330
+ // -------------------------------------------------------------------------
331
+ // --logo-url
332
+ // -------------------------------------------------------------------------
333
+
334
+ test("update --logo-url sets params.logoUrl to the given string", async () => {
335
+ mockGetProvider = () => ({ ...sampleProviderRow });
336
+ mockUpdateProvider = (_key, _params) => ({
337
+ ...sampleProviderRow,
338
+ logoUrl: "https://example.com/logo.png",
339
+ updatedAt: Date.now(),
340
+ });
341
+
342
+ const { exitCode } = await runCommand([
343
+ "providers",
344
+ "update",
345
+ "custom-api",
346
+ "--logo-url",
347
+ "https://example.com/logo.png",
348
+ "--json",
349
+ ]);
350
+ expect(exitCode).toBe(0);
351
+ expect(mockUpdateProviderCalls).toHaveLength(1);
352
+ expect(mockUpdateProviderCalls[0].key).toBe("custom-api");
353
+ expect(mockUpdateProviderCalls[0].params).toEqual({
354
+ logoUrl: "https://example.com/logo.png",
355
+ });
356
+ });
357
+
358
+ test("update --logo-simpleicons-slug expands to CDN URL and passes as params.logoUrl", async () => {
359
+ mockGetProvider = () => ({ ...sampleProviderRow });
360
+ mockUpdateProvider = (_key, _params) => ({
361
+ ...sampleProviderRow,
362
+ logoUrl: "https://cdn.simpleicons.org/notion",
363
+ updatedAt: Date.now(),
364
+ });
365
+
366
+ const { exitCode } = await runCommand([
367
+ "providers",
368
+ "update",
369
+ "custom-api",
370
+ "--logo-simpleicons-slug",
371
+ "notion",
372
+ "--json",
373
+ ]);
374
+ expect(exitCode).toBe(0);
375
+ expect(mockUpdateProviderCalls).toHaveLength(1);
376
+ expect(mockUpdateProviderCalls[0].params).toEqual({
377
+ logoUrl: "https://cdn.simpleicons.org/notion",
378
+ });
379
+ });
380
+
381
+ test('update --logo-url "" clears params.logoUrl to null', async () => {
382
+ mockGetProvider = () => ({ ...sampleProviderRow });
383
+ mockUpdateProvider = (_key, _params) => ({
384
+ ...sampleProviderRow,
385
+ logoUrl: null,
386
+ updatedAt: Date.now(),
387
+ });
388
+
389
+ const { exitCode } = await runCommand([
390
+ "providers",
391
+ "update",
392
+ "custom-api",
393
+ "--logo-url",
394
+ "",
395
+ "--json",
396
+ ]);
397
+ expect(exitCode).toBe(0);
398
+ expect(mockUpdateProviderCalls).toHaveLength(1);
399
+ expect(mockUpdateProviderCalls[0].params).toEqual({
400
+ logoUrl: null,
401
+ });
402
+ });
403
+
404
+ test("update rejects both --logo-url and --logo-simpleicons-slug simultaneously", async () => {
405
+ mockGetProvider = () => ({ ...sampleProviderRow });
406
+
407
+ const { exitCode, stdout } = await runCommand([
408
+ "providers",
409
+ "update",
410
+ "custom-api",
411
+ "--logo-url",
412
+ "https://example.com/logo.png",
413
+ "--logo-simpleicons-slug",
414
+ "notion",
415
+ "--json",
416
+ ]);
417
+ expect(exitCode).toBe(1);
418
+ const parsed = JSON.parse(stdout);
419
+ expect(parsed.ok).toBe(false);
420
+ expect(parsed.error).toContain("mutually exclusive");
421
+ expect(mockUpdateProviderCalls).toHaveLength(0);
422
+ });
423
+
424
+ // -------------------------------------------------------------------------
425
+ // Successful update with injection templates, identity config, and setup metadata
426
+ // -------------------------------------------------------------------------
427
+
324
428
  test("successful update with injection templates and identity config passes new fields to updateProvider", async () => {
325
429
  const injectionTemplates = [
326
430
  {
@@ -11,7 +11,7 @@ let mockGetProvider: (
11
11
  ) => Record<string, unknown> | undefined = () => undefined;
12
12
 
13
13
  let mockListConnections: (
14
- providerKey: string,
14
+ provider: string,
15
15
  ) => Array<Record<string, unknown>> = () => [];
16
16
 
17
17
  let mockIsManagedMode: (key: string) => boolean = () => false;
@@ -35,7 +35,7 @@ mock.module("../../../../config/loader.js", () => ({
35
35
 
36
36
  mock.module("../../../../oauth/oauth-store.js", () => ({
37
37
  getProvider: (key: string) => mockGetProvider(key),
38
- listConnections: (providerKey: string) => mockListConnections(providerKey),
38
+ listConnections: (provider: string) => mockListConnections(provider),
39
39
  getConnection: () => undefined,
40
40
  getConnectionByProvider: () => undefined,
41
41
  getActiveConnection: () => undefined,
@@ -235,7 +235,7 @@ describe("assistant oauth status", () => {
235
235
  describe("managed mode", () => {
236
236
  beforeEach(() => {
237
237
  mockGetProvider = () => ({
238
- providerKey: "google",
238
+ provider: "google",
239
239
  managedServiceConfigKey: "google-oauth",
240
240
  });
241
241
  mockIsManagedMode = () => true;
@@ -360,7 +360,7 @@ describe("assistant oauth status", () => {
360
360
  describe("BYO mode", () => {
361
361
  beforeEach(() => {
362
362
  mockGetProvider = () => ({
363
- providerKey: "google",
363
+ provider: "google",
364
364
  managedServiceConfigKey: null,
365
365
  });
366
366
  mockIsManagedMode = () => false;
@@ -371,7 +371,7 @@ describe("assistant oauth status", () => {
371
371
  mockListConnections = () => [
372
372
  {
373
373
  id: "conn-local-1",
374
- providerKey: "google",
374
+ provider: "google",
375
375
  accountInfo: "localuser@gmail.com",
376
376
  grantedScopes: '["email","profile"]',
377
377
  expiresAt,
@@ -405,7 +405,7 @@ describe("assistant oauth status", () => {
405
405
  mockListConnections = () => [
406
406
  {
407
407
  id: "conn-local-2",
408
- providerKey: "google",
408
+ provider: "google",
409
409
  accountInfo: null,
410
410
  grantedScopes: "[]",
411
411
  expiresAt: null,
@@ -432,7 +432,7 @@ describe("assistant oauth status", () => {
432
432
  mockListConnections = () => [
433
433
  {
434
434
  id: "conn-active",
435
- providerKey: "google",
435
+ provider: "google",
436
436
  accountInfo: "user@gmail.com",
437
437
  grantedScopes: "[]",
438
438
  expiresAt: null,
@@ -441,7 +441,7 @@ describe("assistant oauth status", () => {
441
441
  },
442
442
  {
443
443
  id: "conn-revoked",
444
- providerKey: "google",
444
+ provider: "google",
445
445
  accountInfo: "old@gmail.com",
446
446
  grantedScopes: "[]",
447
447
  expiresAt: null,
@@ -489,7 +489,7 @@ describe("assistant oauth status", () => {
489
489
  mockListConnections = () => [
490
490
  {
491
491
  id: "conn-structure",
492
- providerKey: "google",
492
+ provider: "google",
493
493
  accountInfo: "check@gmail.com",
494
494
  grantedScopes: '["scope1"]',
495
495
  expiresAt: Date.now() + 60_000,
@@ -527,7 +527,7 @@ describe("assistant oauth status", () => {
527
527
  mockListConnections = () => [
528
528
  {
529
529
  id: "conn-bad-scopes",
530
- providerKey: "google",
530
+ provider: "google",
531
531
  accountInfo: null,
532
532
  grantedScopes: "not-valid-json",
533
533
  expiresAt: null,
@@ -9,7 +9,7 @@ import { Command } from "commander";
9
9
  let mockIsManagedMode: (key: string) => boolean = () => false;
10
10
 
11
11
  let mockGetActiveConnection: (
12
- providerKey: string,
12
+ provider: string,
13
13
  options?: { clientId?: string; account?: string },
14
14
  ) => Record<string, unknown> | undefined = () => undefined;
15
15
 
@@ -34,9 +34,9 @@ mock.module("../../../../oauth/oauth-store.js", () => ({
34
34
  getConnection: () => undefined,
35
35
  getConnectionByProvider: () => undefined,
36
36
  getActiveConnection: (
37
- providerKey: string,
37
+ provider: string,
38
38
  options?: { clientId?: string; account?: string },
39
- ) => mockGetActiveConnection(providerKey, options),
39
+ ) => mockGetActiveConnection(provider, options),
40
40
  listActiveConnectionsByProvider: () => [],
41
41
  disconnectOAuthProvider: async () => "not-found" as const,
42
42
  upsertApp: async () => ({}),
@@ -265,11 +265,11 @@ describe("assistant oauth token", () => {
265
265
 
266
266
  describe("--account option", () => {
267
267
  test("resolves connection by account and uses connectionId", async () => {
268
- mockGetActiveConnection = (_providerKey, options) => {
268
+ mockGetActiveConnection = (_provider, options) => {
269
269
  if (options?.account === "user@gmail.com") {
270
270
  return {
271
271
  id: "conn-abc-123",
272
- providerKey: "google",
272
+ provider: "google",
273
273
  accountInfo: "user@gmail.com",
274
274
  status: "active",
275
275
  };
@@ -322,11 +322,11 @@ describe("assistant oauth token", () => {
322
322
 
323
323
  describe("--client-id option", () => {
324
324
  test("resolves connection by client-id and uses connectionId", async () => {
325
- mockGetActiveConnection = (_providerKey, options) => {
325
+ mockGetActiveConnection = (_provider, options) => {
326
326
  if (options?.clientId === "my-client-id") {
327
327
  return {
328
328
  id: "conn-client-456",
329
- providerKey: "google",
329
+ provider: "google",
330
330
  accountInfo: null,
331
331
  status: "active",
332
332
  };
@@ -41,14 +41,17 @@ const log = getCliLogger("cli");
41
41
  /** Format an app row for output, converting timestamps to ISO strings. */
42
42
  function formatAppRow(row: {
43
43
  id: string;
44
- providerKey: string;
44
+ provider: string;
45
45
  clientId: string;
46
46
  createdAt: number;
47
47
  updatedAt: number;
48
48
  }) {
49
49
  return {
50
50
  id: row.id,
51
- providerKey: row.providerKey,
51
+ // Wire key stays `providerKey` for backward compatibility with existing
52
+ // CLI script consumers of `assistant oauth apps list/get/upsert --json`;
53
+ // the internal Drizzle TS-side field is `provider`.
54
+ providerKey: row.provider,
52
55
  clientId: row.clientId,
53
56
  createdAt: new Date(row.createdAt).toISOString(),
54
57
  updatedAt: new Date(row.updatedAt).toISOString(),
@@ -94,7 +97,7 @@ Examples:
94
97
  Returns registered OAuth apps with their provider key, client ID, and
95
98
  timestamps. Output is an array of app objects.
96
99
 
97
- When --provider-key is specified, only apps whose providerKey exactly matches
100
+ When --provider-key is specified, only apps whose provider exactly matches
98
101
  the given value are returned. Without the flag, all apps are listed.
99
102
 
100
103
  In JSON mode (--json), returns the array directly. In human mode, logs a
@@ -288,7 +291,7 @@ Examples:
288
291
  );
289
292
 
290
293
  if (!shouldOutputJson(cmd)) {
291
- log.info(`Upserted app: ${row.id} (provider: ${row.providerKey})`);
294
+ log.info(`Upserted app: ${row.id} (provider: ${row.provider})`);
292
295
  }
293
296
 
294
297
  writeOutput(cmd, formatAppRow(row));