@vellumai/assistant 0.7.0 → 0.7.2

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 (989) hide show
  1. package/ARCHITECTURE.md +38 -56
  2. package/Dockerfile +2 -0
  3. package/README.md +3 -4
  4. package/__tests__/permissions/gateway-threshold-reader.test.ts +88 -142
  5. package/bun.lock +29 -26
  6. package/docs/architecture/security.md +38 -16
  7. package/docs/plugins.md +7 -9
  8. package/knip.json +2 -0
  9. package/node_modules/@vellumai/gateway-client/src/index.ts +1 -0
  10. package/node_modules/@vellumai/gateway-client/src/ipc-client.ts +39 -1
  11. package/node_modules/@vellumai/gateway-client/src/types.ts +11 -0
  12. package/node_modules/@vellumai/service-contracts/package.json +2 -0
  13. package/node_modules/@vellumai/service-contracts/src/__tests__/contracts.test.ts +4 -0
  14. package/node_modules/@vellumai/service-contracts/src/__tests__/ingress.test.ts +107 -0
  15. package/node_modules/@vellumai/service-contracts/src/index.ts +5 -1
  16. package/node_modules/@vellumai/service-contracts/src/ingress.ts +24 -0
  17. package/node_modules/@vellumai/service-contracts/src/twilio-ingress.ts +84 -0
  18. package/node_modules/@vellumai/skill-host-contracts/__tests__/client.test.ts +1 -5
  19. package/node_modules/@vellumai/skill-host-contracts/src/assistant-event.ts +9 -5
  20. package/node_modules/@vellumai/skill-host-contracts/src/client.ts +10 -16
  21. package/node_modules/@vellumai/skill-host-contracts/src/skill-host.ts +1 -9
  22. package/node_modules/@vellumai/skill-host-contracts/src/tool-types.ts +12 -12
  23. package/node_modules/@vellumai/slack-text/bun.lock +24 -0
  24. package/node_modules/@vellumai/slack-text/package.json +18 -0
  25. package/node_modules/@vellumai/slack-text/src/index.test.ts +153 -0
  26. package/node_modules/@vellumai/slack-text/src/index.ts +235 -0
  27. package/node_modules/@vellumai/slack-text/tsconfig.json +20 -0
  28. package/node_modules/@vellumai/twilio-client/bun.lock +24 -0
  29. package/node_modules/@vellumai/twilio-client/package.json +18 -0
  30. package/node_modules/@vellumai/twilio-client/src/__tests__/twilio-client.test.ts +128 -0
  31. package/node_modules/@vellumai/twilio-client/src/index.ts +179 -0
  32. package/node_modules/@vellumai/twilio-client/tsconfig.json +20 -0
  33. package/openapi.yaml +869 -129
  34. package/package.json +8 -3
  35. package/scripts/generate-openapi.ts +16 -111
  36. package/src/__tests__/agent-wake-override-profile.test.ts +23 -1
  37. package/src/__tests__/anthropic-provider.test.ts +56 -13
  38. package/src/__tests__/app-builder-tool-scripts.test.ts +3 -3
  39. package/src/__tests__/app-bundler.test.ts +170 -1
  40. package/src/__tests__/app-control-flow.test.ts +374 -0
  41. package/src/__tests__/app-control-no-global-cgevent.test.ts +98 -0
  42. package/src/__tests__/app-control-tool-schemas.test.ts +621 -0
  43. package/src/__tests__/app-conversation-ids-backfill.test.ts +278 -0
  44. package/src/__tests__/app-conversation-ids.test.ts +151 -0
  45. package/src/__tests__/app-executors.test.ts +30 -43
  46. package/src/__tests__/approval-cascade.test.ts +0 -15
  47. package/src/__tests__/approval-routes-http.test.ts +29 -23
  48. package/src/__tests__/assistant-event-hub-machine-name.test.ts +146 -0
  49. package/src/__tests__/assistant-event-hub-targeted.test.ts +257 -0
  50. package/src/__tests__/assistant-event-hub.test.ts +235 -79
  51. package/src/__tests__/assistant-event.test.ts +10 -5
  52. package/src/__tests__/assistant-events-sse-hardening.test.ts +44 -17
  53. package/src/__tests__/assistant-feature-flags-integration.test.ts +11 -36
  54. package/src/__tests__/background-shell-host-bash.test.ts +46 -56
  55. package/src/__tests__/bootstrap-turn-cleanup.test.ts +44 -0
  56. package/src/__tests__/btw-routes.test.ts +13 -4
  57. package/src/__tests__/call-controller.test.ts +50 -2
  58. package/src/__tests__/call-domain.test.ts +0 -2
  59. package/src/__tests__/call-routes-http.test.ts +0 -2
  60. package/src/__tests__/call-site-routing-provider.test.ts +193 -0
  61. package/src/__tests__/channel-approval-routes.test.ts +10 -296
  62. package/src/__tests__/channel-approvals.test.ts +25 -17
  63. package/src/__tests__/channel-guardian.test.ts +100 -146
  64. package/src/__tests__/channel-readiness-service.test.ts +59 -1
  65. package/src/__tests__/checker.test.ts +23 -38
  66. package/src/__tests__/compact-event-conversation-id-guard.test.ts +50 -0
  67. package/src/__tests__/compaction-events.test.ts +2 -0
  68. package/src/__tests__/config-loader-backfill.test.ts +90 -155
  69. package/src/__tests__/config-loader-platform-defaults.test.ts +196 -0
  70. package/src/__tests__/config-schema-cmd.test.ts +0 -1
  71. package/src/__tests__/config-schema.test.ts +6 -48
  72. package/src/__tests__/config-set-platform-guard.test.ts +48 -4
  73. package/src/__tests__/config-watcher-cleanup-throttle.test.ts +2 -2
  74. package/src/__tests__/config-watcher.test.ts +14 -2
  75. package/src/__tests__/connection-policy.test.ts +1 -52
  76. package/src/__tests__/contacts-write.test.ts +2 -64
  77. package/src/__tests__/context-image-dimensions.test.ts +1 -1
  78. package/src/__tests__/context-search-memory-source.test.ts +120 -1
  79. package/src/__tests__/context-search-memory-v2-source.test.ts +383 -0
  80. package/src/__tests__/context-search-pkb-source.test.ts +49 -0
  81. package/src/__tests__/context-search-workspace-source.test.ts +9 -22
  82. package/src/__tests__/context-window-manager.test.ts +46 -0
  83. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +2 -0
  84. package/src/__tests__/conversation-agent-loop-overflow.test.ts +102 -29
  85. package/src/__tests__/conversation-agent-loop.test.ts +980 -13
  86. package/src/__tests__/conversation-analysis-routes.test.ts +12 -10
  87. package/src/__tests__/conversation-app-control-instantiation.test.ts +392 -0
  88. package/src/__tests__/conversation-app-control-lifecycle.test.ts +237 -0
  89. package/src/__tests__/conversation-attention-telegram.test.ts +11 -3
  90. package/src/__tests__/conversation-confirmation-signals.test.ts +0 -291
  91. package/src/__tests__/conversation-history-web-search.test.ts +4 -3
  92. package/src/__tests__/conversation-inference-profile-route.test.ts +12 -23
  93. package/src/__tests__/conversation-init.benchmark.test.ts +0 -2
  94. package/src/__tests__/conversation-lifecycle.test.ts +40 -4
  95. package/src/__tests__/conversation-process-app-control-preactivation.test.ts +283 -0
  96. package/src/__tests__/conversation-process-callsite.test.ts +79 -2
  97. package/src/__tests__/conversation-queue.test.ts +3 -8
  98. package/src/__tests__/conversation-routes-disk-view.test.ts +7 -161
  99. package/src/__tests__/conversation-routes-guardian-reply.test.ts +120 -104
  100. package/src/__tests__/conversation-routes-slash-commands.test.ts +76 -66
  101. package/src/__tests__/conversation-runtime-assembly.test.ts +257 -3
  102. package/src/__tests__/conversation-slash-commands.test.ts +24 -8
  103. package/src/__tests__/conversation-slash-queue.test.ts +2 -0
  104. package/src/__tests__/conversation-speed-override.test.ts +0 -3
  105. package/src/__tests__/conversation-starter-routes.test.ts +79 -2
  106. package/src/__tests__/conversation-surfaces-action-delivery.test.ts +202 -0
  107. package/src/__tests__/conversation-surfaces-app-control.test.ts +317 -0
  108. package/src/__tests__/conversation-surfaces-standalone-payloads.test.ts +12 -5
  109. package/src/__tests__/conversation-surfaces-standalone.test.ts +18 -14
  110. package/src/__tests__/conversation-surfaces-state-update.test.ts +3 -2
  111. package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +8 -46
  112. package/src/__tests__/conversation-usage.test.ts +253 -3
  113. package/src/__tests__/credential-execution-feature-gates.test.ts +5 -12
  114. package/src/__tests__/credential-execution-managed-contract.test.ts +3 -131
  115. package/src/__tests__/credential-execution-shell-lockdown.test.ts +0 -39
  116. package/src/__tests__/credential-health-service.test.ts +68 -0
  117. package/src/__tests__/credential-security-e2e.test.ts +4 -3
  118. package/src/__tests__/credential-security-invariants.test.ts +1 -5
  119. package/src/__tests__/credential-token-resolver.test.ts +180 -0
  120. package/src/__tests__/credentials-cli.test.ts +5 -12
  121. package/src/__tests__/cu-unified-flow.test.ts +206 -27
  122. package/src/__tests__/daemon-assistant-events.test.ts +34 -21
  123. package/src/__tests__/daemon-credential-client.test.ts +102 -17
  124. package/src/__tests__/db-connection-isolation.test.ts +125 -0
  125. package/src/__tests__/db-migration-rollback.test.ts +101 -0
  126. package/src/__tests__/db-schedule-syntax-migration.test.ts +2 -0
  127. package/src/__tests__/db-slack-compaction-watermark-migration.test.ts +169 -0
  128. package/src/__tests__/deterministic-verification-control-plane.test.ts +7 -80
  129. package/src/__tests__/document-conversations.test.ts +332 -0
  130. package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +0 -1
  131. package/src/__tests__/embedding-managed-proxy-selection.test.ts +2 -2
  132. package/src/__tests__/emit-event-signal.test.ts +4 -6
  133. package/src/__tests__/events-client-registration.test.ts +193 -49
  134. package/src/__tests__/filing-service.test.ts +58 -7
  135. package/src/__tests__/first-greeting.test.ts +156 -150
  136. package/src/__tests__/fixtures/mock-chrome-extension.ts +108 -66
  137. package/src/__tests__/gateway-only-enforcement.test.ts +0 -1
  138. package/src/__tests__/get-skill-detail-audit.test.ts +3 -8
  139. package/src/__tests__/guardian-binding-drift-heal.test.ts +1 -1
  140. package/src/__tests__/guardian-dispatch.test.ts +1 -1
  141. package/src/__tests__/guardian-grant-minting.test.ts +7 -2
  142. package/src/__tests__/guardian-routing-invariants.test.ts +7 -2
  143. package/src/__tests__/guardian-routing-state.test.ts +1 -1
  144. package/src/__tests__/guardian-verification-voice-binding.test.ts +0 -2
  145. package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +30 -11
  146. package/src/__tests__/handlers-user-message-approval-consumption.test.ts +2 -84
  147. package/src/__tests__/headless-browser-mode.test.ts +4 -9
  148. package/src/__tests__/headless-browser-navigate.test.ts +21 -20
  149. package/src/__tests__/heartbeat-service.test.ts +1007 -8
  150. package/src/__tests__/helpers/call-route-handler.ts +7 -1
  151. package/src/__tests__/helpers/channel-test-adapter.ts +2 -2
  152. package/src/__tests__/helpers/create-guardian-binding.ts +91 -0
  153. package/src/__tests__/host-app-control-proxy.test.ts +602 -0
  154. package/src/__tests__/host-app-control-routes.test.ts +263 -0
  155. package/src/__tests__/host-bash-proxy.test.ts +270 -147
  156. package/src/__tests__/host-bash-routes.test.ts +294 -0
  157. package/src/__tests__/host-browser-proxy.test.ts +126 -198
  158. package/src/__tests__/host-browser-routes.test.ts +50 -54
  159. package/src/__tests__/host-cu-proxy.test.ts +78 -144
  160. package/src/__tests__/host-cu-routes-targeted.test.ts +300 -0
  161. package/src/__tests__/host-file-edit-tool.test.ts +47 -1
  162. package/src/__tests__/host-file-proxy-targeted.test.ts +339 -0
  163. package/src/__tests__/host-file-proxy.test.ts +62 -122
  164. package/src/__tests__/host-file-read-tool.test.ts +59 -21
  165. package/src/__tests__/host-file-routes-targeted.test.ts +262 -0
  166. package/src/__tests__/host-file-write-tool.test.ts +42 -1
  167. package/src/__tests__/host-proxy-base.test.ts +312 -0
  168. package/src/__tests__/host-shell-tool.test.ts +53 -70
  169. package/src/__tests__/host-transfer-pending-interactions.test.ts +2 -18
  170. package/src/__tests__/host-transfer-proxy-targeted.test.ts +583 -0
  171. package/src/__tests__/host-transfer-proxy.test.ts +145 -56
  172. package/src/__tests__/host-transfer-routes-targeted.test.ts +447 -0
  173. package/src/__tests__/http-user-message-parity.test.ts +1 -6
  174. package/src/__tests__/identity-intro-cache.test.ts +29 -0
  175. package/src/__tests__/identity-routes.test.ts +103 -1
  176. package/src/__tests__/inbound-slack-persistence.test.ts +31 -0
  177. package/src/__tests__/init-feature-flag-overrides.test.ts +26 -3
  178. package/src/__tests__/injector-chain.test.ts +10 -5
  179. package/src/__tests__/injector-pkb-v2-silenced.test.ts +124 -0
  180. package/src/__tests__/inline-command-runner.test.ts +0 -67
  181. package/src/__tests__/inline-skill-load-permissions.test.ts +5 -13
  182. package/src/__tests__/install-skill-routing.test.ts +1 -13
  183. package/src/__tests__/integration-status.test.ts +85 -5
  184. package/src/__tests__/intent-routing.test.ts +0 -1
  185. package/src/__tests__/jobs-store-qdrant-breaker.test.ts +95 -5
  186. package/src/__tests__/lifecycle-memory-v2-seed.test.ts +17 -0
  187. package/src/__tests__/llm-callsite-catalog.test.ts +34 -0
  188. package/src/__tests__/llm-catalog-parity.test.ts +90 -0
  189. package/src/__tests__/llm-context-resolution.test.ts +180 -0
  190. package/src/__tests__/llm-resolver.test.ts +80 -12
  191. package/src/__tests__/llm-usage-store.test.ts +269 -4
  192. package/src/__tests__/log-export-routes.test.ts +89 -0
  193. package/src/__tests__/managed-profile-guard.test.ts +225 -0
  194. package/src/__tests__/managed-skill-lifecycle.test.ts +0 -11
  195. package/src/__tests__/manual-token-reconciliation.test.ts +334 -0
  196. package/src/__tests__/mcp-auth-routes.test.ts +197 -0
  197. package/src/__tests__/mcp-cli.test.ts +338 -2
  198. package/src/__tests__/memory-jobs-worker-lanes.test.ts +188 -0
  199. package/src/__tests__/memory-v2-static-injector.test.ts +95 -0
  200. package/src/__tests__/migration-cross-version-compatibility.test.ts +197 -291
  201. package/src/__tests__/migration-export-http.test.ts +33 -26
  202. package/src/__tests__/migration-export-streaming.test.ts +18 -10
  203. package/src/__tests__/migration-export-to-gcs.test.ts +49 -9
  204. package/src/__tests__/migration-import-commit-http.test.ts +172 -21
  205. package/src/__tests__/migration-import-from-gcs.test.ts +50 -9
  206. package/src/__tests__/migration-import-from-url.test.ts +20 -6
  207. package/src/__tests__/migration-import-preflight-http.test.ts +95 -95
  208. package/src/__tests__/migration-parity-persistence.test.ts +62 -25
  209. package/src/__tests__/migration-transport.test.ts +115 -23
  210. package/src/__tests__/migration-validate-http.test.ts +105 -80
  211. package/src/__tests__/migration-wizard.test.ts +133 -27
  212. package/src/__tests__/mock-gateway-ipc.ts +1 -0
  213. package/src/__tests__/non-member-access-request.test.ts +1 -1
  214. package/src/__tests__/notification-guardian-path.test.ts +1 -1
  215. package/src/__tests__/oauth-cli.test.ts +0 -2
  216. package/src/__tests__/oauth-store.test.ts +19 -0
  217. package/src/__tests__/oauth2-gateway-transport.test.ts +0 -1
  218. package/src/__tests__/persistence-secret-redaction.test.ts +299 -0
  219. package/src/__tests__/platform-bash-auto-approve.test.ts +26 -21
  220. package/src/__tests__/prechat-onboarding-contract.test.ts +34 -8
  221. package/src/__tests__/pricing.test.ts +68 -4
  222. package/src/__tests__/process-message-background-slack.test.ts +333 -0
  223. package/src/__tests__/provider-commit-message-generator.test.ts +0 -1
  224. package/src/__tests__/provider-managed-proxy-integration.test.ts +153 -17
  225. package/src/__tests__/provider-send-message-override-profile.test.ts +50 -0
  226. package/src/__tests__/provider-usage-tracking.test.ts +208 -0
  227. package/src/__tests__/public-ingress-urls.test.ts +97 -0
  228. package/src/__tests__/reaction-persistence.test.ts +9 -6
  229. package/src/__tests__/rebind-secrets-screen.test.ts +53 -16
  230. package/src/__tests__/recording-handler.test.ts +64 -81
  231. package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +4 -3
  232. package/src/__tests__/relay-server.test.ts +18 -13
  233. package/src/__tests__/require-fresh-approval.test.ts +13 -23
  234. package/src/__tests__/retry-backoff.test.ts +87 -0
  235. package/src/__tests__/runtime-attachment-metadata.test.ts +1 -1
  236. package/src/__tests__/runtime-events-sse-parity.test.ts +3 -4
  237. package/src/__tests__/runtime-events-sse.test.ts +13 -18
  238. package/src/__tests__/sanitize-config-for-transfer.test.ts +24 -2
  239. package/src/__tests__/schedule-retry.test.ts +715 -0
  240. package/src/__tests__/script-proxy-mitm-handler.test.ts +1 -1
  241. package/src/__tests__/search-skills-unified.test.ts +9 -15
  242. package/src/__tests__/secret-ingress-cli.test.ts +2 -5
  243. package/src/__tests__/secret-ingress-http.test.ts +1 -4
  244. package/src/__tests__/secret-onetime-send.test.ts +4 -2
  245. package/src/__tests__/secret-prompt-log-hygiene.test.ts +24 -7
  246. package/src/__tests__/secret-prompter-channel-fallback.test.ts +42 -47
  247. package/src/__tests__/secret-response-routing.test.ts +29 -15
  248. package/src/__tests__/secret-routes-managed-proxy.test.ts +5 -1
  249. package/src/__tests__/secret-scanner.test.ts +2 -545
  250. package/src/__tests__/send-endpoint-busy.test.ts +12 -24
  251. package/src/__tests__/settings-routes.test.ts +1 -1
  252. package/src/__tests__/shell-credential-ref.test.ts +0 -8
  253. package/src/__tests__/shell-tool-proxy-mode.test.ts +0 -57
  254. package/src/__tests__/skill-feature-flags.test.ts +43 -41
  255. package/src/__tests__/skill-load-feature-flag.test.ts +13 -14
  256. package/src/__tests__/skill-load-inline-command.test.ts +0 -51
  257. package/src/__tests__/skill-load-inline-includes.test.ts +0 -43
  258. package/src/__tests__/skill-projection.benchmark.test.ts +0 -1
  259. package/src/__tests__/skill-script-runner-sandbox.test.ts +0 -12
  260. package/src/__tests__/skill-tool-factory.test.ts +97 -0
  261. package/src/__tests__/skills-file-content-endpoint.test.ts +9 -30
  262. package/src/__tests__/skills-files-catalog-fallback.test.ts +11 -17
  263. package/src/__tests__/slack-channel-config.test.ts +9 -14
  264. package/src/__tests__/slack-inbound-verification.test.ts +1 -62
  265. package/src/__tests__/subagent-fork-notifications.test.ts +57 -47
  266. package/src/__tests__/subagent-manager-notify.test.ts +70 -70
  267. package/src/__tests__/subagent-notify-parent.test.ts +80 -83
  268. package/src/__tests__/system-prompt-ask-mode.test.ts +0 -1
  269. package/src/__tests__/system-prompt.test.ts +115 -14
  270. package/src/__tests__/telegram-config.test.ts +0 -1
  271. package/src/__tests__/terminal-tools.test.ts +0 -89
  272. package/src/__tests__/test-preload.ts +8 -0
  273. package/src/__tests__/thread-backfill.test.ts +945 -31
  274. package/src/__tests__/tool-approval-handler.test.ts +3 -4
  275. package/src/__tests__/tool-audit-listener.test.ts +48 -0
  276. package/src/__tests__/tool-domain-event-publisher.test.ts +0 -36
  277. package/src/__tests__/tool-execute-pipeline.test.ts +0 -7
  278. package/src/__tests__/tool-execution-abort-cleanup.test.ts +0 -17
  279. package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +9 -19
  280. package/src/__tests__/tool-executor-lifecycle-events.test.ts +4 -8
  281. package/src/__tests__/tool-executor.test.ts +12 -20
  282. package/src/__tests__/tool-metrics-listener.test.ts +0 -35
  283. package/src/__tests__/tool-side-effects-slack-dm.test.ts +1 -0
  284. package/src/__tests__/tool-trace-listener.test.ts +0 -17
  285. package/src/__tests__/transfer-progress-screen.test.ts +63 -26
  286. package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +2 -149
  287. package/src/__tests__/trusted-contact-multichannel.test.ts +2 -4
  288. package/src/__tests__/trusted-contact-verification.test.ts +1 -1
  289. package/src/__tests__/tts-catalog-parity.test.ts +16 -5
  290. package/src/__tests__/twilio-config.test.ts +3 -16
  291. package/src/__tests__/twilio-routes.test.ts +3 -5
  292. package/src/__tests__/twilio-validation.test.ts +93 -0
  293. package/src/__tests__/usage-attribution.test.ts +247 -0
  294. package/src/__tests__/usage-cli.test.ts +143 -0
  295. package/src/__tests__/usage-grouped-buckets.test.ts +155 -0
  296. package/src/__tests__/usage-routes.test.ts +150 -0
  297. package/src/__tests__/validation-results-screen.test.ts +39 -16
  298. package/src/__tests__/vbundle-pax-and-symlink.test.ts +12 -3
  299. package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +47 -138
  300. package/src/__tests__/verification-control-plane-policy.test.ts +6 -11
  301. package/src/__tests__/voice-ingress-preflight.test.ts +19 -0
  302. package/src/__tests__/voice-session-bridge.test.ts +5 -5
  303. package/src/__tests__/workspace-migration-006-services-config.test.ts +3 -2
  304. package/src/__tests__/workspace-migration-062-drop-memory-v2-edges-json.test.ts +103 -0
  305. package/src/__tests__/workspace-migration-063-release-notes-dynamic-model-context.test.ts +77 -0
  306. package/src/__tests__/workspace-migration-064-unwind-main-agent-opus-seed.test.ts +225 -0
  307. package/src/__tests__/workspace-migration-backfill-installation-id.test.ts +1 -5
  308. package/src/__tests__/workspace-migration-down-functions.test.ts +8 -8
  309. package/src/__tests__/workspace-migration-memory-v2-init.test.ts +8 -30
  310. package/src/__tests__/workspace-migration-unify-llm-callsite-configs.test.ts +10 -6
  311. package/src/acp/index.ts +0 -15
  312. package/src/acp/session-manager.ts +37 -34
  313. package/src/agent/loop.ts +16 -1
  314. package/src/approvals/AGENTS.md +4 -0
  315. package/src/approvals/__tests__/guardian-feed-event.test.ts +10 -3
  316. package/src/approvals/guardian-request-resolvers.ts +10 -2
  317. package/src/backup/__tests__/paths.test.ts +0 -22
  318. package/src/backup/__tests__/restore.test.ts +94 -177
  319. package/src/backup/paths.ts +2 -15
  320. package/src/backup/restore.ts +107 -231
  321. package/src/browser-session/events.ts +0 -9
  322. package/src/bundler/app-bundler.ts +51 -3
  323. package/src/calls/call-store.ts +1 -34
  324. package/src/calls/guardian-question-copy.ts +0 -108
  325. package/src/calls/relay-server.ts +4 -68
  326. package/src/calls/twilio-config.ts +2 -17
  327. package/src/calls/twilio-rest.ts +31 -141
  328. package/src/calls/twilio-routes.ts +12 -13
  329. package/src/calls/voice-session-bridge.ts +7 -38
  330. package/src/channels/types.ts +8 -42
  331. package/src/cli/commands/__tests__/backup.test.ts +6 -277
  332. package/src/cli/commands/__tests__/cache.test.ts +152 -5
  333. package/src/cli/commands/__tests__/gateway.test.ts +288 -0
  334. package/src/cli/commands/__tests__/memory-v2.test.ts +18 -28
  335. package/src/cli/commands/__tests__/trust.test.ts +21 -387
  336. package/src/cli/commands/__tests__/webhooks.test.ts +0 -1
  337. package/src/cli/commands/backup.ts +6 -331
  338. package/src/cli/commands/cache-fs.ts +8 -0
  339. package/src/cli/commands/cache.ts +153 -82
  340. package/src/cli/commands/clients.ts +64 -7
  341. package/src/cli/commands/completions.ts +3 -3
  342. package/src/cli/commands/contacts.ts +304 -76
  343. package/src/cli/commands/conversations.ts +2 -5
  344. package/src/cli/commands/credentials.ts +15 -7
  345. package/src/cli/commands/domain.ts +66 -15
  346. package/src/cli/commands/gateway.ts +183 -0
  347. package/src/cli/commands/keys.ts +13 -7
  348. package/src/cli/commands/mcp.ts +116 -156
  349. package/src/cli/commands/memory-v2.ts +320 -53
  350. package/src/cli/commands/oauth/shared.ts +2 -29
  351. package/src/cli/commands/pending.ts +102 -0
  352. package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +0 -1
  353. package/src/cli/commands/platform/__tests__/connect.test.ts +0 -2
  354. package/src/cli/commands/platform/__tests__/disconnect.test.ts +0 -2
  355. package/src/cli/commands/platform/__tests__/status.test.ts +13 -15
  356. package/src/cli/commands/platform/disconnect.ts +5 -4
  357. package/src/cli/commands/platform/index.ts +0 -18
  358. package/src/cli/commands/skills.ts +77 -35
  359. package/src/cli/commands/trust.ts +70 -430
  360. package/src/cli/commands/usage.ts +25 -16
  361. package/src/cli/lib/daemon-credential-client.ts +115 -19
  362. package/src/cli/program.ts +4 -0
  363. package/src/cli.ts +0 -21
  364. package/src/config/__tests__/feature-flag-registry-guard.test.ts +2 -2
  365. package/src/config/assistant-feature-flags.ts +67 -10
  366. package/src/config/bundled-skills/acp/SKILL.md +6 -0
  367. package/src/config/bundled-skills/acp/TOOLS.json +1 -22
  368. package/src/config/bundled-skills/app-builder/SKILL.md +14 -109
  369. package/src/config/bundled-skills/app-builder/TOOLS.json +1 -28
  370. package/src/config/bundled-skills/app-builder/tools/app-create.ts +1 -10
  371. package/src/config/bundled-skills/app-control/SKILL.md +75 -0
  372. package/src/config/bundled-skills/app-control/TOOLS.json +299 -0
  373. package/src/config/bundled-skills/app-control/tools/app-control-click.ts +12 -0
  374. package/src/config/bundled-skills/app-control/tools/app-control-combo.ts +12 -0
  375. package/src/config/bundled-skills/app-control/tools/app-control-drag.ts +12 -0
  376. package/src/config/bundled-skills/app-control/tools/app-control-observe.ts +12 -0
  377. package/src/config/bundled-skills/app-control/tools/app-control-press.ts +12 -0
  378. package/src/config/bundled-skills/app-control/tools/app-control-sequence.ts +12 -0
  379. package/src/config/bundled-skills/app-control/tools/app-control-start.ts +12 -0
  380. package/src/config/bundled-skills/app-control/tools/app-control-stop.ts +12 -0
  381. package/src/config/bundled-skills/app-control/tools/app-control-type.ts +12 -0
  382. package/src/config/bundled-skills/computer-use/SKILL.md +6 -0
  383. package/src/config/bundled-skills/computer-use/TOOLS.json +67 -43
  384. package/src/config/bundled-skills/contacts/TOOLS.json +0 -16
  385. package/src/config/bundled-skills/document/TOOLS.json +0 -8
  386. package/src/config/bundled-skills/followups/TOOLS.json +0 -12
  387. package/src/config/bundled-skills/image-studio/SKILL.md +4 -0
  388. package/src/config/bundled-skills/image-studio/TOOLS.json +0 -4
  389. package/src/config/bundled-skills/media-processing/TOOLS.json +0 -24
  390. package/src/config/bundled-skills/messaging/TOOLS.json +14 -44
  391. package/src/config/bundled-skills/phone-calls/TOOLS.json +0 -12
  392. package/src/config/bundled-skills/phone-calls/references/TROUBLESHOOTING.md +19 -4
  393. package/src/config/bundled-skills/playbooks/TOOLS.json +0 -16
  394. package/src/config/bundled-skills/schedule/TOOLS.json +14 -14
  395. package/src/config/bundled-skills/sequences/TOOLS.json +0 -36
  396. package/src/config/bundled-skills/settings/SKILL.md +4 -0
  397. package/src/config/bundled-skills/settings/TOOLS.json +0 -12
  398. package/src/config/bundled-skills/skill-management/SKILL.md +6 -0
  399. package/src/config/bundled-skills/skill-management/TOOLS.json +0 -8
  400. package/src/config/bundled-skills/subagent/SKILL.md +6 -2
  401. package/src/config/bundled-skills/subagent/TOOLS.json +0 -20
  402. package/src/config/bundled-skills/transcribe/SKILL.md +4 -0
  403. package/src/config/bundled-skills/transcribe/TOOLS.json +0 -4
  404. package/src/config/bundled-tool-registry.ts +21 -0
  405. package/src/config/env-registry.ts +12 -4
  406. package/src/config/env.ts +22 -26
  407. package/src/config/feature-flag-registry.json +40 -152
  408. package/src/config/llm-callsite-catalog.ts +12 -0
  409. package/src/config/llm-context-resolution.ts +80 -0
  410. package/src/config/llm-resolver.ts +58 -22
  411. package/src/config/loader.ts +76 -102
  412. package/src/config/sanitize-for-transfer.ts +2 -0
  413. package/src/config/schema.ts +2 -158
  414. package/src/config/schemas/__tests__/memory-lifecycle.test.ts +80 -0
  415. package/src/config/schemas/__tests__/memory-v2.test.ts +8 -4
  416. package/src/config/schemas/call-site-catalog.ts +271 -0
  417. package/src/config/schemas/calls.ts +5 -14
  418. package/src/config/schemas/heartbeat.ts +63 -0
  419. package/src/config/schemas/inference.ts +1 -1
  420. package/src/config/schemas/ingress.ts +11 -7
  421. package/src/config/schemas/llm.ts +34 -11
  422. package/src/config/schemas/memory-lifecycle.ts +77 -24
  423. package/src/config/schemas/memory-retrieval.ts +2 -2
  424. package/src/config/schemas/memory-v2.ts +57 -4
  425. package/src/config/schemas/platform.ts +6 -0
  426. package/src/config/schemas/security.ts +1 -42
  427. package/src/config/schemas/services.ts +7 -21
  428. package/src/config/schemas/skills.ts +5 -11
  429. package/src/config/schemas/tts.ts +1 -1
  430. package/src/config/seed-inference-profiles.ts +117 -0
  431. package/src/config/skills.ts +0 -90
  432. package/src/config/types.ts +3 -6
  433. package/src/contacts/contact-store.ts +0 -47
  434. package/src/contacts/contacts-write.ts +1 -132
  435. package/src/context/window-manager.ts +43 -5
  436. package/src/credential-execution/feature-gates.ts +10 -10
  437. package/src/credential-execution/process-manager.ts +46 -51
  438. package/src/credential-health/credential-health-service.ts +21 -16
  439. package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +75 -82
  440. package/src/daemon/__tests__/conversation-tool-setup.test.ts +126 -5
  441. package/src/daemon/__tests__/daemon-skill-host.test.ts +2 -9
  442. package/src/daemon/bootstrap-turn-cleanup.ts +45 -0
  443. package/src/daemon/config-watcher.ts +4 -3
  444. package/src/daemon/connection-policy.ts +1 -26
  445. package/src/daemon/conversation-agent-loop-handlers.ts +74 -7
  446. package/src/daemon/conversation-agent-loop.ts +309 -64
  447. package/src/daemon/conversation-history.ts +8 -8
  448. package/src/daemon/conversation-launch.ts +20 -135
  449. package/src/daemon/conversation-lifecycle.ts +8 -1
  450. package/src/daemon/conversation-messaging.ts +1 -0
  451. package/src/daemon/conversation-process.ts +97 -172
  452. package/src/daemon/conversation-runtime-assembly.ts +219 -76
  453. package/src/daemon/conversation-slash.ts +47 -5
  454. package/src/daemon/conversation-store.ts +7 -31
  455. package/src/daemon/conversation-surfaces.ts +144 -29
  456. package/src/daemon/conversation-tool-setup.ts +18 -87
  457. package/src/daemon/conversation-usage.ts +36 -0
  458. package/src/daemon/conversation.ts +134 -231
  459. package/src/daemon/daemon-control.ts +3 -71
  460. package/src/daemon/daemon-skill-host.ts +8 -11
  461. package/src/daemon/dictation-profile-store.ts +2 -26
  462. package/src/daemon/doordash-steps.ts +1 -1
  463. package/src/daemon/first-greeting.ts +44 -156
  464. package/src/daemon/handlers/config-channels.ts +12 -12
  465. package/src/daemon/handlers/config-ingress.ts +4 -165
  466. package/src/daemon/handlers/config-model.ts +1 -1
  467. package/src/daemon/handlers/config-voice.ts +0 -42
  468. package/src/daemon/handlers/conversations.ts +11 -190
  469. package/src/daemon/handlers/recording.ts +26 -158
  470. package/src/daemon/handlers/shared.ts +27 -72
  471. package/src/daemon/handlers/skills.ts +42 -93
  472. package/src/daemon/host-app-control-proxy.ts +293 -0
  473. package/src/daemon/host-bash-proxy.ts +124 -92
  474. package/src/daemon/host-browser-proxy.ts +111 -88
  475. package/src/daemon/host-cu-proxy.ts +100 -104
  476. package/src/daemon/host-file-proxy.ts +136 -91
  477. package/src/daemon/host-proxy-base.ts +294 -0
  478. package/src/daemon/host-proxy-preactivation.ts +82 -0
  479. package/src/daemon/host-transfer-proxy.ts +303 -147
  480. package/src/daemon/lifecycle.ts +164 -132
  481. package/src/daemon/message-protocol.ts +3 -8
  482. package/src/daemon/message-types/contacts.ts +23 -1
  483. package/src/daemon/message-types/conversations.ts +18 -8
  484. package/src/daemon/message-types/host-app-control.ts +150 -0
  485. package/src/daemon/message-types/host-bash.ts +5 -0
  486. package/src/daemon/message-types/host-cu.ts +3 -0
  487. package/src/daemon/message-types/host-file.ts +5 -0
  488. package/src/daemon/message-types/host-transfer.ts +4 -0
  489. package/src/daemon/message-types/messages.ts +10 -9
  490. package/src/daemon/message-types/schedules.ts +8 -3
  491. package/src/daemon/message-types/skills.ts +2 -2
  492. package/src/daemon/message-types/workspace.ts +1 -1
  493. package/src/daemon/process-message.ts +119 -239
  494. package/src/daemon/server.ts +13 -462
  495. package/src/daemon/shutdown-handlers.ts +2 -5
  496. package/src/daemon/tool-setup-types.ts +51 -0
  497. package/src/daemon/tool-side-effects.ts +126 -108
  498. package/src/daemon/trust-context.ts +13 -0
  499. package/src/daemon/wake-target-adapter.ts +4 -9
  500. package/src/events/domain-events.ts +0 -8
  501. package/src/events/tool-audit-listener.ts +5 -2
  502. package/src/events/tool-domain-event-publisher.ts +0 -10
  503. package/src/events/tool-metrics-listener.ts +0 -17
  504. package/src/events/tool-trace-listener.ts +0 -14
  505. package/src/filing/filing-service.ts +13 -1
  506. package/src/heartbeat/__tests__/heartbeat-feed-event.test.ts +21 -9
  507. package/src/heartbeat/__tests__/heartbeat-run-store.test.ts +216 -0
  508. package/src/heartbeat/heartbeat-run-store.ts +236 -0
  509. package/src/heartbeat/heartbeat-service.ts +303 -54
  510. package/src/home/__tests__/feed-writer.test.ts +0 -4
  511. package/src/home/__tests__/post-connect-feed.test.ts +99 -0
  512. package/src/home/__tests__/relationship-state-writer.test.ts +41 -9
  513. package/src/home/__tests__/suggested-prompts.test.ts +89 -0
  514. package/src/home/feed-writer.ts +1 -2
  515. package/src/home/post-connect-feed.ts +68 -0
  516. package/src/home/relationship-state-writer.ts +33 -95
  517. package/src/home/suggested-prompts.ts +46 -10
  518. package/src/inbound/public-ingress-urls.ts +32 -34
  519. package/src/ipc/__tests__/browser-ipc.test.ts +2 -12
  520. package/src/ipc/__tests__/route-error-envelope.test.ts +80 -0
  521. package/src/ipc/__tests__/skill-server-bidirectional.test.ts +0 -1
  522. package/src/ipc/assistant-server.ts +17 -11
  523. package/src/ipc/cli-client.ts +32 -1
  524. package/src/ipc/routes/__tests__/memory-v2-backfill.test.ts +39 -20
  525. package/src/ipc/routes/route-adapter.ts +1 -1
  526. package/src/ipc/routes/trust-rules.test.ts +0 -95
  527. package/src/ipc/skill-ipc-types.ts +41 -0
  528. package/src/ipc/skill-routes/__tests__/events-ipc.test.ts +13 -27
  529. package/src/ipc/skill-routes/__tests__/identity.test.ts +4 -23
  530. package/src/ipc/skill-routes/events.ts +12 -23
  531. package/src/ipc/skill-routes/identity.ts +4 -17
  532. package/src/ipc/skill-routes/index.ts +1 -1
  533. package/src/ipc/skill-server.ts +6 -39
  534. package/src/live-voice/__tests__/runtime-websocket-shell.test.ts +0 -8
  535. package/src/live-voice/live-voice-metrics.ts +10 -10
  536. package/src/live-voice/protocol.ts +4 -13
  537. package/src/mcp/__tests__/mcp-auth-orchestrator.test.ts +304 -0
  538. package/src/mcp/manager.ts +0 -5
  539. package/src/mcp/mcp-auth-orchestrator.ts +213 -0
  540. package/src/mcp/mcp-auth-state.ts +133 -0
  541. package/src/mcp/mcp-oauth-provider.ts +19 -0
  542. package/src/memory/__tests__/fixtures/memory-v2-activation-fixtures.ts +55 -0
  543. package/src/memory/__tests__/jobs-store-job-classes.test.ts +24 -0
  544. package/src/memory/__tests__/memory-v2-activation-log-store.test.ts +127 -0
  545. package/src/memory/__tests__/qdrant-client-sentinel.test.ts +49 -0
  546. package/src/memory/__tests__/sparse-tokenize.test.ts +66 -0
  547. package/src/memory/anisotropy.test.ts +247 -0
  548. package/src/memory/anisotropy.ts +443 -0
  549. package/src/memory/app-git-service.ts +0 -32
  550. package/src/memory/app-store.ts +154 -0
  551. package/src/memory/attachments-store.ts +6 -0
  552. package/src/memory/auto-analysis-constants.ts +17 -0
  553. package/src/memory/auto-analysis-guard.ts +5 -15
  554. package/src/memory/canonical-guardian-store.ts +7 -7
  555. package/src/memory/context-search/__tests__/agent-runner-redaction.test.ts +122 -0
  556. package/src/memory/context-search/agent-protocol.ts +6 -6
  557. package/src/memory/context-search/agent-runner.ts +32 -7
  558. package/src/memory/context-search/sources/memory-v2.ts +590 -0
  559. package/src/memory/context-search/sources/memory.ts +5 -0
  560. package/src/memory/context-search/sources/pkb.ts +10 -1
  561. package/src/memory/context-search/sources/workspace.ts +3 -2
  562. package/src/memory/conversation-crud.ts +30 -5
  563. package/src/memory/conversation-disk-view.ts +1 -5
  564. package/src/memory/conversation-key-store.ts +2 -15
  565. package/src/memory/conversation-starter-checkpoints.ts +63 -0
  566. package/src/memory/db-connection.ts +62 -0
  567. package/src/memory/db-init.ts +18 -0
  568. package/src/memory/embedding-backend.ts +12 -42
  569. package/src/memory/embedding-gemini.ts +0 -2
  570. package/src/memory/embedding-local.ts +6 -6
  571. package/src/memory/embedding-ollama.ts +6 -6
  572. package/src/memory/embedding-openai.ts +6 -6
  573. package/src/memory/embedding-types.ts +21 -0
  574. package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +49 -8
  575. package/src/memory/graph/conversation-graph-memory.ts +35 -36
  576. package/src/memory/graph/graph-search.ts +8 -0
  577. package/src/memory/graph/injection.test.ts +2 -2
  578. package/src/memory/graph/injection.ts +1 -1
  579. package/src/memory/graph/retriever.ts +28 -0
  580. package/src/memory/graph/tools.ts +1 -1
  581. package/src/memory/guardian-action-store.ts +0 -83
  582. package/src/memory/guardian-approvals.ts +0 -48
  583. package/src/memory/indexer.ts +1 -15
  584. package/src/memory/job-handlers/conversation-starters.ts +36 -53
  585. package/src/memory/job-utils.ts +0 -6
  586. package/src/memory/jobs/__tests__/embed-concept-page.test.ts +8 -2
  587. package/src/memory/jobs/embed-concept-page.ts +28 -2
  588. package/src/memory/jobs/embed-pkb-file.test.ts +2 -2
  589. package/src/memory/jobs-store.ts +66 -23
  590. package/src/memory/jobs-worker.ts +114 -79
  591. package/src/memory/llm-request-log-store.ts +0 -41
  592. package/src/memory/llm-usage-store.ts +129 -43
  593. package/src/memory/memory-v2-activation-log-store.ts +115 -0
  594. package/src/memory/migrations/233-document-conversations.ts +54 -0
  595. package/src/memory/migrations/234-memory-v2-activation-logs.ts +55 -0
  596. package/src/memory/migrations/235-llm-usage-attribution.ts +31 -0
  597. package/src/memory/migrations/235-slack-compaction-watermark.ts +44 -0
  598. package/src/memory/migrations/236-tool-invocations-matched-rule-id.ts +26 -0
  599. package/src/memory/migrations/237-heartbeat-runs.ts +45 -0
  600. package/src/memory/migrations/238-schedule-retry-policy.ts +20 -0
  601. package/src/memory/migrations/__tests__/234-memory-v2-activation-logs.test.ts +182 -0
  602. package/src/memory/migrations/index.ts +19 -0
  603. package/src/memory/migrations/registry.ts +32 -0
  604. package/src/memory/pkb/pkb-search.ts +7 -0
  605. package/src/memory/qdrant-client.ts +50 -20
  606. package/src/memory/raw-query.ts +2 -68
  607. package/src/memory/schema/conversations.ts +7 -0
  608. package/src/memory/schema/infrastructure.ts +40 -0
  609. package/src/memory/search/semantic.ts +12 -16
  610. package/src/memory/sparse-tokenize.ts +49 -0
  611. package/src/memory/tool-usage-store.ts +2 -0
  612. package/src/memory/usage-buckets.ts +40 -1
  613. package/src/memory/usage-grouped-buckets.ts +127 -0
  614. package/src/memory/v2/__tests__/activation.test.ts +361 -180
  615. package/src/memory/v2/__tests__/backfill-jobs.test.ts +2 -129
  616. package/src/memory/v2/__tests__/consolidation-job.test.ts +28 -11
  617. package/src/memory/v2/__tests__/edge-index.test.ts +278 -0
  618. package/src/memory/v2/__tests__/injection.test.ts +424 -33
  619. package/src/memory/v2/__tests__/migration.test.ts +64 -36
  620. package/src/memory/v2/__tests__/page-store.test.ts +191 -8
  621. package/src/memory/v2/__tests__/prompts-consolidation.test.ts +181 -0
  622. package/src/memory/v2/__tests__/sim.test.ts +166 -6
  623. package/src/memory/v2/__tests__/skill-store.test.ts +115 -3
  624. package/src/memory/v2/__tests__/sparse-bm25.test.ts +292 -0
  625. package/src/memory/v2/__tests__/static-context.test.ts +152 -0
  626. package/src/memory/v2/activation.ts +215 -163
  627. package/src/memory/v2/backfill-jobs.ts +15 -100
  628. package/src/memory/v2/consolidation-job.ts +17 -17
  629. package/src/memory/v2/constants.ts +7 -0
  630. package/src/memory/v2/edge-index.ts +191 -0
  631. package/src/memory/v2/injection.ts +241 -84
  632. package/src/memory/v2/migration.ts +57 -64
  633. package/src/memory/v2/now-text.ts +2 -3
  634. package/src/memory/v2/page-store.ts +168 -31
  635. package/src/memory/v2/prompts/consolidation.ts +385 -88
  636. package/src/memory/v2/prompts/sweep.ts +3 -3
  637. package/src/memory/v2/qdrant.ts +99 -1
  638. package/src/memory/v2/sim.ts +126 -16
  639. package/src/memory/v2/skill-qdrant.ts +12 -3
  640. package/src/memory/v2/skill-store.ts +71 -8
  641. package/src/memory/v2/sparse-bm25.ts +245 -0
  642. package/src/memory/v2/static-context.ts +63 -0
  643. package/src/memory/v2/types.ts +10 -20
  644. package/src/memory/validation.ts +0 -11
  645. package/src/messaging/draft-store.ts +0 -6
  646. package/src/messaging/provider-types.ts +8 -0
  647. package/src/messaging/provider.ts +7 -0
  648. package/src/messaging/providers/gmail/client.ts +1 -121
  649. package/src/messaging/providers/gmail/types.ts +0 -49
  650. package/src/messaging/providers/outlook/client.ts +0 -73
  651. package/src/messaging/providers/slack/__tests__/adapter-mention-rendering.test.ts +226 -0
  652. package/src/messaging/providers/slack/adapter.ts +123 -52
  653. package/src/messaging/providers/slack/backfill.test.ts +95 -6
  654. package/src/messaging/providers/slack/backfill.ts +89 -11
  655. package/src/messaging/providers/slack/client.ts +10 -124
  656. package/src/messaging/providers/slack/message-metadata.ts +12 -2
  657. package/src/messaging/providers/slack/render-transcript.test.ts +56 -0
  658. package/src/messaging/providers/slack/render-transcript.ts +126 -25
  659. package/src/messaging/providers/slack/types.ts +1 -32
  660. package/src/notifications/README.md +10 -10
  661. package/src/notifications/broadcaster.ts +1 -1
  662. package/src/notifications/guardian-question-mode.ts +5 -5
  663. package/src/oauth/connect-orchestrator.ts +4 -0
  664. package/src/oauth/connection-resolver.test.ts +8 -0
  665. package/src/oauth/connection-resolver.ts +8 -16
  666. package/src/oauth/credential-token-resolver.ts +95 -0
  667. package/src/oauth/manual-token-connection.ts +26 -34
  668. package/src/oauth/oauth-store.ts +6 -4
  669. package/src/outbound-proxy/certs.ts +0 -7
  670. package/src/outbound-proxy/index.ts +1 -59
  671. package/src/outbound-proxy/logging.ts +1 -1
  672. package/src/outbound-proxy/policy.ts +6 -5
  673. package/src/outbound-proxy/router.ts +2 -1
  674. package/src/permissions/approval-policy.test.ts +6 -275
  675. package/src/permissions/approval-policy.ts +0 -51
  676. package/src/permissions/approval-provenance.test.ts +184 -0
  677. package/src/permissions/approval-provenance.ts +70 -0
  678. package/src/permissions/checker.test.ts +0 -1
  679. package/src/permissions/checker.ts +7 -18
  680. package/src/permissions/gateway-threshold-reader.ts +6 -1
  681. package/src/permissions/prompter.ts +43 -3
  682. package/src/permissions/secret-prompter.ts +25 -48
  683. package/src/permissions/types.ts +33 -0
  684. package/src/permissions/workspace-policy.ts +0 -5
  685. package/src/platform/sync-identity.ts +0 -8
  686. package/src/plugins/defaults/injectors.ts +69 -2
  687. package/src/plugins/defaults/overflow-reduce.ts +3 -2
  688. package/src/plugins/types.ts +8 -0
  689. package/src/prompts/bootstrap-cleanup.ts +27 -0
  690. package/src/prompts/system-prompt.ts +37 -88
  691. package/src/prompts/templates/BOOTSTRAP.md +52 -6
  692. package/src/prompts/templates/SOUL.md +13 -1
  693. package/src/prompts/update-bulletin-job.ts +2 -0
  694. package/src/providers/__tests__/retry-callsite.test.ts +138 -1
  695. package/src/providers/anthropic/client.ts +72 -33
  696. package/src/providers/call-site-routing.ts +42 -3
  697. package/src/providers/gemini/client.ts +18 -2
  698. package/src/providers/managed-proxy/context.ts +0 -5
  699. package/src/providers/model-catalog.ts +105 -19
  700. package/src/providers/openai/chat-completions-provider.ts +6 -0
  701. package/src/providers/openai/responses-provider.ts +7 -1
  702. package/src/providers/provider-send-message.ts +45 -2
  703. package/src/providers/ratelimit.ts +7 -2
  704. package/src/providers/registry.ts +14 -9
  705. package/src/providers/retry.ts +96 -8
  706. package/src/providers/speech-to-text/provider-catalog.ts +7 -8
  707. package/src/providers/types.ts +13 -0
  708. package/src/providers/usage-tracking.ts +96 -0
  709. package/src/runtime/AGENTS.md +10 -6
  710. package/src/runtime/__tests__/agent-wake.test.ts +89 -0
  711. package/src/runtime/agent-wake.ts +39 -2
  712. package/src/runtime/assistant-event-hub.ts +570 -52
  713. package/src/runtime/assistant-event.ts +2 -6
  714. package/src/runtime/auth/__tests__/middleware.test.ts +11 -56
  715. package/src/runtime/auth/context.ts +0 -9
  716. package/src/runtime/auth/middleware.ts +1 -97
  717. package/src/runtime/auth/route-policy.ts +30 -9
  718. package/src/runtime/auth/token-service.ts +0 -11
  719. package/src/runtime/btw-sidechain.ts +2 -3
  720. package/src/runtime/channel-approvals.ts +6 -2
  721. package/src/runtime/channel-invite-transport.ts +2 -48
  722. package/src/runtime/channel-invite-transports/email.ts +1 -1
  723. package/src/runtime/channel-invite-transports/slack.ts +1 -1
  724. package/src/runtime/channel-invite-transports/telegram.ts +1 -1
  725. package/src/runtime/channel-invite-transports/voice.ts +1 -1
  726. package/src/runtime/channel-invite-transports/whatsapp.ts +1 -1
  727. package/src/runtime/channel-invite-types.ts +54 -0
  728. package/src/runtime/channel-readiness-service.ts +32 -13
  729. package/src/runtime/channel-verification-service.ts +3 -5
  730. package/src/runtime/http-errors.ts +0 -34
  731. package/src/runtime/http-router.ts +6 -3
  732. package/src/runtime/http-server.ts +16 -402
  733. package/src/runtime/http-types.ts +5 -5
  734. package/src/runtime/interactive-ui.ts +0 -1
  735. package/src/runtime/middleware/auth.ts +0 -20
  736. package/src/runtime/migrations/__tests__/v1-test-helpers.ts +112 -0
  737. package/src/runtime/migrations/__tests__/vbundle-builder-credentials.test.ts +11 -4
  738. package/src/runtime/migrations/__tests__/vbundle-builder-v1-shape.test.ts +253 -0
  739. package/src/runtime/migrations/__tests__/vbundle-import-credentials.test.ts +19 -6
  740. package/src/runtime/migrations/__tests__/vbundle-import-parity.test.ts +413 -0
  741. package/src/runtime/migrations/__tests__/vbundle-import-policy.test.ts +260 -0
  742. package/src/runtime/migrations/__tests__/vbundle-import-version-compat.test.ts +189 -0
  743. package/src/runtime/migrations/__tests__/vbundle-legacy-user-md.test.ts +71 -27
  744. package/src/runtime/migrations/__tests__/vbundle-metadata-merge-integration.test.ts +41 -2
  745. package/src/runtime/migrations/__tests__/vbundle-streaming-importer.test.ts +296 -80
  746. package/src/runtime/migrations/__tests__/vbundle-streaming-validator.test.ts +143 -23
  747. package/src/runtime/migrations/__tests__/vbundle-symlink-importer.test.ts +451 -0
  748. package/src/runtime/migrations/__tests__/vbundle-symlink-streaming-importer.test.ts +0 -0
  749. package/src/runtime/migrations/__tests__/vbundle-symlink-streaming.test.ts +515 -0
  750. package/src/runtime/migrations/__tests__/vbundle-symlink-tar.test.ts +437 -0
  751. package/src/runtime/migrations/__tests__/vbundle-symlink-walker.test.ts +319 -0
  752. package/src/runtime/migrations/__tests__/vbundle-tar-stream.test.ts +2 -2
  753. package/src/runtime/migrations/__tests__/vbundle-validator-v1-schema.test.ts +421 -0
  754. package/src/runtime/migrations/migration-transport.ts +49 -16
  755. package/src/runtime/migrations/migration-wizard.ts +2 -2
  756. package/src/runtime/migrations/origin-mode.ts +40 -0
  757. package/src/runtime/migrations/vbundle-builder.ts +457 -136
  758. package/src/runtime/migrations/vbundle-import-analyzer.ts +13 -11
  759. package/src/runtime/migrations/vbundle-import-policy.ts +172 -0
  760. package/src/runtime/migrations/vbundle-importer.ts +251 -74
  761. package/src/runtime/migrations/vbundle-metadata-merge.ts +1 -1
  762. package/src/runtime/migrations/vbundle-streaming-importer.ts +329 -38
  763. package/src/runtime/migrations/vbundle-streaming-validator.ts +203 -28
  764. package/src/runtime/migrations/vbundle-tar-stream.ts +15 -6
  765. package/src/runtime/migrations/vbundle-validator.ts +328 -41
  766. package/src/runtime/pending-interactions.ts +48 -13
  767. package/src/runtime/routes/__tests__/acp-routes.test.ts +0 -1
  768. package/src/runtime/routes/__tests__/backup-routes.test.ts +49 -168
  769. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +333 -0
  770. package/src/runtime/routes/__tests__/gateway-log-routes.test.ts +242 -0
  771. package/src/runtime/routes/__tests__/heartbeat-routes.test.ts +112 -0
  772. package/src/runtime/routes/__tests__/llm-call-sites-routes.test.ts +58 -0
  773. package/src/runtime/routes/__tests__/migration-export-secrets-redacted.test.ts +54 -0
  774. package/src/runtime/routes/__tests__/migration-import-credential-filter.test.ts +19 -6
  775. package/src/runtime/routes/__tests__/user-route-dispatcher.test.ts +7 -7
  776. package/src/runtime/routes/acp-routes.test.ts +0 -3
  777. package/src/runtime/routes/acp-routes.ts +3 -7
  778. package/src/runtime/routes/app-management-routes.ts +18 -9
  779. package/src/runtime/routes/approval-interception-types.ts +13 -0
  780. package/src/runtime/routes/approval-routes.ts +55 -14
  781. package/src/runtime/routes/approval-strategies/guardian-text-engine-strategy.ts +1 -1
  782. package/src/runtime/routes/avatar-routes.ts +3 -5
  783. package/src/runtime/routes/backup-routes.ts +15 -38
  784. package/src/runtime/routes/browser-routes.ts +1 -15
  785. package/src/runtime/routes/btw-routes.ts +14 -37
  786. package/src/runtime/routes/channel-guardian-routes.ts +1 -5
  787. package/src/runtime/routes/channel-readiness-routes.ts +3 -7
  788. package/src/runtime/routes/channel-route-shared.ts +2 -28
  789. package/src/runtime/routes/client-routes.ts +46 -12
  790. package/src/runtime/routes/consolidation-routes.ts +115 -0
  791. package/src/runtime/routes/contact-prompt-routes.ts +183 -0
  792. package/src/runtime/routes/conversation-list-routes.ts +12 -29
  793. package/src/runtime/routes/conversation-management-routes.ts +14 -51
  794. package/src/runtime/routes/conversation-query-routes.ts +156 -9
  795. package/src/runtime/routes/conversation-routes.ts +72 -539
  796. package/src/runtime/routes/conversation-starter-routes.ts +19 -40
  797. package/src/runtime/routes/document-pdf-renderer.ts +165 -0
  798. package/src/runtime/routes/documents-routes.ts +83 -18
  799. package/src/runtime/routes/errors.ts +19 -4
  800. package/src/runtime/routes/events-routes.ts +68 -94
  801. package/src/runtime/routes/filing-routes.ts +18 -1
  802. package/src/runtime/routes/gateway-log-routes.ts +79 -0
  803. package/src/runtime/routes/guardian-action-routes.ts +4 -9
  804. package/src/runtime/routes/guardian-approval-interception.ts +2 -8
  805. package/src/runtime/routes/heartbeat-routes.ts +103 -38
  806. package/src/runtime/routes/host-app-control-routes.ts +134 -0
  807. package/src/runtime/routes/host-bash-routes.ts +37 -6
  808. package/src/runtime/routes/host-browser-routes.ts +96 -25
  809. package/src/runtime/routes/host-cu-routes.ts +48 -13
  810. package/src/runtime/routes/host-file-routes.ts +35 -11
  811. package/src/runtime/routes/host-transfer-routes.ts +73 -37
  812. package/src/runtime/routes/http-adapter.ts +1 -0
  813. package/src/runtime/routes/identity-intro-cache.ts +30 -0
  814. package/src/runtime/routes/identity-routes.ts +93 -49
  815. package/src/runtime/routes/inbound-message-handler.ts +581 -146
  816. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +2 -95
  817. package/src/runtime/routes/inbound-stages/background-dispatch.ts +3 -0
  818. package/src/runtime/routes/inbound-stages/edit-intercept.ts +0 -8
  819. package/src/runtime/routes/inbound-stages/transcribe-audio.test.ts +0 -20
  820. package/src/runtime/routes/inbound-stages/transcribe-audio.ts +5 -13
  821. package/src/runtime/routes/index.ts +12 -0
  822. package/src/runtime/routes/integrations/slack/channel.ts +0 -24
  823. package/src/runtime/routes/llm-call-sites-routes.ts +22 -0
  824. package/src/runtime/routes/mcp-auth-routes.ts +132 -0
  825. package/src/runtime/routes/memory-item-routes.ts +10 -12
  826. package/src/runtime/routes/memory-v2-routes.ts +451 -16
  827. package/src/runtime/routes/migration-routes.ts +284 -31
  828. package/src/runtime/routes/playground/guard.ts +1 -1
  829. package/src/runtime/routes/playground/index.ts +0 -2
  830. package/src/runtime/routes/recording-routes.ts +4 -24
  831. package/src/runtime/routes/rename-conversation-routes.ts +2 -6
  832. package/src/runtime/routes/schedule-routes.ts +10 -6
  833. package/src/runtime/routes/secret-routes.ts +87 -18
  834. package/src/runtime/routes/settings-routes.ts +29 -28
  835. package/src/runtime/routes/skills-routes.ts +12 -31
  836. package/src/runtime/routes/suggest-trust-rule-routes.ts +32 -1
  837. package/src/runtime/routes/task-routes.ts +6 -6
  838. package/src/runtime/routes/trust-rules-routes.ts +3 -94
  839. package/src/runtime/routes/types.ts +4 -4
  840. package/src/runtime/routes/upgrade-broadcast-routes.ts +3 -10
  841. package/src/runtime/routes/usage-routes.ts +87 -10
  842. package/src/runtime/routes/user-routes.ts +17 -31
  843. package/src/runtime/routes/work-items-routes.ts +1 -4
  844. package/src/runtime/services/__tests__/analyze-conversation.test.ts +2 -2
  845. package/src/runtime/services/analyze-conversation.ts +7 -17
  846. package/src/runtime/services/conversation-serializer.ts +2 -4
  847. package/src/runtime/verification-outbound-actions.ts +1 -1
  848. package/src/runtime/verification-rate-limiter.ts +1 -1
  849. package/src/runtime/verification-templates.ts +4 -7
  850. package/src/schedule/integration-status.ts +66 -2
  851. package/src/schedule/recurrence-engine.ts +4 -1
  852. package/src/schedule/retry-backoff.ts +18 -0
  853. package/src/schedule/retry-policy.ts +82 -0
  854. package/src/schedule/schedule-recovery.ts +64 -0
  855. package/src/schedule/schedule-store.ts +106 -18
  856. package/src/schedule/scheduler-types.ts +25 -0
  857. package/src/schedule/scheduler.ts +63 -38
  858. package/src/security/oauth-callback-registry.ts +8 -0
  859. package/src/security/secret-scanner.ts +14 -547
  860. package/src/security/secure-keys.ts +31 -11
  861. package/src/security/token-manager.ts +7 -3
  862. package/src/sequence/analytics.ts +5 -5
  863. package/src/sequence/engine.ts +1 -1
  864. package/src/signals/cancel.ts +16 -25
  865. package/src/signals/conversation-undo.ts +2 -27
  866. package/src/signals/emit-event.ts +1 -2
  867. package/src/signals/user-message.ts +108 -22
  868. package/src/skills/catalog-files.ts +2 -8
  869. package/src/skills/catalog-install.ts +1 -0
  870. package/src/skills/clawhub.ts +2 -2
  871. package/src/skills/include-graph.ts +5 -5
  872. package/src/skills/inline-command-runner.ts +1 -7
  873. package/src/skills/remote-skill-policy.ts +5 -5
  874. package/src/skills/skill-file-provider.ts +1 -1
  875. package/src/skills/skill-file-types.ts +13 -0
  876. package/src/skills/skillssh-audit-types.ts +28 -0
  877. package/src/skills/skillssh-registry.ts +8 -21
  878. package/src/subagent/manager.ts +67 -84
  879. package/src/tasks/task-store.ts +1 -28
  880. package/src/telemetry/types.ts +8 -0
  881. package/src/telemetry/usage-telemetry-reporter.test.ts +59 -15
  882. package/src/telemetry/usage-telemetry-reporter.ts +4 -5
  883. package/src/tools/acp/spawn.test.ts +1 -2
  884. package/src/tools/acp/steer.test.ts +1 -2
  885. package/src/tools/app-control/skill-proxy-bridge.ts +28 -0
  886. package/src/tools/apps/executors.ts +56 -69
  887. package/src/tools/browser/__tests__/browser-status.test.ts +55 -135
  888. package/src/tools/browser/browser-execution.ts +31 -147
  889. package/src/tools/browser/cdp-client/__tests__/factory.test.ts +145 -70
  890. package/src/tools/browser/cdp-client/cdp-inspect/__tests__/ws-transport.test.ts +12 -6
  891. package/src/tools/browser/cdp-client/factory.ts +62 -91
  892. package/src/tools/browser/cdp-client/index.ts +1 -27
  893. package/src/tools/computer-use/definitions.ts +42 -20
  894. package/src/tools/executor.ts +46 -31
  895. package/src/tools/host-filesystem/edit.ts +29 -2
  896. package/src/tools/host-filesystem/read.ts +29 -2
  897. package/src/tools/host-filesystem/transfer.test.ts +45 -42
  898. package/src/tools/host-filesystem/transfer.ts +35 -4
  899. package/src/tools/host-filesystem/write.ts +29 -2
  900. package/src/tools/host-terminal/host-shell.ts +62 -3
  901. package/src/tools/network/script-proxy/index.ts +1 -10
  902. package/src/tools/permission-checker.ts +66 -1
  903. package/src/tools/schedule/create.ts +6 -0
  904. package/src/tools/schedule/list.ts +2 -0
  905. package/src/tools/schedule/update.ts +10 -0
  906. package/src/tools/shared/filesystem/file-ops-service.ts +2 -0
  907. package/src/tools/shared/filesystem/path-policy.ts +25 -1
  908. package/src/tools/skills/load.ts +0 -32
  909. package/src/tools/skills/sandbox-runner.ts +1 -6
  910. package/src/tools/skills/skill-tool-factory.ts +32 -0
  911. package/src/tools/terminal/safe-env.ts +1 -0
  912. package/src/tools/terminal/shell.ts +2 -78
  913. package/src/tools/tool-approval-handler.ts +1 -5
  914. package/src/tools/types.ts +16 -39
  915. package/src/tts/__tests__/provider-catalog.test.ts +2 -2
  916. package/src/tts/provider-catalog.ts +1 -1
  917. package/src/usage/actors.ts +2 -1
  918. package/src/usage/attribution.ts +185 -0
  919. package/src/usage/pricing.ts +166 -0
  920. package/src/usage/types.ts +14 -0
  921. package/src/util/json.ts +13 -0
  922. package/src/util/logger.ts +3 -3
  923. package/src/util/pricing.ts +50 -3
  924. package/src/work-items/work-item-runner.ts +15 -42
  925. package/src/workspace/hatched-date.ts +86 -0
  926. package/src/workspace/migrations/003-seed-device-id.ts +1 -1
  927. package/src/workspace/migrations/006-services-config.ts +8 -5
  928. package/src/workspace/migrations/016-extract-feature-flags-to-protected.ts +3 -9
  929. package/src/workspace/migrations/021-move-signals-to-workspace.ts +4 -10
  930. package/src/workspace/migrations/022-move-hooks-to-workspace.ts +4 -10
  931. package/src/workspace/migrations/023-move-config-files-to-workspace.ts +4 -11
  932. package/src/workspace/migrations/024-move-runtime-files-to-workspace.ts +3 -10
  933. package/src/workspace/migrations/040-seed-latency-callsite-defaults.ts +3 -2
  934. package/src/workspace/migrations/050-seed-main-agent-opus-callsite.ts +6 -4
  935. package/src/workspace/migrations/052-seed-default-inference-profiles.ts +3 -3
  936. package/src/workspace/migrations/059-move-pid-to-workspace.ts +3 -8
  937. package/src/workspace/migrations/060-memory-v2-init.ts +2 -18
  938. package/src/workspace/migrations/061-move-backup-key-to-workspace.ts +54 -0
  939. package/src/workspace/migrations/062-drop-memory-v2-edges-json.ts +27 -0
  940. package/src/workspace/migrations/063-release-notes-dynamic-model-context.ts +70 -0
  941. package/src/workspace/migrations/064-unwind-main-agent-opus-seed.ts +64 -0
  942. package/src/workspace/migrations/AGENTS.md +1 -1
  943. package/src/workspace/migrations/migrate-to-workspace-volume.ts +4 -10
  944. package/src/workspace/migrations/registry.ts +8 -0
  945. package/src/workspace/migrations/utils.ts +21 -0
  946. package/src/workspace/provider-commit-message-generator.ts +3 -3
  947. package/src/__tests__/host-browser-e2e-cloud.test.ts +0 -904
  948. package/src/__tests__/host-browser-e2e-self-hosted-capability.test.ts +0 -296
  949. package/src/__tests__/host-browser-ws-events-e2e.test.ts +0 -431
  950. package/src/__tests__/sandbox-diagnostics.test.ts +0 -138
  951. package/src/__tests__/sandbox-host-parity.test.ts +0 -1024
  952. package/src/__tests__/secret-detection-handler.test.ts +0 -67
  953. package/src/__tests__/secret-scanner-executor.test.ts +0 -450
  954. package/src/__tests__/tcc-sandbox-deny.test.ts +0 -198
  955. package/src/__tests__/terminal-sandbox.test.ts +0 -374
  956. package/src/__tests__/tool-notification-listener.test.ts +0 -65
  957. package/src/__tests__/twilio-rest.test.ts +0 -34
  958. package/src/backup/__tests__/backup-key.test.ts +0 -152
  959. package/src/backup/__tests__/backup-worker.test.ts +0 -754
  960. package/src/backup/__tests__/offsite-writer.test.ts +0 -641
  961. package/src/backup/__tests__/stream-crypt.test.ts +0 -228
  962. package/src/backup/backup-key.ts +0 -137
  963. package/src/backup/backup-worker.ts +0 -438
  964. package/src/backup/offsite-writer.ts +0 -222
  965. package/src/backup/stream-crypt.ts +0 -263
  966. package/src/context/__tests__/microcompact.test.ts +0 -805
  967. package/src/context/microcompact.ts +0 -443
  968. package/src/daemon/handlers/slack-channel-oauth-install.ts +0 -197
  969. package/src/daemon/message-types/pairing.ts +0 -58
  970. package/src/events/tool-notification-listener.ts +0 -17
  971. package/src/ipc/routes/__tests__/memory-v2-validate.test.ts +0 -219
  972. package/src/memory/v2/__tests__/edges.test.ts +0 -435
  973. package/src/memory/v2/edges.ts +0 -217
  974. package/src/outbound-proxy/config.ts +0 -94
  975. package/src/outbound-proxy/health.ts +0 -62
  976. package/src/outbound-proxy/types.ts +0 -150
  977. package/src/prompts/__tests__/system-prompt-memory-v2.test.ts +0 -197
  978. package/src/runtime/__tests__/chrome-extension-registry.test.ts +0 -518
  979. package/src/runtime/__tests__/client-registry.test.ts +0 -271
  980. package/src/runtime/capability-tokens.ts +0 -190
  981. package/src/runtime/chrome-extension-registry.ts +0 -368
  982. package/src/runtime/client-registry.ts +0 -254
  983. package/src/runtime/routes/inbound-stages/verification-intercept.ts +0 -329
  984. package/src/signals/mcp-reload.ts +0 -18
  985. package/src/tools/secret-detection-handler.ts +0 -269
  986. package/src/tools/terminal/backends/native.ts +0 -327
  987. package/src/tools/terminal/backends/types.ts +0 -37
  988. package/src/tools/terminal/sandbox-diagnostics.ts +0 -87
  989. package/src/tools/terminal/sandbox.ts +0 -40
@@ -1,904 +0,0 @@
1
- /**
2
- * E2E smoke test for the cloud-hosted `host_browser_request` round-trip.
3
- *
4
- * Boots the runtime HTTP server in-process, opens a mock chrome-extension
5
- * WebSocket against `/v1/browser-relay`, and drives
6
- * `HostBrowserProxy.request()` end-to-end:
7
- *
8
- * proxy.request()
9
- * → sendToClient (routed via ChromeExtensionRegistry by guardianId)
10
- * → mock extension WebSocket receives host_browser_request
11
- * → mock CDP handler (Browser.getVersion fake)
12
- * → POST /v1/host-browser-result
13
- * → handleHostBrowserResult → conversation.resolveHostBrowser
14
- * → proxy.resolve() → request() resolves
15
- *
16
- * Covers:
17
- * - Happy path: Browser.getVersion round-trips and returns the fake
18
- * product string.
19
- * - Abort: an aborted AbortSignal resolves with "Aborted" and the mock
20
- * extension receives a host_browser_cancel frame.
21
- * - Timeout: if the mock extension receives the frame but never
22
- * POSTs a result, the proxy's setTimeout path fires and surfaces
23
- * a "timed out waiting for client response" error.
24
- *
25
- * The test runs entirely in Bun + loopback WebSocket/fetch — no real
26
- * Chrome required.
27
- */
28
- import { afterEach, beforeEach, describe, expect, mock, test } from "bun:test";
29
-
30
- // ── Module mocks (must be declared before the real imports below) ────
31
-
32
- mock.module("../util/logger.js", () => ({
33
- getLogger: () =>
34
- new Proxy({} as Record<string, unknown>, {
35
- get: () => () => {},
36
- }),
37
- }));
38
-
39
- mock.module("../config/loader.js", () => ({
40
- getConfig: () => ({
41
- ui: {},
42
- model: "test",
43
- provider: "test",
44
- memory: { enabled: false },
45
- rateLimit: { maxRequestsPerMinute: 0 },
46
- secretDetection: { enabled: false },
47
- contextWindow: { maxInputTokens: 200000 },
48
- services: {
49
- inference: {
50
- mode: "your-own",
51
- provider: "anthropic",
52
- model: "claude-opus-4-6",
53
- },
54
- "image-generation": {
55
- mode: "your-own",
56
- provider: "gemini",
57
- model: "gemini-3.1-flash-image-preview",
58
- },
59
- "web-search": { mode: "your-own", provider: "inference-provider-native" },
60
- },
61
- }),
62
- }));
63
-
64
- // ── Real imports (after mocks) ──────────────────────────────────────
65
-
66
- import type { Conversation } from "../daemon/conversation.js";
67
- import { HostBrowserProxy } from "../daemon/host-browser-proxy.js";
68
- import type { ServerMessage } from "../daemon/message-protocol.js";
69
- import { getDb } from "../memory/db-connection.js";
70
- import { initializeDb } from "../memory/db-init.js";
71
- import { mintToken } from "../runtime/auth/token-service.js";
72
- import {
73
- __resetChromeExtensionRegistryForTests,
74
- getChromeExtensionRegistry,
75
- } from "../runtime/chrome-extension-registry.js";
76
- import { RuntimeHttpServer } from "../runtime/http-server.js";
77
- import * as pendingInteractions from "../runtime/pending-interactions.js";
78
-
79
- initializeDb();
80
-
81
- // ── Helpers ─────────────────────────────────────────────────────────
82
-
83
- /**
84
- * Wrap a HostBrowserProxy in a sendToClient that:
85
- * 1. Routes host_browser_request/host_browser_cancel via the Chrome
86
- * extension registry for the given guardianId.
87
- * 2. Registers a pending interaction for each request so the
88
- * `/v1/host-browser-result` HTTP route can find the stub
89
- * conversation and call `resolveHostBrowser` on it.
90
- *
91
- * Returns the proxy and its stub conversation. In production this
92
- * wiring lives in `conversation-routes.ts` `makeHubPublisher`; the test
93
- * reproduces the minimum surface needed for the round-trip.
94
- */
95
- function createBoundProxy(
96
- guardianId: string,
97
- conversationId: string,
98
- ): { proxy: HostBrowserProxy; conversation: Conversation } {
99
- // The stub Conversation's `resolveHostBrowser` routes straight back
100
- // to the real proxy. Declare the proxy reference first so the stub
101
- // can close over it before the proxy itself is constructed below.
102
- let proxyRef: HostBrowserProxy | null = null;
103
- const conversation = {
104
- resolveHostBrowser(
105
- requestId: string,
106
- response: { content: string; isError: boolean },
107
- ) {
108
- proxyRef?.resolve(requestId, response);
109
- },
110
- } as unknown as Conversation;
111
-
112
- const sendToClient = (msg: ServerMessage) => {
113
- // Register pending interactions for host_browser_request envelopes
114
- // so the /v1/host-browser-result route can look them up.
115
- if ((msg as { type: string }).type === "host_browser_request") {
116
- const requestId = (msg as { requestId: string }).requestId;
117
- pendingInteractions.register(requestId, {
118
- conversation,
119
- conversationId,
120
- kind: "host_browser",
121
- });
122
- }
123
- const ok = getChromeExtensionRegistry().send(guardianId, msg);
124
- if (!ok) {
125
- throw new Error(
126
- `chrome-extension host_browser send failed: no active connection for guardian ${guardianId}`,
127
- );
128
- }
129
- };
130
-
131
- const proxy = new HostBrowserProxy(sendToClient);
132
- proxyRef = proxy;
133
- return { proxy, conversation };
134
- }
135
-
136
- /**
137
- * Mint an actor-bound JWT for the given guardianId. The WebSocket
138
- * upgrade handler parses `sub=actor:<assistantId>:<actorPrincipalId>`
139
- * and treats `actorPrincipalId` as the guardianId.
140
- */
141
- function mintActorToken(guardianId: string): string {
142
- return mintToken({
143
- aud: "vellum-daemon",
144
- sub: `actor:self:${guardianId}`,
145
- scope_profile: "actor_client_v1",
146
- policy_epoch: 1,
147
- ttlSeconds: 3600,
148
- });
149
- }
150
-
151
- // ── Tests ───────────────────────────────────────────────────────────
152
-
153
- describe("host_browser cloud-hosted e2e round-trip", () => {
154
- let server: RuntimeHttpServer;
155
- let port: number;
156
- let runtimeBaseUrl: string;
157
-
158
- beforeEach(async () => {
159
- // Each test gets a clean DB and a fresh registry so connection
160
- // state doesn't leak between cases.
161
- const db = getDb();
162
- db.run("DELETE FROM contact_channels");
163
- db.run("DELETE FROM contacts");
164
- pendingInteractions.clear();
165
- __resetChromeExtensionRegistryForTests();
166
-
167
- port = 19800 + Math.floor(Math.random() * 200);
168
- runtimeBaseUrl = `http://127.0.0.1:${port}`;
169
- server = new RuntimeHttpServer({ port });
170
- await server.start();
171
- });
172
-
173
- afterEach(async () => {
174
- await server?.stop();
175
- pendingInteractions.clear();
176
- __resetChromeExtensionRegistryForTests();
177
- });
178
-
179
- test("happy path: Browser.getVersion round-trips through the mock extension", async () => {
180
- const guardianId = `test-guardian-${crypto.randomUUID()}`;
181
- const token = mintActorToken(guardianId);
182
-
183
- // Dynamic import keeps the module cache warm across tests but avoids
184
- // binding the fixture at file-load time (where the mocks might not
185
- // yet have applied for a freshly forked test worker).
186
- const { createMockChromeExtension } =
187
- await import("./fixtures/mock-chrome-extension.js");
188
- const mockExt = createMockChromeExtension({
189
- runtimeBaseUrl,
190
- token,
191
- });
192
- await mockExt.start();
193
- await mockExt.waitForConnection();
194
-
195
- // Give the open handler a tick to register the connection in the
196
- // ChromeExtensionRegistry (Bun's WebSocket open callback fires
197
- // asynchronously after the upgrade handler returns).
198
- await waitForRegistryEntry(guardianId);
199
-
200
- const { proxy } = createBoundProxy(guardianId, "conv-happy");
201
-
202
- const result = await proxy.request(
203
- { cdpMethod: "Browser.getVersion" },
204
- "conv-happy",
205
- );
206
-
207
- expect(result.isError).toBe(false);
208
- expect(result.content).toContain("Chrome/MockTest");
209
-
210
- const received = mockExt.receivedRequests();
211
- expect(received).toHaveLength(1);
212
- expect(received[0].cdpMethod).toBe("Browser.getVersion");
213
- expect(typeof received[0].requestId).toBe("string");
214
- expect(received[0].conversationId).toBe("conv-happy");
215
-
216
- proxy.dispose();
217
- await mockExt.stop();
218
- });
219
-
220
- test("happy path (WS result transport): Browser.getVersion round-trips when the extension returns the result over the same WS", async () => {
221
- const guardianId = `test-guardian-${crypto.randomUUID()}`;
222
- const token = mintActorToken(guardianId);
223
-
224
- const { createMockChromeExtension } =
225
- await import("./fixtures/mock-chrome-extension.js");
226
- // Same fixture as the HTTP happy path, but configured to return
227
- // results over the /v1/browser-relay WebSocket instead of POSTing
228
- // /v1/host-browser-result. This exercises the runtime WS
229
- // `message` handler's host_browser_result dispatch path.
230
- const mockExt = createMockChromeExtension({
231
- runtimeBaseUrl,
232
- token,
233
- resultTransport: "ws",
234
- });
235
- await mockExt.start();
236
- await mockExt.waitForConnection();
237
- await waitForRegistryEntry(guardianId);
238
-
239
- const { proxy } = createBoundProxy(guardianId, "conv-happy-ws");
240
-
241
- const result = await proxy.request(
242
- { cdpMethod: "Browser.getVersion" },
243
- "conv-happy-ws",
244
- );
245
-
246
- expect(result.isError).toBe(false);
247
- expect(result.content).toContain("Chrome/MockTest");
248
-
249
- const received = mockExt.receivedRequests();
250
- expect(received).toHaveLength(1);
251
- expect(received[0].cdpMethod).toBe("Browser.getVersion");
252
- expect(received[0].conversationId).toBe("conv-happy-ws");
253
-
254
- // The pending interaction must be fully consumed — if the WS
255
- // handler silently no-op'd, the entry would still be registered
256
- // after the proxy resolves.
257
- expect(pendingInteractions.get(received[0].requestId)).toBeUndefined();
258
-
259
- proxy.dispose();
260
- await mockExt.stop();
261
- });
262
-
263
- test("abort: AbortSignal resolves to 'Aborted' and extension receives host_browser_cancel", async () => {
264
- const guardianId = `test-guardian-${crypto.randomUUID()}`;
265
- const token = mintActorToken(guardianId);
266
-
267
- const { createMockChromeExtension } =
268
- await import("./fixtures/mock-chrome-extension.js");
269
- const mockExt = createMockChromeExtension({
270
- runtimeBaseUrl,
271
- token,
272
- // Hang forever so we can abort mid-flight without a race against
273
- // the default handler's immediate response.
274
- cdpHandler: () => new Promise(() => {}),
275
- });
276
- await mockExt.start();
277
- await mockExt.waitForConnection();
278
- await waitForRegistryEntry(guardianId);
279
-
280
- const { proxy } = createBoundProxy(guardianId, "conv-abort");
281
-
282
- const controller = new AbortController();
283
- const resultPromise = proxy.request(
284
- { cdpMethod: "Browser.getVersion" },
285
- "conv-abort",
286
- controller.signal,
287
- );
288
-
289
- // Wait for the mock extension to observe the request, then abort so
290
- // the cancel envelope has somewhere to land.
291
- await waitFor(() => mockExt.receivedRequests().length === 1);
292
-
293
- controller.abort();
294
- const result = await resultPromise;
295
-
296
- expect(result.content).toBe("Aborted");
297
- expect(result.isError).toBe(true);
298
-
299
- // The cancel frame is dispatched synchronously from the abort
300
- // listener, but the WebSocket delivers it asynchronously — give it a
301
- // few turns to arrive before asserting.
302
- await waitFor(() => mockExt.receivedCancels().length === 1);
303
- const cancels = mockExt.receivedCancels();
304
- expect(cancels).toHaveLength(1);
305
- expect(cancels[0].requestId).toBe(mockExt.receivedRequests()[0].requestId);
306
-
307
- proxy.dispose();
308
- await mockExt.stop();
309
- });
310
-
311
- test("abort: late /v1/host-browser-result POST after cancel is ignored (no ghost completion)", async () => {
312
- // The daemon-side proxy must treat a late result POST — arriving
313
- // after the caller has already been resolved with "Aborted" —
314
- // as a benign race, not a noisy false-positive timeout. It must
315
- // also NOT resolve the caller a second time.
316
- //
317
- // We exercise this from the daemon's perspective by:
318
- // 1. Starting a request with an AbortSignal.
319
- // 2. Aborting the signal so the proxy resolves with "Aborted".
320
- // 3. Manually POSTing a host_browser_result for the same
321
- // requestId straight to /v1/host-browser-result (bypassing
322
- // the compliant dispatcher's cancel-suppression).
323
- // 4. Verifying the POST is accepted by the runtime (i.e. the
324
- // HTTP layer doesn't explode) and the caller's promise
325
- // never fulfils twice.
326
- const guardianId = `test-guardian-${crypto.randomUUID()}`;
327
- const token = mintActorToken(guardianId);
328
-
329
- const { createMockChromeExtension } =
330
- await import("./fixtures/mock-chrome-extension.js");
331
- const mockExt = createMockChromeExtension({
332
- runtimeBaseUrl,
333
- token,
334
- // Hang forever — same gating trick as the plain abort test,
335
- // so we can cancel before the handler returns anything.
336
- cdpHandler: () => new Promise(() => {}),
337
- });
338
- await mockExt.start();
339
- await mockExt.waitForConnection();
340
- await waitForRegistryEntry(guardianId);
341
-
342
- const { proxy } = createBoundProxy(guardianId, "conv-abort-late");
343
-
344
- let resolveCount = 0;
345
- const controller = new AbortController();
346
- const resultPromise = proxy
347
- .request(
348
- { cdpMethod: "Browser.getVersion" },
349
- "conv-abort-late",
350
- controller.signal,
351
- )
352
- .then((r) => {
353
- resolveCount += 1;
354
- return r;
355
- });
356
-
357
- await waitFor(() => mockExt.receivedRequests().length === 1);
358
- const pendingRequestId = mockExt.receivedRequests()[0].requestId;
359
-
360
- controller.abort();
361
- const result = await resultPromise;
362
- expect(result.content).toBe("Aborted");
363
- expect(result.isError).toBe(true);
364
- expect(resolveCount).toBe(1);
365
-
366
- // Now manually submit a late result for the same requestId —
367
- // simulating a non-compliant client that failed to honour the
368
- // cancel envelope. The runtime must accept the POST without
369
- // error and the proxy must NOT resolve the caller a second time.
370
- const lateResp = await fetch(`${runtimeBaseUrl}/v1/host-browser-result`, {
371
- method: "POST",
372
- headers: {
373
- "Content-Type": "application/json",
374
- Authorization: `Bearer ${token}`,
375
- },
376
- body: JSON.stringify({
377
- requestId: pendingRequestId,
378
- content: JSON.stringify({ product: "Chrome/LateResult" }),
379
- isError: false,
380
- }),
381
- });
382
- await lateResp.body?.cancel();
383
-
384
- // Give the runtime a few turns to process the POST and hit its
385
- // "no pending request" debug branch. If the proxy resolved a
386
- // second time, `resolveCount` would be 2 here.
387
- await new Promise((r) => setTimeout(r, 20));
388
- expect(resolveCount).toBe(1);
389
-
390
- proxy.dispose();
391
- await mockExt.stop();
392
- });
393
-
394
- test("timeout: proxy.request resolves with timeout error when client never responds", async () => {
395
- const guardianId = `test-guardian-${crypto.randomUUID()}`;
396
- const token = mintActorToken(guardianId);
397
-
398
- const { createMockChromeExtension } =
399
- await import("./fixtures/mock-chrome-extension.js");
400
- // CDP handler that never resolves — the request frame reaches the
401
- // mock extension successfully, but no result is ever POSTed back.
402
- // This exercises the proxy's `setTimeout` path (as opposed to a
403
- // synchronous send failure, which is a separate code path).
404
- const mockExt = createMockChromeExtension({
405
- runtimeBaseUrl,
406
- token,
407
- cdpHandler: () => new Promise(() => {}),
408
- });
409
- await mockExt.start();
410
- await mockExt.waitForConnection();
411
- await waitForRegistryEntry(guardianId);
412
-
413
- const { proxy } = createBoundProxy(guardianId, "conv-timeout");
414
-
415
- // 50ms timeout — short enough to keep the test fast, long enough
416
- // for the request frame to make the WS round-trip to the mock
417
- // extension before the timer fires.
418
- const result = await proxy.request(
419
- { cdpMethod: "Browser.getVersion", timeout_seconds: 0.05 },
420
- "conv-timeout",
421
- );
422
-
423
- expect(result.isError).toBe(true);
424
- expect(result.content).toContain("timed out");
425
-
426
- // Sanity check: the frame actually reached the mock extension (so
427
- // we know we're exercising the proxy's timer, not a send failure).
428
- expect(mockExt.receivedRequests()).toHaveLength(1);
429
- expect(mockExt.receivedRequests()[0].cdpMethod).toBe("Browser.getVersion");
430
-
431
- proxy.dispose();
432
- await mockExt.stop();
433
- });
434
- });
435
-
436
- // ── macOS message ingress with connected extension ──────────────────
437
- //
438
- // Verifies the end-to-end path for macOS-originated turns when the user
439
- // has the chrome extension connected. On macOS, browser commands should
440
- // route through the registry-backed host browser flow (extension → user's
441
- // real Chrome session) rather than falling back to local Playwright.
442
- //
443
- // The macOS browser backend preference order is:
444
- //
445
- // macOS + extension connected → extension backend (registry-routed)
446
- // macOS + extension absent → cdp-inspect (desktop-auto) → local
447
- //
448
- // NOTE: These tests construct a HostBrowserProxy directly and call
449
- // proxy.request(), which validates the extension relay round-trip but
450
- // bypasses handleSendMessage / conversation-routes. Full ingress-path
451
- // coverage (interface propagation, resolveHostBrowserSender wiring, and
452
- // CDP factory candidate selection) is exercised by the route-level tests
453
- // in conversation-routes-disk-view.test.ts.
454
- //
455
- // If future refactors break the wiring between conversation-routes
456
- // (`resolveHostBrowserSender`) and the CDP factory's candidate list, those
457
- // route-level tests will fail.
458
-
459
- describe("macOS message ingress with connected extension", () => {
460
- let server: RuntimeHttpServer;
461
- let port: number;
462
- let runtimeBaseUrl: string;
463
-
464
- beforeEach(async () => {
465
- const db = getDb();
466
- db.run("DELETE FROM contact_channels");
467
- db.run("DELETE FROM contacts");
468
- pendingInteractions.clear();
469
- __resetChromeExtensionRegistryForTests();
470
-
471
- port = 20000 + Math.floor(Math.random() * 200);
472
- runtimeBaseUrl = `http://127.0.0.1:${port}`;
473
- server = new RuntimeHttpServer({ port });
474
- await server.start();
475
- });
476
-
477
- afterEach(async () => {
478
- await server?.stop();
479
- pendingInteractions.clear();
480
- __resetChromeExtensionRegistryForTests();
481
- });
482
-
483
- test("macOS turn routes Browser.getVersion through the registry-backed extension, not local Playwright", async () => {
484
- // Arrange: connect a mock extension for a given guardianId.
485
- const guardianId = `test-guardian-macos-${crypto.randomUUID()}`;
486
- const token = mintActorToken(guardianId);
487
-
488
- const { createMockChromeExtension } =
489
- await import("./fixtures/mock-chrome-extension.js");
490
- const mockExt = createMockChromeExtension({
491
- runtimeBaseUrl,
492
- token,
493
- });
494
- await mockExt.start();
495
- await mockExt.waitForConnection();
496
- await waitForRegistryEntry(guardianId);
497
-
498
- // Build a proxy bound to the guardian's extension connection, mimicking
499
- // the wiring that conversation-routes.ts performs for macOS turns when
500
- // the ChromeExtensionRegistry has an active entry for the guardian.
501
- const { proxy } = createBoundProxy(guardianId, "conv-macos-ext");
502
-
503
- // Act: issue a CDP command through the proxy (same as how browser tools
504
- // dispatch commands during a macOS turn with extension override).
505
- const result = await proxy.request(
506
- { cdpMethod: "Browser.getVersion" },
507
- "conv-macos-ext",
508
- );
509
-
510
- // Assert: the command reached the mock extension (not local Playwright)
511
- // and the round-trip completed successfully.
512
- expect(result.isError).toBe(false);
513
- expect(result.content).toContain("Chrome/MockTest");
514
-
515
- const received = mockExt.receivedRequests();
516
- expect(received).toHaveLength(1);
517
- expect(received[0].cdpMethod).toBe("Browser.getVersion");
518
- expect(received[0].conversationId).toBe("conv-macos-ext");
519
-
520
- proxy.dispose();
521
- await mockExt.stop();
522
- });
523
-
524
- test("macOS turn with extension disconnected mid-conversation does not hang (proxy detects unavailability)", async () => {
525
- // Arrange: connect a mock extension then forcibly disconnect it.
526
- const guardianId = `test-guardian-macos-disco-${crypto.randomUUID()}`;
527
- const token = mintActorToken(guardianId);
528
-
529
- const { createMockChromeExtension } =
530
- await import("./fixtures/mock-chrome-extension.js");
531
- const mockExt = createMockChromeExtension({
532
- runtimeBaseUrl,
533
- token,
534
- });
535
- await mockExt.start();
536
- await mockExt.waitForConnection();
537
- await waitForRegistryEntry(guardianId);
538
-
539
- // The proxy is bound while the extension is still connected.
540
- const { proxy } = createBoundProxy(guardianId, "conv-macos-disco");
541
-
542
- // Disconnect the extension before sending any commands.
543
- mockExt.forceDisconnect();
544
-
545
- // Wait for the registry to notice the close event.
546
- await waitFor(
547
- () => getChromeExtensionRegistry().get(guardianId) === undefined,
548
- );
549
-
550
- // Act: attempt a CDP command through the proxy. The registry send should
551
- // fail because the connection is gone, and the proxy's sendToClient
552
- // wrapper throws immediately.
553
- try {
554
- await proxy.request(
555
- { cdpMethod: "Browser.getVersion", timeout_seconds: 0.5 },
556
- "conv-macos-disco",
557
- );
558
- // If we reach here, the test should still verify the result indicates
559
- // an error rather than a successful extension round-trip.
560
- expect(true).toBe(false); // Should not reach here
561
- } catch {
562
- // Expected: the send failed because the extension is disconnected.
563
- // This confirms the macOS path detects disconnection rather than
564
- // silently routing to the wrong backend.
565
- }
566
-
567
- proxy.dispose();
568
- await mockExt.stop();
569
- });
570
- });
571
-
572
- // ── macOS SSE bridge ingress (no extension registry) ────────────────
573
- //
574
- // Exercises the cloud-hosted + desktop SSE bridge path for macOS turns
575
- // WITHOUT relying on the ChromeExtensionRegistry. This validates the
576
- // native macOS host-browser proxy path where `host_browser_request`
577
- // frames travel through `assistantEventHub` (SSE) rather than the
578
- // extension WebSocket.
579
- //
580
- // In production, this path is used when:
581
- // - The macOS desktop client is connected to the assistant via SSE
582
- // - The user does NOT have the Chrome extension installed
583
- // - The desktop client receives `host_browser_request` frames via SSE,
584
- // executes CDP commands against the local Chrome, and POSTs results
585
- // back to `/v1/host-browser-result`
586
- //
587
- // The test constructs a HostBrowserProxy wired to a mock SSE sender
588
- // (simulating the `onEvent` hub publisher) and a mock macOS client that
589
- // observes the sent frames and returns results via POST.
590
-
591
- describe("macOS SSE bridge ingress (no extension registry)", () => {
592
- let server: RuntimeHttpServer;
593
- let port: number;
594
- let runtimeBaseUrl: string;
595
-
596
- beforeEach(async () => {
597
- const db = getDb();
598
- db.run("DELETE FROM contact_channels");
599
- db.run("DELETE FROM contacts");
600
- pendingInteractions.clear();
601
- __resetChromeExtensionRegistryForTests();
602
-
603
- port = 20200 + Math.floor(Math.random() * 200);
604
- runtimeBaseUrl = `http://127.0.0.1:${port}`;
605
- server = new RuntimeHttpServer({ port });
606
- await server.start();
607
- });
608
-
609
- afterEach(async () => {
610
- await server?.stop();
611
- pendingInteractions.clear();
612
- __resetChromeExtensionRegistryForTests();
613
- });
614
-
615
- /**
616
- * Create a HostBrowserProxy wired to a mock SSE sender. The sender
617
- * captures `host_browser_request` frames and simulates what the macOS
618
- * desktop client does: execute the CDP command locally and POST the
619
- * result back to `/v1/host-browser-result`.
620
- *
621
- * Unlike `createBoundProxy` (which routes through the extension
622
- * registry), this helper routes through a direct function call —
623
- * simulating the `onEvent` SSE hub publisher path.
624
- */
625
- function createSseBoundProxy(
626
- conversationId: string,
627
- token: string,
628
- ): {
629
- proxy: HostBrowserProxy;
630
- conversation: Conversation;
631
- sentFrames: Array<{ type: string; [key: string]: unknown }>;
632
- } {
633
- let proxyRef: HostBrowserProxy | null = null;
634
- const conversation = {
635
- resolveHostBrowser(
636
- requestId: string,
637
- response: { content: string; isError: boolean },
638
- ) {
639
- proxyRef?.resolve(requestId, response);
640
- },
641
- } as unknown as Conversation;
642
-
643
- const sentFrames: Array<{ type: string; [key: string]: unknown }> = [];
644
-
645
- // The SSE sender simulates what `assistantEventHub.publish` does in
646
- // production: it delivers the message to the connected SSE client.
647
- // Here we capture the frame and immediately simulate the macOS client
648
- // handling it — executing a mock CDP command and POSTing the result
649
- // back to the runtime.
650
- const sseSender = (msg: ServerMessage) => {
651
- const frame = msg as { type: string; [key: string]: unknown };
652
- sentFrames.push(frame);
653
-
654
- if (frame.type === "host_browser_request") {
655
- const requestId = frame.requestId as string;
656
-
657
- // Register the pending interaction (in production this happens
658
- // in makeHubPublisher inside conversation-routes.ts).
659
- pendingInteractions.register(requestId, {
660
- conversation,
661
- conversationId,
662
- kind: "host_browser",
663
- });
664
-
665
- // Simulate the macOS desktop client processing the CDP command
666
- // and POSTing the result back to the runtime.
667
- const cdpMethod = frame.cdpMethod as string;
668
- let content: string;
669
- let isError = false;
670
- if (cdpMethod === "Browser.getVersion") {
671
- content = JSON.stringify({
672
- product: "Chrome/macOS-SSE-Test",
673
- protocolVersion: "1.3",
674
- revision: "@macos-sse",
675
- userAgent: "Mozilla/5.0 (macOS SSE bridge e2e fixture)",
676
- jsVersion: "0.0.0-macos-sse",
677
- });
678
- } else if (cdpMethod === "Runtime.evaluate") {
679
- content = JSON.stringify({ result: { value: "complete" } });
680
- } else {
681
- content = `mock macOS client: unsupported cdpMethod "${cdpMethod}"`;
682
- isError = true;
683
- }
684
-
685
- // POST result asynchronously (simulating the real macOS client).
686
- void fetch(`${runtimeBaseUrl}/v1/host-browser-result`, {
687
- method: "POST",
688
- headers: {
689
- "Content-Type": "application/json",
690
- Authorization: `Bearer ${token}`,
691
- },
692
- body: JSON.stringify({ requestId, content, isError }),
693
- })
694
- .then((res) => res.body?.cancel())
695
- .catch(() => {});
696
- }
697
- };
698
-
699
- const proxy = new HostBrowserProxy(sseSender);
700
- proxyRef = proxy;
701
- return { proxy, conversation, sentFrames };
702
- }
703
-
704
- test("happy path: Browser.getVersion round-trips through the SSE bridge without extension registry", async () => {
705
- const guardianId = `test-guardian-macos-sse-${crypto.randomUUID()}`;
706
- const token = mintActorToken(guardianId);
707
-
708
- const { proxy, sentFrames } = createSseBoundProxy(
709
- "conv-macos-sse-happy",
710
- token,
711
- );
712
-
713
- const result = await proxy.request(
714
- { cdpMethod: "Browser.getVersion" },
715
- "conv-macos-sse-happy",
716
- );
717
-
718
- // The request completed via the SSE bridge path, not the extension registry.
719
- expect(result.isError).toBe(false);
720
- expect(result.content).toContain("Chrome/macOS-SSE-Test");
721
-
722
- // The SSE sender received exactly one host_browser_request frame.
723
- const requests = sentFrames.filter(
724
- (f) => f.type === "host_browser_request",
725
- );
726
- expect(requests).toHaveLength(1);
727
- expect(requests[0].cdpMethod).toBe("Browser.getVersion");
728
- expect(requests[0].conversationId).toBe("conv-macos-sse-happy");
729
-
730
- // The extension registry should NOT have been involved — no entries exist.
731
- expect(getChromeExtensionRegistry().get(guardianId)).toBeUndefined();
732
-
733
- proxy.dispose();
734
- });
735
-
736
- test("abort: SSE-bridged request resolves to 'Aborted' when signal fires", async () => {
737
- const guardianId = `test-guardian-macos-sse-abort-${crypto.randomUUID()}`;
738
- const _token = mintActorToken(guardianId);
739
-
740
- // Use a CDP handler that hangs forever so we can abort mid-flight.
741
- const sentFrames: Array<{ type: string; [key: string]: unknown }> = [];
742
- let proxyRef: HostBrowserProxy | null = null;
743
- const conversation = {
744
- resolveHostBrowser(
745
- requestId: string,
746
- response: { content: string; isError: boolean },
747
- ) {
748
- proxyRef?.resolve(requestId, response);
749
- },
750
- } as unknown as Conversation;
751
-
752
- const hangingSender = (msg: ServerMessage) => {
753
- const frame = msg as { type: string; [key: string]: unknown };
754
- sentFrames.push(frame);
755
- if (frame.type === "host_browser_request") {
756
- const requestId = frame.requestId as string;
757
- pendingInteractions.register(requestId, {
758
- conversation,
759
- conversationId: "conv-macos-sse-abort",
760
- kind: "host_browser",
761
- });
762
- // Simulate a macOS client that never responds (hangs).
763
- }
764
- };
765
-
766
- const proxy = new HostBrowserProxy(hangingSender);
767
- proxyRef = proxy;
768
-
769
- const controller = new AbortController();
770
- const resultPromise = proxy.request(
771
- { cdpMethod: "Browser.getVersion" },
772
- "conv-macos-sse-abort",
773
- controller.signal,
774
- );
775
-
776
- // Wait for the SSE sender to observe the request.
777
- await waitFor(() => sentFrames.length === 1);
778
-
779
- controller.abort();
780
- const result = await resultPromise;
781
-
782
- expect(result.content).toBe("Aborted");
783
- expect(result.isError).toBe(true);
784
-
785
- // The cancel frame should have been sent through the SSE sender.
786
- const cancels = sentFrames.filter((f) => f.type === "host_browser_cancel");
787
- expect(cancels).toHaveLength(1);
788
-
789
- proxy.dispose();
790
- });
791
-
792
- test("timeout: SSE-bridged request surfaces timeout when macOS client never responds", async () => {
793
- const guardianId = `test-guardian-macos-sse-timeout-${crypto.randomUUID()}`;
794
- const _token = mintActorToken(guardianId);
795
-
796
- const sentFrames: Array<{ type: string; [key: string]: unknown }> = [];
797
- let proxyRef: HostBrowserProxy | null = null;
798
- const conversation = {
799
- resolveHostBrowser(
800
- requestId: string,
801
- response: { content: string; isError: boolean },
802
- ) {
803
- proxyRef?.resolve(requestId, response);
804
- },
805
- } as unknown as Conversation;
806
-
807
- const hangingSender = (msg: ServerMessage) => {
808
- const frame = msg as { type: string; [key: string]: unknown };
809
- sentFrames.push(frame);
810
- if (frame.type === "host_browser_request") {
811
- const requestId = frame.requestId as string;
812
- pendingInteractions.register(requestId, {
813
- conversation,
814
- conversationId: "conv-macos-sse-timeout",
815
- kind: "host_browser",
816
- });
817
- // Never respond — simulate unresponsive macOS client.
818
- }
819
- };
820
-
821
- const proxy = new HostBrowserProxy(hangingSender);
822
- proxyRef = proxy;
823
-
824
- const result = await proxy.request(
825
- { cdpMethod: "Browser.getVersion", timeout_seconds: 0.05 },
826
- "conv-macos-sse-timeout",
827
- );
828
-
829
- expect(result.isError).toBe(true);
830
- expect(result.content).toContain("timed out");
831
-
832
- // The SSE sender received the request frame (confirming the timeout
833
- // is from the proxy timer, not a send failure).
834
- const requests = sentFrames.filter(
835
- (f) => f.type === "host_browser_request",
836
- );
837
- expect(requests).toHaveLength(1);
838
- expect(requests[0].cdpMethod).toBe("Browser.getVersion");
839
-
840
- proxy.dispose();
841
- });
842
-
843
- test("multiple sequential commands round-trip through the SSE bridge", async () => {
844
- const guardianId = `test-guardian-macos-sse-seq-${crypto.randomUUID()}`;
845
- const token = mintActorToken(guardianId);
846
-
847
- const { proxy, sentFrames } = createSseBoundProxy(
848
- "conv-macos-sse-seq",
849
- token,
850
- );
851
-
852
- // First command: Browser.getVersion
853
- const result1 = await proxy.request(
854
- { cdpMethod: "Browser.getVersion" },
855
- "conv-macos-sse-seq",
856
- );
857
- expect(result1.isError).toBe(false);
858
- expect(result1.content).toContain("Chrome/macOS-SSE-Test");
859
-
860
- // Second command: Runtime.evaluate
861
- const result2 = await proxy.request(
862
- { cdpMethod: "Runtime.evaluate", cdpParams: { expression: "1+1" } },
863
- "conv-macos-sse-seq",
864
- );
865
- expect(result2.isError).toBe(false);
866
-
867
- // Both requests went through the SSE sender.
868
- const requests = sentFrames.filter(
869
- (f) => f.type === "host_browser_request",
870
- );
871
- expect(requests).toHaveLength(2);
872
- expect(requests[0].cdpMethod).toBe("Browser.getVersion");
873
- expect(requests[1].cdpMethod).toBe("Runtime.evaluate");
874
-
875
- proxy.dispose();
876
- });
877
- });
878
-
879
- // ── Local wait helpers ──────────────────────────────────────────────
880
-
881
- async function waitFor(
882
- predicate: () => boolean,
883
- timeoutMs = 2000,
884
- ): Promise<void> {
885
- const deadline = Date.now() + timeoutMs;
886
- while (!predicate()) {
887
- if (Date.now() > deadline) {
888
- throw new Error(
889
- `waitFor: predicate did not become true within ${timeoutMs}ms`,
890
- );
891
- }
892
- await new Promise((r) => setTimeout(r, 10));
893
- }
894
- }
895
-
896
- async function waitForRegistryEntry(
897
- guardianId: string,
898
- timeoutMs = 2000,
899
- ): Promise<void> {
900
- await waitFor(
901
- () => getChromeExtensionRegistry().get(guardianId) !== undefined,
902
- timeoutMs,
903
- );
904
- }