@vellumai/assistant 0.7.0 → 0.7.1

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 (666) hide show
  1. package/ARCHITECTURE.md +6 -7
  2. package/Dockerfile +1 -0
  3. package/README.md +2 -2
  4. package/__tests__/permissions/gateway-threshold-reader.test.ts +79 -139
  5. package/bun.lock +3 -0
  6. package/docs/architecture/security.md +18 -16
  7. package/knip.json +1 -0
  8. package/node_modules/@vellumai/skill-host-contracts/__tests__/client.test.ts +1 -5
  9. package/node_modules/@vellumai/skill-host-contracts/src/assistant-event.ts +0 -5
  10. package/node_modules/@vellumai/skill-host-contracts/src/client.ts +10 -16
  11. package/node_modules/@vellumai/skill-host-contracts/src/skill-host.ts +1 -9
  12. package/node_modules/@vellumai/skill-host-contracts/src/tool-types.ts +12 -12
  13. package/node_modules/@vellumai/slack-text/bun.lock +24 -0
  14. package/node_modules/@vellumai/slack-text/package.json +18 -0
  15. package/node_modules/@vellumai/slack-text/src/index.test.ts +153 -0
  16. package/node_modules/@vellumai/slack-text/src/index.ts +235 -0
  17. package/node_modules/@vellumai/slack-text/tsconfig.json +20 -0
  18. package/openapi.yaml +294 -107
  19. package/package.json +4 -2
  20. package/scripts/generate-openapi.ts +16 -111
  21. package/src/__tests__/agent-wake-override-profile.test.ts +23 -1
  22. package/src/__tests__/anthropic-provider.test.ts +56 -13
  23. package/src/__tests__/app-conversation-ids-backfill.test.ts +278 -0
  24. package/src/__tests__/app-conversation-ids.test.ts +151 -0
  25. package/src/__tests__/approval-cascade.test.ts +0 -15
  26. package/src/__tests__/approval-routes-http.test.ts +6 -17
  27. package/src/__tests__/assistant-event-hub.test.ts +126 -77
  28. package/src/__tests__/assistant-event.test.ts +0 -5
  29. package/src/__tests__/assistant-events-sse-hardening.test.ts +37 -15
  30. package/src/__tests__/assistant-feature-flags-integration.test.ts +0 -29
  31. package/src/__tests__/background-shell-host-bash.test.ts +34 -43
  32. package/src/__tests__/call-controller.test.ts +1 -1
  33. package/src/__tests__/call-site-routing-provider.test.ts +193 -0
  34. package/src/__tests__/channel-approval-routes.test.ts +10 -296
  35. package/src/__tests__/channel-approvals.test.ts +25 -17
  36. package/src/__tests__/channel-guardian.test.ts +100 -146
  37. package/src/__tests__/checker.test.ts +20 -34
  38. package/src/__tests__/compact-event-conversation-id-guard.test.ts +50 -0
  39. package/src/__tests__/compaction-events.test.ts +2 -0
  40. package/src/__tests__/config-schema.test.ts +6 -48
  41. package/src/__tests__/config-watcher.test.ts +12 -0
  42. package/src/__tests__/connection-policy.test.ts +1 -52
  43. package/src/__tests__/contacts-write.test.ts +2 -64
  44. package/src/__tests__/context-image-dimensions.test.ts +1 -1
  45. package/src/__tests__/context-search-memory-source.test.ts +120 -1
  46. package/src/__tests__/context-search-memory-v2-source.test.ts +383 -0
  47. package/src/__tests__/context-search-pkb-source.test.ts +49 -0
  48. package/src/__tests__/context-search-workspace-source.test.ts +9 -22
  49. package/src/__tests__/context-window-manager.test.ts +46 -0
  50. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +2 -0
  51. package/src/__tests__/conversation-agent-loop-overflow.test.ts +102 -29
  52. package/src/__tests__/conversation-agent-loop.test.ts +980 -13
  53. package/src/__tests__/conversation-analysis-routes.test.ts +12 -10
  54. package/src/__tests__/conversation-attention-telegram.test.ts +11 -3
  55. package/src/__tests__/conversation-confirmation-signals.test.ts +0 -291
  56. package/src/__tests__/conversation-history-web-search.test.ts +4 -3
  57. package/src/__tests__/conversation-inference-profile-route.test.ts +12 -23
  58. package/src/__tests__/conversation-lifecycle.test.ts +4 -4
  59. package/src/__tests__/conversation-process-callsite.test.ts +79 -2
  60. package/src/__tests__/conversation-queue.test.ts +3 -8
  61. package/src/__tests__/conversation-routes-disk-view.test.ts +1 -161
  62. package/src/__tests__/conversation-routes-guardian-reply.test.ts +0 -32
  63. package/src/__tests__/conversation-routes-slash-commands.test.ts +75 -66
  64. package/src/__tests__/conversation-runtime-assembly.test.ts +257 -3
  65. package/src/__tests__/conversation-slash-commands.test.ts +24 -4
  66. package/src/__tests__/conversation-slash-queue.test.ts +2 -0
  67. package/src/__tests__/conversation-speed-override.test.ts +0 -3
  68. package/src/__tests__/conversation-starter-routes.test.ts +79 -2
  69. package/src/__tests__/conversation-surfaces-standalone-payloads.test.ts +12 -5
  70. package/src/__tests__/conversation-surfaces-standalone.test.ts +18 -14
  71. package/src/__tests__/conversation-surfaces-state-update.test.ts +3 -2
  72. package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +8 -46
  73. package/src/__tests__/conversation-usage.test.ts +253 -3
  74. package/src/__tests__/credential-execution-shell-lockdown.test.ts +0 -39
  75. package/src/__tests__/credential-health-service.test.ts +68 -0
  76. package/src/__tests__/credential-security-e2e.test.ts +4 -3
  77. package/src/__tests__/credential-security-invariants.test.ts +1 -5
  78. package/src/__tests__/credential-token-resolver.test.ts +180 -0
  79. package/src/__tests__/cu-unified-flow.test.ts +33 -16
  80. package/src/__tests__/daemon-assistant-events.test.ts +34 -21
  81. package/src/__tests__/daemon-credential-client.test.ts +4 -1
  82. package/src/__tests__/db-connection-isolation.test.ts +125 -0
  83. package/src/__tests__/db-migration-rollback.test.ts +101 -0
  84. package/src/__tests__/db-slack-compaction-watermark-migration.test.ts +169 -0
  85. package/src/__tests__/deterministic-verification-control-plane.test.ts +7 -80
  86. package/src/__tests__/document-conversations.test.ts +332 -0
  87. package/src/__tests__/embedding-managed-proxy-selection.test.ts +2 -2
  88. package/src/__tests__/emit-event-signal.test.ts +4 -6
  89. package/src/__tests__/events-client-registration.test.ts +193 -49
  90. package/src/__tests__/filing-service.test.ts +58 -7
  91. package/src/__tests__/first-greeting.test.ts +156 -150
  92. package/src/__tests__/fixtures/mock-chrome-extension.ts +108 -66
  93. package/src/__tests__/get-skill-detail-audit.test.ts +3 -8
  94. package/src/__tests__/guardian-binding-drift-heal.test.ts +1 -1
  95. package/src/__tests__/guardian-dispatch.test.ts +1 -1
  96. package/src/__tests__/guardian-grant-minting.test.ts +7 -2
  97. package/src/__tests__/guardian-routing-invariants.test.ts +7 -2
  98. package/src/__tests__/guardian-routing-state.test.ts +1 -1
  99. package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +32 -11
  100. package/src/__tests__/handlers-user-message-approval-consumption.test.ts +2 -83
  101. package/src/__tests__/headless-browser-mode.test.ts +4 -9
  102. package/src/__tests__/headless-browser-navigate.test.ts +21 -20
  103. package/src/__tests__/heartbeat-service.test.ts +289 -7
  104. package/src/__tests__/helpers/channel-test-adapter.ts +2 -2
  105. package/src/__tests__/helpers/create-guardian-binding.ts +91 -0
  106. package/src/__tests__/host-bash-proxy.test.ts +46 -122
  107. package/src/__tests__/host-browser-e2e-cloud.test.ts +36 -497
  108. package/src/__tests__/host-browser-e2e-self-hosted-capability.test.ts +26 -96
  109. package/src/__tests__/host-browser-proxy.test.ts +111 -185
  110. package/src/__tests__/host-browser-routes.test.ts +45 -75
  111. package/src/__tests__/host-browser-ws-events-e2e.test.ts +26 -30
  112. package/src/__tests__/host-cu-proxy.test.ts +56 -111
  113. package/src/__tests__/host-file-proxy.test.ts +44 -98
  114. package/src/__tests__/host-file-read-tool.test.ts +42 -21
  115. package/src/__tests__/host-shell-tool.test.ts +33 -68
  116. package/src/__tests__/host-transfer-pending-interactions.test.ts +2 -18
  117. package/src/__tests__/host-transfer-proxy.test.ts +43 -53
  118. package/src/__tests__/http-user-message-parity.test.ts +0 -6
  119. package/src/__tests__/inbound-slack-persistence.test.ts +31 -0
  120. package/src/__tests__/injector-chain.test.ts +10 -5
  121. package/src/__tests__/injector-pkb-v2-silenced.test.ts +124 -0
  122. package/src/__tests__/inline-command-runner.test.ts +0 -66
  123. package/src/__tests__/inline-skill-load-permissions.test.ts +0 -2
  124. package/src/__tests__/install-skill-routing.test.ts +1 -13
  125. package/src/__tests__/llm-callsite-catalog.test.ts +34 -0
  126. package/src/__tests__/llm-catalog-parity.test.ts +90 -0
  127. package/src/__tests__/llm-context-resolution.test.ts +180 -0
  128. package/src/__tests__/llm-resolver.test.ts +80 -12
  129. package/src/__tests__/llm-usage-store.test.ts +269 -4
  130. package/src/__tests__/log-export-routes.test.ts +89 -0
  131. package/src/__tests__/managed-profile-guard.test.ts +225 -0
  132. package/src/__tests__/managed-skill-lifecycle.test.ts +0 -10
  133. package/src/__tests__/manual-token-reconciliation.test.ts +334 -0
  134. package/src/__tests__/memory-v2-static-injector.test.ts +95 -0
  135. package/src/__tests__/migration-cross-version-compatibility.test.ts +197 -291
  136. package/src/__tests__/migration-export-http.test.ts +33 -26
  137. package/src/__tests__/migration-export-streaming.test.ts +18 -10
  138. package/src/__tests__/migration-export-to-gcs.test.ts +49 -9
  139. package/src/__tests__/migration-import-commit-http.test.ts +66 -21
  140. package/src/__tests__/migration-import-from-gcs.test.ts +50 -9
  141. package/src/__tests__/migration-import-from-url.test.ts +20 -6
  142. package/src/__tests__/migration-import-preflight-http.test.ts +95 -95
  143. package/src/__tests__/migration-parity-persistence.test.ts +62 -25
  144. package/src/__tests__/migration-transport.test.ts +115 -23
  145. package/src/__tests__/migration-validate-http.test.ts +105 -80
  146. package/src/__tests__/migration-wizard.test.ts +133 -27
  147. package/src/__tests__/non-member-access-request.test.ts +1 -1
  148. package/src/__tests__/notification-guardian-path.test.ts +1 -1
  149. package/src/__tests__/oauth-store.test.ts +19 -0
  150. package/src/__tests__/platform-bash-auto-approve.test.ts +21 -12
  151. package/src/__tests__/prechat-onboarding-contract.test.ts +31 -7
  152. package/src/__tests__/pricing.test.ts +68 -4
  153. package/src/__tests__/process-message-background-slack.test.ts +331 -0
  154. package/src/__tests__/provider-managed-proxy-integration.test.ts +153 -17
  155. package/src/__tests__/provider-send-message-override-profile.test.ts +50 -0
  156. package/src/__tests__/provider-usage-tracking.test.ts +208 -0
  157. package/src/__tests__/reaction-persistence.test.ts +9 -6
  158. package/src/__tests__/rebind-secrets-screen.test.ts +53 -16
  159. package/src/__tests__/recording-handler.test.ts +64 -81
  160. package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +4 -3
  161. package/src/__tests__/relay-server.test.ts +18 -13
  162. package/src/__tests__/require-fresh-approval.test.ts +13 -22
  163. package/src/__tests__/runtime-attachment-metadata.test.ts +1 -1
  164. package/src/__tests__/runtime-events-sse-parity.test.ts +3 -4
  165. package/src/__tests__/runtime-events-sse.test.ts +3 -12
  166. package/src/__tests__/search-skills-unified.test.ts +9 -15
  167. package/src/__tests__/secret-ingress-cli.test.ts +2 -5
  168. package/src/__tests__/secret-ingress-http.test.ts +0 -4
  169. package/src/__tests__/secret-onetime-send.test.ts +4 -2
  170. package/src/__tests__/secret-prompt-log-hygiene.test.ts +24 -7
  171. package/src/__tests__/secret-prompter-channel-fallback.test.ts +42 -47
  172. package/src/__tests__/secret-response-routing.test.ts +29 -15
  173. package/src/__tests__/secret-routes-managed-proxy.test.ts +5 -1
  174. package/src/__tests__/secret-scanner.test.ts +2 -545
  175. package/src/__tests__/send-endpoint-busy.test.ts +9 -24
  176. package/src/__tests__/settings-routes.test.ts +1 -1
  177. package/src/__tests__/shell-credential-ref.test.ts +0 -8
  178. package/src/__tests__/shell-tool-proxy-mode.test.ts +0 -56
  179. package/src/__tests__/skill-script-runner-sandbox.test.ts +0 -11
  180. package/src/__tests__/skill-tool-factory.test.ts +97 -0
  181. package/src/__tests__/skills-file-content-endpoint.test.ts +9 -30
  182. package/src/__tests__/skills-files-catalog-fallback.test.ts +11 -17
  183. package/src/__tests__/slack-inbound-verification.test.ts +1 -62
  184. package/src/__tests__/subagent-fork-notifications.test.ts +57 -47
  185. package/src/__tests__/subagent-manager-notify.test.ts +70 -70
  186. package/src/__tests__/subagent-notify-parent.test.ts +80 -83
  187. package/src/__tests__/system-prompt.test.ts +115 -13
  188. package/src/__tests__/terminal-tools.test.ts +0 -89
  189. package/src/__tests__/thread-backfill.test.ts +945 -31
  190. package/src/__tests__/tool-domain-event-publisher.test.ts +0 -36
  191. package/src/__tests__/tool-execute-pipeline.test.ts +0 -6
  192. package/src/__tests__/tool-execution-abort-cleanup.test.ts +0 -16
  193. package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +9 -19
  194. package/src/__tests__/tool-executor-lifecycle-events.test.ts +4 -7
  195. package/src/__tests__/tool-executor.test.ts +12 -19
  196. package/src/__tests__/tool-metrics-listener.test.ts +0 -35
  197. package/src/__tests__/tool-side-effects-slack-dm.test.ts +1 -0
  198. package/src/__tests__/tool-trace-listener.test.ts +0 -17
  199. package/src/__tests__/transfer-progress-screen.test.ts +63 -26
  200. package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +2 -149
  201. package/src/__tests__/trusted-contact-multichannel.test.ts +2 -4
  202. package/src/__tests__/trusted-contact-verification.test.ts +1 -1
  203. package/src/__tests__/tts-catalog-parity.test.ts +16 -5
  204. package/src/__tests__/usage-attribution.test.ts +247 -0
  205. package/src/__tests__/usage-cli.test.ts +143 -0
  206. package/src/__tests__/usage-grouped-buckets.test.ts +155 -0
  207. package/src/__tests__/usage-routes.test.ts +150 -0
  208. package/src/__tests__/validation-results-screen.test.ts +39 -16
  209. package/src/__tests__/vbundle-pax-and-symlink.test.ts +12 -3
  210. package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +49 -137
  211. package/src/__tests__/verification-control-plane-policy.test.ts +4 -7
  212. package/src/__tests__/voice-session-bridge.test.ts +5 -5
  213. package/src/__tests__/workspace-migration-062-drop-memory-v2-edges-json.test.ts +103 -0
  214. package/src/__tests__/workspace-migration-063-release-notes-dynamic-model-context.test.ts +77 -0
  215. package/src/__tests__/workspace-migration-064-unwind-main-agent-opus-seed.test.ts +225 -0
  216. package/src/__tests__/workspace-migration-memory-v2-init.test.ts +8 -30
  217. package/src/acp/index.ts +0 -15
  218. package/src/acp/session-manager.ts +37 -34
  219. package/src/agent/loop.ts +16 -1
  220. package/src/approvals/AGENTS.md +4 -0
  221. package/src/approvals/__tests__/guardian-feed-event.test.ts +10 -3
  222. package/src/approvals/guardian-request-resolvers.ts +10 -2
  223. package/src/backup/__tests__/backup-worker.test.ts +36 -8
  224. package/src/backup/__tests__/paths.test.ts +2 -2
  225. package/src/backup/__tests__/restore.test.ts +45 -28
  226. package/src/backup/backup-worker.ts +36 -2
  227. package/src/backup/paths.ts +9 -6
  228. package/src/browser-session/events.ts +0 -9
  229. package/src/calls/call-store.ts +1 -34
  230. package/src/calls/guardian-question-copy.ts +0 -108
  231. package/src/calls/relay-server.ts +0 -24
  232. package/src/calls/twilio-rest.ts +0 -38
  233. package/src/calls/twilio-routes.ts +1 -1
  234. package/src/calls/voice-session-bridge.ts +7 -38
  235. package/src/channels/types.ts +1 -36
  236. package/src/cli/commands/__tests__/cache.test.ts +152 -5
  237. package/src/cli/commands/__tests__/memory-v2.test.ts +14 -28
  238. package/src/cli/commands/__tests__/trust.test.ts +21 -387
  239. package/src/cli/commands/backup.ts +4 -4
  240. package/src/cli/commands/cache-fs.ts +8 -0
  241. package/src/cli/commands/cache.ts +153 -82
  242. package/src/cli/commands/clients.ts +63 -5
  243. package/src/cli/commands/completions.ts +3 -3
  244. package/src/cli/commands/contacts.ts +231 -76
  245. package/src/cli/commands/keys.ts +4 -1
  246. package/src/cli/commands/memory-v2.ts +24 -52
  247. package/src/cli/commands/oauth/shared.ts +2 -29
  248. package/src/cli/commands/pending.ts +102 -0
  249. package/src/cli/commands/skills.ts +77 -35
  250. package/src/cli/commands/trust.ts +70 -430
  251. package/src/cli/commands/usage.ts +25 -16
  252. package/src/cli/lib/daemon-credential-client.ts +14 -0
  253. package/src/cli/program.ts +2 -0
  254. package/src/cli.ts +0 -21
  255. package/src/config/__tests__/feature-flag-registry-guard.test.ts +2 -2
  256. package/src/config/bundled-skills/messaging/TOOLS.json +14 -4
  257. package/src/config/env-registry.ts +12 -2
  258. package/src/config/env.ts +3 -14
  259. package/src/config/feature-flag-registry.json +30 -30
  260. package/src/config/llm-callsite-catalog.ts +12 -0
  261. package/src/config/llm-context-resolution.ts +80 -0
  262. package/src/config/llm-resolver.ts +58 -22
  263. package/src/config/loader.ts +3 -3
  264. package/src/config/schema.ts +2 -158
  265. package/src/config/schemas/__tests__/memory-v2.test.ts +1 -0
  266. package/src/config/schemas/call-site-catalog.ts +271 -0
  267. package/src/config/schemas/calls.ts +5 -5
  268. package/src/config/schemas/inference.ts +1 -1
  269. package/src/config/schemas/ingress.ts +1 -1
  270. package/src/config/schemas/llm.ts +31 -3
  271. package/src/config/schemas/memory-retrieval.ts +2 -2
  272. package/src/config/schemas/memory-v2.ts +9 -0
  273. package/src/config/schemas/security.ts +1 -42
  274. package/src/config/schemas/services.ts +6 -6
  275. package/src/config/schemas/skills.ts +5 -5
  276. package/src/config/schemas/tts.ts +1 -1
  277. package/src/config/seed-inference-profiles.ts +117 -0
  278. package/src/config/skills.ts +0 -90
  279. package/src/config/types.ts +3 -6
  280. package/src/contacts/contact-store.ts +0 -17
  281. package/src/contacts/contacts-write.ts +1 -105
  282. package/src/context/window-manager.ts +44 -5
  283. package/src/credential-execution/process-manager.ts +34 -10
  284. package/src/credential-health/credential-health-service.ts +21 -16
  285. package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +75 -82
  286. package/src/daemon/__tests__/daemon-skill-host.test.ts +2 -9
  287. package/src/daemon/connection-policy.ts +1 -26
  288. package/src/daemon/conversation-agent-loop-handlers.ts +53 -4
  289. package/src/daemon/conversation-agent-loop.ts +277 -36
  290. package/src/daemon/conversation-history.ts +8 -8
  291. package/src/daemon/conversation-launch.ts +20 -135
  292. package/src/daemon/conversation-lifecycle.ts +1 -1
  293. package/src/daemon/conversation-messaging.ts +1 -0
  294. package/src/daemon/conversation-process.ts +83 -163
  295. package/src/daemon/conversation-runtime-assembly.ts +219 -76
  296. package/src/daemon/conversation-slash.ts +47 -5
  297. package/src/daemon/conversation-store.ts +7 -31
  298. package/src/daemon/conversation-surfaces.ts +22 -28
  299. package/src/daemon/conversation-tool-setup.ts +3 -33
  300. package/src/daemon/conversation-usage.ts +36 -0
  301. package/src/daemon/conversation.ts +117 -233
  302. package/src/daemon/daemon-control.ts +3 -71
  303. package/src/daemon/daemon-skill-host.ts +8 -11
  304. package/src/daemon/dictation-profile-store.ts +2 -26
  305. package/src/daemon/first-greeting.ts +44 -156
  306. package/src/daemon/handlers/config-channels.ts +12 -12
  307. package/src/daemon/handlers/config-ingress.ts +4 -165
  308. package/src/daemon/handlers/config-model.ts +1 -1
  309. package/src/daemon/handlers/config-voice.ts +0 -42
  310. package/src/daemon/handlers/conversations.ts +11 -190
  311. package/src/daemon/handlers/recording.ts +26 -158
  312. package/src/daemon/handlers/shared.ts +23 -71
  313. package/src/daemon/handlers/skills.ts +42 -93
  314. package/src/daemon/host-bash-proxy.ts +67 -45
  315. package/src/daemon/host-browser-proxy.ts +65 -27
  316. package/src/daemon/host-cu-proxy.ts +40 -39
  317. package/src/daemon/host-file-proxy.ts +58 -37
  318. package/src/daemon/host-transfer-proxy.ts +84 -46
  319. package/src/daemon/lifecycle.ts +49 -15
  320. package/src/daemon/message-types/conversations.ts +7 -0
  321. package/src/daemon/message-types/host-bash.ts +1 -0
  322. package/src/daemon/message-types/host-cu.ts +1 -0
  323. package/src/daemon/message-types/host-file.ts +1 -0
  324. package/src/daemon/message-types/host-transfer.ts +1 -0
  325. package/src/daemon/message-types/messages.ts +10 -9
  326. package/src/daemon/message-types/workspace.ts +1 -1
  327. package/src/daemon/process-message.ts +102 -239
  328. package/src/daemon/server.ts +13 -462
  329. package/src/daemon/shutdown-handlers.ts +2 -2
  330. package/src/daemon/tool-side-effects.ts +125 -107
  331. package/src/daemon/trust-context.ts +13 -0
  332. package/src/daemon/wake-target-adapter.ts +4 -9
  333. package/src/events/domain-events.ts +0 -8
  334. package/src/events/tool-audit-listener.ts +3 -1
  335. package/src/events/tool-domain-event-publisher.ts +0 -10
  336. package/src/events/tool-metrics-listener.ts +0 -17
  337. package/src/events/tool-trace-listener.ts +0 -14
  338. package/src/filing/filing-service.ts +13 -1
  339. package/src/heartbeat/__tests__/heartbeat-feed-event.test.ts +6 -2
  340. package/src/heartbeat/heartbeat-service.ts +23 -5
  341. package/src/home/__tests__/feed-writer.test.ts +0 -4
  342. package/src/home/__tests__/relationship-state-writer.test.ts +30 -0
  343. package/src/home/feed-writer.ts +1 -2
  344. package/src/home/relationship-state-writer.ts +16 -3
  345. package/src/ipc/__tests__/browser-ipc.test.ts +2 -12
  346. package/src/ipc/__tests__/skill-server-bidirectional.test.ts +0 -1
  347. package/src/ipc/assistant-server.ts +3 -10
  348. package/src/ipc/routes/__tests__/memory-v2-backfill.test.ts +39 -20
  349. package/src/ipc/routes/route-adapter.ts +1 -1
  350. package/src/ipc/routes/trust-rules.test.ts +0 -95
  351. package/src/ipc/skill-ipc-types.ts +41 -0
  352. package/src/ipc/skill-routes/__tests__/events-ipc.test.ts +13 -27
  353. package/src/ipc/skill-routes/__tests__/identity.test.ts +4 -23
  354. package/src/ipc/skill-routes/events.ts +12 -23
  355. package/src/ipc/skill-routes/identity.ts +4 -17
  356. package/src/ipc/skill-routes/index.ts +1 -1
  357. package/src/ipc/skill-server.ts +6 -39
  358. package/src/live-voice/__tests__/runtime-websocket-shell.test.ts +0 -8
  359. package/src/live-voice/protocol.ts +4 -13
  360. package/src/mcp/manager.ts +0 -5
  361. package/src/memory/__tests__/fixtures/memory-v2-activation-fixtures.ts +55 -0
  362. package/src/memory/__tests__/memory-v2-activation-log-store.test.ts +127 -0
  363. package/src/memory/app-git-service.ts +0 -32
  364. package/src/memory/app-store.ts +154 -0
  365. package/src/memory/attachments-store.ts +6 -0
  366. package/src/memory/context-search/sources/memory-v2.ts +578 -0
  367. package/src/memory/context-search/sources/memory.ts +5 -0
  368. package/src/memory/context-search/sources/pkb.ts +10 -1
  369. package/src/memory/context-search/sources/workspace.ts +3 -2
  370. package/src/memory/conversation-crud.ts +29 -4
  371. package/src/memory/conversation-disk-view.ts +1 -5
  372. package/src/memory/conversation-starter-checkpoints.ts +63 -0
  373. package/src/memory/db-connection.ts +62 -0
  374. package/src/memory/db-init.ts +14 -0
  375. package/src/memory/embedding-backend.ts +3 -21
  376. package/src/memory/embedding-gemini.ts +0 -2
  377. package/src/memory/embedding-local.ts +6 -6
  378. package/src/memory/embedding-ollama.ts +6 -6
  379. package/src/memory/embedding-openai.ts +6 -6
  380. package/src/memory/embedding-types.ts +21 -0
  381. package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +3 -7
  382. package/src/memory/graph/conversation-graph-memory.ts +35 -13
  383. package/src/memory/graph/injection.test.ts +2 -2
  384. package/src/memory/graph/injection.ts +1 -1
  385. package/src/memory/guardian-action-store.ts +0 -83
  386. package/src/memory/guardian-approvals.ts +0 -48
  387. package/src/memory/indexer.ts +1 -15
  388. package/src/memory/job-handlers/conversation-starters.ts +36 -53
  389. package/src/memory/job-utils.ts +0 -6
  390. package/src/memory/jobs-store.ts +0 -1
  391. package/src/memory/jobs-worker.ts +2 -16
  392. package/src/memory/llm-request-log-store.ts +0 -41
  393. package/src/memory/llm-usage-store.ts +129 -43
  394. package/src/memory/memory-v2-activation-log-store.ts +115 -0
  395. package/src/memory/migrations/233-document-conversations.ts +54 -0
  396. package/src/memory/migrations/234-memory-v2-activation-logs.ts +55 -0
  397. package/src/memory/migrations/235-llm-usage-attribution.ts +31 -0
  398. package/src/memory/migrations/235-slack-compaction-watermark.ts +44 -0
  399. package/src/memory/migrations/236-tool-invocations-matched-rule-id.ts +26 -0
  400. package/src/memory/migrations/__tests__/234-memory-v2-activation-logs.test.ts +182 -0
  401. package/src/memory/migrations/index.ts +14 -0
  402. package/src/memory/migrations/registry.ts +24 -0
  403. package/src/memory/raw-query.ts +2 -68
  404. package/src/memory/schema/conversations.ts +7 -0
  405. package/src/memory/schema/infrastructure.ts +25 -0
  406. package/src/memory/search/semantic.ts +5 -16
  407. package/src/memory/tool-usage-store.ts +2 -0
  408. package/src/memory/usage-buckets.ts +40 -1
  409. package/src/memory/usage-grouped-buckets.ts +127 -0
  410. package/src/memory/v2/__tests__/activation.test.ts +289 -90
  411. package/src/memory/v2/__tests__/backfill-jobs.test.ts +2 -129
  412. package/src/memory/v2/__tests__/consolidation-job.test.ts +28 -11
  413. package/src/memory/v2/__tests__/edge-index.test.ts +278 -0
  414. package/src/memory/v2/__tests__/injection.test.ts +384 -15
  415. package/src/memory/v2/__tests__/migration.test.ts +64 -36
  416. package/src/memory/v2/__tests__/page-store.test.ts +191 -8
  417. package/src/memory/v2/__tests__/prompts-consolidation.test.ts +181 -0
  418. package/src/memory/v2/__tests__/skill-store.test.ts +115 -3
  419. package/src/memory/v2/__tests__/static-context.test.ts +153 -0
  420. package/src/memory/v2/activation.ts +168 -97
  421. package/src/memory/v2/backfill-jobs.ts +15 -100
  422. package/src/memory/v2/consolidation-job.ts +14 -12
  423. package/src/memory/v2/edge-index.ts +191 -0
  424. package/src/memory/v2/injection.ts +182 -58
  425. package/src/memory/v2/migration.ts +57 -64
  426. package/src/memory/v2/now-text.ts +2 -3
  427. package/src/memory/v2/page-store.ts +168 -31
  428. package/src/memory/v2/prompts/consolidation.ts +118 -42
  429. package/src/memory/v2/prompts/sweep.ts +3 -3
  430. package/src/memory/v2/skill-store.ts +55 -7
  431. package/src/memory/v2/static-context.ts +62 -0
  432. package/src/memory/v2/types.ts +10 -20
  433. package/src/memory/validation.ts +0 -11
  434. package/src/messaging/draft-store.ts +0 -6
  435. package/src/messaging/provider-types.ts +8 -0
  436. package/src/messaging/provider.ts +7 -0
  437. package/src/messaging/providers/gmail/client.ts +1 -121
  438. package/src/messaging/providers/outlook/client.ts +0 -73
  439. package/src/messaging/providers/slack/__tests__/adapter-mention-rendering.test.ts +226 -0
  440. package/src/messaging/providers/slack/adapter.ts +122 -21
  441. package/src/messaging/providers/slack/backfill.test.ts +95 -6
  442. package/src/messaging/providers/slack/backfill.ts +89 -11
  443. package/src/messaging/providers/slack/client.ts +10 -124
  444. package/src/messaging/providers/slack/message-metadata.ts +12 -2
  445. package/src/messaging/providers/slack/render-transcript.test.ts +56 -0
  446. package/src/messaging/providers/slack/render-transcript.ts +126 -25
  447. package/src/messaging/providers/slack/types.ts +1 -0
  448. package/src/oauth/connection-resolver.test.ts +8 -0
  449. package/src/oauth/connection-resolver.ts +8 -16
  450. package/src/oauth/credential-token-resolver.ts +97 -0
  451. package/src/oauth/manual-token-connection.ts +30 -34
  452. package/src/oauth/oauth-store.ts +6 -4
  453. package/src/outbound-proxy/certs.ts +0 -7
  454. package/src/outbound-proxy/config.ts +0 -74
  455. package/src/outbound-proxy/health.ts +0 -44
  456. package/src/outbound-proxy/index.ts +0 -22
  457. package/src/permissions/approval-provenance.test.ts +184 -0
  458. package/src/permissions/approval-provenance.ts +70 -0
  459. package/src/permissions/checker.ts +4 -1
  460. package/src/permissions/gateway-threshold-reader.ts +4 -1
  461. package/src/permissions/prompter.ts +9 -2
  462. package/src/permissions/secret-prompter.ts +21 -48
  463. package/src/permissions/types.ts +33 -0
  464. package/src/permissions/workspace-policy.ts +0 -5
  465. package/src/platform/sync-identity.ts +0 -8
  466. package/src/plugins/defaults/injectors.ts +69 -2
  467. package/src/plugins/defaults/overflow-reduce.ts +3 -2
  468. package/src/plugins/types.ts +8 -0
  469. package/src/prompts/system-prompt.ts +34 -70
  470. package/src/prompts/templates/BOOTSTRAP.md +52 -6
  471. package/src/prompts/update-bulletin-job.ts +2 -0
  472. package/src/providers/__tests__/retry-callsite.test.ts +138 -1
  473. package/src/providers/anthropic/client.ts +72 -33
  474. package/src/providers/call-site-routing.ts +42 -3
  475. package/src/providers/gemini/client.ts +18 -2
  476. package/src/providers/managed-proxy/context.ts +0 -5
  477. package/src/providers/model-catalog.ts +105 -19
  478. package/src/providers/openai/chat-completions-provider.ts +6 -0
  479. package/src/providers/openai/responses-provider.ts +7 -1
  480. package/src/providers/provider-send-message.ts +45 -2
  481. package/src/providers/ratelimit.ts +7 -2
  482. package/src/providers/registry.ts +14 -9
  483. package/src/providers/retry.ts +96 -8
  484. package/src/providers/types.ts +13 -0
  485. package/src/providers/usage-tracking.ts +96 -0
  486. package/src/runtime/AGENTS.md +10 -6
  487. package/src/runtime/__tests__/agent-wake.test.ts +89 -0
  488. package/src/runtime/agent-wake.ts +39 -2
  489. package/src/runtime/assistant-event-hub.ts +541 -45
  490. package/src/runtime/assistant-event.ts +1 -6
  491. package/src/runtime/auth/context.ts +0 -9
  492. package/src/runtime/auth/middleware.ts +1 -1
  493. package/src/runtime/auth/route-policy.ts +11 -9
  494. package/src/runtime/auth/token-service.ts +0 -11
  495. package/src/runtime/channel-approvals.ts +6 -2
  496. package/src/runtime/channel-verification-service.ts +3 -5
  497. package/src/runtime/http-errors.ts +0 -34
  498. package/src/runtime/http-router.ts +6 -3
  499. package/src/runtime/http-server.ts +22 -82
  500. package/src/runtime/http-types.ts +5 -0
  501. package/src/runtime/interactive-ui.ts +0 -1
  502. package/src/runtime/middleware/auth.ts +0 -20
  503. package/src/runtime/migrations/__tests__/v1-test-helpers.ts +112 -0
  504. package/src/runtime/migrations/__tests__/vbundle-builder-credentials.test.ts +11 -4
  505. package/src/runtime/migrations/__tests__/vbundle-builder-v1-shape.test.ts +253 -0
  506. package/src/runtime/migrations/__tests__/vbundle-import-credentials.test.ts +19 -6
  507. package/src/runtime/migrations/__tests__/vbundle-legacy-user-md.test.ts +71 -27
  508. package/src/runtime/migrations/__tests__/vbundle-metadata-merge-integration.test.ts +41 -2
  509. package/src/runtime/migrations/__tests__/vbundle-streaming-importer.test.ts +143 -79
  510. package/src/runtime/migrations/__tests__/vbundle-streaming-validator.test.ts +143 -23
  511. package/src/runtime/migrations/__tests__/vbundle-tar-stream.test.ts +2 -2
  512. package/src/runtime/migrations/__tests__/vbundle-validator-v1-schema.test.ts +371 -0
  513. package/src/runtime/migrations/migration-transport.ts +46 -13
  514. package/src/runtime/migrations/migration-wizard.ts +2 -2
  515. package/src/runtime/migrations/origin-mode.ts +40 -0
  516. package/src/runtime/migrations/vbundle-builder.ts +133 -79
  517. package/src/runtime/migrations/vbundle-import-analyzer.ts +9 -7
  518. package/src/runtime/migrations/vbundle-importer.ts +7 -7
  519. package/src/runtime/migrations/vbundle-metadata-merge.ts +1 -1
  520. package/src/runtime/migrations/vbundle-streaming-importer.ts +3 -3
  521. package/src/runtime/migrations/vbundle-streaming-validator.ts +48 -26
  522. package/src/runtime/migrations/vbundle-validator.ts +214 -41
  523. package/src/runtime/pending-interactions.ts +13 -4
  524. package/src/runtime/routes/__tests__/acp-routes.test.ts +0 -1
  525. package/src/runtime/routes/__tests__/backup-routes.test.ts +28 -19
  526. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +235 -0
  527. package/src/runtime/routes/__tests__/llm-call-sites-routes.test.ts +58 -0
  528. package/src/runtime/routes/__tests__/migration-export-secrets-redacted.test.ts +54 -0
  529. package/src/runtime/routes/__tests__/migration-import-credential-filter.test.ts +19 -6
  530. package/src/runtime/routes/__tests__/user-route-dispatcher.test.ts +7 -7
  531. package/src/runtime/routes/acp-routes.test.ts +0 -3
  532. package/src/runtime/routes/acp-routes.ts +3 -7
  533. package/src/runtime/routes/app-management-routes.ts +18 -9
  534. package/src/runtime/routes/approval-routes.ts +55 -14
  535. package/src/runtime/routes/avatar-routes.ts +3 -5
  536. package/src/runtime/routes/browser-routes.ts +1 -15
  537. package/src/runtime/routes/channel-guardian-routes.ts +1 -5
  538. package/src/runtime/routes/channel-readiness-routes.ts +3 -7
  539. package/src/runtime/routes/channel-route-shared.ts +2 -28
  540. package/src/runtime/routes/client-routes.ts +45 -12
  541. package/src/runtime/routes/consolidation-routes.ts +115 -0
  542. package/src/runtime/routes/conversation-list-routes.ts +12 -29
  543. package/src/runtime/routes/conversation-management-routes.ts +14 -51
  544. package/src/runtime/routes/conversation-query-routes.ts +120 -8
  545. package/src/runtime/routes/conversation-routes.ts +44 -528
  546. package/src/runtime/routes/conversation-starter-routes.ts +19 -40
  547. package/src/runtime/routes/documents-routes.ts +53 -18
  548. package/src/runtime/routes/events-routes.ts +59 -91
  549. package/src/runtime/routes/filing-routes.ts +18 -1
  550. package/src/runtime/routes/guardian-action-routes.ts +4 -9
  551. package/src/runtime/routes/host-bash-routes.ts +3 -2
  552. package/src/runtime/routes/host-browser-routes.ts +9 -33
  553. package/src/runtime/routes/host-cu-routes.ts +6 -1
  554. package/src/runtime/routes/host-file-routes.ts +3 -2
  555. package/src/runtime/routes/host-transfer-routes.ts +11 -15
  556. package/src/runtime/routes/identity-routes.ts +78 -6
  557. package/src/runtime/routes/inbound-message-handler.ts +580 -137
  558. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +2 -88
  559. package/src/runtime/routes/inbound-stages/background-dispatch.ts +3 -0
  560. package/src/runtime/routes/index.ts +4 -0
  561. package/src/runtime/routes/integrations/slack/channel.ts +0 -24
  562. package/src/runtime/routes/llm-call-sites-routes.ts +22 -0
  563. package/src/runtime/routes/memory-v2-routes.ts +10 -15
  564. package/src/runtime/routes/migration-routes.ts +188 -31
  565. package/src/runtime/routes/playground/guard.ts +1 -1
  566. package/src/runtime/routes/playground/index.ts +0 -2
  567. package/src/runtime/routes/recording-routes.ts +4 -24
  568. package/src/runtime/routes/rename-conversation-routes.ts +2 -6
  569. package/src/runtime/routes/schedule-routes.ts +3 -6
  570. package/src/runtime/routes/secret-routes.ts +87 -18
  571. package/src/runtime/routes/settings-routes.ts +29 -28
  572. package/src/runtime/routes/skills-routes.ts +12 -31
  573. package/src/runtime/routes/suggest-trust-rule-routes.ts +32 -1
  574. package/src/runtime/routes/task-routes.ts +6 -6
  575. package/src/runtime/routes/trust-rules-routes.ts +3 -94
  576. package/src/runtime/routes/types.ts +4 -4
  577. package/src/runtime/routes/upgrade-broadcast-routes.ts +3 -10
  578. package/src/runtime/routes/usage-routes.ts +87 -10
  579. package/src/runtime/routes/user-routes.ts +17 -31
  580. package/src/runtime/routes/work-items-routes.ts +1 -4
  581. package/src/runtime/services/__tests__/analyze-conversation.test.ts +2 -2
  582. package/src/runtime/services/analyze-conversation.ts +7 -17
  583. package/src/runtime/services/conversation-serializer.ts +2 -4
  584. package/src/runtime/verification-outbound-actions.ts +1 -1
  585. package/src/runtime/verification-rate-limiter.ts +1 -1
  586. package/src/schedule/schedule-store.ts +0 -16
  587. package/src/security/secret-scanner.ts +14 -547
  588. package/src/security/secure-keys.ts +31 -11
  589. package/src/security/token-manager.ts +7 -3
  590. package/src/signals/cancel.ts +16 -25
  591. package/src/signals/conversation-undo.ts +2 -27
  592. package/src/signals/emit-event.ts +1 -2
  593. package/src/signals/user-message.ts +108 -22
  594. package/src/skills/catalog-install.ts +1 -0
  595. package/src/skills/clawhub.ts +2 -2
  596. package/src/skills/inline-command-runner.ts +1 -7
  597. package/src/subagent/manager.ts +67 -84
  598. package/src/tasks/task-store.ts +1 -28
  599. package/src/telemetry/types.ts +6 -0
  600. package/src/telemetry/usage-telemetry-reporter.test.ts +38 -15
  601. package/src/telemetry/usage-telemetry-reporter.ts +3 -5
  602. package/src/tools/acp/spawn.test.ts +1 -2
  603. package/src/tools/acp/steer.test.ts +1 -2
  604. package/src/tools/browser/__tests__/browser-status.test.ts +44 -127
  605. package/src/tools/browser/browser-execution.ts +31 -147
  606. package/src/tools/browser/cdp-client/__tests__/factory.test.ts +92 -68
  607. package/src/tools/browser/cdp-client/factory.ts +48 -76
  608. package/src/tools/browser/cdp-client/index.ts +1 -14
  609. package/src/tools/executor.ts +44 -31
  610. package/src/tools/host-filesystem/edit.ts +3 -2
  611. package/src/tools/host-filesystem/read.ts +3 -2
  612. package/src/tools/host-filesystem/transfer.test.ts +45 -42
  613. package/src/tools/host-filesystem/transfer.ts +4 -3
  614. package/src/tools/host-filesystem/write.ts +3 -2
  615. package/src/tools/host-terminal/host-shell.ts +4 -3
  616. package/src/tools/network/script-proxy/index.ts +1 -10
  617. package/src/tools/permission-checker.ts +66 -1
  618. package/src/tools/skills/sandbox-runner.ts +1 -6
  619. package/src/tools/skills/skill-tool-factory.ts +32 -0
  620. package/src/tools/terminal/safe-env.ts +1 -0
  621. package/src/tools/terminal/shell.ts +2 -78
  622. package/src/tools/types.ts +12 -39
  623. package/src/tts/__tests__/provider-catalog.test.ts +2 -2
  624. package/src/tts/provider-catalog.ts +1 -1
  625. package/src/usage/actors.ts +2 -1
  626. package/src/usage/attribution.ts +185 -0
  627. package/src/usage/pricing.ts +166 -0
  628. package/src/usage/types.ts +14 -0
  629. package/src/util/json.ts +13 -0
  630. package/src/util/logger.ts +3 -3
  631. package/src/util/pricing.ts +50 -3
  632. package/src/work-items/work-item-runner.ts +15 -42
  633. package/src/workspace/migrations/050-seed-main-agent-opus-callsite.ts +4 -3
  634. package/src/workspace/migrations/052-seed-default-inference-profiles.ts +3 -3
  635. package/src/workspace/migrations/060-memory-v2-init.ts +2 -18
  636. package/src/workspace/migrations/061-move-backup-key-to-workspace.ts +59 -0
  637. package/src/workspace/migrations/062-drop-memory-v2-edges-json.ts +27 -0
  638. package/src/workspace/migrations/063-release-notes-dynamic-model-context.ts +70 -0
  639. package/src/workspace/migrations/064-unwind-main-agent-opus-seed.ts +64 -0
  640. package/src/workspace/migrations/registry.ts +8 -0
  641. package/src/workspace/provider-commit-message-generator.ts +3 -3
  642. package/src/__tests__/sandbox-diagnostics.test.ts +0 -138
  643. package/src/__tests__/sandbox-host-parity.test.ts +0 -1024
  644. package/src/__tests__/secret-detection-handler.test.ts +0 -67
  645. package/src/__tests__/secret-scanner-executor.test.ts +0 -450
  646. package/src/__tests__/tcc-sandbox-deny.test.ts +0 -198
  647. package/src/__tests__/terminal-sandbox.test.ts +0 -374
  648. package/src/__tests__/tool-notification-listener.test.ts +0 -65
  649. package/src/context/__tests__/microcompact.test.ts +0 -805
  650. package/src/context/microcompact.ts +0 -443
  651. package/src/daemon/handlers/slack-channel-oauth-install.ts +0 -197
  652. package/src/events/tool-notification-listener.ts +0 -17
  653. package/src/ipc/routes/__tests__/memory-v2-validate.test.ts +0 -219
  654. package/src/memory/v2/__tests__/edges.test.ts +0 -435
  655. package/src/memory/v2/edges.ts +0 -217
  656. package/src/prompts/__tests__/system-prompt-memory-v2.test.ts +0 -197
  657. package/src/runtime/__tests__/chrome-extension-registry.test.ts +0 -518
  658. package/src/runtime/__tests__/client-registry.test.ts +0 -271
  659. package/src/runtime/chrome-extension-registry.ts +0 -368
  660. package/src/runtime/client-registry.ts +0 -254
  661. package/src/runtime/routes/inbound-stages/verification-intercept.ts +0 -329
  662. package/src/tools/secret-detection-handler.ts +0 -269
  663. package/src/tools/terminal/backends/native.ts +0 -327
  664. package/src/tools/terminal/backends/types.ts +0 -37
  665. package/src/tools/terminal/sandbox-diagnostics.ts +0 -87
  666. package/src/tools/terminal/sandbox.ts +0 -40
@@ -113,6 +113,29 @@ mock.module("../../../../util/logger.js", () => ({
113
113
  }),
114
114
  }));
115
115
 
116
+ /** Mutable singleton proxy. Tests set this to control extension availability. */
117
+ let mockSingletonProxy: HostBrowserProxy | null = null;
118
+
119
+ /** Default proxy that reports unavailable — used when no test override is set. */
120
+ const unavailableFallback: HostBrowserProxy = {
121
+ isAvailable: () => false,
122
+ request: () => Promise.reject(new Error("no extension")),
123
+ resolve: () => {},
124
+ hasPendingRequest: () => false,
125
+ dispose: () => {},
126
+ } as unknown as HostBrowserProxy;
127
+
128
+ mock.module("../../../../daemon/host-browser-proxy.js", () => ({
129
+ HostBrowserProxy: {
130
+ get instance() {
131
+ return mockSingletonProxy ?? unavailableFallback;
132
+ },
133
+ reset() {
134
+ mockSingletonProxy = null;
135
+ },
136
+ },
137
+ }));
138
+
116
139
  // Import under test AFTER mock.module calls so that the factory's
117
140
  // top-level imports resolve to our fakes.
118
141
  const {
@@ -127,9 +150,9 @@ const {
127
150
  } = await import("../factory.js");
128
151
 
129
152
  /**
130
- * Minimal ToolContext suitable for factory tests. Only the fields the
131
- * factory reads (`conversationId` and `hostBrowserProxy`) need to be
132
- * populated; other required fields are cast away.
153
+ * Minimal ToolContext suitable for factory tests. Only `conversationId`
154
+ * needs to be populated; other required fields are cast away.
155
+ * Extension availability is controlled via `mockSingletonProxy`.
133
156
  */
134
157
  function makeContext(
135
158
  overrides: Partial<ToolContext> & { conversationId: string },
@@ -171,15 +194,16 @@ describe("getCdpClient", () => {
171
194
  _resetDesktopAutoCooldown();
172
195
  logWarnCalls.length = 0;
173
196
  logDebugCalls.length = 0;
197
+ mockSingletonProxy = null;
174
198
  });
175
199
 
176
200
  // ── Candidate selection (kind reported before first send) ────────────
177
201
 
178
202
  test("routes to ExtensionCdpClient when hostBrowserProxy is set and available", async () => {
179
203
  const fakeProxy = makeAvailableProxy();
204
+ mockSingletonProxy = fakeProxy;
180
205
  const ctx = makeContext({
181
206
  conversationId: "test-convo",
182
- hostBrowserProxy: fakeProxy,
183
207
  });
184
208
 
185
209
  const client = getCdpClient(ctx);
@@ -205,9 +229,9 @@ describe("getCdpClient", () => {
205
229
 
206
230
  test("skips extension when hostBrowserProxy is present but unavailable", async () => {
207
231
  const fakeProxy = makeUnavailableProxy();
232
+ mockSingletonProxy = fakeProxy;
208
233
  const ctx = makeContext({
209
234
  conversationId: "disconnected-proxy",
210
- hostBrowserProxy: fakeProxy,
211
235
  });
212
236
 
213
237
  const client = getCdpClient(ctx);
@@ -227,9 +251,9 @@ describe("getCdpClient", () => {
227
251
  test("skips extension but uses cdp-inspect when proxy unavailable and cdp-inspect enabled", async () => {
228
252
  cdpInspectEnabled = true;
229
253
  const fakeProxy = makeUnavailableProxy();
254
+ mockSingletonProxy = fakeProxy;
230
255
  const ctx = makeContext({
231
256
  conversationId: "disconnected-inspect",
232
- hostBrowserProxy: fakeProxy,
233
257
  });
234
258
 
235
259
  const client = getCdpClient(ctx);
@@ -247,9 +271,9 @@ describe("getCdpClient", () => {
247
271
  test("extension wins even when cdpInspect is enabled", async () => {
248
272
  cdpInspectEnabled = true;
249
273
  const fakeProxy = makeAvailableProxy();
274
+ mockSingletonProxy = fakeProxy;
250
275
  const ctx = makeContext({
251
276
  conversationId: "ext-wins",
252
- hostBrowserProxy: fakeProxy,
253
277
  });
254
278
 
255
279
  const client = getCdpClient(ctx);
@@ -268,7 +292,6 @@ describe("getCdpClient", () => {
268
292
  cdpInspectEnabled = true;
269
293
  const ctx = makeContext({
270
294
  conversationId: "inspect-convo",
271
- hostBrowserProxy: undefined,
272
295
  });
273
296
 
274
297
  const client = getCdpClient(ctx);
@@ -295,7 +318,6 @@ describe("getCdpClient", () => {
295
318
  cdpInspectEnabled = false;
296
319
  const ctx = makeContext({
297
320
  conversationId: "local-convo",
298
- hostBrowserProxy: undefined,
299
321
  });
300
322
 
301
323
  const client = getCdpClient(ctx);
@@ -333,9 +355,9 @@ describe("getCdpClient", () => {
333
355
 
334
356
  test("getCdpClient without options behaves identically to auto mode", async () => {
335
357
  const fakeProxy = makeAvailableProxy();
358
+ mockSingletonProxy = fakeProxy;
336
359
  const ctx = makeContext({
337
360
  conversationId: "no-opts",
338
- hostBrowserProxy: fakeProxy,
339
361
  });
340
362
 
341
363
  const client = getCdpClient(ctx);
@@ -361,9 +383,9 @@ describe("getCdpClient", () => {
361
383
 
362
384
  test("forwards send() through the manager to the extension-backed client", async () => {
363
385
  const fakeProxy = makeAvailableProxy();
386
+ mockSingletonProxy = fakeProxy;
364
387
  const ctx = makeContext({
365
388
  conversationId: "send-ext",
366
- hostBrowserProxy: fakeProxy,
367
389
  });
368
390
 
369
391
  const client = getCdpClient(ctx);
@@ -507,9 +529,9 @@ describe("getCdpClient", () => {
507
529
 
508
530
  test("dispose() on an extension-backed client tears down the extension client", async () => {
509
531
  const fakeProxy = makeAvailableProxy();
532
+ mockSingletonProxy = fakeProxy;
510
533
  const ctx = makeContext({
511
534
  conversationId: "dispose-ext",
512
- hostBrowserProxy: fakeProxy,
513
535
  });
514
536
 
515
537
  const client = getCdpClient(ctx);
@@ -576,9 +598,9 @@ describe("getCdpClient", () => {
576
598
 
577
599
  test("context with transportInterface set routes normally to extension backend", async () => {
578
600
  const fakeProxy = makeAvailableProxy();
601
+ mockSingletonProxy = fakeProxy;
579
602
  const ctx = makeContext({
580
603
  conversationId: "macos-ext",
581
- hostBrowserProxy: fakeProxy,
582
604
  transportInterface: "macos",
583
605
  });
584
606
 
@@ -629,13 +651,14 @@ describe("buildCandidateList", () => {
629
651
  cdpInspectEnabled = false;
630
652
  desktopAutoConfig = { enabled: true, cooldownMs: 30_000 };
631
653
  _resetDesktopAutoCooldown();
654
+ mockSingletonProxy = null;
632
655
  });
633
656
 
634
657
  test("includes extension candidate when proxy is present and available", () => {
635
658
  const fakeProxy = makeAvailableProxy();
659
+ mockSingletonProxy = fakeProxy;
636
660
  const ctx = makeContext({
637
661
  conversationId: "candidates-ext",
638
- hostBrowserProxy: fakeProxy,
639
662
  });
640
663
 
641
664
  const candidates = buildCandidateList(ctx);
@@ -648,9 +671,9 @@ describe("buildCandidateList", () => {
648
671
 
649
672
  test("excludes extension candidate when proxy is present but unavailable", () => {
650
673
  const fakeProxy = makeUnavailableProxy();
674
+ mockSingletonProxy = fakeProxy;
651
675
  const ctx = makeContext({
652
676
  conversationId: "candidates-no-ext",
653
- hostBrowserProxy: fakeProxy,
654
677
  });
655
678
 
656
679
  const candidates = buildCandidateList(ctx);
@@ -672,9 +695,9 @@ describe("buildCandidateList", () => {
672
695
  test("candidate order: extension > cdp-inspect > local when all present", () => {
673
696
  cdpInspectEnabled = true;
674
697
  const fakeProxy = makeAvailableProxy();
698
+ mockSingletonProxy = fakeProxy;
675
699
  const ctx = makeContext({
676
700
  conversationId: "candidates-all",
677
- hostBrowserProxy: fakeProxy,
678
701
  });
679
702
 
680
703
  const candidates = buildCandidateList(ctx);
@@ -710,10 +733,12 @@ describe("buildChainedClient failover", () => {
710
733
  _resetDesktopAutoCooldown();
711
734
  logWarnCalls.length = 0;
712
735
  logDebugCalls.length = 0;
736
+ mockSingletonProxy = null;
713
737
  });
714
738
 
715
739
  test("fails over from extension to local on transport_error", async () => {
716
740
  const fakeProxy = makeAvailableProxy();
741
+ mockSingletonProxy = fakeProxy;
717
742
 
718
743
  // Make extension client fail with transport_error
719
744
  createExtensionCdpClientMock.mockImplementationOnce(
@@ -735,7 +760,6 @@ describe("buildChainedClient failover", () => {
735
760
 
736
761
  const ctx = makeContext({
737
762
  conversationId: "failover-ext-to-local",
738
- hostBrowserProxy: fakeProxy,
739
763
  });
740
764
 
741
765
  const client = getCdpClient(ctx);
@@ -754,6 +778,7 @@ describe("buildChainedClient failover", () => {
754
778
  test("fails over from extension to cdp-inspect to local on transport errors", async () => {
755
779
  cdpInspectEnabled = true;
756
780
  const fakeProxy = makeAvailableProxy();
781
+ mockSingletonProxy = fakeProxy;
757
782
 
758
783
  // Make extension fail with transport_error
759
784
  createExtensionCdpClientMock.mockImplementationOnce(
@@ -785,7 +810,6 @@ describe("buildChainedClient failover", () => {
785
810
 
786
811
  const ctx = makeContext({
787
812
  conversationId: "failover-chain",
788
- hostBrowserProxy: fakeProxy,
789
813
  });
790
814
 
791
815
  const client = getCdpClient(ctx);
@@ -803,6 +827,7 @@ describe("buildChainedClient failover", () => {
803
827
  test("does NOT fail over on cdp_error -- propagates immediately", async () => {
804
828
  cdpInspectEnabled = true;
805
829
  const fakeProxy = makeAvailableProxy();
830
+ mockSingletonProxy = fakeProxy;
806
831
 
807
832
  // Make extension fail with cdp_error (not transport_error)
808
833
  createExtensionCdpClientMock.mockImplementationOnce(
@@ -820,7 +845,6 @@ describe("buildChainedClient failover", () => {
820
845
 
821
846
  const ctx = makeContext({
822
847
  conversationId: "no-failover-cdp-error",
823
- hostBrowserProxy: fakeProxy,
824
848
  });
825
849
 
826
850
  const client = getCdpClient(ctx);
@@ -868,6 +892,7 @@ describe("buildChainedClient failover", () => {
868
892
  test("backend becomes sticky after first successful command", async () => {
869
893
  cdpInspectEnabled = true;
870
894
  const fakeProxy = makeAvailableProxy();
895
+ mockSingletonProxy = fakeProxy;
871
896
 
872
897
  // Make extension fail on first call with transport_error
873
898
  createExtensionCdpClientMock.mockImplementationOnce(
@@ -885,7 +910,6 @@ describe("buildChainedClient failover", () => {
885
910
 
886
911
  const ctx = makeContext({
887
912
  conversationId: "sticky-test",
888
- hostBrowserProxy: fakeProxy,
889
913
  });
890
914
 
891
915
  const client = getCdpClient(ctx);
@@ -946,6 +970,7 @@ describe("buildChainedClient failover", () => {
946
970
 
947
971
  test("kind reflects the active backend after failover", async () => {
948
972
  const fakeProxy = makeAvailableProxy();
973
+ mockSingletonProxy = fakeProxy;
949
974
 
950
975
  // Make extension fail
951
976
  createExtensionCdpClientMock.mockImplementationOnce(
@@ -961,7 +986,6 @@ describe("buildChainedClient failover", () => {
961
986
 
962
987
  const ctx = makeContext({
963
988
  conversationId: "kind-after-failover",
964
- hostBrowserProxy: fakeProxy,
965
989
  });
966
990
 
967
991
  const client = getCdpClient(ctx);
@@ -976,6 +1000,7 @@ describe("buildChainedClient failover", () => {
976
1000
 
977
1001
  test("dispose cleans up failed backends from failover chain", async () => {
978
1002
  const fakeProxy = makeAvailableProxy();
1003
+ mockSingletonProxy = fakeProxy;
979
1004
 
980
1005
  // Make extension fail
981
1006
  createExtensionCdpClientMock.mockImplementationOnce(
@@ -991,7 +1016,6 @@ describe("buildChainedClient failover", () => {
991
1016
 
992
1017
  const ctx = makeContext({
993
1018
  conversationId: "dispose-failover",
994
- hostBrowserProxy: fakeProxy,
995
1019
  });
996
1020
 
997
1021
  const client = getCdpClient(ctx);
@@ -1023,6 +1047,7 @@ describe("desktop-auto cdp-inspect (macOS)", () => {
1023
1047
  _resetDesktopAutoCooldown();
1024
1048
  logWarnCalls.length = 0;
1025
1049
  logDebugCalls.length = 0;
1050
+ mockSingletonProxy = null;
1026
1051
  });
1027
1052
 
1028
1053
  // ── buildCandidateList with desktopAuto ─────────────────────────────
@@ -1043,9 +1068,9 @@ describe("desktop-auto cdp-inspect (macOS)", () => {
1043
1068
 
1044
1069
  test("macOS turn with extension available: extension > cdp-inspect > local", () => {
1045
1070
  const fakeProxy = makeAvailableProxy();
1071
+ mockSingletonProxy = fakeProxy;
1046
1072
  const ctx = makeContext({
1047
1073
  conversationId: "macos-all",
1048
- hostBrowserProxy: fakeProxy,
1049
1074
  transportInterface: "macos",
1050
1075
  });
1051
1076
 
@@ -1060,38 +1085,33 @@ describe("desktop-auto cdp-inspect (macOS)", () => {
1060
1085
 
1061
1086
  test("macOS turn with registry-routed proxy unavailable skips desktop-auto cdp-inspect (extension intent)", () => {
1062
1087
  const fakeProxy = makeUnavailableProxy();
1088
+ mockSingletonProxy = fakeProxy;
1063
1089
  const ctx = makeContext({
1064
1090
  conversationId: "macos-proxy-unavailable-no-inspect",
1065
- hostBrowserProxy: fakeProxy,
1066
1091
  transportInterface: "macos",
1067
- hostBrowserRegistryRouted: true,
1068
1092
  });
1069
1093
 
1070
1094
  const candidates = buildCandidateList(ctx);
1071
1095
 
1072
- // Should only include local -- cdp-inspect is suppressed because extension
1073
- // transport is expected (registry-routed proxy) but temporarily unavailable.
1074
- expect(candidates.length).toBe(1);
1075
- expect(candidates[0].kind).toBe("local");
1096
+ // Extension unavailable => cdp-inspect (desktop-auto) + local
1097
+ expect(candidates.length).toBe(2);
1098
+ expect(candidates[0].kind).toBe("cdp-inspect");
1099
+ expect(candidates[1].kind).toBe("local");
1076
1100
  });
1077
1101
 
1078
- test("macOS turn with SSE-backed proxy unavailable still includes desktop-auto cdp-inspect", () => {
1102
+ test("macOS turn with singleton proxy unavailable still includes desktop-auto cdp-inspect", () => {
1079
1103
  const fakeProxy = makeUnavailableProxy();
1104
+ mockSingletonProxy = fakeProxy;
1080
1105
  const ctx = makeContext({
1081
- conversationId: "macos-sse-proxy-unavailable-inspect-allowed",
1082
- hostBrowserProxy: fakeProxy,
1106
+ conversationId: "macos-proxy-unavailable-inspect-allowed",
1083
1107
  transportInterface: "macos",
1084
- // hostBrowserRegistryRouted is NOT set -- SSE-backed proxy
1085
1108
  });
1086
1109
 
1087
1110
  const candidates = buildCandidateList(ctx);
1088
1111
 
1089
- // SSE-backed proxy that is unavailable (non-interactive turn) should NOT
1090
- // suppress cdp-inspect -- the SSE proxy was never expected to service
1091
- // browser requests, so cdp-inspect remains available as a fallback.
1112
+ // Extension unavailable => cdp-inspect (desktop-auto) + local
1092
1113
  expect(candidates.length).toBe(2);
1093
1114
  expect(candidates[0].kind).toBe("cdp-inspect");
1094
- expect(candidates[0].reason).toContain("desktopAuto");
1095
1115
  expect(candidates[1].kind).toBe("local");
1096
1116
  });
1097
1117
 
@@ -1112,9 +1132,9 @@ describe("desktop-auto cdp-inspect (macOS)", () => {
1112
1132
 
1113
1133
  test("macOS turn with extension available still includes cdp-inspect as fallback", () => {
1114
1134
  const fakeProxy = makeAvailableProxy();
1135
+ mockSingletonProxy = fakeProxy;
1115
1136
  const ctx = makeContext({
1116
1137
  conversationId: "macos-ext-available-inspect-fallback",
1117
- hostBrowserProxy: fakeProxy,
1118
1138
  transportInterface: "macos",
1119
1139
  });
1120
1140
 
@@ -1263,43 +1283,41 @@ describe("desktop-auto cdp-inspect (macOS)", () => {
1263
1283
  expect(candidates[0].kind).toBe("local");
1264
1284
  });
1265
1285
 
1266
- test("macOS turn with registry-routed proxy unavailable routes to local without trying cdp-inspect", async () => {
1286
+ test("macOS turn with registry-routed proxy unavailable still tries cdp-inspect (desktop-auto)", async () => {
1267
1287
  const fakeProxy = makeUnavailableProxy();
1288
+ mockSingletonProxy = fakeProxy;
1268
1289
  const ctx = makeContext({
1269
1290
  conversationId: "macos-proxy-unavail-route",
1270
- hostBrowserProxy: fakeProxy,
1271
1291
  transportInterface: "macos",
1272
- hostBrowserRegistryRouted: true,
1273
1292
  });
1274
1293
 
1275
1294
  const client = getCdpClient(ctx);
1276
1295
 
1277
- // Should go straight to local -- no cdp-inspect candidate inserted
1278
- // because the registry-routed extension was expected but is unavailable.
1279
- expect(client.kind).toBe("local");
1296
+ // Extension unavailable no longer suppresses cdp-inspect desktop-auto
1297
+ // inserts it as a candidate and it succeeds.
1298
+ expect(client.kind).toBe("cdp-inspect");
1280
1299
  const result = await client.send<{ ok: boolean; via: string }>(
1281
1300
  "Page.navigate",
1282
1301
  );
1283
- expect(result).toEqual({ ok: true, via: "local" });
1284
- expect(createCdpInspectClientMock).not.toHaveBeenCalled();
1302
+ expect(result).toEqual({ ok: true, via: "cdp-inspect" });
1303
+ expect(createCdpInspectClientMock).toHaveBeenCalledTimes(1);
1285
1304
  expect(createExtensionCdpClientMock).not.toHaveBeenCalled();
1286
- expect(createLocalCdpClientMock).toHaveBeenCalledTimes(1);
1305
+ expect(createLocalCdpClientMock).not.toHaveBeenCalled();
1287
1306
  client.dispose();
1288
1307
  });
1289
1308
 
1290
- test("macOS turn with SSE-backed proxy unavailable falls through to cdp-inspect", async () => {
1309
+ test("macOS turn with singleton proxy unavailable still tries cdp-inspect (desktop-auto)", async () => {
1291
1310
  const fakeProxy = makeUnavailableProxy();
1311
+ mockSingletonProxy = fakeProxy;
1292
1312
  const ctx = makeContext({
1293
- conversationId: "macos-sse-proxy-unavail-inspect",
1294
- hostBrowserProxy: fakeProxy,
1313
+ conversationId: "macos-proxy-unavail-local",
1295
1314
  transportInterface: "macos",
1296
- // hostBrowserRegistryRouted is NOT set -- SSE-backed proxy
1297
1315
  });
1298
1316
 
1299
1317
  const client = getCdpClient(ctx);
1300
1318
 
1301
- // SSE-backed proxy unavailable (non-interactive turn) should NOT
1302
- // suppress cdp-inspect -- it falls through to desktop-auto cdp-inspect.
1319
+ // Extension unavailable no longer suppresses cdp-inspect desktop-auto
1320
+ // inserts it as a candidate and it succeeds.
1303
1321
  expect(client.kind).toBe("cdp-inspect");
1304
1322
  const result = await client.send<{ ok: boolean; via: string }>(
1305
1323
  "Page.navigate",
@@ -1307,6 +1325,7 @@ describe("desktop-auto cdp-inspect (macOS)", () => {
1307
1325
  expect(result).toEqual({ ok: true, via: "cdp-inspect" });
1308
1326
  expect(createExtensionCdpClientMock).not.toHaveBeenCalled();
1309
1327
  expect(createCdpInspectClientMock).toHaveBeenCalledTimes(1);
1328
+ expect(createLocalCdpClientMock).not.toHaveBeenCalled();
1310
1329
  client.dispose();
1311
1330
  });
1312
1331
 
@@ -1380,15 +1399,16 @@ describe("pinned-mode selection", () => {
1380
1399
  _resetDesktopAutoCooldown();
1381
1400
  logWarnCalls.length = 0;
1382
1401
  logDebugCalls.length = 0;
1402
+ mockSingletonProxy = null;
1383
1403
  });
1384
1404
 
1385
1405
  // ── Pinned extension ────────────────────────────────────────────────
1386
1406
 
1387
1407
  test("pinned extension mode routes to extension when proxy is available", async () => {
1388
1408
  const fakeProxy = makeAvailableProxy();
1409
+ mockSingletonProxy = fakeProxy;
1389
1410
  const ctx = makeContext({
1390
1411
  conversationId: "pinned-ext",
1391
- hostBrowserProxy: fakeProxy,
1392
1412
  });
1393
1413
 
1394
1414
  const client = getCdpClient(ctx, { mode: "extension" });
@@ -1415,7 +1435,7 @@ describe("pinned-mode selection", () => {
1415
1435
  const cdpErr = err as CdpError;
1416
1436
  expect(cdpErr.code).toBe("transport_error");
1417
1437
  expect(cdpErr.message).toContain('Pinned mode "extension" unavailable');
1418
- expect(cdpErr.message).toContain("no host browser proxy provisioned");
1438
+ expect(cdpErr.message).toContain("no active extension connection");
1419
1439
  expect(cdpErr.attemptDiagnostics).toBeDefined();
1420
1440
  expect(cdpErr.attemptDiagnostics).toHaveLength(1);
1421
1441
  expect(cdpErr.attemptDiagnostics![0].candidateKind).toBe("extension");
@@ -1425,9 +1445,9 @@ describe("pinned-mode selection", () => {
1425
1445
 
1426
1446
  test("pinned extension mode throws when proxy is present but unavailable", () => {
1427
1447
  const fakeProxy = makeUnavailableProxy();
1448
+ mockSingletonProxy = fakeProxy;
1428
1449
  const ctx = makeContext({
1429
1450
  conversationId: "pinned-ext-unavail",
1430
- hostBrowserProxy: fakeProxy,
1431
1451
  });
1432
1452
 
1433
1453
  expect(() => getCdpClient(ctx, { mode: "extension" })).toThrow(CdpError);
@@ -1437,13 +1457,14 @@ describe("pinned-mode selection", () => {
1437
1457
  } catch (err) {
1438
1458
  const cdpErr = err as CdpError;
1439
1459
  expect(cdpErr.code).toBe("transport_error");
1440
- expect(cdpErr.message).toContain("not connected");
1460
+ expect(cdpErr.message).toContain("no active extension connection");
1441
1461
  expect(cdpErr.attemptDiagnostics![0].stage).toBe("candidate_selection");
1442
1462
  }
1443
1463
  });
1444
1464
 
1445
1465
  test("pinned extension mode does NOT fall back to local on transport error", async () => {
1446
1466
  const fakeProxy = makeAvailableProxy();
1467
+ mockSingletonProxy = fakeProxy;
1447
1468
 
1448
1469
  // Make extension fail with transport_error
1449
1470
  createExtensionCdpClientMock.mockImplementationOnce(
@@ -1459,7 +1480,6 @@ describe("pinned-mode selection", () => {
1459
1480
 
1460
1481
  const ctx = makeContext({
1461
1482
  conversationId: "pinned-ext-no-fallback",
1462
- hostBrowserProxy: fakeProxy,
1463
1483
  });
1464
1484
 
1465
1485
  const client = getCdpClient(ctx, { mode: "extension" });
@@ -1535,9 +1555,9 @@ describe("pinned-mode selection", () => {
1535
1555
 
1536
1556
  test("pinned local mode routes to local", async () => {
1537
1557
  const fakeProxy = makeAvailableProxy();
1558
+ mockSingletonProxy = fakeProxy;
1538
1559
  const ctx = makeContext({
1539
1560
  conversationId: "pinned-local",
1540
- hostBrowserProxy: fakeProxy,
1541
1561
  });
1542
1562
 
1543
1563
  // Even with proxy available, pinned local should skip extension
@@ -1591,13 +1611,14 @@ describe("buildPinnedCandidateList", () => {
1591
1611
  cdpInspectEnabled = false;
1592
1612
  desktopAutoConfig = { enabled: true, cooldownMs: 30_000 };
1593
1613
  _resetDesktopAutoCooldown();
1614
+ mockSingletonProxy = null;
1594
1615
  });
1595
1616
 
1596
1617
  test("extension mode produces single extension candidate", () => {
1597
1618
  const fakeProxy = makeAvailableProxy();
1619
+ mockSingletonProxy = fakeProxy;
1598
1620
  const ctx = makeContext({
1599
1621
  conversationId: "bpl-ext",
1600
- hostBrowserProxy: fakeProxy,
1601
1622
  });
1602
1623
 
1603
1624
  const candidates = buildPinnedCandidateList(ctx, "extension");
@@ -1663,11 +1684,13 @@ describe("attempt diagnostics", () => {
1663
1684
  _resetDesktopAutoCooldown();
1664
1685
  logWarnCalls.length = 0;
1665
1686
  logDebugCalls.length = 0;
1687
+ mockSingletonProxy = null;
1666
1688
  });
1667
1689
 
1668
1690
  test("exhausted candidates error includes full attempt diagnostics", async () => {
1669
1691
  cdpInspectEnabled = true;
1670
1692
  const fakeProxy = makeAvailableProxy();
1693
+ mockSingletonProxy = fakeProxy;
1671
1694
 
1672
1695
  // Make extension fail
1673
1696
  createExtensionCdpClientMock.mockImplementationOnce(
@@ -1707,7 +1730,6 @@ describe("attempt diagnostics", () => {
1707
1730
 
1708
1731
  const ctx = makeContext({
1709
1732
  conversationId: "diag-all-fail",
1710
- hostBrowserProxy: fakeProxy,
1711
1733
  });
1712
1734
 
1713
1735
  const client = getCdpClient(ctx);
@@ -1750,6 +1772,7 @@ describe("attempt diagnostics", () => {
1750
1772
 
1751
1773
  test("successful fallback still records diagnostics for failed candidates", async () => {
1752
1774
  const fakeProxy = makeAvailableProxy();
1775
+ mockSingletonProxy = fakeProxy;
1753
1776
 
1754
1777
  // Make extension fail
1755
1778
  createExtensionCdpClientMock.mockImplementationOnce(
@@ -1765,7 +1788,6 @@ describe("attempt diagnostics", () => {
1765
1788
 
1766
1789
  const ctx = makeContext({
1767
1790
  conversationId: "diag-partial",
1768
- hostBrowserProxy: fakeProxy,
1769
1791
  });
1770
1792
 
1771
1793
  const client = getCdpClient(ctx);
@@ -1786,6 +1808,7 @@ describe("attempt diagnostics", () => {
1786
1808
  test("auto-mode fallback log includes candidate sequence and failure reasons", async () => {
1787
1809
  cdpInspectEnabled = true;
1788
1810
  const fakeProxy = makeAvailableProxy();
1811
+ mockSingletonProxy = fakeProxy;
1789
1812
 
1790
1813
  // Make extension fail
1791
1814
  createExtensionCdpClientMock.mockImplementationOnce(
@@ -1813,7 +1836,6 @@ describe("attempt diagnostics", () => {
1813
1836
 
1814
1837
  const ctx = makeContext({
1815
1838
  conversationId: "diag-log-shape",
1816
- hostBrowserProxy: fakeProxy,
1817
1839
  });
1818
1840
 
1819
1841
  const client = getCdpClient(ctx);
@@ -1937,10 +1959,12 @@ describe("no-fallback guarantees", () => {
1937
1959
  desktopAutoConfig = { enabled: true, cooldownMs: 30_000 };
1938
1960
  _resetDesktopAutoCooldown();
1939
1961
  logWarnCalls.length = 0;
1962
+ mockSingletonProxy = null;
1940
1963
  });
1941
1964
 
1942
1965
  test("pinned extension: only one candidate is ever constructed", async () => {
1943
1966
  const fakeProxy = makeAvailableProxy();
1967
+ mockSingletonProxy = fakeProxy;
1944
1968
 
1945
1969
  // Make extension fail
1946
1970
  createExtensionCdpClientMock.mockImplementationOnce(
@@ -1956,7 +1980,6 @@ describe("no-fallback guarantees", () => {
1956
1980
 
1957
1981
  const ctx = makeContext({
1958
1982
  conversationId: "nofb-ext",
1959
- hostBrowserProxy: fakeProxy,
1960
1983
  });
1961
1984
  const client = getCdpClient(ctx, { mode: "extension" });
1962
1985
 
@@ -2043,7 +2066,7 @@ describe("no-fallback guarantees", () => {
2043
2066
  // Verify that macOS turns can use the host browser proxy without requiring
2044
2067
  // extension registry connectivity. When a HostBrowserProxy is provisioned
2045
2068
  // via the SSE sender path (no extension), the factory should select
2046
- // extension as the top candidate (because hostBrowserProxy is available).
2069
+ // extension as the top candidate (because the singleton proxy is available).
2047
2070
  // When both proxy and fallback backends exist, selection is deterministic:
2048
2071
  // extension > cdp-inspect > local.
2049
2072
 
@@ -2060,15 +2083,16 @@ describe("macOS host-browser proxy without extension registry", () => {
2060
2083
  _resetDesktopAutoCooldown();
2061
2084
  logWarnCalls.length = 0;
2062
2085
  logDebugCalls.length = 0;
2086
+ mockSingletonProxy = null;
2063
2087
  });
2064
2088
 
2065
2089
  test("macOS turn with SSE-provisioned hostBrowserProxy selects extension backend", async () => {
2066
2090
  // Simulates macOS provisioning a HostBrowserProxy via SSE (no extension
2067
2091
  // registry connection). The proxy is available so extension is selected.
2068
2092
  const fakeProxy = makeAvailableProxy();
2093
+ mockSingletonProxy = fakeProxy;
2069
2094
  const ctx = makeContext({
2070
2095
  conversationId: "macos-sse-proxy",
2071
- hostBrowserProxy: fakeProxy,
2072
2096
  transportInterface: "macos",
2073
2097
  });
2074
2098
 
@@ -2085,9 +2109,9 @@ describe("macOS host-browser proxy without extension registry", () => {
2085
2109
 
2086
2110
  test("macOS turn with both proxy and cdp-inspect produces deterministic 3-candidate chain", () => {
2087
2111
  const fakeProxy = makeAvailableProxy();
2112
+ mockSingletonProxy = fakeProxy;
2088
2113
  const ctx = makeContext({
2089
2114
  conversationId: "macos-deterministic",
2090
- hostBrowserProxy: fakeProxy,
2091
2115
  transportInterface: "macos",
2092
2116
  });
2093
2117
 
@@ -2119,9 +2143,9 @@ describe("macOS host-browser proxy without extension registry", () => {
2119
2143
  // enablement — proxy presence drives extension selection regardless of
2120
2144
  // interface.
2121
2145
  const fakeProxy = makeAvailableProxy();
2146
+ mockSingletonProxy = fakeProxy;
2122
2147
  const ctx = makeContext({
2123
2148
  conversationId: "non-macos-proxy",
2124
- hostBrowserProxy: fakeProxy,
2125
2149
  transportInterface: "cli",
2126
2150
  });
2127
2151