@vellumai/assistant 0.7.0 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ARCHITECTURE.md +6 -7
- package/Dockerfile +1 -0
- package/README.md +2 -2
- package/__tests__/permissions/gateway-threshold-reader.test.ts +79 -139
- package/bun.lock +3 -0
- package/docs/architecture/security.md +18 -16
- package/knip.json +1 -0
- package/node_modules/@vellumai/skill-host-contracts/__tests__/client.test.ts +1 -5
- package/node_modules/@vellumai/skill-host-contracts/src/assistant-event.ts +0 -5
- package/node_modules/@vellumai/skill-host-contracts/src/client.ts +10 -16
- package/node_modules/@vellumai/skill-host-contracts/src/skill-host.ts +1 -9
- package/node_modules/@vellumai/skill-host-contracts/src/tool-types.ts +12 -12
- package/node_modules/@vellumai/slack-text/bun.lock +24 -0
- package/node_modules/@vellumai/slack-text/package.json +18 -0
- package/node_modules/@vellumai/slack-text/src/index.test.ts +153 -0
- package/node_modules/@vellumai/slack-text/src/index.ts +235 -0
- package/node_modules/@vellumai/slack-text/tsconfig.json +20 -0
- package/openapi.yaml +294 -107
- package/package.json +4 -2
- package/scripts/generate-openapi.ts +16 -111
- package/src/__tests__/agent-wake-override-profile.test.ts +23 -1
- package/src/__tests__/anthropic-provider.test.ts +56 -13
- package/src/__tests__/app-conversation-ids-backfill.test.ts +278 -0
- package/src/__tests__/app-conversation-ids.test.ts +151 -0
- package/src/__tests__/approval-cascade.test.ts +0 -15
- package/src/__tests__/approval-routes-http.test.ts +6 -17
- package/src/__tests__/assistant-event-hub.test.ts +126 -77
- package/src/__tests__/assistant-event.test.ts +0 -5
- package/src/__tests__/assistant-events-sse-hardening.test.ts +37 -15
- package/src/__tests__/assistant-feature-flags-integration.test.ts +0 -29
- package/src/__tests__/background-shell-host-bash.test.ts +34 -43
- package/src/__tests__/call-controller.test.ts +1 -1
- package/src/__tests__/call-site-routing-provider.test.ts +193 -0
- package/src/__tests__/channel-approval-routes.test.ts +10 -296
- package/src/__tests__/channel-approvals.test.ts +25 -17
- package/src/__tests__/channel-guardian.test.ts +100 -146
- package/src/__tests__/checker.test.ts +20 -34
- package/src/__tests__/compact-event-conversation-id-guard.test.ts +50 -0
- package/src/__tests__/compaction-events.test.ts +2 -0
- package/src/__tests__/config-schema.test.ts +6 -48
- package/src/__tests__/config-watcher.test.ts +12 -0
- package/src/__tests__/connection-policy.test.ts +1 -52
- package/src/__tests__/contacts-write.test.ts +2 -64
- package/src/__tests__/context-image-dimensions.test.ts +1 -1
- package/src/__tests__/context-search-memory-source.test.ts +120 -1
- package/src/__tests__/context-search-memory-v2-source.test.ts +383 -0
- package/src/__tests__/context-search-pkb-source.test.ts +49 -0
- package/src/__tests__/context-search-workspace-source.test.ts +9 -22
- package/src/__tests__/context-window-manager.test.ts +46 -0
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +2 -0
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +102 -29
- package/src/__tests__/conversation-agent-loop.test.ts +980 -13
- package/src/__tests__/conversation-analysis-routes.test.ts +12 -10
- package/src/__tests__/conversation-attention-telegram.test.ts +11 -3
- package/src/__tests__/conversation-confirmation-signals.test.ts +0 -291
- package/src/__tests__/conversation-history-web-search.test.ts +4 -3
- package/src/__tests__/conversation-inference-profile-route.test.ts +12 -23
- package/src/__tests__/conversation-lifecycle.test.ts +4 -4
- package/src/__tests__/conversation-process-callsite.test.ts +79 -2
- package/src/__tests__/conversation-queue.test.ts +3 -8
- package/src/__tests__/conversation-routes-disk-view.test.ts +1 -161
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +0 -32
- package/src/__tests__/conversation-routes-slash-commands.test.ts +75 -66
- package/src/__tests__/conversation-runtime-assembly.test.ts +257 -3
- package/src/__tests__/conversation-slash-commands.test.ts +24 -4
- package/src/__tests__/conversation-slash-queue.test.ts +2 -0
- package/src/__tests__/conversation-speed-override.test.ts +0 -3
- package/src/__tests__/conversation-starter-routes.test.ts +79 -2
- package/src/__tests__/conversation-surfaces-standalone-payloads.test.ts +12 -5
- package/src/__tests__/conversation-surfaces-standalone.test.ts +18 -14
- package/src/__tests__/conversation-surfaces-state-update.test.ts +3 -2
- package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +8 -46
- package/src/__tests__/conversation-usage.test.ts +253 -3
- package/src/__tests__/credential-execution-shell-lockdown.test.ts +0 -39
- package/src/__tests__/credential-health-service.test.ts +68 -0
- package/src/__tests__/credential-security-e2e.test.ts +4 -3
- package/src/__tests__/credential-security-invariants.test.ts +1 -5
- package/src/__tests__/credential-token-resolver.test.ts +180 -0
- package/src/__tests__/cu-unified-flow.test.ts +33 -16
- package/src/__tests__/daemon-assistant-events.test.ts +34 -21
- package/src/__tests__/daemon-credential-client.test.ts +4 -1
- package/src/__tests__/db-connection-isolation.test.ts +125 -0
- package/src/__tests__/db-migration-rollback.test.ts +101 -0
- package/src/__tests__/db-slack-compaction-watermark-migration.test.ts +169 -0
- package/src/__tests__/deterministic-verification-control-plane.test.ts +7 -80
- package/src/__tests__/document-conversations.test.ts +332 -0
- package/src/__tests__/embedding-managed-proxy-selection.test.ts +2 -2
- package/src/__tests__/emit-event-signal.test.ts +4 -6
- package/src/__tests__/events-client-registration.test.ts +193 -49
- package/src/__tests__/filing-service.test.ts +58 -7
- package/src/__tests__/first-greeting.test.ts +156 -150
- package/src/__tests__/fixtures/mock-chrome-extension.ts +108 -66
- package/src/__tests__/get-skill-detail-audit.test.ts +3 -8
- package/src/__tests__/guardian-binding-drift-heal.test.ts +1 -1
- package/src/__tests__/guardian-dispatch.test.ts +1 -1
- package/src/__tests__/guardian-grant-minting.test.ts +7 -2
- package/src/__tests__/guardian-routing-invariants.test.ts +7 -2
- package/src/__tests__/guardian-routing-state.test.ts +1 -1
- package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +32 -11
- package/src/__tests__/handlers-user-message-approval-consumption.test.ts +2 -83
- package/src/__tests__/headless-browser-mode.test.ts +4 -9
- package/src/__tests__/headless-browser-navigate.test.ts +21 -20
- package/src/__tests__/heartbeat-service.test.ts +289 -7
- package/src/__tests__/helpers/channel-test-adapter.ts +2 -2
- package/src/__tests__/helpers/create-guardian-binding.ts +91 -0
- package/src/__tests__/host-bash-proxy.test.ts +46 -122
- package/src/__tests__/host-browser-e2e-cloud.test.ts +36 -497
- package/src/__tests__/host-browser-e2e-self-hosted-capability.test.ts +26 -96
- package/src/__tests__/host-browser-proxy.test.ts +111 -185
- package/src/__tests__/host-browser-routes.test.ts +45 -75
- package/src/__tests__/host-browser-ws-events-e2e.test.ts +26 -30
- package/src/__tests__/host-cu-proxy.test.ts +56 -111
- package/src/__tests__/host-file-proxy.test.ts +44 -98
- package/src/__tests__/host-file-read-tool.test.ts +42 -21
- package/src/__tests__/host-shell-tool.test.ts +33 -68
- package/src/__tests__/host-transfer-pending-interactions.test.ts +2 -18
- package/src/__tests__/host-transfer-proxy.test.ts +43 -53
- package/src/__tests__/http-user-message-parity.test.ts +0 -6
- package/src/__tests__/inbound-slack-persistence.test.ts +31 -0
- package/src/__tests__/injector-chain.test.ts +10 -5
- package/src/__tests__/injector-pkb-v2-silenced.test.ts +124 -0
- package/src/__tests__/inline-command-runner.test.ts +0 -66
- package/src/__tests__/inline-skill-load-permissions.test.ts +0 -2
- package/src/__tests__/install-skill-routing.test.ts +1 -13
- package/src/__tests__/llm-callsite-catalog.test.ts +34 -0
- package/src/__tests__/llm-catalog-parity.test.ts +90 -0
- package/src/__tests__/llm-context-resolution.test.ts +180 -0
- package/src/__tests__/llm-resolver.test.ts +80 -12
- package/src/__tests__/llm-usage-store.test.ts +269 -4
- package/src/__tests__/log-export-routes.test.ts +89 -0
- package/src/__tests__/managed-profile-guard.test.ts +225 -0
- package/src/__tests__/managed-skill-lifecycle.test.ts +0 -10
- package/src/__tests__/manual-token-reconciliation.test.ts +334 -0
- package/src/__tests__/memory-v2-static-injector.test.ts +95 -0
- package/src/__tests__/migration-cross-version-compatibility.test.ts +197 -291
- package/src/__tests__/migration-export-http.test.ts +33 -26
- package/src/__tests__/migration-export-streaming.test.ts +18 -10
- package/src/__tests__/migration-export-to-gcs.test.ts +49 -9
- package/src/__tests__/migration-import-commit-http.test.ts +66 -21
- package/src/__tests__/migration-import-from-gcs.test.ts +50 -9
- package/src/__tests__/migration-import-from-url.test.ts +20 -6
- package/src/__tests__/migration-import-preflight-http.test.ts +95 -95
- package/src/__tests__/migration-parity-persistence.test.ts +62 -25
- package/src/__tests__/migration-transport.test.ts +115 -23
- package/src/__tests__/migration-validate-http.test.ts +105 -80
- package/src/__tests__/migration-wizard.test.ts +133 -27
- package/src/__tests__/non-member-access-request.test.ts +1 -1
- package/src/__tests__/notification-guardian-path.test.ts +1 -1
- package/src/__tests__/oauth-store.test.ts +19 -0
- package/src/__tests__/platform-bash-auto-approve.test.ts +21 -12
- package/src/__tests__/prechat-onboarding-contract.test.ts +31 -7
- package/src/__tests__/pricing.test.ts +68 -4
- package/src/__tests__/process-message-background-slack.test.ts +331 -0
- package/src/__tests__/provider-managed-proxy-integration.test.ts +153 -17
- package/src/__tests__/provider-send-message-override-profile.test.ts +50 -0
- package/src/__tests__/provider-usage-tracking.test.ts +208 -0
- package/src/__tests__/reaction-persistence.test.ts +9 -6
- package/src/__tests__/rebind-secrets-screen.test.ts +53 -16
- package/src/__tests__/recording-handler.test.ts +64 -81
- package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +4 -3
- package/src/__tests__/relay-server.test.ts +18 -13
- package/src/__tests__/require-fresh-approval.test.ts +13 -22
- package/src/__tests__/runtime-attachment-metadata.test.ts +1 -1
- package/src/__tests__/runtime-events-sse-parity.test.ts +3 -4
- package/src/__tests__/runtime-events-sse.test.ts +3 -12
- package/src/__tests__/search-skills-unified.test.ts +9 -15
- package/src/__tests__/secret-ingress-cli.test.ts +2 -5
- package/src/__tests__/secret-ingress-http.test.ts +0 -4
- package/src/__tests__/secret-onetime-send.test.ts +4 -2
- package/src/__tests__/secret-prompt-log-hygiene.test.ts +24 -7
- package/src/__tests__/secret-prompter-channel-fallback.test.ts +42 -47
- package/src/__tests__/secret-response-routing.test.ts +29 -15
- package/src/__tests__/secret-routes-managed-proxy.test.ts +5 -1
- package/src/__tests__/secret-scanner.test.ts +2 -545
- package/src/__tests__/send-endpoint-busy.test.ts +9 -24
- package/src/__tests__/settings-routes.test.ts +1 -1
- package/src/__tests__/shell-credential-ref.test.ts +0 -8
- package/src/__tests__/shell-tool-proxy-mode.test.ts +0 -56
- package/src/__tests__/skill-script-runner-sandbox.test.ts +0 -11
- package/src/__tests__/skill-tool-factory.test.ts +97 -0
- package/src/__tests__/skills-file-content-endpoint.test.ts +9 -30
- package/src/__tests__/skills-files-catalog-fallback.test.ts +11 -17
- package/src/__tests__/slack-inbound-verification.test.ts +1 -62
- package/src/__tests__/subagent-fork-notifications.test.ts +57 -47
- package/src/__tests__/subagent-manager-notify.test.ts +70 -70
- package/src/__tests__/subagent-notify-parent.test.ts +80 -83
- package/src/__tests__/system-prompt.test.ts +115 -13
- package/src/__tests__/terminal-tools.test.ts +0 -89
- package/src/__tests__/thread-backfill.test.ts +945 -31
- package/src/__tests__/tool-domain-event-publisher.test.ts +0 -36
- package/src/__tests__/tool-execute-pipeline.test.ts +0 -6
- package/src/__tests__/tool-execution-abort-cleanup.test.ts +0 -16
- package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +9 -19
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +4 -7
- package/src/__tests__/tool-executor.test.ts +12 -19
- package/src/__tests__/tool-metrics-listener.test.ts +0 -35
- package/src/__tests__/tool-side-effects-slack-dm.test.ts +1 -0
- package/src/__tests__/tool-trace-listener.test.ts +0 -17
- package/src/__tests__/transfer-progress-screen.test.ts +63 -26
- package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +2 -149
- package/src/__tests__/trusted-contact-multichannel.test.ts +2 -4
- package/src/__tests__/trusted-contact-verification.test.ts +1 -1
- package/src/__tests__/tts-catalog-parity.test.ts +16 -5
- package/src/__tests__/usage-attribution.test.ts +247 -0
- package/src/__tests__/usage-cli.test.ts +143 -0
- package/src/__tests__/usage-grouped-buckets.test.ts +155 -0
- package/src/__tests__/usage-routes.test.ts +150 -0
- package/src/__tests__/validation-results-screen.test.ts +39 -16
- package/src/__tests__/vbundle-pax-and-symlink.test.ts +12 -3
- package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +49 -137
- package/src/__tests__/verification-control-plane-policy.test.ts +4 -7
- package/src/__tests__/voice-session-bridge.test.ts +5 -5
- package/src/__tests__/workspace-migration-062-drop-memory-v2-edges-json.test.ts +103 -0
- package/src/__tests__/workspace-migration-063-release-notes-dynamic-model-context.test.ts +77 -0
- package/src/__tests__/workspace-migration-064-unwind-main-agent-opus-seed.test.ts +225 -0
- package/src/__tests__/workspace-migration-memory-v2-init.test.ts +8 -30
- package/src/acp/index.ts +0 -15
- package/src/acp/session-manager.ts +37 -34
- package/src/agent/loop.ts +16 -1
- package/src/approvals/AGENTS.md +4 -0
- package/src/approvals/__tests__/guardian-feed-event.test.ts +10 -3
- package/src/approvals/guardian-request-resolvers.ts +10 -2
- package/src/backup/__tests__/backup-worker.test.ts +36 -8
- package/src/backup/__tests__/paths.test.ts +2 -2
- package/src/backup/__tests__/restore.test.ts +45 -28
- package/src/backup/backup-worker.ts +36 -2
- package/src/backup/paths.ts +9 -6
- package/src/browser-session/events.ts +0 -9
- package/src/calls/call-store.ts +1 -34
- package/src/calls/guardian-question-copy.ts +0 -108
- package/src/calls/relay-server.ts +0 -24
- package/src/calls/twilio-rest.ts +0 -38
- package/src/calls/twilio-routes.ts +1 -1
- package/src/calls/voice-session-bridge.ts +7 -38
- package/src/channels/types.ts +1 -36
- package/src/cli/commands/__tests__/cache.test.ts +152 -5
- package/src/cli/commands/__tests__/memory-v2.test.ts +14 -28
- package/src/cli/commands/__tests__/trust.test.ts +21 -387
- package/src/cli/commands/backup.ts +4 -4
- package/src/cli/commands/cache-fs.ts +8 -0
- package/src/cli/commands/cache.ts +153 -82
- package/src/cli/commands/clients.ts +63 -5
- package/src/cli/commands/completions.ts +3 -3
- package/src/cli/commands/contacts.ts +231 -76
- package/src/cli/commands/keys.ts +4 -1
- package/src/cli/commands/memory-v2.ts +24 -52
- package/src/cli/commands/oauth/shared.ts +2 -29
- package/src/cli/commands/pending.ts +102 -0
- package/src/cli/commands/skills.ts +77 -35
- package/src/cli/commands/trust.ts +70 -430
- package/src/cli/commands/usage.ts +25 -16
- package/src/cli/lib/daemon-credential-client.ts +14 -0
- package/src/cli/program.ts +2 -0
- package/src/cli.ts +0 -21
- package/src/config/__tests__/feature-flag-registry-guard.test.ts +2 -2
- package/src/config/bundled-skills/messaging/TOOLS.json +14 -4
- package/src/config/env-registry.ts +12 -2
- package/src/config/env.ts +3 -14
- package/src/config/feature-flag-registry.json +30 -30
- package/src/config/llm-callsite-catalog.ts +12 -0
- package/src/config/llm-context-resolution.ts +80 -0
- package/src/config/llm-resolver.ts +58 -22
- package/src/config/loader.ts +3 -3
- package/src/config/schema.ts +2 -158
- package/src/config/schemas/__tests__/memory-v2.test.ts +1 -0
- package/src/config/schemas/call-site-catalog.ts +271 -0
- package/src/config/schemas/calls.ts +5 -5
- package/src/config/schemas/inference.ts +1 -1
- package/src/config/schemas/ingress.ts +1 -1
- package/src/config/schemas/llm.ts +31 -3
- package/src/config/schemas/memory-retrieval.ts +2 -2
- package/src/config/schemas/memory-v2.ts +9 -0
- package/src/config/schemas/security.ts +1 -42
- package/src/config/schemas/services.ts +6 -6
- package/src/config/schemas/skills.ts +5 -5
- package/src/config/schemas/tts.ts +1 -1
- package/src/config/seed-inference-profiles.ts +117 -0
- package/src/config/skills.ts +0 -90
- package/src/config/types.ts +3 -6
- package/src/contacts/contact-store.ts +0 -17
- package/src/contacts/contacts-write.ts +1 -105
- package/src/context/window-manager.ts +44 -5
- package/src/credential-execution/process-manager.ts +34 -10
- package/src/credential-health/credential-health-service.ts +21 -16
- package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +75 -82
- package/src/daemon/__tests__/daemon-skill-host.test.ts +2 -9
- package/src/daemon/connection-policy.ts +1 -26
- package/src/daemon/conversation-agent-loop-handlers.ts +53 -4
- package/src/daemon/conversation-agent-loop.ts +277 -36
- package/src/daemon/conversation-history.ts +8 -8
- package/src/daemon/conversation-launch.ts +20 -135
- package/src/daemon/conversation-lifecycle.ts +1 -1
- package/src/daemon/conversation-messaging.ts +1 -0
- package/src/daemon/conversation-process.ts +83 -163
- package/src/daemon/conversation-runtime-assembly.ts +219 -76
- package/src/daemon/conversation-slash.ts +47 -5
- package/src/daemon/conversation-store.ts +7 -31
- package/src/daemon/conversation-surfaces.ts +22 -28
- package/src/daemon/conversation-tool-setup.ts +3 -33
- package/src/daemon/conversation-usage.ts +36 -0
- package/src/daemon/conversation.ts +117 -233
- package/src/daemon/daemon-control.ts +3 -71
- package/src/daemon/daemon-skill-host.ts +8 -11
- package/src/daemon/dictation-profile-store.ts +2 -26
- package/src/daemon/first-greeting.ts +44 -156
- package/src/daemon/handlers/config-channels.ts +12 -12
- package/src/daemon/handlers/config-ingress.ts +4 -165
- package/src/daemon/handlers/config-model.ts +1 -1
- package/src/daemon/handlers/config-voice.ts +0 -42
- package/src/daemon/handlers/conversations.ts +11 -190
- package/src/daemon/handlers/recording.ts +26 -158
- package/src/daemon/handlers/shared.ts +23 -71
- package/src/daemon/handlers/skills.ts +42 -93
- package/src/daemon/host-bash-proxy.ts +67 -45
- package/src/daemon/host-browser-proxy.ts +65 -27
- package/src/daemon/host-cu-proxy.ts +40 -39
- package/src/daemon/host-file-proxy.ts +58 -37
- package/src/daemon/host-transfer-proxy.ts +84 -46
- package/src/daemon/lifecycle.ts +49 -15
- package/src/daemon/message-types/conversations.ts +7 -0
- package/src/daemon/message-types/host-bash.ts +1 -0
- package/src/daemon/message-types/host-cu.ts +1 -0
- package/src/daemon/message-types/host-file.ts +1 -0
- package/src/daemon/message-types/host-transfer.ts +1 -0
- package/src/daemon/message-types/messages.ts +10 -9
- package/src/daemon/message-types/workspace.ts +1 -1
- package/src/daemon/process-message.ts +102 -239
- package/src/daemon/server.ts +13 -462
- package/src/daemon/shutdown-handlers.ts +2 -2
- package/src/daemon/tool-side-effects.ts +125 -107
- package/src/daemon/trust-context.ts +13 -0
- package/src/daemon/wake-target-adapter.ts +4 -9
- package/src/events/domain-events.ts +0 -8
- package/src/events/tool-audit-listener.ts +3 -1
- package/src/events/tool-domain-event-publisher.ts +0 -10
- package/src/events/tool-metrics-listener.ts +0 -17
- package/src/events/tool-trace-listener.ts +0 -14
- package/src/filing/filing-service.ts +13 -1
- package/src/heartbeat/__tests__/heartbeat-feed-event.test.ts +6 -2
- package/src/heartbeat/heartbeat-service.ts +23 -5
- package/src/home/__tests__/feed-writer.test.ts +0 -4
- package/src/home/__tests__/relationship-state-writer.test.ts +30 -0
- package/src/home/feed-writer.ts +1 -2
- package/src/home/relationship-state-writer.ts +16 -3
- package/src/ipc/__tests__/browser-ipc.test.ts +2 -12
- package/src/ipc/__tests__/skill-server-bidirectional.test.ts +0 -1
- package/src/ipc/assistant-server.ts +3 -10
- package/src/ipc/routes/__tests__/memory-v2-backfill.test.ts +39 -20
- package/src/ipc/routes/route-adapter.ts +1 -1
- package/src/ipc/routes/trust-rules.test.ts +0 -95
- package/src/ipc/skill-ipc-types.ts +41 -0
- package/src/ipc/skill-routes/__tests__/events-ipc.test.ts +13 -27
- package/src/ipc/skill-routes/__tests__/identity.test.ts +4 -23
- package/src/ipc/skill-routes/events.ts +12 -23
- package/src/ipc/skill-routes/identity.ts +4 -17
- package/src/ipc/skill-routes/index.ts +1 -1
- package/src/ipc/skill-server.ts +6 -39
- package/src/live-voice/__tests__/runtime-websocket-shell.test.ts +0 -8
- package/src/live-voice/protocol.ts +4 -13
- package/src/mcp/manager.ts +0 -5
- package/src/memory/__tests__/fixtures/memory-v2-activation-fixtures.ts +55 -0
- package/src/memory/__tests__/memory-v2-activation-log-store.test.ts +127 -0
- package/src/memory/app-git-service.ts +0 -32
- package/src/memory/app-store.ts +154 -0
- package/src/memory/attachments-store.ts +6 -0
- package/src/memory/context-search/sources/memory-v2.ts +578 -0
- package/src/memory/context-search/sources/memory.ts +5 -0
- package/src/memory/context-search/sources/pkb.ts +10 -1
- package/src/memory/context-search/sources/workspace.ts +3 -2
- package/src/memory/conversation-crud.ts +29 -4
- package/src/memory/conversation-disk-view.ts +1 -5
- package/src/memory/conversation-starter-checkpoints.ts +63 -0
- package/src/memory/db-connection.ts +62 -0
- package/src/memory/db-init.ts +14 -0
- package/src/memory/embedding-backend.ts +3 -21
- package/src/memory/embedding-gemini.ts +0 -2
- package/src/memory/embedding-local.ts +6 -6
- package/src/memory/embedding-ollama.ts +6 -6
- package/src/memory/embedding-openai.ts +6 -6
- package/src/memory/embedding-types.ts +21 -0
- package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +3 -7
- package/src/memory/graph/conversation-graph-memory.ts +35 -13
- package/src/memory/graph/injection.test.ts +2 -2
- package/src/memory/graph/injection.ts +1 -1
- package/src/memory/guardian-action-store.ts +0 -83
- package/src/memory/guardian-approvals.ts +0 -48
- package/src/memory/indexer.ts +1 -15
- package/src/memory/job-handlers/conversation-starters.ts +36 -53
- package/src/memory/job-utils.ts +0 -6
- package/src/memory/jobs-store.ts +0 -1
- package/src/memory/jobs-worker.ts +2 -16
- package/src/memory/llm-request-log-store.ts +0 -41
- package/src/memory/llm-usage-store.ts +129 -43
- package/src/memory/memory-v2-activation-log-store.ts +115 -0
- package/src/memory/migrations/233-document-conversations.ts +54 -0
- package/src/memory/migrations/234-memory-v2-activation-logs.ts +55 -0
- package/src/memory/migrations/235-llm-usage-attribution.ts +31 -0
- package/src/memory/migrations/235-slack-compaction-watermark.ts +44 -0
- package/src/memory/migrations/236-tool-invocations-matched-rule-id.ts +26 -0
- package/src/memory/migrations/__tests__/234-memory-v2-activation-logs.test.ts +182 -0
- package/src/memory/migrations/index.ts +14 -0
- package/src/memory/migrations/registry.ts +24 -0
- package/src/memory/raw-query.ts +2 -68
- package/src/memory/schema/conversations.ts +7 -0
- package/src/memory/schema/infrastructure.ts +25 -0
- package/src/memory/search/semantic.ts +5 -16
- package/src/memory/tool-usage-store.ts +2 -0
- package/src/memory/usage-buckets.ts +40 -1
- package/src/memory/usage-grouped-buckets.ts +127 -0
- package/src/memory/v2/__tests__/activation.test.ts +289 -90
- package/src/memory/v2/__tests__/backfill-jobs.test.ts +2 -129
- package/src/memory/v2/__tests__/consolidation-job.test.ts +28 -11
- package/src/memory/v2/__tests__/edge-index.test.ts +278 -0
- package/src/memory/v2/__tests__/injection.test.ts +384 -15
- package/src/memory/v2/__tests__/migration.test.ts +64 -36
- package/src/memory/v2/__tests__/page-store.test.ts +191 -8
- package/src/memory/v2/__tests__/prompts-consolidation.test.ts +181 -0
- package/src/memory/v2/__tests__/skill-store.test.ts +115 -3
- package/src/memory/v2/__tests__/static-context.test.ts +153 -0
- package/src/memory/v2/activation.ts +168 -97
- package/src/memory/v2/backfill-jobs.ts +15 -100
- package/src/memory/v2/consolidation-job.ts +14 -12
- package/src/memory/v2/edge-index.ts +191 -0
- package/src/memory/v2/injection.ts +182 -58
- package/src/memory/v2/migration.ts +57 -64
- package/src/memory/v2/now-text.ts +2 -3
- package/src/memory/v2/page-store.ts +168 -31
- package/src/memory/v2/prompts/consolidation.ts +118 -42
- package/src/memory/v2/prompts/sweep.ts +3 -3
- package/src/memory/v2/skill-store.ts +55 -7
- package/src/memory/v2/static-context.ts +62 -0
- package/src/memory/v2/types.ts +10 -20
- package/src/memory/validation.ts +0 -11
- package/src/messaging/draft-store.ts +0 -6
- package/src/messaging/provider-types.ts +8 -0
- package/src/messaging/provider.ts +7 -0
- package/src/messaging/providers/gmail/client.ts +1 -121
- package/src/messaging/providers/outlook/client.ts +0 -73
- package/src/messaging/providers/slack/__tests__/adapter-mention-rendering.test.ts +226 -0
- package/src/messaging/providers/slack/adapter.ts +122 -21
- package/src/messaging/providers/slack/backfill.test.ts +95 -6
- package/src/messaging/providers/slack/backfill.ts +89 -11
- package/src/messaging/providers/slack/client.ts +10 -124
- package/src/messaging/providers/slack/message-metadata.ts +12 -2
- package/src/messaging/providers/slack/render-transcript.test.ts +56 -0
- package/src/messaging/providers/slack/render-transcript.ts +126 -25
- package/src/messaging/providers/slack/types.ts +1 -0
- package/src/oauth/connection-resolver.test.ts +8 -0
- package/src/oauth/connection-resolver.ts +8 -16
- package/src/oauth/credential-token-resolver.ts +97 -0
- package/src/oauth/manual-token-connection.ts +30 -34
- package/src/oauth/oauth-store.ts +6 -4
- package/src/outbound-proxy/certs.ts +0 -7
- package/src/outbound-proxy/config.ts +0 -74
- package/src/outbound-proxy/health.ts +0 -44
- package/src/outbound-proxy/index.ts +0 -22
- package/src/permissions/approval-provenance.test.ts +184 -0
- package/src/permissions/approval-provenance.ts +70 -0
- package/src/permissions/checker.ts +4 -1
- package/src/permissions/gateway-threshold-reader.ts +4 -1
- package/src/permissions/prompter.ts +9 -2
- package/src/permissions/secret-prompter.ts +21 -48
- package/src/permissions/types.ts +33 -0
- package/src/permissions/workspace-policy.ts +0 -5
- package/src/platform/sync-identity.ts +0 -8
- package/src/plugins/defaults/injectors.ts +69 -2
- package/src/plugins/defaults/overflow-reduce.ts +3 -2
- package/src/plugins/types.ts +8 -0
- package/src/prompts/system-prompt.ts +34 -70
- package/src/prompts/templates/BOOTSTRAP.md +52 -6
- package/src/prompts/update-bulletin-job.ts +2 -0
- package/src/providers/__tests__/retry-callsite.test.ts +138 -1
- package/src/providers/anthropic/client.ts +72 -33
- package/src/providers/call-site-routing.ts +42 -3
- package/src/providers/gemini/client.ts +18 -2
- package/src/providers/managed-proxy/context.ts +0 -5
- package/src/providers/model-catalog.ts +105 -19
- package/src/providers/openai/chat-completions-provider.ts +6 -0
- package/src/providers/openai/responses-provider.ts +7 -1
- package/src/providers/provider-send-message.ts +45 -2
- package/src/providers/ratelimit.ts +7 -2
- package/src/providers/registry.ts +14 -9
- package/src/providers/retry.ts +96 -8
- package/src/providers/types.ts +13 -0
- package/src/providers/usage-tracking.ts +96 -0
- package/src/runtime/AGENTS.md +10 -6
- package/src/runtime/__tests__/agent-wake.test.ts +89 -0
- package/src/runtime/agent-wake.ts +39 -2
- package/src/runtime/assistant-event-hub.ts +541 -45
- package/src/runtime/assistant-event.ts +1 -6
- package/src/runtime/auth/context.ts +0 -9
- package/src/runtime/auth/middleware.ts +1 -1
- package/src/runtime/auth/route-policy.ts +11 -9
- package/src/runtime/auth/token-service.ts +0 -11
- package/src/runtime/channel-approvals.ts +6 -2
- package/src/runtime/channel-verification-service.ts +3 -5
- package/src/runtime/http-errors.ts +0 -34
- package/src/runtime/http-router.ts +6 -3
- package/src/runtime/http-server.ts +22 -82
- package/src/runtime/http-types.ts +5 -0
- package/src/runtime/interactive-ui.ts +0 -1
- package/src/runtime/middleware/auth.ts +0 -20
- package/src/runtime/migrations/__tests__/v1-test-helpers.ts +112 -0
- package/src/runtime/migrations/__tests__/vbundle-builder-credentials.test.ts +11 -4
- package/src/runtime/migrations/__tests__/vbundle-builder-v1-shape.test.ts +253 -0
- package/src/runtime/migrations/__tests__/vbundle-import-credentials.test.ts +19 -6
- package/src/runtime/migrations/__tests__/vbundle-legacy-user-md.test.ts +71 -27
- package/src/runtime/migrations/__tests__/vbundle-metadata-merge-integration.test.ts +41 -2
- package/src/runtime/migrations/__tests__/vbundle-streaming-importer.test.ts +143 -79
- package/src/runtime/migrations/__tests__/vbundle-streaming-validator.test.ts +143 -23
- package/src/runtime/migrations/__tests__/vbundle-tar-stream.test.ts +2 -2
- package/src/runtime/migrations/__tests__/vbundle-validator-v1-schema.test.ts +371 -0
- package/src/runtime/migrations/migration-transport.ts +46 -13
- package/src/runtime/migrations/migration-wizard.ts +2 -2
- package/src/runtime/migrations/origin-mode.ts +40 -0
- package/src/runtime/migrations/vbundle-builder.ts +133 -79
- package/src/runtime/migrations/vbundle-import-analyzer.ts +9 -7
- package/src/runtime/migrations/vbundle-importer.ts +7 -7
- package/src/runtime/migrations/vbundle-metadata-merge.ts +1 -1
- package/src/runtime/migrations/vbundle-streaming-importer.ts +3 -3
- package/src/runtime/migrations/vbundle-streaming-validator.ts +48 -26
- package/src/runtime/migrations/vbundle-validator.ts +214 -41
- package/src/runtime/pending-interactions.ts +13 -4
- package/src/runtime/routes/__tests__/acp-routes.test.ts +0 -1
- package/src/runtime/routes/__tests__/backup-routes.test.ts +28 -19
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +235 -0
- package/src/runtime/routes/__tests__/llm-call-sites-routes.test.ts +58 -0
- package/src/runtime/routes/__tests__/migration-export-secrets-redacted.test.ts +54 -0
- package/src/runtime/routes/__tests__/migration-import-credential-filter.test.ts +19 -6
- package/src/runtime/routes/__tests__/user-route-dispatcher.test.ts +7 -7
- package/src/runtime/routes/acp-routes.test.ts +0 -3
- package/src/runtime/routes/acp-routes.ts +3 -7
- package/src/runtime/routes/app-management-routes.ts +18 -9
- package/src/runtime/routes/approval-routes.ts +55 -14
- package/src/runtime/routes/avatar-routes.ts +3 -5
- package/src/runtime/routes/browser-routes.ts +1 -15
- package/src/runtime/routes/channel-guardian-routes.ts +1 -5
- package/src/runtime/routes/channel-readiness-routes.ts +3 -7
- package/src/runtime/routes/channel-route-shared.ts +2 -28
- package/src/runtime/routes/client-routes.ts +45 -12
- package/src/runtime/routes/consolidation-routes.ts +115 -0
- package/src/runtime/routes/conversation-list-routes.ts +12 -29
- package/src/runtime/routes/conversation-management-routes.ts +14 -51
- package/src/runtime/routes/conversation-query-routes.ts +120 -8
- package/src/runtime/routes/conversation-routes.ts +44 -528
- package/src/runtime/routes/conversation-starter-routes.ts +19 -40
- package/src/runtime/routes/documents-routes.ts +53 -18
- package/src/runtime/routes/events-routes.ts +59 -91
- package/src/runtime/routes/filing-routes.ts +18 -1
- package/src/runtime/routes/guardian-action-routes.ts +4 -9
- package/src/runtime/routes/host-bash-routes.ts +3 -2
- package/src/runtime/routes/host-browser-routes.ts +9 -33
- package/src/runtime/routes/host-cu-routes.ts +6 -1
- package/src/runtime/routes/host-file-routes.ts +3 -2
- package/src/runtime/routes/host-transfer-routes.ts +11 -15
- package/src/runtime/routes/identity-routes.ts +78 -6
- package/src/runtime/routes/inbound-message-handler.ts +580 -137
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +2 -88
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +3 -0
- package/src/runtime/routes/index.ts +4 -0
- package/src/runtime/routes/integrations/slack/channel.ts +0 -24
- package/src/runtime/routes/llm-call-sites-routes.ts +22 -0
- package/src/runtime/routes/memory-v2-routes.ts +10 -15
- package/src/runtime/routes/migration-routes.ts +188 -31
- package/src/runtime/routes/playground/guard.ts +1 -1
- package/src/runtime/routes/playground/index.ts +0 -2
- package/src/runtime/routes/recording-routes.ts +4 -24
- package/src/runtime/routes/rename-conversation-routes.ts +2 -6
- package/src/runtime/routes/schedule-routes.ts +3 -6
- package/src/runtime/routes/secret-routes.ts +87 -18
- package/src/runtime/routes/settings-routes.ts +29 -28
- package/src/runtime/routes/skills-routes.ts +12 -31
- package/src/runtime/routes/suggest-trust-rule-routes.ts +32 -1
- package/src/runtime/routes/task-routes.ts +6 -6
- package/src/runtime/routes/trust-rules-routes.ts +3 -94
- package/src/runtime/routes/types.ts +4 -4
- package/src/runtime/routes/upgrade-broadcast-routes.ts +3 -10
- package/src/runtime/routes/usage-routes.ts +87 -10
- package/src/runtime/routes/user-routes.ts +17 -31
- package/src/runtime/routes/work-items-routes.ts +1 -4
- package/src/runtime/services/__tests__/analyze-conversation.test.ts +2 -2
- package/src/runtime/services/analyze-conversation.ts +7 -17
- package/src/runtime/services/conversation-serializer.ts +2 -4
- package/src/runtime/verification-outbound-actions.ts +1 -1
- package/src/runtime/verification-rate-limiter.ts +1 -1
- package/src/schedule/schedule-store.ts +0 -16
- package/src/security/secret-scanner.ts +14 -547
- package/src/security/secure-keys.ts +31 -11
- package/src/security/token-manager.ts +7 -3
- package/src/signals/cancel.ts +16 -25
- package/src/signals/conversation-undo.ts +2 -27
- package/src/signals/emit-event.ts +1 -2
- package/src/signals/user-message.ts +108 -22
- package/src/skills/catalog-install.ts +1 -0
- package/src/skills/clawhub.ts +2 -2
- package/src/skills/inline-command-runner.ts +1 -7
- package/src/subagent/manager.ts +67 -84
- package/src/tasks/task-store.ts +1 -28
- package/src/telemetry/types.ts +6 -0
- package/src/telemetry/usage-telemetry-reporter.test.ts +38 -15
- package/src/telemetry/usage-telemetry-reporter.ts +3 -5
- package/src/tools/acp/spawn.test.ts +1 -2
- package/src/tools/acp/steer.test.ts +1 -2
- package/src/tools/browser/__tests__/browser-status.test.ts +44 -127
- package/src/tools/browser/browser-execution.ts +31 -147
- package/src/tools/browser/cdp-client/__tests__/factory.test.ts +92 -68
- package/src/tools/browser/cdp-client/factory.ts +48 -76
- package/src/tools/browser/cdp-client/index.ts +1 -14
- package/src/tools/executor.ts +44 -31
- package/src/tools/host-filesystem/edit.ts +3 -2
- package/src/tools/host-filesystem/read.ts +3 -2
- package/src/tools/host-filesystem/transfer.test.ts +45 -42
- package/src/tools/host-filesystem/transfer.ts +4 -3
- package/src/tools/host-filesystem/write.ts +3 -2
- package/src/tools/host-terminal/host-shell.ts +4 -3
- package/src/tools/network/script-proxy/index.ts +1 -10
- package/src/tools/permission-checker.ts +66 -1
- package/src/tools/skills/sandbox-runner.ts +1 -6
- package/src/tools/skills/skill-tool-factory.ts +32 -0
- package/src/tools/terminal/safe-env.ts +1 -0
- package/src/tools/terminal/shell.ts +2 -78
- package/src/tools/types.ts +12 -39
- package/src/tts/__tests__/provider-catalog.test.ts +2 -2
- package/src/tts/provider-catalog.ts +1 -1
- package/src/usage/actors.ts +2 -1
- package/src/usage/attribution.ts +185 -0
- package/src/usage/pricing.ts +166 -0
- package/src/usage/types.ts +14 -0
- package/src/util/json.ts +13 -0
- package/src/util/logger.ts +3 -3
- package/src/util/pricing.ts +50 -3
- package/src/work-items/work-item-runner.ts +15 -42
- package/src/workspace/migrations/050-seed-main-agent-opus-callsite.ts +4 -3
- package/src/workspace/migrations/052-seed-default-inference-profiles.ts +3 -3
- package/src/workspace/migrations/060-memory-v2-init.ts +2 -18
- package/src/workspace/migrations/061-move-backup-key-to-workspace.ts +59 -0
- package/src/workspace/migrations/062-drop-memory-v2-edges-json.ts +27 -0
- package/src/workspace/migrations/063-release-notes-dynamic-model-context.ts +70 -0
- package/src/workspace/migrations/064-unwind-main-agent-opus-seed.ts +64 -0
- package/src/workspace/migrations/registry.ts +8 -0
- package/src/workspace/provider-commit-message-generator.ts +3 -3
- package/src/__tests__/sandbox-diagnostics.test.ts +0 -138
- package/src/__tests__/sandbox-host-parity.test.ts +0 -1024
- package/src/__tests__/secret-detection-handler.test.ts +0 -67
- package/src/__tests__/secret-scanner-executor.test.ts +0 -450
- package/src/__tests__/tcc-sandbox-deny.test.ts +0 -198
- package/src/__tests__/terminal-sandbox.test.ts +0 -374
- package/src/__tests__/tool-notification-listener.test.ts +0 -65
- package/src/context/__tests__/microcompact.test.ts +0 -805
- package/src/context/microcompact.ts +0 -443
- package/src/daemon/handlers/slack-channel-oauth-install.ts +0 -197
- package/src/events/tool-notification-listener.ts +0 -17
- package/src/ipc/routes/__tests__/memory-v2-validate.test.ts +0 -219
- package/src/memory/v2/__tests__/edges.test.ts +0 -435
- package/src/memory/v2/edges.ts +0 -217
- package/src/prompts/__tests__/system-prompt-memory-v2.test.ts +0 -197
- package/src/runtime/__tests__/chrome-extension-registry.test.ts +0 -518
- package/src/runtime/__tests__/client-registry.test.ts +0 -271
- package/src/runtime/chrome-extension-registry.ts +0 -368
- package/src/runtime/client-registry.ts +0 -254
- package/src/runtime/routes/inbound-stages/verification-intercept.ts +0 -329
- package/src/tools/secret-detection-handler.ts +0 -269
- package/src/tools/terminal/backends/native.ts +0 -327
- package/src/tools/terminal/backends/types.ts +0 -37
- package/src/tools/terminal/sandbox-diagnostics.ts +0 -87
- package/src/tools/terminal/sandbox.ts +0 -40
|
@@ -65,7 +65,15 @@ describe("first-greeting", () => {
|
|
|
65
65
|
|
|
66
66
|
it("no-onboarding greeting uses two-paragraph structure", () => {
|
|
67
67
|
expect(CANNED_FIRST_GREETING).toContain("\n\n");
|
|
68
|
-
|
|
68
|
+
const paragraphs = CANNED_FIRST_GREETING.split("\n\n");
|
|
69
|
+
expect(paragraphs.length).toBe(2);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it("no-onboarding greeting does not contain old self-deprecation text", () => {
|
|
73
|
+
expect(CANNED_FIRST_GREETING).not.toContain("no name, no memories");
|
|
74
|
+
expect(CANNED_FIRST_GREETING).not.toContain("Brand new");
|
|
75
|
+
expect(CANNED_FIRST_GREETING).not.toContain("I can ask");
|
|
76
|
+
expect(CANNED_FIRST_GREETING).not.toContain("get sharper");
|
|
69
77
|
});
|
|
70
78
|
});
|
|
71
79
|
|
|
@@ -73,229 +81,227 @@ describe("first-greeting", () => {
|
|
|
73
81
|
const base: OnboardingGreetingContext = {
|
|
74
82
|
tools: [],
|
|
75
83
|
tasks: [],
|
|
76
|
-
tone: "
|
|
84
|
+
tone: "grounded",
|
|
77
85
|
};
|
|
78
86
|
|
|
79
|
-
it("
|
|
87
|
+
it("grounded + name + assistantName", () => {
|
|
80
88
|
const greeting = getCannedFirstGreeting({
|
|
81
89
|
...base,
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
assistantName: "Pip",
|
|
90
|
+
tone: "grounded",
|
|
91
|
+
userName: "Alice",
|
|
92
|
+
assistantName: "Pax",
|
|
86
93
|
});
|
|
87
|
-
expect(greeting).
|
|
88
|
-
|
|
89
|
-
expect(greeting).toContain(
|
|
90
|
-
"shipping code or figuring out what to ship next",
|
|
94
|
+
expect(greeting).toBe(
|
|
95
|
+
"Hey Alice, I'm Pax.\n\nWe can get into whatever you've got, or just talk first — that tends to go better. Up to you.",
|
|
91
96
|
);
|
|
92
|
-
expect(greeting).toContain("\n\n");
|
|
93
97
|
});
|
|
94
98
|
|
|
95
|
-
it("
|
|
99
|
+
it("warm + name + assistantName", () => {
|
|
96
100
|
const greeting = getCannedFirstGreeting({
|
|
97
101
|
...base,
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
assistantName: "Pip",
|
|
102
|
+
tone: "warm",
|
|
103
|
+
userName: "Alice",
|
|
104
|
+
assistantName: "Remy",
|
|
102
105
|
});
|
|
103
|
-
expect(greeting).
|
|
104
|
-
|
|
106
|
+
expect(greeting).toBe(
|
|
107
|
+
"Hey Alice, I'm Remy. Good to meet you.\n\nWe can start on something specific, or just talk for a bit first — honestly that tends to work out better. Either way, I'm here.",
|
|
108
|
+
);
|
|
105
109
|
});
|
|
106
110
|
|
|
107
|
-
it("
|
|
111
|
+
it("energetic + no names", () => {
|
|
108
112
|
const greeting = getCannedFirstGreeting({
|
|
109
113
|
...base,
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
userName: "Bob",
|
|
113
|
-
assistantName: "Luna",
|
|
114
|
+
tone: "energetic",
|
|
115
|
+
assistantName: "Pax",
|
|
114
116
|
});
|
|
115
|
-
expect(greeting).
|
|
116
|
-
|
|
117
|
+
expect(greeting).toBe(
|
|
118
|
+
"Hey, I'm Pax. Let's see what you've got.\n\nWe can jump straight into whatever you've got, or take a few minutes to just talk first. What sounds right?",
|
|
119
|
+
);
|
|
117
120
|
});
|
|
118
121
|
|
|
119
|
-
it("
|
|
122
|
+
it("poetic + name + assistantName", () => {
|
|
120
123
|
const greeting = getCannedFirstGreeting({
|
|
121
124
|
...base,
|
|
122
|
-
|
|
123
|
-
userName: "
|
|
124
|
-
assistantName: "
|
|
125
|
+
tone: "poetic",
|
|
126
|
+
userName: "Alice",
|
|
127
|
+
assistantName: "Pax",
|
|
125
128
|
});
|
|
126
|
-
expect(greeting).
|
|
127
|
-
|
|
129
|
+
expect(greeting).toBe(
|
|
130
|
+
"Hey Alice, I'm Pax.\n\nWe can start with whatever's in front of you, or just talk for a bit first. Either way.",
|
|
131
|
+
);
|
|
128
132
|
});
|
|
129
133
|
|
|
130
|
-
it("
|
|
134
|
+
it("name only (no assistantName)", () => {
|
|
131
135
|
const greeting = getCannedFirstGreeting({
|
|
132
136
|
...base,
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
userName: "Bob",
|
|
136
|
-
assistantName: "Pip",
|
|
137
|
+
tone: "grounded",
|
|
138
|
+
userName: "Alice",
|
|
137
139
|
});
|
|
138
|
-
expect(greeting).
|
|
140
|
+
expect(greeting).toBe(
|
|
141
|
+
"Hey Alice,\n\nWe can get into whatever you've got, or just talk first — that tends to go better. Up to you.",
|
|
142
|
+
);
|
|
139
143
|
});
|
|
140
144
|
|
|
141
|
-
it("
|
|
145
|
+
it("assistantName only (no userName)", () => {
|
|
142
146
|
const greeting = getCannedFirstGreeting({
|
|
143
147
|
...base,
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
assistantName: "Pip",
|
|
148
|
+
tone: "grounded",
|
|
149
|
+
assistantName: "Pax",
|
|
147
150
|
});
|
|
148
|
-
expect(greeting).
|
|
149
|
-
|
|
151
|
+
expect(greeting).toBe(
|
|
152
|
+
"Hey, I'm Pax.\n\nWe can get into whatever you've got, or just talk first — that tends to go better. Up to you.",
|
|
153
|
+
);
|
|
150
154
|
});
|
|
151
155
|
|
|
152
|
-
it("
|
|
156
|
+
it("no name, no assistantName, no tone returns CANNED_FIRST_GREETING", () => {
|
|
153
157
|
const greeting = getCannedFirstGreeting({
|
|
154
|
-
|
|
155
|
-
tasks: [
|
|
156
|
-
|
|
157
|
-
"writing",
|
|
158
|
-
"research",
|
|
159
|
-
"project-management",
|
|
160
|
-
"scheduling",
|
|
161
|
-
"personal",
|
|
162
|
-
],
|
|
163
|
-
userName: "Bob",
|
|
164
|
-
assistantName: "Pip",
|
|
158
|
+
tools: [],
|
|
159
|
+
tasks: [],
|
|
160
|
+
tone: "",
|
|
165
161
|
});
|
|
166
|
-
expect(greeting).
|
|
162
|
+
expect(greeting).toBe(CANNED_FIRST_GREETING);
|
|
167
163
|
});
|
|
168
164
|
|
|
169
|
-
it("no
|
|
165
|
+
it("no names but valid tone uses tone-aware greeting", () => {
|
|
170
166
|
const greeting = getCannedFirstGreeting({
|
|
171
|
-
|
|
172
|
-
tools: ["gmail", "linear"],
|
|
167
|
+
tools: [],
|
|
173
168
|
tasks: [],
|
|
174
|
-
|
|
175
|
-
assistantName: "Pip",
|
|
169
|
+
tone: "warm",
|
|
176
170
|
});
|
|
177
|
-
expect(greeting).
|
|
178
|
-
|
|
171
|
+
expect(greeting).toBe(
|
|
172
|
+
"Hey,\n\nWe can start on something specific, or just talk for a bit first — honestly that tends to work out better. Either way, I'm here.",
|
|
173
|
+
);
|
|
179
174
|
});
|
|
180
175
|
|
|
181
|
-
it("
|
|
182
|
-
const
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
expect(greeting).toStartWith("Hey, I'm Pip.");
|
|
176
|
+
it("each valid tone with no names produces distinct invite", () => {
|
|
177
|
+
const greetings = ["grounded", "warm", "energetic", "poetic"].map(
|
|
178
|
+
(tone) => getCannedFirstGreeting({ tools: [], tasks: [], tone }),
|
|
179
|
+
);
|
|
180
|
+
const unique = new Set(greetings);
|
|
181
|
+
expect(unique.size).toBe(4);
|
|
188
182
|
});
|
|
189
183
|
|
|
190
|
-
it("
|
|
184
|
+
it("unknown tone falls back to grounded defaults", () => {
|
|
191
185
|
const greeting = getCannedFirstGreeting({
|
|
192
186
|
...base,
|
|
193
|
-
|
|
194
|
-
userName: "
|
|
195
|
-
assistantName: "
|
|
187
|
+
tone: "mysterious-future-tone",
|
|
188
|
+
userName: "Alice",
|
|
189
|
+
assistantName: "Pax",
|
|
196
190
|
});
|
|
197
|
-
expect(greeting).
|
|
191
|
+
expect(greeting).toBe(
|
|
192
|
+
"Hey Alice, I'm Pax.\n\nWe can get into whatever you've got, or just talk first — that tends to go better. Up to you.",
|
|
193
|
+
);
|
|
198
194
|
});
|
|
199
195
|
|
|
200
|
-
it("
|
|
196
|
+
it("two-paragraph structure preserved", () => {
|
|
201
197
|
const greeting = getCannedFirstGreeting({
|
|
202
198
|
...base,
|
|
203
|
-
|
|
204
|
-
userName: "
|
|
205
|
-
assistantName: "
|
|
199
|
+
tone: "grounded",
|
|
200
|
+
userName: "Alice",
|
|
201
|
+
assistantName: "Pax",
|
|
206
202
|
});
|
|
207
|
-
|
|
208
|
-
|
|
203
|
+
const paragraphs = greeting.split("\n\n");
|
|
204
|
+
expect(paragraphs.length).toBe(2);
|
|
205
|
+
});
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
describe("tone-specific greetings", () => {
|
|
209
|
+
const base: OnboardingGreetingContext = {
|
|
210
|
+
tools: [],
|
|
211
|
+
tasks: [],
|
|
212
|
+
tone: "grounded",
|
|
213
|
+
userName: "Bob",
|
|
214
|
+
assistantName: "Pax",
|
|
215
|
+
};
|
|
216
|
+
|
|
217
|
+
it("grounded intro close is empty, invite is grounded", () => {
|
|
218
|
+
const greeting = getCannedFirstGreeting({ ...base, tone: "grounded" });
|
|
219
|
+
const [intro, invite] = greeting.split("\n\n");
|
|
220
|
+
expect(intro).toBe("Hey Bob, I'm Pax.");
|
|
221
|
+
expect(invite).toBe(
|
|
222
|
+
"We can get into whatever you've got, or just talk first — that tends to go better. Up to you.",
|
|
209
223
|
);
|
|
210
224
|
});
|
|
211
225
|
|
|
212
|
-
it("
|
|
213
|
-
const greeting = getCannedFirstGreeting({
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
expect(greeting).toContain("I'm Pip");
|
|
220
|
-
expect(greeting).toContain("I'll get sharper");
|
|
221
|
-
expect(greeting).toContain("Am I on the right track");
|
|
226
|
+
it("warm intro close is 'Good to meet you.', invite is warm", () => {
|
|
227
|
+
const greeting = getCannedFirstGreeting({ ...base, tone: "warm" });
|
|
228
|
+
const [intro, invite] = greeting.split("\n\n");
|
|
229
|
+
expect(intro).toBe("Hey Bob, I'm Pax. Good to meet you.");
|
|
230
|
+
expect(invite).toBe(
|
|
231
|
+
"We can start on something specific, or just talk for a bit first — honestly that tends to work out better. Either way, I'm here.",
|
|
232
|
+
);
|
|
222
233
|
});
|
|
223
234
|
|
|
224
|
-
it("
|
|
225
|
-
const greeting = getCannedFirstGreeting({
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
const paragraphs = greeting.split("\n\n");
|
|
232
|
-
expect(paragraphs.length).toBe(2);
|
|
235
|
+
it("energetic intro close is 'Let's see what you've got.', invite is energetic", () => {
|
|
236
|
+
const greeting = getCannedFirstGreeting({ ...base, tone: "energetic" });
|
|
237
|
+
const [intro, invite] = greeting.split("\n\n");
|
|
238
|
+
expect(intro).toBe("Hey Bob, I'm Pax. Let's see what you've got.");
|
|
239
|
+
expect(invite).toBe(
|
|
240
|
+
"We can jump straight into whatever you've got, or take a few minutes to just talk first. What sounds right?",
|
|
241
|
+
);
|
|
233
242
|
});
|
|
234
243
|
|
|
235
|
-
it("
|
|
236
|
-
const greeting = getCannedFirstGreeting({
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
"google-calendar",
|
|
243
|
-
"github",
|
|
244
|
-
"apple-notes",
|
|
245
|
-
],
|
|
246
|
-
tasks: ["code-building", "project-management"],
|
|
247
|
-
userName: "Bob",
|
|
248
|
-
assistantName: "Pip",
|
|
249
|
-
});
|
|
250
|
-
expect(greeting).toContain("You mentioned using GitHub and Linear");
|
|
251
|
-
expect(greeting).not.toContain("Apple Notes");
|
|
252
|
-
expect(greeting).not.toContain("Notion");
|
|
244
|
+
it("poetic intro close is empty, invite is poetic", () => {
|
|
245
|
+
const greeting = getCannedFirstGreeting({ ...base, tone: "poetic" });
|
|
246
|
+
const [intro, invite] = greeting.split("\n\n");
|
|
247
|
+
expect(intro).toBe("Hey Bob, I'm Pax.");
|
|
248
|
+
expect(invite).toBe(
|
|
249
|
+
"We can start with whatever's in front of you, or just talk for a bit first. Either way.",
|
|
250
|
+
);
|
|
253
251
|
});
|
|
254
252
|
|
|
255
|
-
it("
|
|
256
|
-
const
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
tasks: ["code-building"],
|
|
260
|
-
userName: "Bob",
|
|
261
|
-
assistantName: "Pip",
|
|
253
|
+
it("each tone produces a distinct full greeting", () => {
|
|
254
|
+
const tones = ["grounded", "warm", "energetic", "poetic"];
|
|
255
|
+
const greetings = tones.map((tone) => {
|
|
256
|
+
return getCannedFirstGreeting({ ...base, tone });
|
|
262
257
|
});
|
|
263
|
-
|
|
264
|
-
expect(
|
|
258
|
+
const unique = new Set(greetings);
|
|
259
|
+
expect(unique.size).toBe(tones.length);
|
|
265
260
|
});
|
|
266
261
|
|
|
267
|
-
it("
|
|
268
|
-
const
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
userName: "Bob",
|
|
273
|
-
assistantName: "Pip",
|
|
262
|
+
it("each tone produces distinct invite text", () => {
|
|
263
|
+
const tones = ["grounded", "warm", "energetic", "poetic"];
|
|
264
|
+
const invites = tones.map((tone) => {
|
|
265
|
+
const greeting = getCannedFirstGreeting({ ...base, tone });
|
|
266
|
+
return greeting.split("\n\n")[1];
|
|
274
267
|
});
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
);
|
|
278
|
-
expect(greeting).toContain("juggling travel, bills, or household stuff");
|
|
268
|
+
const unique = new Set(invites);
|
|
269
|
+
expect(unique.size).toBe(tones.length);
|
|
279
270
|
});
|
|
271
|
+
});
|
|
280
272
|
|
|
281
|
-
|
|
273
|
+
describe("tasks and tools fields are ignored", () => {
|
|
274
|
+
it("tasks do not appear in output", () => {
|
|
282
275
|
const greeting = getCannedFirstGreeting({
|
|
283
|
-
|
|
284
|
-
|
|
276
|
+
tools: ["github", "linear"],
|
|
277
|
+
tasks: ["code-building", "project-management"],
|
|
278
|
+
tone: "grounded",
|
|
279
|
+
userName: "Alice",
|
|
280
|
+
assistantName: "Pax",
|
|
285
281
|
});
|
|
286
|
-
expect(greeting).toContain("
|
|
287
|
-
expect(greeting).not.toContain("
|
|
282
|
+
expect(greeting).not.toContain("GitHub");
|
|
283
|
+
expect(greeting).not.toContain("Linear");
|
|
284
|
+
expect(greeting).not.toContain("code");
|
|
285
|
+
expect(greeting).not.toContain("shipping");
|
|
286
|
+
expect(greeting).not.toContain("You mentioned using");
|
|
287
|
+
expect(greeting).not.toContain("wear a lot of hats");
|
|
288
|
+
expect(greeting).not.toContain("Am I on the right track");
|
|
288
289
|
});
|
|
289
290
|
|
|
290
|
-
it("
|
|
291
|
+
it("tools do not appear in output", () => {
|
|
291
292
|
const greeting = getCannedFirstGreeting({
|
|
292
|
-
|
|
293
|
-
tasks: ["
|
|
293
|
+
tools: ["gmail", "google-calendar", "slack", "notion"],
|
|
294
|
+
tasks: ["scheduling", "personal", "writing", "research"],
|
|
295
|
+
tone: "warm",
|
|
294
296
|
userName: "Bob",
|
|
295
|
-
assistantName: "
|
|
297
|
+
assistantName: "Remy",
|
|
296
298
|
});
|
|
297
|
-
expect(greeting).toContain("
|
|
298
|
-
expect(greeting).not.toContain("
|
|
299
|
+
expect(greeting).not.toContain("Gmail");
|
|
300
|
+
expect(greeting).not.toContain("Google Calendar");
|
|
301
|
+
expect(greeting).not.toContain("Slack");
|
|
302
|
+
expect(greeting).not.toContain("Notion");
|
|
303
|
+
expect(greeting).not.toContain("scheduling");
|
|
304
|
+
expect(greeting).not.toContain("personal");
|
|
299
305
|
});
|
|
300
306
|
});
|
|
301
307
|
});
|
|
@@ -1,18 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Mock Chrome extension test fixture.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* `host_browser_request` frames by calling a mock CDP proxy, and POSTs
|
|
4
|
+
* Subscribes to the runtime's `/events` SSE endpoint (registering in the
|
|
5
|
+
* client registry with `interfaceId: "chrome-extension"`), handles incoming
|
|
6
|
+
* `host_browser_request` events by calling a mock CDP proxy, and POSTs
|
|
8
7
|
* the result back to `/v1/host-browser-result`.
|
|
9
8
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
9
|
+
* Optionally opens a WebSocket to `/v1/browser-relay` for sending inbound
|
|
10
|
+
* frames (events, session-invalidation, keepalive) and for the WS result
|
|
11
|
+
* transport variant.
|
|
12
12
|
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
* end-to-end.
|
|
13
|
+
* Used by e2e tests to exercise the full round-trip without requiring a
|
|
14
|
+
* real Chrome browser or the real extension worker.
|
|
16
15
|
*/
|
|
17
16
|
|
|
18
17
|
// ── Types ───────────────────────────────────────────────────────────
|
|
@@ -73,13 +72,14 @@ export interface MockChromeExtensionOptions {
|
|
|
73
72
|
* - "http" (default): POST to `/v1/host-browser-result`.
|
|
74
73
|
* - "ws": send a `host_browser_result` frame back over the same
|
|
75
74
|
* `/v1/browser-relay` WebSocket that delivered the request.
|
|
76
|
-
*
|
|
77
|
-
* Both transports are expected to be fully functional in the runtime.
|
|
78
|
-
* The HTTP path is the legacy transport; the WS path was added so the
|
|
79
|
-
* extension can avoid an extra round-trip through the cloud ingress
|
|
80
|
-
* stack for each CDP command.
|
|
81
75
|
*/
|
|
82
76
|
resultTransport?: "http" | "ws";
|
|
77
|
+
/**
|
|
78
|
+
* Separate JWT for SSE `/events` auth. When the primary `token` is a
|
|
79
|
+
* capability token (not a JWT), provide a real JWT here so the SSE
|
|
80
|
+
* endpoint accepts the connection.
|
|
81
|
+
*/
|
|
82
|
+
sseToken?: string;
|
|
83
83
|
}
|
|
84
84
|
|
|
85
85
|
export interface MockChromeExtension {
|
|
@@ -172,9 +172,12 @@ export function createMockChromeExtension(
|
|
|
172
172
|
const baseHttp = options.runtimeBaseUrl.replace(/\/$/, "");
|
|
173
173
|
const wsBase = baseHttp.replace(/^http/i, "ws");
|
|
174
174
|
const wsUrl = `${wsBase}/v1/browser-relay?token=${encodeURIComponent(options.token)}`;
|
|
175
|
+
const clientId = `mock-ext-${crypto.randomUUID()}`;
|
|
175
176
|
|
|
176
177
|
let ws: WebSocket | null = null;
|
|
177
|
-
let
|
|
178
|
+
let wsConnected = false;
|
|
179
|
+
let sseAbort: AbortController | null = null;
|
|
180
|
+
let sseConnected = false;
|
|
178
181
|
let handler = options.cdpHandler ?? defaultCdpHandler;
|
|
179
182
|
const receivedRequests: HostBrowserRequestFrame[] = [];
|
|
180
183
|
const receivedCancels: HostBrowserCancelFrame[] = [];
|
|
@@ -197,9 +200,6 @@ export function createMockChromeExtension(
|
|
|
197
200
|
} finally {
|
|
198
201
|
inFlight.delete(frame.requestId);
|
|
199
202
|
}
|
|
200
|
-
// If the request was aborted mid-flight, drop the result entirely
|
|
201
|
-
// (mirroring the production dispatcher, which doesn't POST a result
|
|
202
|
-
// for cancelled requests).
|
|
203
203
|
if (abortCtl.signal.aborted) return;
|
|
204
204
|
|
|
205
205
|
const body: HostBrowserResultBody = {
|
|
@@ -208,21 +208,12 @@ export function createMockChromeExtension(
|
|
|
208
208
|
isError: result.isError,
|
|
209
209
|
};
|
|
210
210
|
if (resultTransport === "ws") {
|
|
211
|
-
// Send the result back over the same `/v1/browser-relay` socket
|
|
212
|
-
// that delivered the request. The runtime WS message handler
|
|
213
|
-
// parses `host_browser_result` frames and resolves the pending
|
|
214
|
-
// interaction via the same core resolver the HTTP endpoint uses.
|
|
215
211
|
const sock = ws;
|
|
216
212
|
if (sock && sock.readyState === WebSocket.OPEN) {
|
|
217
213
|
try {
|
|
218
|
-
sock.send(
|
|
219
|
-
JSON.stringify({
|
|
220
|
-
type: "host_browser_result",
|
|
221
|
-
...body,
|
|
222
|
-
}),
|
|
223
|
-
);
|
|
214
|
+
sock.send(JSON.stringify({ type: "host_browser_result", ...body }));
|
|
224
215
|
} catch {
|
|
225
|
-
//
|
|
216
|
+
// best-effort
|
|
226
217
|
}
|
|
227
218
|
}
|
|
228
219
|
return;
|
|
@@ -236,14 +227,13 @@ export function createMockChromeExtension(
|
|
|
236
227
|
},
|
|
237
228
|
body: JSON.stringify(body),
|
|
238
229
|
});
|
|
239
|
-
// Consume the body so Bun doesn't leak the response handle.
|
|
240
230
|
await res.body?.cancel();
|
|
241
231
|
} catch {
|
|
242
|
-
//
|
|
243
|
-
// will throw. Tests assert on proxy behaviour, not POST success.
|
|
232
|
+
// best-effort
|
|
244
233
|
}
|
|
245
234
|
}
|
|
246
235
|
|
|
236
|
+
/** Handle an incoming message (from SSE event or WS frame). */
|
|
247
237
|
function handleMessage(raw: string): void {
|
|
248
238
|
let parsed: unknown;
|
|
249
239
|
try {
|
|
@@ -269,43 +259,92 @@ export function createMockChromeExtension(
|
|
|
269
259
|
}
|
|
270
260
|
return;
|
|
271
261
|
}
|
|
272
|
-
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/** Start SSE connection to /events — registers in client registry and
|
|
265
|
+
* receives outbound host_browser events from the event hub. */
|
|
266
|
+
async function startSse(): Promise<void> {
|
|
267
|
+
sseAbort = new AbortController();
|
|
268
|
+
const sseUrl = `${baseHttp}/v1/events`;
|
|
269
|
+
const res = await fetch(sseUrl, {
|
|
270
|
+
headers: {
|
|
271
|
+
Accept: "text/event-stream",
|
|
272
|
+
Authorization: `Bearer ${options.sseToken ?? options.token}`,
|
|
273
|
+
"X-Vellum-Client-Id": clientId,
|
|
274
|
+
"X-Vellum-Interface-Id": "chrome-extension",
|
|
275
|
+
},
|
|
276
|
+
signal: sseAbort.signal,
|
|
277
|
+
});
|
|
278
|
+
if (!res.ok || !res.body) {
|
|
279
|
+
throw new Error(`SSE connect failed: ${res.status}`);
|
|
280
|
+
}
|
|
281
|
+
sseConnected = true;
|
|
282
|
+
|
|
283
|
+
// Read SSE stream in the background
|
|
284
|
+
const reader = res.body.getReader();
|
|
285
|
+
const decoder = new TextDecoder();
|
|
286
|
+
let buffer = "";
|
|
287
|
+
void (async () => {
|
|
288
|
+
try {
|
|
289
|
+
while (true) {
|
|
290
|
+
const { done, value } = await reader.read();
|
|
291
|
+
if (done) break;
|
|
292
|
+
buffer += decoder.decode(value, { stream: true });
|
|
293
|
+
// Parse SSE frames: "data: ...\n\n"
|
|
294
|
+
const parts = buffer.split("\n\n");
|
|
295
|
+
buffer = parts.pop() ?? "";
|
|
296
|
+
for (const part of parts) {
|
|
297
|
+
const lines = part.split("\n");
|
|
298
|
+
for (const line of lines) {
|
|
299
|
+
if (line.startsWith("data: ")) {
|
|
300
|
+
const data = line.slice(6);
|
|
301
|
+
// SSE data is JSON-encoded AssistantEvent; extract
|
|
302
|
+
// the message field
|
|
303
|
+
try {
|
|
304
|
+
const event = JSON.parse(data) as {
|
|
305
|
+
message?: unknown;
|
|
306
|
+
};
|
|
307
|
+
if (event.message) {
|
|
308
|
+
handleMessage(JSON.stringify(event.message));
|
|
309
|
+
}
|
|
310
|
+
} catch {
|
|
311
|
+
// skip malformed SSE data
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
} catch {
|
|
318
|
+
// SSE stream ended (abort or server shutdown)
|
|
319
|
+
} finally {
|
|
320
|
+
sseConnected = false;
|
|
321
|
+
}
|
|
322
|
+
})();
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
/** Start the optional WS connection for sending inbound frames. */
|
|
326
|
+
async function startWs(): Promise<void> {
|
|
327
|
+
const wsOptions: { headers?: Record<string, string> } = {};
|
|
328
|
+
if (options.extraHandshakeHeaders) {
|
|
329
|
+
wsOptions.headers = options.extraHandshakeHeaders;
|
|
330
|
+
}
|
|
331
|
+
ws = new WebSocket(wsUrl, wsOptions as unknown as string | string[]);
|
|
332
|
+
ws.addEventListener("open", () => {
|
|
333
|
+
wsConnected = true;
|
|
334
|
+
});
|
|
335
|
+
ws.addEventListener("close", () => {
|
|
336
|
+
wsConnected = false;
|
|
337
|
+
});
|
|
273
338
|
}
|
|
274
339
|
|
|
275
340
|
return {
|
|
276
341
|
async start() {
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
// object with a `headers` field (a Bun-specific extension of the
|
|
280
|
-
// standard WebSocket API). We forward `extraHandshakeHeaders`
|
|
281
|
-
// through it so tests using service tokens can supply the
|
|
282
|
-
// `x-guardian-id` fallback expected by `/v1/browser-relay`.
|
|
283
|
-
//
|
|
284
|
-
// We cast through `unknown` because the DOM `WebSocket` type only
|
|
285
|
-
// knows about `(url, protocols)`. If this fixture is ever run in
|
|
286
|
-
// an environment that isn't Bun, the options object would be
|
|
287
|
-
// silently ignored — acceptable for a test fixture.
|
|
288
|
-
const wsOptions: { headers?: Record<string, string> } = {};
|
|
289
|
-
if (options.extraHandshakeHeaders) {
|
|
290
|
-
wsOptions.headers = options.extraHandshakeHeaders;
|
|
291
|
-
}
|
|
292
|
-
ws = new WebSocket(wsUrl, wsOptions as unknown as string | string[]);
|
|
293
|
-
ws.addEventListener("open", () => {
|
|
294
|
-
connected = true;
|
|
295
|
-
});
|
|
296
|
-
ws.addEventListener("message", (ev: MessageEvent) => {
|
|
297
|
-
const data = ev.data;
|
|
298
|
-
if (typeof data === "string") {
|
|
299
|
-
handleMessage(data);
|
|
300
|
-
} else if (data instanceof ArrayBuffer) {
|
|
301
|
-
handleMessage(new TextDecoder().decode(data));
|
|
302
|
-
}
|
|
303
|
-
});
|
|
304
|
-
ws.addEventListener("close", () => {
|
|
305
|
-
connected = false;
|
|
306
|
-
});
|
|
342
|
+
await startSse();
|
|
343
|
+
await startWs();
|
|
307
344
|
},
|
|
308
345
|
async stop() {
|
|
346
|
+
sseAbort?.abort();
|
|
347
|
+
sseAbort = null;
|
|
309
348
|
const sock = ws;
|
|
310
349
|
ws = null;
|
|
311
350
|
if (sock) {
|
|
@@ -322,10 +361,10 @@ export function createMockChromeExtension(
|
|
|
322
361
|
},
|
|
323
362
|
async waitForConnection(timeoutMs = 2000) {
|
|
324
363
|
const deadline = Date.now() + timeoutMs;
|
|
325
|
-
while (!
|
|
364
|
+
while (!sseConnected || !wsConnected) {
|
|
326
365
|
if (Date.now() > deadline) {
|
|
327
366
|
throw new Error(
|
|
328
|
-
`mock-chrome-extension: timed out waiting for
|
|
367
|
+
`mock-chrome-extension: timed out waiting for connection (SSE=${sseConnected}, WS=${wsConnected}) after ${timeoutMs}ms`,
|
|
329
368
|
);
|
|
330
369
|
}
|
|
331
370
|
await new Promise((r) => setTimeout(r, 10));
|
|
@@ -341,9 +380,12 @@ export function createMockChromeExtension(
|
|
|
341
380
|
handler = next;
|
|
342
381
|
},
|
|
343
382
|
forceDisconnect() {
|
|
383
|
+
sseAbort?.abort();
|
|
384
|
+
sseAbort = null;
|
|
385
|
+
sseConnected = false;
|
|
344
386
|
const sock = ws;
|
|
345
387
|
ws = null;
|
|
346
|
-
|
|
388
|
+
wsConnected = false;
|
|
347
389
|
if (sock) {
|
|
348
390
|
try {
|
|
349
391
|
sock.close(4000, "forced disconnect");
|