@vellumai/assistant 0.6.2 → 0.6.4
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 +273 -10
- package/Dockerfile +2 -3
- package/bun.lock +41 -49
- package/bunfig.toml +3 -0
- package/docs/architecture/memory.md +1 -1
- package/docs/backup-troubleshooting.md +52 -0
- package/docs/browser-use-architecture-phase2.md +174 -0
- package/docs/stt-provider-onboarding.md +120 -0
- package/knip.json +12 -2
- package/node_modules/@vellumai/ces-contracts/bun.lock +8 -6
- package/node_modules/@vellumai/ces-contracts/package.json +3 -3
- package/node_modules/@vellumai/ces-contracts/src/rpc.ts +42 -0
- package/openapi.yaml +1111 -86
- package/package.json +40 -42
- package/scripts/generate-openapi.ts +0 -2
- package/scripts/test.sh +73 -18
- package/src/__tests__/acp-session.test.ts +43 -0
- package/src/__tests__/agent-image-optimize.test.ts +28 -0
- package/src/__tests__/agent-loop.test.ts +123 -0
- package/src/__tests__/anthropic-provider.test.ts +263 -10
- package/src/__tests__/app-builder-tool-scripts.test.ts +1 -0
- package/src/__tests__/app-executors.test.ts +1 -0
- package/src/__tests__/app-source-watcher.test.ts +37 -11
- package/src/__tests__/approval-routes-http.test.ts +178 -1
- package/src/__tests__/auto-analysis-end-to-end.test.ts +550 -0
- package/src/__tests__/auto-analysis-prompt.test.ts +50 -0
- package/src/__tests__/browser-fill-credential.test.ts +240 -94
- package/src/__tests__/browser-manager.test.ts +40 -27
- package/src/__tests__/browser-skill-baseline-tool-payload.test.ts +2 -2
- package/src/__tests__/browser-skill-endstate.test.ts +31 -7
- package/src/__tests__/btw-routes.test.ts +7 -0
- package/src/__tests__/call-controller.test.ts +581 -20
- package/src/__tests__/catalog-files.test.ts +1000 -0
- package/src/__tests__/channel-approvals.test.ts +53 -0
- package/src/__tests__/channel-invite-transport.test.ts +2 -2
- package/src/__tests__/channel-readiness-routes.test.ts +16 -20
- package/src/__tests__/channel-readiness-service.test.ts +12 -7
- package/src/__tests__/checker.test.ts +157 -10
- package/src/__tests__/clawhub-files.test.ts +347 -0
- package/src/__tests__/commit-message-enrichment-service.test.ts +36 -19
- package/src/__tests__/config-analysis.test.ts +100 -0
- package/src/__tests__/config-managed-gemini-defaults.test.ts +326 -0
- package/src/__tests__/config-schema-cmd.test.ts +2 -2
- package/src/__tests__/config-schema.test.ts +1248 -224
- package/src/__tests__/config-watcher-cleanup-throttle.test.ts +339 -0
- package/src/__tests__/config-watcher.test.ts +43 -8
- package/src/__tests__/confirmation-request-guardian-bridge.test.ts +23 -0
- package/src/__tests__/contact-store-user-file.test.ts +512 -0
- package/src/__tests__/contacts-write.test.ts +197 -0
- package/src/__tests__/context-overflow-approval.test.ts +16 -1
- package/src/__tests__/context-window-manager.test.ts +88 -0
- package/src/__tests__/conversation-abort-tool-results.test.ts +2 -0
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +2 -1
- package/src/__tests__/conversation-agent-loop.test.ts +99 -3
- package/src/__tests__/conversation-analysis-routes.test.ts +2 -2
- package/src/__tests__/conversation-attachments.test.ts +80 -4
- package/src/__tests__/conversation-confirmation-signals.test.ts +290 -0
- package/src/__tests__/conversation-error.test.ts +70 -0
- package/src/__tests__/conversation-fork-crud.test.ts +17 -0
- package/src/__tests__/conversation-history-web-search.test.ts +12 -4
- package/src/__tests__/conversation-host-access-routes.test.ts +229 -0
- package/src/__tests__/conversation-init.benchmark.test.ts +6 -1
- package/src/__tests__/conversation-inject-context.test.ts +103 -0
- package/src/__tests__/conversation-launcher-skill-regression.test.ts +51 -0
- package/src/__tests__/conversation-list-source.test.ts +145 -0
- package/src/__tests__/conversation-pre-run-repair.test.ts +2 -0
- package/src/__tests__/conversation-provider-retry-repair.test.ts +2 -0
- package/src/__tests__/conversation-queue.test.ts +946 -62
- package/src/__tests__/conversation-routes-disk-view.test.ts +275 -0
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +16 -0
- package/src/__tests__/conversation-routes-slash-commands.test.ts +1 -0
- package/src/__tests__/conversation-runtime-assembly.test.ts +324 -46
- package/src/__tests__/conversation-skill-tools.test.ts +7 -4
- package/src/__tests__/conversation-slash-commands.test.ts +33 -0
- package/src/__tests__/conversation-slash-queue.test.ts +89 -18
- package/src/__tests__/conversation-slash-unknown.test.ts +2 -0
- package/src/__tests__/conversation-starter-routes.test.ts +126 -0
- package/src/__tests__/conversation-starters-cadence.test.ts +161 -0
- package/src/__tests__/conversation-store.test.ts +195 -0
- package/src/__tests__/conversation-tool-setup-batch-authorized.test.ts +226 -0
- package/src/__tests__/conversation-workspace-cache-state.test.ts +193 -0
- package/src/__tests__/conversation-workspace-injection.test.ts +2 -0
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +2 -0
- package/src/__tests__/credential-execution-approval-bridge.test.ts +32 -1
- package/src/__tests__/credential-health-service.test.ts +352 -0
- package/src/__tests__/credential-security-invariants.test.ts +6 -3
- package/src/__tests__/credential-vault-unit.test.ts +383 -7
- package/src/__tests__/credential-vault.test.ts +152 -13
- package/src/__tests__/credentials-cli.test.ts +42 -18
- package/src/__tests__/cross-provider-web-search.test.ts +146 -35
- package/src/__tests__/date-context.test.ts +4 -4
- package/src/__tests__/deterministic-verification-control-plane.test.ts +10 -1
- package/src/__tests__/device-id.test.ts +112 -0
- package/src/__tests__/docker-signing-key-bootstrap.test.ts +167 -4
- package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +1 -3
- package/src/__tests__/email-html-renderer.test.ts +71 -0
- package/src/__tests__/email-invite-adapter.test.ts +36 -32
- package/src/__tests__/embedding-managed-proxy-selection.test.ts +256 -0
- package/src/__tests__/emit-event-signal.test.ts +71 -0
- package/src/__tests__/extension-id-sync-guard.test.ts +222 -0
- package/src/__tests__/fixtures/mock-chrome-extension.ts +386 -0
- package/src/__tests__/gateway-only-enforcement.test.ts +206 -1
- package/src/__tests__/gateway-only-guard.test.ts +2 -0
- package/src/__tests__/gemini-provider.test.ts +66 -2
- package/src/__tests__/get-skill-detail-audit.test.ts +325 -0
- package/src/__tests__/gmail-archive-fallback.test.ts +193 -0
- package/src/__tests__/gmail-archive-gate.test.ts +246 -0
- package/src/__tests__/gmail-preferences.test.ts +117 -0
- package/src/__tests__/guardian-routing-invariants.test.ts +70 -2
- package/src/__tests__/headless-browser-interactions.test.ts +738 -359
- package/src/__tests__/headless-browser-mode.test.ts +614 -0
- package/src/__tests__/headless-browser-navigate.test.ts +528 -49
- package/src/__tests__/headless-browser-read-tools.test.ts +274 -100
- package/src/__tests__/headless-browser-snapshot.test.ts +250 -77
- package/src/__tests__/heartbeat-service.test.ts +70 -17
- package/src/__tests__/home-state-routes.test.ts +162 -0
- package/src/__tests__/host-bash-proxy.test.ts +145 -1
- package/src/__tests__/host-browser-e2e-cloud.test.ts +596 -0
- package/src/__tests__/host-browser-e2e-self-hosted-capability.test.ts +286 -0
- package/src/__tests__/host-browser-e2e-self-hosted.test.ts +374 -0
- package/src/__tests__/host-browser-event-routes.test.ts +350 -0
- package/src/__tests__/host-browser-proxy.test.ts +444 -0
- package/src/__tests__/host-browser-routes.test.ts +198 -0
- package/src/__tests__/host-browser-ws-events-e2e.test.ts +423 -0
- package/src/__tests__/host-cu-proxy.test.ts +166 -1
- package/src/__tests__/host-file-proxy.test.ts +185 -1
- package/src/__tests__/host-file-read-tool.test.ts +52 -0
- package/src/__tests__/host-proxy-interface.test.ts +165 -0
- package/src/__tests__/host-shell-tool.test.ts +1 -11
- package/src/__tests__/http-user-message-parity.test.ts +1 -0
- package/src/__tests__/identity-intro-cache.test.ts +40 -10
- package/src/__tests__/init-feature-flag-overrides.test.ts +38 -112
- package/src/__tests__/integration-status.test.ts +6 -7
- package/src/__tests__/jobs-store-upsert-debounced.test.ts +141 -0
- package/src/__tests__/list-messages-tool-merge.test.ts +37 -12
- package/src/__tests__/llm-context-normalization.test.ts +488 -0
- package/src/__tests__/llm-context-route-provider.test.ts +86 -5
- package/src/__tests__/llm-usage-store.test.ts +363 -0
- package/src/__tests__/mcp-client-auth.test.ts +40 -4
- package/src/__tests__/mcp-health-check.test.ts +10 -3
- package/src/__tests__/media-stream-output.test.ts +555 -0
- package/src/__tests__/media-stream-parser.test.ts +374 -0
- package/src/__tests__/media-stream-server-integration.test.ts +1234 -0
- package/src/__tests__/media-stream-stt-session.test.ts +588 -0
- package/src/__tests__/media-turn-detector.test.ts +440 -0
- package/src/__tests__/message-queue.test.ts +125 -0
- package/src/__tests__/migration-cross-version-compatibility.test.ts +3 -1
- package/src/__tests__/migration-export-http.test.ts +67 -8
- package/src/__tests__/migration-export-streaming.test.ts +66 -0
- package/src/__tests__/migration-import-commit-http.test.ts +109 -7
- package/src/__tests__/migration-import-preflight-http.test.ts +6 -5
- package/src/__tests__/migration-validate-http.test.ts +3 -3
- package/src/__tests__/mock-gateway-ipc.ts +151 -0
- package/src/__tests__/model-intents.test.ts +2 -2
- package/src/__tests__/native-host-marker-sync-guard.test.ts +157 -0
- package/src/__tests__/oauth-apps-routes.test.ts +18 -12
- package/src/__tests__/oauth-cli.test.ts +709 -60
- package/src/__tests__/oauth-connect-orchestrator.test.ts +118 -24
- package/src/__tests__/oauth-provider-seed-logos.test.ts +23 -0
- package/src/__tests__/oauth-provider-serializer.test.ts +147 -10
- package/src/__tests__/oauth-provider-visibility.test.ts +19 -21
- package/src/__tests__/oauth-providers-routes.test.ts +52 -14
- package/src/__tests__/oauth-store.test.ts +1465 -176
- package/src/__tests__/oauth2-gateway-transport.test.ts +460 -26
- package/src/__tests__/onboarding-template-contract.test.ts +81 -70
- package/src/__tests__/openai-provider.test.ts +178 -2
- package/src/__tests__/openai-responses-cutover-guard.test.ts +184 -0
- package/src/__tests__/openai-responses-provider.test.ts +1105 -0
- package/src/__tests__/openrouter-token-estimation.test.ts +100 -0
- package/src/__tests__/outlook-categories.test.ts +1 -1
- package/src/__tests__/outlook-client-automation.test.ts +1 -1
- package/src/__tests__/outlook-compose-tools.test.ts +1 -1
- package/src/__tests__/outlook-email-watcher.test.ts +1 -1
- package/src/__tests__/outlook-follow-up.test.ts +1 -1
- package/src/__tests__/outlook-messaging-provider.test.ts +2 -2
- package/src/__tests__/outlook-trash.test.ts +1 -1
- package/src/__tests__/outlook-unsubscribe.test.ts +32 -3
- package/src/__tests__/permission-checker-host-gate.test.ts +74 -14
- package/src/__tests__/permission-mode.test.ts +28 -56
- package/src/__tests__/persona-resolver.test.ts +251 -0
- package/src/__tests__/platform-bash-auto-approve.test.ts +4 -0
- package/src/__tests__/platform-callback-registration.test.ts +19 -0
- package/src/__tests__/platform.test.ts +92 -1
- package/src/__tests__/post-turn-tool-result-truncation.test.ts +343 -0
- package/src/__tests__/prechat-onboarding-contract.test.ts +267 -0
- package/src/__tests__/pricing.test.ts +174 -0
- package/src/__tests__/proxy-approval-callback.test.ts +18 -0
- package/src/__tests__/qdrant-manager.test.ts +29 -8
- package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +194 -0
- package/src/__tests__/relationship-state-contract.test.ts +175 -0
- package/src/__tests__/relay-server.test.ts +423 -5
- package/src/__tests__/require-fresh-approval.test.ts +40 -1
- package/src/__tests__/sanitize-config-for-transfer.test.ts +132 -0
- package/src/__tests__/schedule-routes.test.ts +162 -0
- package/src/__tests__/search-skills-unified.test.ts +118 -0
- package/src/__tests__/secret-detection-handler.test.ts +84 -0
- package/src/__tests__/secret-ingress-http.test.ts +1 -0
- package/src/__tests__/secret-scanner-executor.test.ts +4 -0
- package/src/__tests__/secure-keys.test.ts +107 -0
- package/src/__tests__/send-endpoint-busy.test.ts +8 -1
- package/src/__tests__/sequence-store.test.ts +1 -1
- package/src/__tests__/server-history-render.test.ts +49 -0
- package/src/__tests__/set-permission-mode.test.ts +13 -250
- package/src/__tests__/settings-routes.test.ts +201 -0
- package/src/__tests__/skill-load-feature-flag.test.ts +1 -0
- package/src/__tests__/skills-file-content-endpoint.test.ts +801 -0
- package/src/__tests__/skills-files-catalog-fallback.test.ts +738 -0
- package/src/__tests__/skills.test.ts +5 -2
- package/src/__tests__/skillssh-files.test.ts +446 -0
- package/src/__tests__/slack-block-formatting.test.ts +110 -0
- package/src/__tests__/slack-channel-config.test.ts +576 -16
- package/src/__tests__/stt-catalog-parity.test.ts +282 -0
- package/src/__tests__/stt-stream-session.test.ts +535 -0
- package/src/__tests__/subagent-detail.test.ts +44 -2
- package/src/__tests__/subagent-disposal.test.ts +1 -0
- package/src/__tests__/subagent-fork-notifications.test.ts +291 -0
- package/src/__tests__/subagent-fork-spawn.test.ts +384 -0
- package/src/__tests__/subagent-manager-notify.test.ts +1 -0
- package/src/__tests__/subagent-notify-parent.test.ts +1 -0
- package/src/__tests__/subagent-spawn-tool-fork.test.ts +411 -0
- package/src/__tests__/subagent-tools.test.ts +1 -0
- package/src/__tests__/subagent-types.test.ts +1 -0
- package/src/__tests__/system-prompt-ask-mode.test.ts +27 -71
- package/src/__tests__/system-prompt.test.ts +184 -27
- package/src/__tests__/task-scheduler.test.ts +32 -6
- package/src/__tests__/telegram-config.test.ts +10 -13
- package/src/__tests__/telephony-stt-routing.test.ts +329 -0
- package/src/__tests__/terminal-tools.test.ts +25 -5
- package/src/__tests__/test-preload.ts +18 -0
- package/src/__tests__/test-support/browser-skill-harness.ts +4 -1
- package/src/__tests__/tool-approval-handler.test.ts +73 -0
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +9 -5
- package/src/__tests__/tool-executor-shell-integration.test.ts +4 -0
- package/src/__tests__/tool-executor.test.ts +33 -24
- package/src/__tests__/tool-result-truncation.test.ts +36 -0
- package/src/__tests__/tool-side-effects-slack-dm.test.ts +22 -0
- package/src/__tests__/top-level-renderer.test.ts +73 -1
- package/src/__tests__/transport-hints-queue.test.ts +14 -29
- package/src/__tests__/trust-store.test.ts +7 -1
- package/src/__tests__/trusted-contact-approval-notifier.test.ts +1 -1
- package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +109 -0
- package/src/__tests__/tts-catalog-parity.test.ts +345 -0
- package/src/__tests__/twilio-routes-twiml.test.ts +512 -114
- package/src/__tests__/twilio-routes.test.ts +376 -0
- package/src/__tests__/unicode.test.ts +293 -0
- package/src/__tests__/update-bulletin-format.test.ts +59 -0
- package/src/__tests__/update-bulletin.test.ts +206 -5
- package/src/__tests__/usage-routes.test.ts +25 -4
- package/src/__tests__/user-reference.test.ts +46 -61
- package/src/__tests__/v2-consent-policy.test.ts +103 -0
- package/src/__tests__/verification-control-plane-policy.test.ts +4 -0
- package/src/__tests__/voice-config-update.test.ts +403 -0
- package/src/__tests__/voice-quality.test.ts +434 -19
- package/src/__tests__/workspace-heartbeat-service.test.ts +7 -0
- package/src/__tests__/workspace-migration-033-stt-service-explicit-config.test.ts +547 -0
- package/src/__tests__/workspace-migration-034-remove-calls-voice-transcription-provider.test.ts +596 -0
- package/src/__tests__/workspace-migration-drop-user-md.test.ts +368 -0
- package/src/__tests__/workspace-migration-meets.test.ts +244 -0
- package/src/__tests__/workspace-migration-seed-device-id.test.ts +14 -20
- package/src/__tests__/workspace-policy.test.ts +2 -0
- package/src/acp/client-handler.ts +30 -4
- package/src/agent/image-optimize.ts +24 -12
- package/src/agent/loop.ts +55 -9
- package/src/approvals/guardian-request-resolvers.ts +21 -15
- package/src/backup/__tests__/backup-key.test.ts +152 -0
- package/src/backup/__tests__/backup-worker.test.ts +767 -0
- package/src/backup/__tests__/list-snapshots.test.ts +87 -0
- package/src/backup/__tests__/local-writer.test.ts +218 -0
- package/src/backup/__tests__/offsite-writer.test.ts +641 -0
- package/src/backup/__tests__/paths.test.ts +300 -0
- package/src/backup/__tests__/restore.test.ts +498 -0
- package/src/backup/__tests__/snapshot-lock.test.ts +352 -0
- package/src/backup/__tests__/stream-crypt.test.ts +228 -0
- package/src/backup/backup-key.ts +137 -0
- package/src/backup/backup-worker.ts +459 -0
- package/src/backup/list-snapshots.ts +147 -0
- package/src/backup/local-writer.ts +133 -0
- package/src/backup/offsite-writer.ts +222 -0
- package/src/backup/paths.ts +226 -0
- package/src/backup/restore.ts +322 -0
- package/src/backup/snapshot-lock.ts +431 -0
- package/src/backup/stream-crypt.ts +263 -0
- package/src/browser-session/__tests__/manager.test.ts +297 -0
- package/src/browser-session/backends/cdp-inspect.ts +30 -0
- package/src/browser-session/backends/extension.ts +26 -0
- package/src/browser-session/backends/local.ts +24 -0
- package/src/browser-session/events.ts +164 -0
- package/src/browser-session/index.ts +27 -0
- package/src/browser-session/manager.ts +159 -0
- package/src/browser-session/types.ts +28 -0
- package/src/bundler/package-resolver.ts +4 -0
- package/src/calls/audio-store.ts +11 -5
- package/src/calls/call-controller.ts +226 -71
- package/src/calls/call-domain.ts +9 -0
- package/src/calls/call-speech-output.ts +190 -0
- package/src/calls/call-transport.ts +77 -0
- package/src/calls/media-stream-audio-transcode.ts +173 -0
- package/src/calls/media-stream-output.ts +660 -0
- package/src/calls/media-stream-parser.ts +300 -0
- package/src/calls/media-stream-protocol.ts +166 -0
- package/src/calls/media-stream-server.ts +592 -0
- package/src/calls/media-stream-stt-session.ts +460 -0
- package/src/calls/media-turn-detector.ts +230 -0
- package/src/calls/relay-server.ts +90 -75
- package/src/calls/resolve-call-tts-provider.ts +136 -0
- package/src/calls/telephony-stt-routing.ts +145 -0
- package/src/calls/tts-call-strategy.ts +161 -0
- package/src/calls/tts-text-sanitizer.ts +32 -16
- package/src/calls/twilio-routes.ts +281 -17
- package/src/calls/voice-quality.ts +78 -35
- package/src/calls/voice-session-bridge.ts +8 -1
- package/src/channels/__tests__/types.test.ts +134 -0
- package/src/channels/types.ts +69 -3
- package/src/cli/__tests__/run-assistant-command.ts +11 -1
- package/src/cli/commands/__tests__/backup.test.ts +1165 -0
- package/src/cli/commands/__tests__/domain-register.test.ts +234 -0
- package/src/cli/commands/__tests__/domain-status.test.ts +132 -0
- package/src/cli/commands/__tests__/email-attachment.test.ts +422 -0
- package/src/cli/commands/__tests__/email-download.test.ts +16 -1
- package/src/cli/commands/__tests__/email-list.test.ts +22 -4
- package/src/cli/commands/__tests__/email-register.test.ts +4 -4
- package/src/cli/commands/__tests__/email-send.test.ts +37 -4
- package/src/cli/commands/__tests__/email-status.test.ts +5 -1
- package/src/cli/commands/__tests__/email-unregister.test.ts +34 -5
- package/src/cli/commands/backup.ts +993 -0
- package/src/cli/commands/conversations.ts +77 -0
- package/src/cli/commands/credentials.ts +3 -4
- package/src/cli/commands/domain.ts +210 -0
- package/src/cli/commands/email.ts +273 -16
- package/src/cli/commands/mcp.ts +16 -4
- package/src/cli/commands/oauth/__tests__/connect.test.ts +56 -44
- package/src/cli/commands/oauth/__tests__/disconnect.test.ts +21 -21
- package/src/cli/commands/oauth/__tests__/mode.test.ts +17 -17
- package/src/cli/commands/oauth/__tests__/ping.test.ts +16 -16
- package/src/cli/commands/oauth/__tests__/providers-delete.test.ts +32 -33
- package/src/cli/commands/oauth/__tests__/providers-register.test.ts +330 -0
- package/src/cli/commands/oauth/__tests__/providers-update.test.ts +117 -12
- package/src/cli/commands/oauth/__tests__/status.test.ts +10 -10
- package/src/cli/commands/oauth/__tests__/token.test.ts +7 -7
- package/src/cli/commands/oauth/apps.ts +7 -4
- package/src/cli/commands/oauth/connect.ts +6 -3
- package/src/cli/commands/oauth/disconnect.ts +1 -1
- package/src/cli/commands/oauth/mode.ts +12 -3
- package/src/cli/commands/oauth/providers.ts +215 -36
- package/src/cli/commands/oauth/shared.ts +7 -6
- package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +254 -0
- package/src/cli/commands/platform/__tests__/connect.test.ts +6 -0
- package/src/cli/commands/platform/__tests__/disconnect.test.ts +7 -1
- package/src/cli/commands/platform/__tests__/status.test.ts +6 -0
- package/src/cli/commands/platform/index.ts +107 -10
- package/src/cli/commands/usage.ts +10 -9
- package/src/cli/lib/daemon-credential-client.ts +4 -0
- package/src/cli/program.ts +30 -4
- package/src/config/__tests__/backup-schema.test.ts +134 -0
- package/src/config/assistant-feature-flags.ts +61 -62
- package/src/config/bundled-skills/app-builder/SKILL.md +26 -249
- package/src/config/bundled-skills/app-builder/references/CUSTOM_ROUTES.md +141 -0
- package/src/config/bundled-skills/app-builder/references/INTERACTION_HOOKS.md +56 -0
- package/src/config/bundled-skills/app-builder/references/WIDGETS.md +125 -0
- package/src/config/bundled-skills/browser/SKILL.md +30 -5
- package/src/config/bundled-skills/browser/TOOLS.json +123 -0
- package/src/config/bundled-skills/browser/tools/browser-attach.ts +12 -0
- package/src/config/bundled-skills/browser/tools/browser-detach.ts +12 -0
- package/src/config/bundled-skills/browser/tools/browser-status.ts +12 -0
- package/src/config/bundled-skills/browser/tools/browser-wait-for-download.ts +17 -0
- package/src/config/bundled-skills/contacts/SKILL.md +5 -2
- package/src/config/bundled-skills/document/SKILL.md +4 -0
- package/src/config/bundled-skills/gmail/SKILL.md +54 -8
- package/src/config/bundled-skills/gmail/TOOLS.json +33 -3
- package/src/config/bundled-skills/gmail/tools/gmail-archive.ts +116 -9
- package/src/config/bundled-skills/gmail/tools/gmail-outreach-scan.ts +138 -11
- package/src/config/bundled-skills/gmail/tools/gmail-preferences-tool.ts +59 -0
- package/src/config/bundled-skills/gmail/tools/gmail-preferences.ts +82 -0
- package/src/config/bundled-skills/gmail/tools/gmail-sender-digest.ts +113 -17
- package/src/config/bundled-skills/gmail/tools/gmail-unsubscribe.ts +2 -2
- package/src/config/bundled-skills/media-processing/SKILL.md +3 -9
- package/src/config/bundled-skills/media-processing/TOOLS.json +1 -6
- package/src/config/bundled-skills/media-processing/__tests__/audio-transcribe.test.ts +125 -0
- package/src/config/bundled-skills/media-processing/__tests__/extract-keyframes.test.ts +181 -0
- package/src/config/bundled-skills/media-processing/__tests__/preprocess-audio.test.ts +141 -0
- package/src/config/bundled-skills/media-processing/services/audio-transcribe.ts +32 -87
- package/src/config/bundled-skills/media-processing/services/preprocess.ts +8 -4
- package/src/config/bundled-skills/media-processing/tools/extract-keyframes.ts +0 -10
- package/src/config/bundled-skills/messaging/SKILL.md +3 -3
- package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +2 -2
- package/src/config/bundled-skills/outlook/SKILL.md +9 -2
- package/src/config/bundled-skills/outlook/tools/outlook-unsubscribe.ts +2 -2
- package/src/config/bundled-skills/phone-calls/SKILL.md +2 -2
- package/src/config/bundled-skills/phone-calls/references/CONFIG.md +27 -18
- package/src/config/bundled-skills/phone-calls/references/TROUBLESHOOTING.md +3 -3
- package/src/config/bundled-skills/settings/TOOLS.json +3 -3
- package/src/config/bundled-skills/settings/tools/voice-config-update.ts +26 -22
- package/src/config/bundled-skills/slack/SKILL.md +1 -0
- package/src/config/bundled-skills/subagent/SKILL.md +21 -0
- package/src/config/bundled-skills/subagent/TOOLS.json +8 -4
- package/src/config/bundled-skills/tasks/SKILL.md +5 -0
- package/src/config/bundled-skills/transcribe/SKILL.md +9 -14
- package/src/config/bundled-skills/transcribe/TOOLS.json +2 -7
- package/src/config/bundled-skills/transcribe/tools/transcribe-media.test.ts +256 -0
- package/src/config/bundled-skills/transcribe/tools/transcribe-media.ts +38 -188
- package/src/config/bundled-tool-registry.ts +8 -0
- package/src/config/env-registry.ts +38 -0
- package/src/config/env.ts +49 -4
- package/src/config/feature-flag-registry.json +85 -14
- package/src/config/loader.ts +82 -13
- package/src/config/sanitize-for-transfer.ts +47 -0
- package/src/config/schema.ts +81 -15
- package/src/config/schemas/__tests__/stt.test.ts +43 -0
- package/src/config/schemas/analysis.ts +51 -0
- package/src/config/schemas/backup.ts +72 -0
- package/src/config/schemas/calls.ts +1 -26
- package/src/config/schemas/elevenlabs.ts +0 -59
- package/src/config/schemas/filing.ts +47 -7
- package/src/config/schemas/heartbeat.ts +27 -5
- package/src/config/schemas/host-browser.ts +112 -0
- package/src/config/schemas/inference.ts +1 -1
- package/src/config/schemas/memory-lifecycle.ts +14 -2
- package/src/config/schemas/memory-retrieval.ts +103 -0
- package/src/config/schemas/security.ts +0 -6
- package/src/config/schemas/services.ts +52 -0
- package/src/config/schemas/stt.ts +59 -0
- package/src/config/schemas/tts.ts +230 -0
- package/src/config/schemas/updates.ts +14 -0
- package/src/config/skills.ts +4 -0
- package/src/config/types.ts +4 -1
- package/src/contacts/contact-store.ts +56 -11
- package/src/contacts/contacts-write.ts +38 -1
- package/src/context/post-turn-tool-result-truncation.ts +177 -0
- package/src/context/tool-result-truncation.ts +2 -1
- package/src/context/window-manager.ts +61 -10
- package/src/credential-execution/approval-bridge.ts +49 -15
- package/src/credential-execution/executable-discovery.ts +12 -2
- package/src/credential-execution/process-manager.ts +33 -2
- package/src/credential-health/credential-health-service.ts +366 -0
- package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +324 -0
- package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +497 -0
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +195 -0
- package/src/daemon/__tests__/lifecycle-startup-ordering.test.ts +127 -0
- package/src/daemon/app-source-watcher.ts +35 -0
- package/src/daemon/config-watcher.ts +99 -5
- package/src/daemon/context-overflow-approval.ts +5 -0
- package/src/daemon/conversation-agent-loop-handlers.ts +23 -2
- package/src/daemon/conversation-agent-loop.ts +153 -42
- package/src/daemon/conversation-attachments.ts +40 -0
- package/src/daemon/conversation-error.ts +11 -0
- package/src/daemon/conversation-history.ts +40 -6
- package/src/daemon/conversation-launch.ts +220 -0
- package/src/daemon/conversation-lifecycle.ts +59 -9
- package/src/daemon/conversation-messaging.ts +37 -3
- package/src/daemon/conversation-notifiers.ts +5 -0
- package/src/daemon/conversation-process.ts +622 -13
- package/src/daemon/conversation-queue-manager.ts +24 -0
- package/src/daemon/conversation-runtime-assembly.ts +128 -36
- package/src/daemon/conversation-slash.ts +36 -0
- package/src/daemon/conversation-surfaces.ts +131 -40
- package/src/daemon/conversation-tool-setup.ts +99 -8
- package/src/daemon/conversation-usage.ts +7 -4
- package/src/daemon/conversation-workspace.ts +12 -0
- package/src/daemon/conversation.ts +292 -16
- package/src/daemon/date-context.ts +10 -10
- package/src/daemon/first-greeting.ts +3 -2
- package/src/daemon/handlers/config-slack-channel.ts +269 -94
- package/src/daemon/handlers/conversations.ts +13 -141
- package/src/daemon/handlers/shared.ts +80 -0
- package/src/daemon/handlers/skills.ts +483 -44
- package/src/daemon/host-bash-proxy.ts +48 -13
- package/src/daemon/host-browser-proxy.ts +192 -0
- package/src/daemon/host-cu-proxy.ts +36 -11
- package/src/daemon/host-file-proxy.ts +57 -9
- package/src/daemon/lifecycle.ts +179 -28
- package/src/daemon/message-protocol.ts +13 -0
- package/src/daemon/message-types/conversations.ts +89 -14
- package/src/daemon/message-types/home.ts +40 -0
- package/src/daemon/message-types/host-browser.ts +100 -0
- package/src/daemon/message-types/meet.ts +143 -0
- package/src/daemon/message-types/messages.ts +19 -5
- package/src/daemon/message-types/schedules.ts +34 -2
- package/src/daemon/message-types/skills.ts +26 -0
- package/src/daemon/message-types/subagents.ts +2 -0
- package/src/daemon/message-types/surfaces.ts +2 -0
- package/src/daemon/server.ts +439 -14
- package/src/daemon/shutdown-handlers.ts +32 -4
- package/src/daemon/shutdown-registry.ts +40 -0
- package/src/daemon/tool-side-effects.ts +15 -0
- package/src/daemon/transport-hints.ts +5 -24
- package/src/email/html-renderer.ts +76 -0
- package/src/heartbeat/heartbeat-service.ts +93 -7
- package/src/home/__tests__/assistant-feed-authoring.test.ts +156 -0
- package/src/home/__tests__/emit-feed-event.test.ts +169 -0
- package/src/home/__tests__/feed-scheduler.test.ts +194 -0
- package/src/home/__tests__/feed-types.test.ts +275 -0
- package/src/home/__tests__/feed-writer.test.ts +688 -0
- package/src/home/__tests__/phase5-exit-criteria.test.ts +212 -0
- package/src/home/__tests__/platform-gmail-digest.test.ts +222 -0
- package/src/home/__tests__/progress-formula.test.ts +213 -0
- package/src/home/__tests__/relationship-state-writer.test.ts +740 -0
- package/src/home/__tests__/rollup-producer.test.ts +398 -0
- package/src/home/assistant-feed-authoring.ts +124 -0
- package/src/home/emit-feed-event.ts +158 -0
- package/src/home/feed-scheduler.ts +247 -0
- package/src/home/feed-types.ts +181 -0
- package/src/home/feed-writer.ts +469 -0
- package/src/home/platform-gmail-digest.ts +163 -0
- package/src/home/progress-formula.ts +86 -0
- package/src/home/relationship-state-writer.ts +824 -0
- package/src/home/relationship-state.ts +143 -0
- package/src/home/rollup-producer.ts +384 -0
- package/src/hooks/runner.ts +7 -0
- package/src/inbound/platform-callback-registration.ts +30 -20
- package/src/inbound/public-ingress-urls.ts +12 -0
- package/src/instrument.ts +1 -1
- package/src/ipc/__tests__/cli-ipc.test.ts +200 -0
- package/src/ipc/cli-client.ts +151 -0
- package/src/ipc/cli-server.ts +234 -0
- package/src/ipc/gateway-client.ts +180 -0
- package/src/ipc/routes/index.ts +5 -0
- package/src/ipc/routes/wake-conversation.ts +19 -0
- package/src/mcp/client.ts +59 -24
- package/src/memory/__tests__/auto-analysis-enqueue.test.ts +356 -0
- package/src/memory/__tests__/auto-analysis-guard.test.ts +57 -0
- package/src/memory/__tests__/conversation-analyze-job.test.ts +232 -0
- package/src/memory/__tests__/find-analysis-conversation.test.ts +196 -0
- package/src/memory/app-store.ts +31 -1
- package/src/memory/attachments-store.ts +70 -0
- package/src/memory/auto-analysis-enqueue.ts +127 -0
- package/src/memory/auto-analysis-guard.ts +27 -0
- package/src/memory/cleanup-schedule-state.ts +37 -0
- package/src/memory/conversation-analyze-job.ts +73 -0
- package/src/memory/conversation-crud.ts +122 -0
- package/src/memory/conversation-disk-view.ts +7 -0
- package/src/memory/conversation-group-migration.ts +34 -2
- package/src/memory/conversation-queries.ts +6 -5
- package/src/memory/conversation-starters-cadence.ts +76 -0
- package/src/memory/conversation-title-service.ts +5 -2
- package/src/memory/db-init.ts +18 -0
- package/src/memory/db-maintenance.ts +108 -0
- package/src/memory/db.ts +1 -0
- package/src/memory/embedding-backend.test.ts +75 -0
- package/src/memory/embedding-backend.ts +131 -5
- package/src/memory/embedding-gemini.test.ts +54 -0
- package/src/memory/embedding-gemini.ts +20 -9
- package/src/memory/embedding-local.ts +176 -17
- package/src/memory/graph/consolidation.ts +10 -23
- package/src/memory/graph/conversation-graph-memory.ts +15 -0
- package/src/memory/graph/extraction-job.ts +15 -0
- package/src/memory/graph/extraction.test.ts +23 -0
- package/src/memory/graph/extraction.ts +8 -0
- package/src/memory/graph/retriever.ts +67 -40
- package/src/memory/graph/scoring.test.ts +186 -0
- package/src/memory/graph/scoring.ts +31 -1
- package/src/memory/graph/store.test.ts +7 -3
- package/src/memory/graph/store.ts +47 -12
- package/src/memory/graph/tools.ts +1 -1
- package/src/memory/group-crud.ts +6 -1
- package/src/memory/indexer.ts +95 -16
- package/src/memory/job-handlers/cleanup.ts +11 -8
- package/src/memory/job-handlers/conversation-starters.ts +16 -10
- package/src/memory/jobs-store.ts +64 -4
- package/src/memory/jobs-worker.ts +22 -9
- package/src/memory/llm-usage-store.ts +137 -60
- package/src/memory/migrations/213-oauth-providers-scope-separator.ts +13 -0
- package/src/memory/migrations/214-oauth-providers-refresh-url.ts +11 -0
- package/src/memory/migrations/215-oauth-providers-revoke.ts +14 -0
- package/src/memory/migrations/216-oauth-providers-token-auth-method.ts +30 -0
- package/src/memory/migrations/217-conversation-host-access.ts +40 -0
- package/src/memory/migrations/218-oauth-providers-logo-url.ts +11 -0
- package/src/memory/migrations/219-oauth-providers-token-exchange-body-format.ts +15 -0
- package/src/memory/migrations/220-normalize-user-file-by-principal.ts +190 -0
- package/src/memory/migrations/221-conversations-archived-at.ts +16 -0
- package/src/memory/migrations/index.ts +12 -0
- package/src/memory/migrations/registry.ts +16 -0
- package/src/memory/qdrant-manager.ts +43 -16
- package/src/memory/schema/conversations.ts +3 -0
- package/src/memory/schema/oauth.ts +21 -13
- package/src/memory/usage-buckets.ts +396 -0
- package/src/messaging/providers/gmail/client.ts +57 -6
- package/src/messaging/providers/slack/__tests__/adapter-token-routing.test.ts +282 -0
- package/src/messaging/providers/slack/adapter.ts +143 -38
- package/src/messaging/providers/slack/client.ts +16 -0
- package/src/messaging/providers/slack/types.ts +4 -0
- package/src/notifications/decision-engine.ts +3 -3
- package/src/notifications/signal.ts +5 -0
- package/src/oauth/AGENTS.md +76 -0
- package/src/oauth/__tests__/identity-verifier.test.ts +25 -19
- package/src/oauth/__tests__/seed-providers-managed.test.ts +32 -0
- package/src/oauth/byo-connection.test.ts +26 -9
- package/src/oauth/byo-connection.ts +10 -8
- package/src/oauth/connect-orchestrator.ts +25 -21
- package/src/oauth/connect-types.ts +3 -3
- package/src/oauth/connection-resolver.test.ts +17 -4
- package/src/oauth/connection-resolver.ts +22 -18
- package/src/oauth/connection.ts +3 -1
- package/src/oauth/manual-token-connection.ts +13 -13
- package/src/oauth/oauth-store.ts +223 -100
- package/src/oauth/platform-connection.test.ts +101 -3
- package/src/oauth/platform-connection.ts +56 -35
- package/src/oauth/provider-serializer.ts +31 -5
- package/src/oauth/revoke.ts +76 -0
- package/src/oauth/seed-providers.ts +133 -87
- package/src/oauth/token-persistence.ts +1 -1
- package/src/permissions/checker.ts +16 -6
- package/src/permissions/defaults.ts +49 -1
- package/src/permissions/permission-mode.ts +4 -11
- package/src/permissions/prompter.ts +13 -1
- package/src/permissions/trust-store.ts +3 -3
- package/src/permissions/v2-consent-policy.ts +87 -0
- package/src/permissions/workspace-policy.ts +3 -0
- package/src/platform/client.test.ts +10 -0
- package/src/platform/sync-identity.ts +129 -0
- package/src/prompts/persona-resolver.ts +126 -2
- package/src/prompts/system-prompt.ts +76 -38
- package/src/prompts/templates/BOOTSTRAP-REFERENCE.md +3 -65
- package/src/prompts/templates/BOOTSTRAP.md +59 -105
- package/src/prompts/templates/SOUL.md +3 -1
- package/src/prompts/templates/UPDATES.md +12 -0
- package/src/prompts/templates/channels/slack.md +20 -0
- package/src/prompts/update-bulletin-format.ts +26 -9
- package/src/prompts/update-bulletin.ts +34 -23
- package/src/prompts/user-reference.ts +20 -17
- package/src/providers/__tests__/provider-secret-catalog.test.ts +42 -0
- package/src/providers/anthropic/client.ts +157 -60
- package/src/providers/fireworks/client.ts +2 -2
- package/src/providers/gemini/client.ts +9 -1
- package/src/providers/model-catalog.ts +6 -0
- package/src/providers/model-intents.ts +4 -4
- package/src/providers/ollama/client.ts +2 -2
- package/src/providers/openai/chat-completions-provider.ts +474 -0
- package/src/providers/openai/client.ts +25 -440
- package/src/providers/openai/responses-provider.ts +502 -0
- package/src/providers/openrouter/client.ts +101 -4
- package/src/providers/provider-secret-catalog.ts +139 -0
- package/src/providers/registry.ts +2 -2
- package/src/providers/retry.ts +14 -3
- package/src/providers/speech-to-text/__tests__/provider-catalog.test.ts +251 -0
- package/src/providers/speech-to-text/__tests__/resolve.test.ts +828 -0
- package/src/providers/speech-to-text/deepgram-realtime.test.ts +980 -0
- package/src/providers/speech-to-text/deepgram-realtime.ts +767 -0
- package/src/providers/speech-to-text/deepgram.test.ts +332 -0
- package/src/providers/speech-to-text/deepgram.ts +115 -0
- package/src/providers/speech-to-text/google-gemini-live-stream.test.ts +743 -0
- package/src/providers/speech-to-text/google-gemini-live-stream.ts +625 -0
- package/src/providers/speech-to-text/google-gemini.test.ts +226 -0
- package/src/providers/speech-to-text/google-gemini.ts +101 -0
- package/src/providers/speech-to-text/openai-whisper-stream.test.ts +564 -0
- package/src/providers/speech-to-text/openai-whisper-stream.ts +381 -0
- package/src/providers/speech-to-text/openai-whisper.test.ts +1 -37
- package/src/providers/speech-to-text/openai-whisper.ts +63 -33
- package/src/providers/speech-to-text/provider-catalog.ts +306 -0
- package/src/providers/speech-to-text/resolve.ts +386 -6
- package/src/providers/types.ts +10 -1
- package/src/runtime/AGENTS.md +65 -0
- package/src/runtime/__tests__/agent-wake.test.ts +831 -0
- package/src/runtime/__tests__/browser-extension-pair-routes.test.ts +715 -0
- package/src/runtime/__tests__/capability-tokens.test.ts +258 -0
- package/src/runtime/__tests__/chrome-extension-registry.test.ts +518 -0
- package/src/runtime/__tests__/runtime-mode.test.ts +62 -0
- package/src/runtime/__tests__/slack-block-formatting.test.ts +481 -0
- package/src/runtime/agent-wake.ts +512 -0
- package/src/runtime/assistant-event-hub.ts +2 -2
- package/src/runtime/auth/__tests__/guard-tests.test.ts +1 -0
- package/src/runtime/auth/__tests__/middleware.test.ts +116 -1
- package/src/runtime/auth/__tests__/route-policy.test.ts +48 -0
- package/src/runtime/auth/middleware.ts +98 -0
- package/src/runtime/auth/route-policy.ts +33 -9
- package/src/runtime/auth/token-service.ts +56 -1
- package/src/runtime/btw-sidechain.ts +2 -0
- package/src/runtime/capability-tokens.ts +414 -0
- package/src/runtime/channel-approvals.ts +18 -5
- package/src/runtime/channel-invite-transport.ts +1 -1
- package/src/runtime/channel-invite-transports/email.ts +14 -6
- package/src/runtime/channel-readiness-service.ts +12 -22
- package/src/runtime/chrome-extension-registry.ts +368 -0
- package/src/runtime/confirmation-request-guardian-bridge.ts +6 -0
- package/src/runtime/guardian-decision-types.ts +7 -0
- package/src/runtime/http-server.ts +815 -75
- package/src/runtime/http-types.ts +6 -2
- package/src/runtime/migrations/__tests__/rebind-secrets-credentials.test.ts +172 -0
- package/src/runtime/migrations/__tests__/vbundle-builder-credentials.test.ts +276 -0
- package/src/runtime/migrations/__tests__/vbundle-import-credentials.test.ts +198 -0
- package/src/runtime/migrations/__tests__/vbundle-legacy-user-md.test.ts +360 -0
- package/src/runtime/migrations/migration-transport.ts +7 -0
- package/src/runtime/migrations/migration-wizard.ts +23 -2
- package/src/runtime/migrations/rebind-secrets-screen.ts +76 -15
- package/src/runtime/migrations/vbundle-builder.ts +145 -38
- package/src/runtime/migrations/vbundle-import-analyzer.ts +96 -1
- package/src/runtime/migrations/vbundle-importer.ts +89 -5
- package/src/runtime/pending-interactions.ts +18 -13
- package/src/runtime/routes/__tests__/backup-routes.test.ts +967 -0
- package/src/runtime/routes/__tests__/home-feed-routes.test.ts +507 -0
- package/src/runtime/routes/__tests__/migration-import-credential-filter.test.ts +208 -0
- package/src/runtime/routes/__tests__/stt-routes.test.ts +406 -0
- package/src/runtime/routes/__tests__/tts-routes.test.ts +474 -0
- package/src/runtime/routes/__tests__/user-route-dispatcher.test.ts +148 -17
- package/src/runtime/routes/app-management-routes.ts +12 -18
- package/src/runtime/routes/approval-routes.ts +90 -16
- package/src/runtime/routes/attachment-routes.test.ts +9 -3
- package/src/runtime/routes/attachment-routes.ts +216 -17
- package/src/runtime/routes/backup-routes.ts +519 -0
- package/src/runtime/routes/browser-extension-pair-routes.ts +556 -0
- package/src/runtime/routes/btw-routes.ts +8 -6
- package/src/runtime/routes/contact-routes.test.ts +298 -0
- package/src/runtime/routes/contact-routes.ts +132 -5
- package/src/runtime/routes/conversation-analysis-routes.ts +22 -141
- package/src/runtime/routes/conversation-management-routes.ts +223 -0
- package/src/runtime/routes/conversation-routes.ts +598 -103
- package/src/runtime/routes/conversation-starter-routes.ts +78 -16
- package/src/runtime/routes/filing-routes.ts +93 -0
- package/src/runtime/routes/guardian-action-routes.ts +24 -13
- package/src/runtime/routes/home-feed-routes.ts +334 -0
- package/src/runtime/routes/home-state-routes.ts +138 -0
- package/src/runtime/routes/host-browser-routes.ts +268 -0
- package/src/runtime/routes/host-file-routes.ts +9 -1
- package/src/runtime/routes/identity-intro-cache.ts +7 -3
- package/src/runtime/routes/identity-routes.ts +262 -33
- package/src/runtime/routes/inbound-stages/transcribe-audio.test.ts +46 -39
- package/src/runtime/routes/inbound-stages/transcribe-audio.ts +15 -15
- package/src/runtime/routes/integrations/slack/__tests__/channel.test.ts +137 -0
- package/src/runtime/routes/integrations/slack/__tests__/share.test.ts +179 -0
- package/src/runtime/routes/integrations/slack/channel.ts +11 -3
- package/src/runtime/routes/integrations/slack/share.ts +45 -7
- package/src/runtime/routes/llm-context-normalization.ts +303 -0
- package/src/runtime/routes/log-export-routes.ts +42 -22
- package/src/runtime/routes/memory-item-routes.test.ts +3 -2
- package/src/runtime/routes/memory-item-routes.ts +1 -7
- package/src/runtime/routes/migration-routes.ts +122 -2
- package/src/runtime/routes/oauth-apps.ts +15 -17
- package/src/runtime/routes/oauth-providers.ts +4 -0
- package/src/runtime/routes/schedule-routes.ts +24 -11
- package/src/runtime/routes/settings-routes.ts +31 -102
- package/src/runtime/routes/skills-routes.ts +128 -9
- package/src/runtime/routes/stt-routes.ts +233 -0
- package/src/runtime/routes/subagents-routes.ts +14 -10
- package/src/runtime/routes/surface-action-routes.ts +41 -2
- package/src/runtime/routes/tts-routes.ts +108 -24
- package/src/runtime/routes/usage-routes.ts +38 -9
- package/src/runtime/routes/user-route-dispatcher.ts +50 -5
- package/src/runtime/routes/user-routes.ts +13 -1
- package/src/runtime/routes/work-items-routes.ts +8 -1
- package/src/runtime/routes/workspace-routes.test.ts +22 -0
- package/src/runtime/routes/workspace-routes.ts +8 -1
- package/src/runtime/routes/workspace-utils.ts +2 -0
- package/src/runtime/runtime-mode.ts +33 -0
- package/src/runtime/services/__tests__/analyze-conversation.test.ts +444 -0
- package/src/runtime/services/__tests__/analyze-deps-singleton.test.ts +67 -0
- package/src/runtime/services/__tests__/auto-analysis-prompt.test.ts +53 -0
- package/src/runtime/services/__tests__/manual-analysis-prompt.test.ts +41 -0
- package/src/runtime/services/analyze-conversation.ts +344 -0
- package/src/runtime/services/analyze-deps-singleton.ts +32 -0
- package/src/runtime/services/auto-analysis-prompt.ts +55 -0
- package/src/runtime/skill-route-registry.ts +49 -0
- package/src/runtime/slack-block-formatting.ts +437 -10
- package/src/schedule/scheduler.ts +57 -5
- package/src/security/ces-credential-client.ts +20 -0
- package/src/security/ces-rpc-credential-backend.ts +17 -0
- package/src/security/credential-backend.ts +5 -0
- package/src/security/oauth2.ts +68 -29
- package/src/security/secure-keys.ts +143 -27
- package/src/security/token-manager.ts +31 -10
- package/src/sequence/engine.ts +23 -0
- package/src/sequence/types.ts +1 -1
- package/src/skills/catalog-files.ts +554 -0
- package/src/skills/category-inference.ts +122 -0
- package/src/skills/clawhub-files.ts +213 -0
- package/src/skills/clawhub.ts +84 -23
- package/src/skills/skill-file-provider.ts +40 -0
- package/src/skills/skillssh-files.ts +395 -0
- package/src/skills/skillssh-registry.ts +4 -4
- package/src/stt/__tests__/daemon-batch-transcriber.test.ts +392 -0
- package/src/stt/__tests__/types.test.ts +89 -0
- package/src/stt/daemon-batch-transcriber.ts +195 -0
- package/src/stt/stt-stream-session.ts +499 -0
- package/src/stt/types.ts +330 -0
- package/src/stt/wav-encoder.test.ts +373 -0
- package/src/stt/wav-encoder.ts +175 -0
- package/src/subagent/manager.ts +169 -40
- package/src/subagent/types.ts +19 -0
- package/src/tools/apps/executors.ts +11 -2
- package/src/tools/browser/__tests__/auth-detector.test.ts +202 -108
- package/src/tools/browser/__tests__/browser-mode.test.ts +119 -0
- package/src/tools/browser/__tests__/browser-status.test.ts +123 -0
- package/src/tools/browser/auth-detector.ts +43 -12
- package/src/tools/browser/browser-execution.ts +1787 -342
- package/src/tools/browser/browser-manager.ts +81 -12
- package/src/tools/browser/browser-mode-constants.ts +12 -0
- package/src/tools/browser/browser-mode.ts +92 -0
- package/src/tools/browser/browser-status-constants.ts +33 -0
- package/src/tools/browser/cdp-client/__tests__/accessibility-snapshot.test.ts +318 -0
- package/src/tools/browser/cdp-client/__tests__/cdp-dom-helpers.test.ts +1175 -0
- package/src/tools/browser/cdp-client/__tests__/cdp-inspect-client.test.ts +1263 -0
- package/src/tools/browser/cdp-client/__tests__/extension-cdp-client.test.ts +359 -0
- package/src/tools/browser/cdp-client/__tests__/factory.test.ts +1993 -0
- package/src/tools/browser/cdp-client/__tests__/fixtures/ax-tree-nested-frames.json +64 -0
- package/src/tools/browser/cdp-client/__tests__/fixtures/ax-tree-simple.json +69 -0
- package/src/tools/browser/cdp-client/__tests__/local-cdp-client.test.ts +310 -0
- package/src/tools/browser/cdp-client/__tests__/types.test.ts +96 -0
- package/src/tools/browser/cdp-client/accessibility-snapshot.ts +387 -0
- package/src/tools/browser/cdp-client/cdp-dom-helpers.ts +695 -0
- package/src/tools/browser/cdp-client/cdp-inspect/__tests__/discovery.test.ts +1007 -0
- package/src/tools/browser/cdp-client/cdp-inspect/__tests__/ws-transport.test.ts +580 -0
- package/src/tools/browser/cdp-client/cdp-inspect/discovery.ts +744 -0
- package/src/tools/browser/cdp-client/cdp-inspect/ws-transport.ts +579 -0
- package/src/tools/browser/cdp-client/cdp-inspect-client.ts +868 -0
- package/src/tools/browser/cdp-client/errors.ts +49 -0
- package/src/tools/browser/cdp-client/extension-cdp-client.ts +148 -0
- package/src/tools/browser/cdp-client/factory.ts +914 -0
- package/src/tools/browser/cdp-client/index.ts +28 -0
- package/src/tools/browser/cdp-client/local-cdp-client.ts +187 -0
- package/src/tools/browser/cdp-client/types.ts +120 -0
- package/src/tools/credentials/vault.ts +35 -6
- package/src/tools/filesystem/edit.ts +1 -1
- package/src/tools/filesystem/list.ts +1 -1
- package/src/tools/filesystem/read.ts +1 -1
- package/src/tools/filesystem/write.ts +2 -1
- package/src/tools/host-filesystem/edit.ts +1 -1
- package/src/tools/host-filesystem/read.ts +12 -15
- package/src/tools/host-filesystem/write.ts +1 -1
- package/src/tools/host-terminal/host-shell.ts +21 -16
- package/src/tools/network/web-fetch.ts +5 -2
- package/src/tools/network/web-search.ts +5 -2
- package/src/tools/permission-checker.ts +77 -82
- package/src/tools/registry.ts +0 -2
- package/src/tools/secret-detection-handler.ts +34 -0
- package/src/tools/shared/filesystem/image-read.ts +61 -40
- package/src/tools/shared/shell-output.ts +3 -1
- package/src/tools/side-effects.ts +2 -0
- package/src/tools/skills/sandbox-runner.ts +3 -2
- package/src/tools/subagent/spawn.ts +47 -3
- package/src/tools/subagent/status.ts +2 -0
- package/src/tools/system/register.ts +2 -16
- package/src/tools/terminal/safe-env.ts +15 -0
- package/src/tools/terminal/shell.ts +36 -20
- package/src/tools/tool-approval-handler.ts +48 -2
- package/src/tools/tool-manifest.ts +21 -0
- package/src/tools/types.ts +19 -0
- package/src/tools/ui-surface/definitions.ts +6 -1
- package/src/tts/__tests__/provider-adapters.test.ts +834 -0
- package/src/tts/__tests__/provider-catalog-consistency.test.ts +196 -0
- package/src/tts/__tests__/provider-catalog.test.ts +183 -0
- package/src/tts/__tests__/provider-registry.test.ts +90 -0
- package/src/tts/provider-catalog.ts +201 -0
- package/src/tts/provider-registry.ts +73 -0
- package/src/tts/providers/deepgram-provider.ts +219 -0
- package/src/tts/providers/elevenlabs-provider.ts +211 -0
- package/src/tts/providers/fish-audio-provider.ts +183 -0
- package/src/tts/providers/index.ts +42 -0
- package/src/tts/providers/register-builtins.ts +130 -0
- package/src/tts/synthesize-text.ts +110 -0
- package/src/tts/tts-config-resolver.ts +78 -0
- package/src/tts/types.ts +153 -0
- package/src/types/onboarding-context.ts +7 -0
- package/src/util/abort-reasons.ts +58 -0
- package/src/util/device-id.ts +32 -16
- package/src/util/errors.ts +9 -1
- package/src/util/platform.ts +63 -24
- package/src/util/pricing.ts +66 -3
- package/src/util/spawn.ts +1 -1
- package/src/util/truncate.ts +4 -2
- package/src/util/unicode.ts +201 -0
- package/src/version.ts +19 -24
- package/src/watcher/engine.ts +23 -0
- package/src/watcher/watcher-store.ts +31 -0
- package/src/workspace/migrations/003-seed-device-id.ts +9 -3
- package/src/workspace/migrations/017-seed-persona-dirs.ts +68 -4
- package/src/workspace/migrations/029-seed-pkb.ts +1 -1
- package/src/workspace/migrations/031-drop-user-md.ts +317 -0
- package/src/workspace/migrations/031-llm-log-retention-zero-to-null.ts +73 -0
- package/src/workspace/migrations/032-tts-provider-unification.ts +227 -0
- package/src/workspace/migrations/033-stt-service-explicit-config.ts +122 -0
- package/src/workspace/migrations/034-remove-calls-voice-transcription-provider.ts +215 -0
- package/src/workspace/migrations/035-seed-slack-channel-persona.ts +50 -0
- package/src/workspace/migrations/036-update-pkb-index-bar.ts +37 -0
- package/src/workspace/migrations/037-create-meets-dir.ts +61 -0
- package/src/workspace/migrations/registry.ts +16 -0
- package/src/workspace/top-level-renderer.ts +31 -1
- package/src/workspace/turn-commit.ts +31 -0
- package/src/__tests__/chrome-cdp.test.ts +0 -419
- package/src/__tests__/email-cli.test.ts +0 -297
- package/src/__tests__/email-service-config-fallback.test.ts +0 -102
- package/src/__tests__/permission-mode-sse.test.ts +0 -418
- package/src/__tests__/permission-mode-store.test.ts +0 -277
- package/src/browser-extension-relay/protocol.ts +0 -63
- package/src/browser-extension-relay/server.ts +0 -203
- package/src/cli/commands/browser-relay.ts +0 -536
- package/src/config/schemas/sandbox.ts +0 -14
- package/src/email/guardrails.ts +0 -221
- package/src/email/provider.ts +0 -117
- package/src/email/providers/agentmail.ts +0 -361
- package/src/email/providers/index.ts +0 -65
- package/src/email/service.ts +0 -384
- package/src/email/types.ts +0 -126
- package/src/permissions/permission-mode-store.ts +0 -180
- package/src/prompts/templates/USER.md +0 -13
- package/src/providers/speech-to-text/types.ts +0 -17
- package/src/tools/browser/chrome-cdp.ts +0 -239
- package/src/tools/system/set-permission-mode.ts +0 -103
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* End-to-end smoke test for the self-hosted **capability-token**
|
|
3
|
+
* WebSocket round-trip over `/v1/browser-relay`.
|
|
4
|
+
*
|
|
5
|
+
* This file is the Phase 3 complement to `host-browser-e2e-cloud.test.ts`:
|
|
6
|
+
* it exercises the same mock-chrome-extension → runtime → HostBrowserProxy
|
|
7
|
+
* path, but the extension authenticates with a capability token minted
|
|
8
|
+
* by `mintHostBrowserCapability()` instead of a guardian-bound JWT.
|
|
9
|
+
*
|
|
10
|
+
* Invariants covered:
|
|
11
|
+
*
|
|
12
|
+
* 1. `/v1/browser-relay` accepts capability tokens directly.
|
|
13
|
+
* 2. The WS upgrade handler derives the registry-key guardianId from
|
|
14
|
+
* the capability claims so host_browser_request frames route
|
|
15
|
+
* back to the right connection.
|
|
16
|
+
* 3. A full `Browser.getVersion` request round-trips through the
|
|
17
|
+
* mock fixture and resolves on the proxy side.
|
|
18
|
+
*
|
|
19
|
+
* If this test fails, the self-hosted transport cutover is broken.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
import { afterEach, beforeEach, describe, expect, mock, test } from "bun:test";
|
|
23
|
+
|
|
24
|
+
// ── Module mocks (must be declared before the real imports below) ────
|
|
25
|
+
|
|
26
|
+
mock.module("../util/logger.js", () => ({
|
|
27
|
+
getLogger: () =>
|
|
28
|
+
new Proxy({} as Record<string, unknown>, {
|
|
29
|
+
get: () => () => {},
|
|
30
|
+
}),
|
|
31
|
+
}));
|
|
32
|
+
|
|
33
|
+
mock.module("../config/loader.js", () => ({
|
|
34
|
+
getConfig: () => ({
|
|
35
|
+
ui: {},
|
|
36
|
+
model: "test",
|
|
37
|
+
provider: "test",
|
|
38
|
+
memory: { enabled: false },
|
|
39
|
+
rateLimit: { maxRequestsPerMinute: 0 },
|
|
40
|
+
secretDetection: { enabled: false },
|
|
41
|
+
contextWindow: { maxInputTokens: 200000 },
|
|
42
|
+
services: {
|
|
43
|
+
inference: {
|
|
44
|
+
mode: "your-own",
|
|
45
|
+
provider: "anthropic",
|
|
46
|
+
model: "claude-opus-4-6",
|
|
47
|
+
},
|
|
48
|
+
"image-generation": {
|
|
49
|
+
mode: "your-own",
|
|
50
|
+
provider: "gemini",
|
|
51
|
+
model: "gemini-3.1-flash-image-preview",
|
|
52
|
+
},
|
|
53
|
+
"web-search": { mode: "your-own", provider: "inference-provider-native" },
|
|
54
|
+
},
|
|
55
|
+
}),
|
|
56
|
+
}));
|
|
57
|
+
|
|
58
|
+
// ── Real imports (after mocks) ──────────────────────────────────────
|
|
59
|
+
|
|
60
|
+
import type { Conversation } from "../daemon/conversation.js";
|
|
61
|
+
import { HostBrowserProxy } from "../daemon/host-browser-proxy.js";
|
|
62
|
+
import type { ServerMessage } from "../daemon/message-protocol.js";
|
|
63
|
+
import { getDb, initializeDb } from "../memory/db.js";
|
|
64
|
+
import { mintHostBrowserCapability } from "../runtime/capability-tokens.js";
|
|
65
|
+
import {
|
|
66
|
+
__resetChromeExtensionRegistryForTests,
|
|
67
|
+
getChromeExtensionRegistry,
|
|
68
|
+
} from "../runtime/chrome-extension-registry.js";
|
|
69
|
+
import { RuntimeHttpServer } from "../runtime/http-server.js";
|
|
70
|
+
import * as pendingInteractions from "../runtime/pending-interactions.js";
|
|
71
|
+
|
|
72
|
+
initializeDb();
|
|
73
|
+
|
|
74
|
+
// ── Helpers ─────────────────────────────────────────────────────────
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Wrap a HostBrowserProxy in a sendToClient that routes
|
|
78
|
+
* host_browser_request / host_browser_cancel frames through the
|
|
79
|
+
* ChromeExtensionRegistry for the given guardianId, and registers the
|
|
80
|
+
* corresponding pending interaction so `/v1/host-browser-result` can
|
|
81
|
+
* resolve it back through the proxy. Mirrors the cloud e2e test's
|
|
82
|
+
* `createBoundProxy` helper.
|
|
83
|
+
*/
|
|
84
|
+
function createBoundProxy(
|
|
85
|
+
guardianId: string,
|
|
86
|
+
conversationId: string,
|
|
87
|
+
): { proxy: HostBrowserProxy; conversation: Conversation } {
|
|
88
|
+
let proxyRef: HostBrowserProxy | null = null;
|
|
89
|
+
const conversation = {
|
|
90
|
+
resolveHostBrowser(
|
|
91
|
+
requestId: string,
|
|
92
|
+
response: { content: string; isError: boolean },
|
|
93
|
+
) {
|
|
94
|
+
proxyRef?.resolve(requestId, response);
|
|
95
|
+
},
|
|
96
|
+
} as unknown as Conversation;
|
|
97
|
+
|
|
98
|
+
const sendToClient = (msg: ServerMessage) => {
|
|
99
|
+
if ((msg as { type: string }).type === "host_browser_request") {
|
|
100
|
+
const requestId = (msg as { requestId: string }).requestId;
|
|
101
|
+
pendingInteractions.register(requestId, {
|
|
102
|
+
conversation,
|
|
103
|
+
conversationId,
|
|
104
|
+
kind: "host_browser",
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
const ok = getChromeExtensionRegistry().send(guardianId, msg);
|
|
108
|
+
if (!ok) {
|
|
109
|
+
throw new Error(
|
|
110
|
+
`chrome-extension host_browser send failed: no active connection for guardian ${guardianId}`,
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
const proxy = new HostBrowserProxy(sendToClient);
|
|
116
|
+
proxyRef = proxy;
|
|
117
|
+
return { proxy, conversation };
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// ── Tests ───────────────────────────────────────────────────────────
|
|
121
|
+
|
|
122
|
+
describe("host_browser self-hosted capability-token e2e round-trip", () => {
|
|
123
|
+
let server: RuntimeHttpServer;
|
|
124
|
+
let port: number;
|
|
125
|
+
let runtimeBaseUrl: string;
|
|
126
|
+
|
|
127
|
+
beforeEach(async () => {
|
|
128
|
+
// Each test gets a clean DB and a fresh registry so connection
|
|
129
|
+
// state doesn't leak between cases.
|
|
130
|
+
const db = getDb();
|
|
131
|
+
db.run("DELETE FROM contact_channels");
|
|
132
|
+
db.run("DELETE FROM contacts");
|
|
133
|
+
pendingInteractions.clear();
|
|
134
|
+
__resetChromeExtensionRegistryForTests();
|
|
135
|
+
|
|
136
|
+
port = 19600 + Math.floor(Math.random() * 200);
|
|
137
|
+
runtimeBaseUrl = `http://127.0.0.1:${port}`;
|
|
138
|
+
server = new RuntimeHttpServer({ port });
|
|
139
|
+
await server.start();
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
afterEach(async () => {
|
|
143
|
+
await server?.stop();
|
|
144
|
+
pendingInteractions.clear();
|
|
145
|
+
__resetChromeExtensionRegistryForTests();
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
test("capability token round-trips Browser.getVersion over WS result transport", async () => {
|
|
149
|
+
const guardianId = `self-hosted-guardian-${crypto.randomUUID()}`;
|
|
150
|
+
|
|
151
|
+
// Mint the capability token the chrome extension would have
|
|
152
|
+
// received from the native messaging pair flow. No JWT is minted
|
|
153
|
+
// anywhere in this test — the `/v1/browser-relay` upgrade handler
|
|
154
|
+
// must accept this token directly.
|
|
155
|
+
const { token } = mintHostBrowserCapability(guardianId);
|
|
156
|
+
|
|
157
|
+
const { createMockChromeExtension } =
|
|
158
|
+
await import("./fixtures/mock-chrome-extension.js");
|
|
159
|
+
// WS result transport: the extension returns results over the same
|
|
160
|
+
// `/v1/browser-relay` WebSocket it received the request on. This
|
|
161
|
+
// is the canonical self-hosted return path when the socket is
|
|
162
|
+
// healthy.
|
|
163
|
+
const mockExt = createMockChromeExtension({
|
|
164
|
+
runtimeBaseUrl,
|
|
165
|
+
token,
|
|
166
|
+
resultTransport: "ws",
|
|
167
|
+
});
|
|
168
|
+
await mockExt.start();
|
|
169
|
+
await mockExt.waitForConnection();
|
|
170
|
+
|
|
171
|
+
// Give the open handler a tick to register the connection in the
|
|
172
|
+
// ChromeExtensionRegistry. If the capability-token branch of the
|
|
173
|
+
// upgrade handler is broken, waitForRegistryEntry() will throw
|
|
174
|
+
// before the Browser.getVersion call runs.
|
|
175
|
+
await waitForRegistryEntry(guardianId);
|
|
176
|
+
|
|
177
|
+
const { proxy } = createBoundProxy(guardianId, "conv-cap-happy-ws");
|
|
178
|
+
|
|
179
|
+
const result = await proxy.request(
|
|
180
|
+
{ cdpMethod: "Browser.getVersion" },
|
|
181
|
+
"conv-cap-happy-ws",
|
|
182
|
+
);
|
|
183
|
+
|
|
184
|
+
expect(result.isError).toBe(false);
|
|
185
|
+
expect(result.content).toContain("Chrome/MockTest");
|
|
186
|
+
|
|
187
|
+
const received = mockExt.receivedRequests();
|
|
188
|
+
expect(received).toHaveLength(1);
|
|
189
|
+
expect(received[0].cdpMethod).toBe("Browser.getVersion");
|
|
190
|
+
expect(received[0].conversationId).toBe("conv-cap-happy-ws");
|
|
191
|
+
|
|
192
|
+
proxy.dispose();
|
|
193
|
+
await mockExt.stop();
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
test("capability token round-trips Browser.getVersion over HTTP POST fallback", async () => {
|
|
197
|
+
// HTTP result transport: the extension POSTs results back to
|
|
198
|
+
// `/v1/host-browser-result` with the same capability token used
|
|
199
|
+
// for the WS handshake. This exercises the capability-token-aware
|
|
200
|
+
// auth on the POST route and proves the HTTP fallback path
|
|
201
|
+
// resolves the pending interaction end-to-end.
|
|
202
|
+
const guardianId = `self-hosted-guardian-${crypto.randomUUID()}`;
|
|
203
|
+
const { token } = mintHostBrowserCapability(guardianId);
|
|
204
|
+
|
|
205
|
+
const { createMockChromeExtension } =
|
|
206
|
+
await import("./fixtures/mock-chrome-extension.js");
|
|
207
|
+
const mockExt = createMockChromeExtension({
|
|
208
|
+
runtimeBaseUrl,
|
|
209
|
+
token,
|
|
210
|
+
resultTransport: "http",
|
|
211
|
+
});
|
|
212
|
+
await mockExt.start();
|
|
213
|
+
await mockExt.waitForConnection();
|
|
214
|
+
await waitForRegistryEntry(guardianId);
|
|
215
|
+
|
|
216
|
+
const { proxy } = createBoundProxy(guardianId, "conv-cap-happy-http");
|
|
217
|
+
|
|
218
|
+
const result = await proxy.request(
|
|
219
|
+
{ cdpMethod: "Browser.getVersion" },
|
|
220
|
+
"conv-cap-happy-http",
|
|
221
|
+
);
|
|
222
|
+
|
|
223
|
+
expect(result.isError).toBe(false);
|
|
224
|
+
expect(result.content).toContain("Chrome/MockTest");
|
|
225
|
+
|
|
226
|
+
const received = mockExt.receivedRequests();
|
|
227
|
+
expect(received).toHaveLength(1);
|
|
228
|
+
expect(received[0].cdpMethod).toBe("Browser.getVersion");
|
|
229
|
+
expect(received[0].conversationId).toBe("conv-cap-happy-http");
|
|
230
|
+
|
|
231
|
+
proxy.dispose();
|
|
232
|
+
await mockExt.stop();
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
test("an invalid capability token is rejected with 401", async () => {
|
|
236
|
+
// Sanity check: the capability branch must not be a rubber stamp
|
|
237
|
+
// — a malformed token should still 401 the upgrade. If this ever
|
|
238
|
+
// starts passing on a junk token the self-hosted security
|
|
239
|
+
// posture has regressed.
|
|
240
|
+
const { createMockChromeExtension } =
|
|
241
|
+
await import("./fixtures/mock-chrome-extension.js");
|
|
242
|
+
const mockExt = createMockChromeExtension({
|
|
243
|
+
runtimeBaseUrl,
|
|
244
|
+
token: "not-a-real-token.xxxxxxxxxxxxx",
|
|
245
|
+
});
|
|
246
|
+
await mockExt.start();
|
|
247
|
+
// The upgrade will fail; waitForConnection will time out. We
|
|
248
|
+
// intentionally give it a short window and swallow the timeout.
|
|
249
|
+
let connected = false;
|
|
250
|
+
try {
|
|
251
|
+
await mockExt.waitForConnection(500);
|
|
252
|
+
connected = true;
|
|
253
|
+
} catch {
|
|
254
|
+
// expected
|
|
255
|
+
}
|
|
256
|
+
expect(connected).toBe(false);
|
|
257
|
+
await mockExt.stop();
|
|
258
|
+
});
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
// ── Local wait helpers ──────────────────────────────────────────────
|
|
262
|
+
|
|
263
|
+
async function waitFor(
|
|
264
|
+
predicate: () => boolean,
|
|
265
|
+
timeoutMs = 2000,
|
|
266
|
+
): Promise<void> {
|
|
267
|
+
const deadline = Date.now() + timeoutMs;
|
|
268
|
+
while (!predicate()) {
|
|
269
|
+
if (Date.now() > deadline) {
|
|
270
|
+
throw new Error(
|
|
271
|
+
`waitFor: predicate did not become true within ${timeoutMs}ms`,
|
|
272
|
+
);
|
|
273
|
+
}
|
|
274
|
+
await new Promise((r) => setTimeout(r, 10));
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
async function waitForRegistryEntry(
|
|
279
|
+
guardianId: string,
|
|
280
|
+
timeoutMs = 2000,
|
|
281
|
+
): Promise<void> {
|
|
282
|
+
await waitFor(
|
|
283
|
+
() => getChromeExtensionRegistry().get(guardianId) !== undefined,
|
|
284
|
+
timeoutMs,
|
|
285
|
+
);
|
|
286
|
+
}
|
|
@@ -0,0 +1,374 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* End-to-end smoke test for the self-hosted native-messaging capability
|
|
3
|
+
* bootstrap path.
|
|
4
|
+
*
|
|
5
|
+
* This test exercises the full flow at the subprocess boundary:
|
|
6
|
+
*
|
|
7
|
+
* 1. A minimal Bun HTTP server mounts the real
|
|
8
|
+
* `handleBrowserExtensionPair` route from the assistant runtime.
|
|
9
|
+
* 2. The compiled native helper binary
|
|
10
|
+
* (`clients/chrome-extension/native-host/dist/index.js`) is spawned as
|
|
11
|
+
* a child process and pointed at that server via the `--assistant-port`
|
|
12
|
+
* CLI flag.
|
|
13
|
+
* 3. The test writes a Chrome-native-messaging-framed
|
|
14
|
+
* `{ type: "request_token" }` to the helper's stdin.
|
|
15
|
+
* 4. The helper POSTs `/v1/browser-extension-pair` on the test server,
|
|
16
|
+
* gets back a capability token + guardianId, and echoes them to stdout
|
|
17
|
+
* as a `token_response` frame.
|
|
18
|
+
* 5. The test asserts the returned token verifies via
|
|
19
|
+
* `verifyHostBrowserCapability` — i.e. a fresh install can pair the
|
|
20
|
+
* Chrome extension via the native helper end-to-end without any
|
|
21
|
+
* shortcuts.
|
|
22
|
+
*
|
|
23
|
+
* The test **skips gracefully** if the native helper hasn't been built
|
|
24
|
+
* (`clients/chrome-extension/native-host/dist/index.js` missing). Run
|
|
25
|
+
* `bun run build` in that package first to enable the full path.
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
import { type ChildProcessWithoutNullStreams, spawn } from "node:child_process";
|
|
29
|
+
import { randomBytes } from "node:crypto";
|
|
30
|
+
import {
|
|
31
|
+
chmodSync,
|
|
32
|
+
existsSync,
|
|
33
|
+
mkdtempSync,
|
|
34
|
+
readFileSync,
|
|
35
|
+
rmSync,
|
|
36
|
+
writeFileSync,
|
|
37
|
+
} from "node:fs";
|
|
38
|
+
import { tmpdir } from "node:os";
|
|
39
|
+
import { join, resolve } from "node:path";
|
|
40
|
+
import { afterAll, beforeAll, describe, expect, test } from "bun:test";
|
|
41
|
+
|
|
42
|
+
import {
|
|
43
|
+
mintHostBrowserCapability,
|
|
44
|
+
resetCapabilityTokenSecretForTests,
|
|
45
|
+
setCapabilityTokenSecretForTests,
|
|
46
|
+
verifyHostBrowserCapability,
|
|
47
|
+
} from "../runtime/capability-tokens.js";
|
|
48
|
+
import {
|
|
49
|
+
ALLOWED_EXTENSION_ORIGINS,
|
|
50
|
+
handleBrowserExtensionPair,
|
|
51
|
+
} from "../runtime/routes/browser-extension-pair-routes.js";
|
|
52
|
+
|
|
53
|
+
// ---------------------------------------------------------------------------
|
|
54
|
+
// Native helper binary discovery + skip guard
|
|
55
|
+
// ---------------------------------------------------------------------------
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Resolve the path to the compiled native helper. The helper lives in a
|
|
59
|
+
* sibling package under `clients/chrome-extension/native-host/`, so we
|
|
60
|
+
* walk up from `assistant/src/__tests__/` to the repo root and then back
|
|
61
|
+
* down into the native-host package.
|
|
62
|
+
*/
|
|
63
|
+
function resolveHelperBinary(): string {
|
|
64
|
+
// `import.meta.dir` gives us `.../assistant/src/__tests__`. The repo
|
|
65
|
+
// root is three levels up. Past that, the native host lives at
|
|
66
|
+
// `clients/chrome-extension/native-host/dist/index.js`.
|
|
67
|
+
return resolve(
|
|
68
|
+
import.meta.dir,
|
|
69
|
+
"..",
|
|
70
|
+
"..",
|
|
71
|
+
"..",
|
|
72
|
+
"clients",
|
|
73
|
+
"chrome-extension",
|
|
74
|
+
"native-host",
|
|
75
|
+
"dist",
|
|
76
|
+
"index.js",
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const HELPER_BINARY = resolveHelperBinary();
|
|
81
|
+
const HELPER_EXISTS = existsSync(HELPER_BINARY);
|
|
82
|
+
|
|
83
|
+
const ALLOWED_ORIGIN = (() => {
|
|
84
|
+
const first = Array.from(ALLOWED_EXTENSION_ORIGINS)[0];
|
|
85
|
+
if (!first) {
|
|
86
|
+
throw new Error(
|
|
87
|
+
"ALLOWED_EXTENSION_ORIGINS must contain at least one extension origin for tests",
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
return first;
|
|
91
|
+
})();
|
|
92
|
+
|
|
93
|
+
const SKIP_REASON =
|
|
94
|
+
"clients/chrome-extension/native-host/dist/index.js is missing — run `bun run build` in that package to enable the E2E smoke test.";
|
|
95
|
+
|
|
96
|
+
// ---------------------------------------------------------------------------
|
|
97
|
+
// Chrome native messaging framing (4-byte LE length prefix + UTF-8 JSON)
|
|
98
|
+
// ---------------------------------------------------------------------------
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* These helpers are duplicated from the native-host package's
|
|
102
|
+
* `protocol.ts` so this test is self-contained and does not reach across
|
|
103
|
+
* package boundaries at import time. The framing is fixed by the Chrome
|
|
104
|
+
* native messaging protocol spec, so there is no risk of drift.
|
|
105
|
+
*/
|
|
106
|
+
function encodeFrame(payload: unknown): Buffer {
|
|
107
|
+
const json = Buffer.from(JSON.stringify(payload), "utf8");
|
|
108
|
+
const len = Buffer.alloc(4);
|
|
109
|
+
len.writeUInt32LE(json.length, 0);
|
|
110
|
+
return Buffer.concat([len, json]);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function decodeFrames(buf: Buffer): {
|
|
114
|
+
frames: unknown[];
|
|
115
|
+
remainder: Buffer;
|
|
116
|
+
} {
|
|
117
|
+
const frames: unknown[] = [];
|
|
118
|
+
let offset = 0;
|
|
119
|
+
while (buf.length - offset >= 4) {
|
|
120
|
+
const len = buf.readUInt32LE(offset);
|
|
121
|
+
if (buf.length - offset - 4 < len) break;
|
|
122
|
+
const body = buf.subarray(offset + 4, offset + 4 + len);
|
|
123
|
+
frames.push(JSON.parse(body.toString("utf8")));
|
|
124
|
+
offset += 4 + len;
|
|
125
|
+
}
|
|
126
|
+
return { frames, remainder: buf.subarray(offset) };
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// ---------------------------------------------------------------------------
|
|
130
|
+
// Minimal pair-endpoint HTTP server using the real route handler
|
|
131
|
+
// ---------------------------------------------------------------------------
|
|
132
|
+
|
|
133
|
+
interface PairServer {
|
|
134
|
+
server: ReturnType<typeof Bun.serve>;
|
|
135
|
+
port: number;
|
|
136
|
+
stop: () => void;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Boots a minimal Bun.serve that mounts the real
|
|
141
|
+
* `handleBrowserExtensionPair` route. This is intentionally a narrower
|
|
142
|
+
* surface than `RuntimeHttpServer` — we want to exercise the exact same
|
|
143
|
+
* route handler the daemon uses in production, but without pulling in the
|
|
144
|
+
* full runtime's dependency graph (which would drag in the workspace DB,
|
|
145
|
+
* conversation manager, etc. and make the test flaky + slow).
|
|
146
|
+
*/
|
|
147
|
+
function startPairServer(): PairServer {
|
|
148
|
+
const server = Bun.serve({
|
|
149
|
+
port: 0,
|
|
150
|
+
hostname: "127.0.0.1",
|
|
151
|
+
async fetch(req, srv) {
|
|
152
|
+
const url = new URL(req.url);
|
|
153
|
+
if (url.pathname === "/v1/browser-extension-pair") {
|
|
154
|
+
return handleBrowserExtensionPair(req, {
|
|
155
|
+
requestIP: (_req) => srv.requestIP(_req),
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
return new Response("not found", { status: 404 });
|
|
159
|
+
},
|
|
160
|
+
});
|
|
161
|
+
return {
|
|
162
|
+
server,
|
|
163
|
+
port: server.port as number,
|
|
164
|
+
stop: () => server.stop(true),
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// ---------------------------------------------------------------------------
|
|
169
|
+
// Subprocess helper
|
|
170
|
+
// ---------------------------------------------------------------------------
|
|
171
|
+
|
|
172
|
+
interface HelperRunResult {
|
|
173
|
+
frames: unknown[];
|
|
174
|
+
stderr: string;
|
|
175
|
+
exitCode: number | null;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
function runHelper(options: {
|
|
179
|
+
extensionOrigin: string;
|
|
180
|
+
assistantPort: number;
|
|
181
|
+
stdinBytes: Buffer;
|
|
182
|
+
timeoutMs?: number;
|
|
183
|
+
}): Promise<HelperRunResult> {
|
|
184
|
+
const args: string[] = [
|
|
185
|
+
HELPER_BINARY,
|
|
186
|
+
options.extensionOrigin,
|
|
187
|
+
"--assistant-port",
|
|
188
|
+
String(options.assistantPort),
|
|
189
|
+
];
|
|
190
|
+
|
|
191
|
+
const child: ChildProcessWithoutNullStreams = spawn("node", args, {
|
|
192
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
193
|
+
env: { ...process.env },
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
const stdoutChunks: Buffer[] = [];
|
|
197
|
+
const stderrChunks: Buffer[] = [];
|
|
198
|
+
child.stdout.on("data", (chunk: Buffer) => stdoutChunks.push(chunk));
|
|
199
|
+
child.stderr.on("data", (chunk: Buffer) => stderrChunks.push(chunk));
|
|
200
|
+
|
|
201
|
+
child.stdin.write(options.stdinBytes);
|
|
202
|
+
child.stdin.end();
|
|
203
|
+
|
|
204
|
+
return new Promise<HelperRunResult>((resolvePromise, rejectPromise) => {
|
|
205
|
+
const timeout = setTimeout(() => {
|
|
206
|
+
child.kill("SIGKILL");
|
|
207
|
+
rejectPromise(
|
|
208
|
+
new Error(
|
|
209
|
+
`helper binary timed out after ${options.timeoutMs ?? 5000}ms`,
|
|
210
|
+
),
|
|
211
|
+
);
|
|
212
|
+
}, options.timeoutMs ?? 5000);
|
|
213
|
+
|
|
214
|
+
child.on("error", (err) => {
|
|
215
|
+
clearTimeout(timeout);
|
|
216
|
+
rejectPromise(err);
|
|
217
|
+
});
|
|
218
|
+
child.on("close", (code) => {
|
|
219
|
+
clearTimeout(timeout);
|
|
220
|
+
const stdout = Buffer.concat(stdoutChunks);
|
|
221
|
+
const stderr = Buffer.concat(stderrChunks).toString("utf8");
|
|
222
|
+
try {
|
|
223
|
+
const { frames } = decodeFrames(stdout);
|
|
224
|
+
resolvePromise({ frames, stderr, exitCode: code });
|
|
225
|
+
} catch (err) {
|
|
226
|
+
rejectPromise(err as Error);
|
|
227
|
+
}
|
|
228
|
+
});
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// ---------------------------------------------------------------------------
|
|
233
|
+
// Tests
|
|
234
|
+
// ---------------------------------------------------------------------------
|
|
235
|
+
|
|
236
|
+
describe("host-browser E2E — self-hosted native messaging path", () => {
|
|
237
|
+
let pairServer: PairServer | null = null;
|
|
238
|
+
|
|
239
|
+
beforeAll(() => {
|
|
240
|
+
// Pin the capability-token secret to a deterministic test value so
|
|
241
|
+
// the token the route mints can round-trip through
|
|
242
|
+
// `verifyHostBrowserCapability` in this process. Both sides of the
|
|
243
|
+
// flow share the same in-process module, so setting the secret once
|
|
244
|
+
// is enough for both mint + verify to agree.
|
|
245
|
+
resetCapabilityTokenSecretForTests();
|
|
246
|
+
setCapabilityTokenSecretForTests(randomBytes(32));
|
|
247
|
+
|
|
248
|
+
if (!HELPER_EXISTS) return;
|
|
249
|
+
pairServer = startPairServer();
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
afterAll(() => {
|
|
253
|
+
if (pairServer) pairServer.stop();
|
|
254
|
+
resetCapabilityTokenSecretForTests();
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
if (!HELPER_EXISTS) {
|
|
258
|
+
// Native helper hasn't been built; emit a warning so the gap is
|
|
259
|
+
// visible in test output without registering a placeholder test.
|
|
260
|
+
console.warn(`[host-browser-e2e] ${SKIP_REASON}`);
|
|
261
|
+
} else {
|
|
262
|
+
test("pair flow: request_token -> token_response -> verifiable capability token", async () => {
|
|
263
|
+
// Narrow for TS — pairServer is always set in this branch thanks to
|
|
264
|
+
// the beforeAll guard that mirrors HELPER_EXISTS.
|
|
265
|
+
const srv = pairServer!;
|
|
266
|
+
|
|
267
|
+
const result = await runHelper({
|
|
268
|
+
extensionOrigin: ALLOWED_ORIGIN,
|
|
269
|
+
assistantPort: srv.port,
|
|
270
|
+
stdinBytes: encodeFrame({ type: "request_token" }),
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
// Helper should have exited cleanly after writing one token_response
|
|
274
|
+
// frame. Pipe any stderr into the assertion message to make
|
|
275
|
+
// debugging failures easier.
|
|
276
|
+
expect(result.exitCode, `helper stderr: ${result.stderr}`).toBe(0);
|
|
277
|
+
expect(result.frames).toHaveLength(1);
|
|
278
|
+
|
|
279
|
+
const frame = result.frames[0] as {
|
|
280
|
+
type: string;
|
|
281
|
+
token?: string;
|
|
282
|
+
expiresAt?: string;
|
|
283
|
+
guardianId?: string;
|
|
284
|
+
};
|
|
285
|
+
expect(frame.type).toBe("token_response");
|
|
286
|
+
expect(typeof frame.token).toBe("string");
|
|
287
|
+
expect(frame.token!.length).toBeGreaterThan(0);
|
|
288
|
+
expect(typeof frame.expiresAt).toBe("string");
|
|
289
|
+
|
|
290
|
+
// Gap 3 regression guard: the helper must surface the
|
|
291
|
+
// guardianId returned by /v1/browser-extension-pair on the
|
|
292
|
+
// native-messaging frame so the chrome extension's
|
|
293
|
+
// bootstrapLocalToken() can persist it. The route's
|
|
294
|
+
// resolveLocalGuardianId() falls back to the literal string
|
|
295
|
+
// "local" when no vellum guardian is bootstrapped, which is
|
|
296
|
+
// the case in this test environment, so we assert against the
|
|
297
|
+
// exact value as well as a non-empty type guard.
|
|
298
|
+
expect(typeof frame.guardianId).toBe("string");
|
|
299
|
+
expect(frame.guardianId!.length).toBeGreaterThan(0);
|
|
300
|
+
expect(frame.guardianId).toBe("local");
|
|
301
|
+
|
|
302
|
+
// The returned token must verify via the in-process capability
|
|
303
|
+
// verifier — this is the core invariant the native-messaging
|
|
304
|
+
// bootstrap promises. The daemon is the only party that could
|
|
305
|
+
// have signed this, so a successful verification proves the
|
|
306
|
+
// end-to-end pair flow worked.
|
|
307
|
+
const claims = verifyHostBrowserCapability(frame.token!);
|
|
308
|
+
expect(claims).not.toBeNull();
|
|
309
|
+
expect(claims?.capability).toBe("host_browser_command");
|
|
310
|
+
expect(typeof claims?.guardianId).toBe("string");
|
|
311
|
+
expect(claims?.guardianId.length).toBeGreaterThan(0);
|
|
312
|
+
// The frame's guardianId should match the claim's guardianId —
|
|
313
|
+
// both originate from the same `resolveLocalGuardianId()` call
|
|
314
|
+
// inside the route handler.
|
|
315
|
+
expect(frame.guardianId).toBe(claims?.guardianId);
|
|
316
|
+
// expiresAt in the response frame should agree with the numeric
|
|
317
|
+
// claim expiry to within ISO-string precision.
|
|
318
|
+
const iso = new Date(claims!.expiresAt).toISOString();
|
|
319
|
+
expect(frame.expiresAt).toBe(iso);
|
|
320
|
+
});
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// -------------------------------------------------------------------------
|
|
324
|
+
// Dev-only daemon-token fallback (per-instance protected dir)
|
|
325
|
+
// -------------------------------------------------------------------------
|
|
326
|
+
|
|
327
|
+
describe("dev daemon-token fallback path", () => {
|
|
328
|
+
let tmpDir: string;
|
|
329
|
+
|
|
330
|
+
beforeAll(() => {
|
|
331
|
+
tmpDir = mkdtempSync(join(tmpdir(), "vellum-daemon-token-test-"));
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
afterAll(() => {
|
|
335
|
+
rmSync(tmpDir, { recursive: true, force: true });
|
|
336
|
+
});
|
|
337
|
+
|
|
338
|
+
test("a token written to a local file round-trips through verifyHostBrowserCapability", () => {
|
|
339
|
+
// Emulate the `writeDaemonTokenFallback` lifecycle: mint a fresh
|
|
340
|
+
// capability token, persist it to a 0600 file (the production
|
|
341
|
+
// helper writes to `<protectedDir>/daemon-token`, but we use a
|
|
342
|
+
// tempdir so the test doesn't clobber real dev state), then read
|
|
343
|
+
// it back and verify.
|
|
344
|
+
//
|
|
345
|
+
// This path is what the Mac app's manual "paste daemon token"
|
|
346
|
+
// pairing UI ends up exercising — the file on disk is the only
|
|
347
|
+
// transport. If the bytes on disk don't round-trip through
|
|
348
|
+
// `verifyHostBrowserCapability`, manual pairing is broken.
|
|
349
|
+
resetCapabilityTokenSecretForTests();
|
|
350
|
+
setCapabilityTokenSecretForTests(randomBytes(32));
|
|
351
|
+
|
|
352
|
+
const { token, expiresAt } = mintHostBrowserCapability("local");
|
|
353
|
+
expect(expiresAt).toBeGreaterThan(Date.now());
|
|
354
|
+
|
|
355
|
+
const tokenPath = join(tmpDir, "daemon-token");
|
|
356
|
+
writeFileSync(tokenPath, token, { mode: 0o600 });
|
|
357
|
+
// Explicitly chmod in case the umask clobbered the mode arg to
|
|
358
|
+
// writeFileSync (best-effort — some filesystems ignore this).
|
|
359
|
+
try {
|
|
360
|
+
chmodSync(tokenPath, 0o600);
|
|
361
|
+
} catch {
|
|
362
|
+
/* ignore */
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
const readBack = readFileSync(tokenPath, "utf8");
|
|
366
|
+
expect(readBack).toBe(token);
|
|
367
|
+
|
|
368
|
+
const claims = verifyHostBrowserCapability(readBack);
|
|
369
|
+
expect(claims).not.toBeNull();
|
|
370
|
+
expect(claims?.capability).toBe("host_browser_command");
|
|
371
|
+
expect(claims?.guardianId).toBe("local");
|
|
372
|
+
});
|
|
373
|
+
});
|
|
374
|
+
});
|