@vellumai/assistant 0.7.1 → 0.7.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ARCHITECTURE.md +48 -50
- package/Dockerfile +1 -0
- package/README.md +1 -2
- package/__tests__/permissions/gateway-threshold-reader.test.ts +9 -3
- package/bun.lock +26 -26
- package/docs/architecture/memory.md +5 -2
- package/docs/architecture/security.md +20 -0
- package/docs/plugins.md +7 -9
- package/knip.json +1 -0
- package/node_modules/@vellumai/gateway-client/src/index.ts +1 -0
- package/node_modules/@vellumai/gateway-client/src/ipc-client.ts +52 -5
- package/node_modules/@vellumai/gateway-client/src/types.ts +11 -0
- package/node_modules/@vellumai/service-contracts/package.json +2 -0
- package/node_modules/@vellumai/service-contracts/src/__tests__/contracts.test.ts +4 -0
- package/node_modules/@vellumai/service-contracts/src/__tests__/ingress.test.ts +107 -0
- package/node_modules/@vellumai/service-contracts/src/index.ts +5 -1
- package/node_modules/@vellumai/service-contracts/src/ingress.ts +24 -0
- package/node_modules/@vellumai/service-contracts/src/twilio-ingress.ts +84 -0
- package/node_modules/@vellumai/slack-text/src/index.test.ts +18 -35
- package/node_modules/@vellumai/slack-text/src/index.ts +2 -48
- package/node_modules/@vellumai/twilio-client/bun.lock +24 -0
- package/node_modules/@vellumai/twilio-client/package.json +18 -0
- package/node_modules/@vellumai/twilio-client/src/__tests__/twilio-client.test.ts +128 -0
- package/node_modules/@vellumai/twilio-client/src/index.ts +179 -0
- package/node_modules/@vellumai/twilio-client/tsconfig.json +20 -0
- package/openapi.yaml +1020 -40
- package/package.json +6 -3
- package/src/__tests__/app-builder-tool-scripts.test.ts +3 -3
- package/src/__tests__/app-bundler.test.ts +170 -1
- package/src/__tests__/app-control-flow.test.ts +384 -0
- package/src/__tests__/app-control-no-global-cgevent.test.ts +98 -0
- package/src/__tests__/app-control-tool-schemas.test.ts +621 -0
- package/src/__tests__/app-executors.test.ts +30 -43
- package/src/__tests__/approval-routes-http.test.ts +23 -6
- package/src/__tests__/assistant-event-hub-machine-name.test.ts +146 -0
- package/src/__tests__/assistant-event-hub-targeted.test.ts +257 -0
- package/src/__tests__/assistant-event-hub.test.ts +157 -2
- package/src/__tests__/assistant-feature-flags-integration.test.ts +29 -7
- package/src/__tests__/auto-analysis-end-to-end.test.ts +62 -1
- package/src/__tests__/background-shell-host-bash.test.ts +14 -15
- package/src/__tests__/background-workers-disk-pressure.test.ts +268 -0
- package/src/__tests__/bootstrap-turn-cleanup.test.ts +44 -0
- package/src/__tests__/btw-routes.test.ts +13 -4
- package/src/__tests__/call-controller.test.ts +49 -1
- package/src/__tests__/call-conversation-messages.test.ts +8 -2
- package/src/__tests__/call-domain.test.ts +0 -2
- package/src/__tests__/call-routes-http.test.ts +0 -2
- package/src/__tests__/channel-inbound-disk-pressure.test.ts +537 -0
- package/src/__tests__/channel-readiness-service.test.ts +62 -2
- package/src/__tests__/checker.test.ts +3 -4
- package/src/__tests__/config-loader-backfill.test.ts +461 -147
- package/src/__tests__/config-loader-platform-defaults.test.ts +196 -0
- package/src/__tests__/config-schema-cmd.test.ts +0 -1
- package/src/__tests__/config-schema.test.ts +1 -0
- package/src/__tests__/config-set-platform-guard.test.ts +48 -4
- package/src/__tests__/config-watcher-cleanup-throttle.test.ts +20 -11
- package/src/__tests__/config-watcher.test.ts +142 -71
- package/src/__tests__/context-search-agent-runner.test.ts +61 -3
- package/src/__tests__/context-search-conversations-source.test.ts +0 -24
- package/src/__tests__/context-search-fanout.test.ts +0 -1
- package/src/__tests__/context-search-memory-source.test.ts +3 -7
- package/src/__tests__/context-search-memory-v2-source.test.ts +0 -2
- package/src/__tests__/context-search-pkb-source.test.ts +0 -1
- package/src/__tests__/context-search-workspace-source.test.ts +0 -1
- package/src/__tests__/conversation-abort-tool-results.test.ts +6 -0
- package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +223 -0
- package/src/__tests__/conversation-agent-loop.test.ts +454 -5
- package/src/__tests__/conversation-app-control-instantiation.test.ts +392 -0
- package/src/__tests__/conversation-app-control-lifecycle.test.ts +237 -0
- package/src/__tests__/conversation-error.test.ts +150 -3
- package/src/__tests__/conversation-init.benchmark.test.ts +0 -2
- package/src/__tests__/conversation-lifecycle.test.ts +36 -0
- package/src/__tests__/conversation-process-app-control-preactivation.test.ts +283 -0
- package/src/__tests__/conversation-process-callsite.test.ts +43 -0
- package/src/__tests__/conversation-provider-retry-repair.test.ts +6 -0
- package/src/__tests__/conversation-routes-disk-view.test.ts +6 -0
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +120 -72
- package/src/__tests__/conversation-routes-slash-commands.test.ts +1 -0
- package/src/__tests__/conversation-runtime-assembly.test.ts +65 -0
- package/src/__tests__/conversation-slash-commands.test.ts +0 -4
- package/src/__tests__/conversation-slash-unknown.test.ts +6 -0
- package/src/__tests__/conversation-speed-override.test.ts +0 -3
- package/src/__tests__/conversation-store.test.ts +0 -18
- package/src/__tests__/conversation-surfaces-action-delivery.test.ts +202 -0
- package/src/__tests__/conversation-surfaces-app-control.test.ts +328 -0
- package/src/__tests__/conversation-surfaces-data-persist.test.ts +404 -0
- package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +2 -5
- package/src/__tests__/conversation-workspace-injection.test.ts +6 -0
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +6 -0
- package/src/__tests__/credential-execution-feature-gates.test.ts +5 -12
- package/src/__tests__/credential-execution-managed-contract.test.ts +3 -131
- package/src/__tests__/credentials-cli.test.ts +12 -12
- package/src/__tests__/cu-unified-flow.test.ts +351 -23
- package/src/__tests__/daemon-credential-client.test.ts +101 -19
- package/src/__tests__/date-context.test.ts +164 -2
- package/src/__tests__/db-schedule-syntax-migration.test.ts +2 -0
- package/src/__tests__/disk-pressure-guard.test.ts +262 -0
- package/src/__tests__/disk-pressure-lifecycle.test.ts +168 -0
- package/src/__tests__/disk-pressure-policy.test.ts +241 -0
- package/src/__tests__/disk-pressure-routes.test.ts +379 -0
- package/src/__tests__/disk-pressure-tools.test.ts +277 -0
- package/src/__tests__/disk-usage.test.ts +150 -0
- package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +0 -1
- package/src/__tests__/events-client-registration.test.ts +52 -0
- package/src/__tests__/events-dev-bypass-actor.test.ts +162 -0
- package/src/__tests__/file-write-tool.test.ts +4 -10
- package/src/__tests__/filing-service.test.ts +3 -4
- package/src/__tests__/gateway-only-enforcement.test.ts +0 -1
- package/src/__tests__/guardian-verification-voice-binding.test.ts +0 -2
- package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +0 -2
- package/src/__tests__/handlers-user-message-approval-consumption.test.ts +0 -1
- package/src/__tests__/heartbeat-disk-pressure.test.ts +183 -0
- package/src/__tests__/heartbeat-service.test.ts +968 -2
- package/src/__tests__/helpers/call-route-handler.ts +7 -1
- package/src/__tests__/host-app-control-proxy.test.ts +772 -0
- package/src/__tests__/host-app-control-routes.test.ts +263 -0
- package/src/__tests__/host-bash-proxy.test.ts +439 -47
- package/src/__tests__/host-bash-routes.test.ts +459 -0
- package/src/__tests__/host-browser-proxy.test.ts +24 -22
- package/src/__tests__/host-browser-routes.test.ts +39 -13
- package/src/__tests__/host-cu-proxy.test.ts +248 -52
- package/src/__tests__/host-cu-routes-targeted.test.ts +429 -0
- package/src/__tests__/host-file-edit-tool.test.ts +47 -1
- package/src/__tests__/host-file-proxy-targeted.test.ts +378 -0
- package/src/__tests__/host-file-proxy.test.ts +301 -45
- package/src/__tests__/host-file-read-tool.test.ts +17 -0
- package/src/__tests__/host-file-routes-targeted.test.ts +420 -0
- package/src/__tests__/host-file-write-tool.test.ts +42 -1
- package/src/__tests__/host-proxy-base.test.ts +312 -0
- package/src/__tests__/host-shell-tool.test.ts +22 -4
- package/src/__tests__/host-transfer-proxy-targeted.test.ts +932 -0
- package/src/__tests__/host-transfer-proxy.test.ts +121 -22
- package/src/__tests__/host-transfer-routes-targeted.test.ts +662 -0
- package/src/__tests__/http-user-message-parity.test.ts +108 -1
- package/src/__tests__/identity-intro-cache.test.ts +29 -0
- package/src/__tests__/identity-routes.test.ts +103 -1
- package/src/__tests__/init-feature-flag-overrides.test.ts +26 -3
- package/src/__tests__/injector-chain.test.ts +18 -6
- package/src/__tests__/injector-disk-pressure.test.ts +224 -0
- package/src/__tests__/inline-command-runner.test.ts +0 -1
- package/src/__tests__/inline-skill-load-permissions.test.ts +5 -11
- package/src/__tests__/integration-status.test.ts +85 -5
- package/src/__tests__/intent-routing.test.ts +0 -1
- package/src/__tests__/jobs-store-qdrant-breaker.test.ts +95 -5
- package/src/__tests__/lifecycle-memory-v2-seed.test.ts +17 -0
- package/src/__tests__/managed-profile-guard.test.ts +18 -0
- package/src/__tests__/managed-skill-lifecycle.test.ts +0 -1
- package/src/__tests__/mcp-abort-signal.test.ts +130 -0
- package/src/__tests__/mcp-auth-routes.test.ts +197 -0
- package/src/__tests__/mcp-cli.test.ts +338 -2
- package/src/__tests__/memory-admin-recall.test.ts +3 -11
- package/src/__tests__/memory-jobs-worker-lanes.test.ts +188 -0
- package/src/__tests__/memory-retrieval-pipeline.test.ts +22 -1
- package/src/__tests__/migration-import-commit-http.test.ts +108 -2
- package/src/__tests__/mock-gateway-ipc.ts +1 -0
- package/src/__tests__/normalize-onboarding.test.ts +180 -0
- package/src/__tests__/oauth-cli.test.ts +0 -2
- package/src/__tests__/oauth-connect-routes.test.ts +316 -0
- package/src/__tests__/oauth-provider-seed-logos.test.ts +24 -2
- package/src/__tests__/oauth2-gateway-transport.test.ts +0 -1
- package/src/__tests__/onboarding-persona-write.test.ts +308 -0
- package/src/__tests__/openai-provider.test.ts +45 -8
- package/src/__tests__/persist-onboarding-artifacts.test.ts +44 -64
- package/src/__tests__/persistence-secret-redaction.test.ts +299 -0
- package/src/__tests__/platform-bash-auto-approve.test.ts +5 -9
- package/src/__tests__/platform-callback-registration.test.ts +21 -4
- package/src/__tests__/platform.test.ts +2 -1
- package/src/__tests__/playbook-execution.test.ts +0 -43
- package/src/__tests__/plugin-tool-contribution.test.ts +47 -0
- package/src/__tests__/prechat-onboarding-contract.test.ts +214 -25
- package/src/__tests__/process-message-background-slack.test.ts +2 -0
- package/src/__tests__/provider-commit-message-generator.test.ts +0 -1
- package/src/__tests__/provider-tool-name.test.ts +23 -0
- package/src/__tests__/public-ingress-urls.test.ts +97 -0
- package/src/__tests__/relay-server.test.ts +15 -4
- package/src/__tests__/require-fresh-approval.test.ts +0 -1
- package/src/__tests__/retry-backoff.test.ts +87 -0
- package/src/__tests__/runtime-events-sse.test.ts +2 -2
- package/src/__tests__/sanitize-config-for-transfer.test.ts +24 -2
- package/src/__tests__/schedule-retry.test.ts +715 -0
- package/src/__tests__/scheduler-disk-pressure.test.ts +148 -0
- package/src/__tests__/script-proxy-mitm-handler.test.ts +1 -1
- package/src/__tests__/secret-ingress-http.test.ts +1 -1
- package/src/__tests__/send-endpoint-busy.test.ts +3 -0
- package/src/__tests__/shell-tool-proxy-mode.test.ts +0 -1
- package/src/__tests__/skill-feature-flags.test.ts +43 -41
- package/src/__tests__/skill-load-feature-flag.test.ts +13 -14
- package/src/__tests__/skill-load-inline-command.test.ts +0 -51
- package/src/__tests__/skill-load-inline-includes.test.ts +0 -43
- package/src/__tests__/skill-projection.benchmark.test.ts +0 -1
- package/src/__tests__/skill-script-runner-sandbox.test.ts +0 -1
- package/src/__tests__/slack-channel-config.test.ts +9 -14
- package/src/__tests__/suggestion-routes.test.ts +46 -0
- package/src/__tests__/system-prompt-ask-mode.test.ts +0 -1
- package/src/__tests__/system-prompt.test.ts +0 -1
- package/src/__tests__/telegram-config.test.ts +0 -1
- package/src/__tests__/test-preload.ts +8 -0
- package/src/__tests__/tool-approval-handler.test.ts +3 -4
- package/src/__tests__/tool-audit-listener.test.ts +48 -0
- package/src/__tests__/tool-execute-pipeline.test.ts +0 -1
- package/src/__tests__/tool-execution-abort-cleanup.test.ts +0 -1
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +0 -1
- package/src/__tests__/tool-executor.test.ts +0 -1
- package/src/__tests__/twilio-config.test.ts +3 -16
- package/src/__tests__/twilio-routes.test.ts +3 -5
- package/src/__tests__/twilio-validation.test.ts +93 -0
- package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +1 -4
- package/src/__tests__/verification-control-plane-policy.test.ts +2 -4
- package/src/__tests__/voice-ingress-preflight.test.ts +19 -0
- package/src/__tests__/workspace-migration-006-services-config.test.ts +3 -2
- package/src/__tests__/workspace-migration-065-bump-stale-heartbeat-interval.test.ts +122 -0
- package/src/__tests__/workspace-migration-066-seed-heartbeat-callsite-cost-default.test.ts +285 -0
- package/src/__tests__/workspace-migration-068-release-notes-local-timezone.test.ts +90 -0
- package/src/__tests__/workspace-migration-backfill-installation-id.test.ts +1 -5
- package/src/__tests__/workspace-migration-down-functions.test.ts +8 -8
- package/src/__tests__/workspace-migration-safe-storage-limits-release.test.ts +90 -0
- package/src/__tests__/workspace-migration-unify-llm-callsite-configs.test.ts +10 -6
- package/src/approvals/guardian-decision-primitive.ts +13 -0
- package/src/approvals/guardian-request-resolvers.ts +16 -17
- package/src/backup/__tests__/paths.test.ts +0 -22
- package/src/backup/__tests__/restore.test.ts +51 -151
- package/src/backup/paths.ts +2 -18
- package/src/backup/restore.ts +107 -231
- package/src/backup/snapshot-lock.ts +2 -27
- package/src/bundler/app-bundler.ts +51 -3
- package/src/bundler/compiler-tools.ts +3 -2
- package/src/calls/call-conversation-messages.ts +46 -10
- package/src/calls/relay-server.ts +4 -44
- package/src/calls/twilio-config.ts +2 -17
- package/src/calls/twilio-rest.ts +33 -105
- package/src/calls/twilio-routes.ts +11 -12
- package/src/channels/types.ts +8 -7
- package/src/cli/commands/__tests__/backup.test.ts +6 -277
- package/src/cli/commands/__tests__/gateway.test.ts +288 -0
- package/src/cli/commands/__tests__/memory-v2.test.ts +4 -0
- package/src/cli/commands/__tests__/webhooks.test.ts +0 -5
- package/src/cli/commands/backup.ts +6 -331
- package/src/cli/commands/bash.ts +35 -108
- package/src/cli/commands/clients.ts +36 -37
- package/src/cli/commands/contacts.ts +137 -25
- package/src/cli/commands/conversations.ts +2 -5
- package/src/cli/commands/credentials.ts +71 -7
- package/src/cli/commands/domain.ts +66 -15
- package/src/cli/commands/gateway.ts +183 -0
- package/src/cli/commands/keys.ts +9 -6
- package/src/cli/commands/mcp.ts +116 -156
- package/src/cli/commands/memory-v2.ts +303 -7
- package/src/cli/commands/oauth/__tests__/connect.test.ts +437 -1
- package/src/cli/commands/oauth/connect.ts +127 -1
- package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +0 -4
- package/src/cli/commands/platform/__tests__/connect.test.ts +7 -3
- package/src/cli/commands/platform/__tests__/disconnect.test.ts +7 -3
- package/src/cli/commands/platform/__tests__/status.test.ts +116 -21
- package/src/cli/commands/platform/disconnect.ts +5 -4
- package/src/cli/commands/platform/index.ts +16 -25
- package/src/cli/commands/status.ts +57 -0
- package/src/cli/lib/daemon-credential-client.ts +110 -28
- package/src/cli/program.ts +6 -2
- package/src/config/assistant-feature-flags.ts +79 -12
- package/src/config/bundled-skills/acp/SKILL.md +6 -0
- package/src/config/bundled-skills/acp/TOOLS.json +1 -22
- package/src/config/bundled-skills/app-builder/SKILL.md +14 -109
- package/src/config/bundled-skills/app-builder/TOOLS.json +1 -28
- package/src/config/bundled-skills/app-builder/tools/app-create.ts +1 -10
- package/src/config/bundled-skills/app-control/SKILL.md +75 -0
- package/src/config/bundled-skills/app-control/TOOLS.json +299 -0
- package/src/config/bundled-skills/app-control/tools/app-control-click.ts +12 -0
- package/src/config/bundled-skills/app-control/tools/app-control-combo.ts +12 -0
- package/src/config/bundled-skills/app-control/tools/app-control-drag.ts +12 -0
- package/src/config/bundled-skills/app-control/tools/app-control-observe.ts +12 -0
- package/src/config/bundled-skills/app-control/tools/app-control-press.ts +12 -0
- package/src/config/bundled-skills/app-control/tools/app-control-sequence.ts +12 -0
- package/src/config/bundled-skills/app-control/tools/app-control-start.ts +12 -0
- package/src/config/bundled-skills/app-control/tools/app-control-stop.ts +12 -0
- package/src/config/bundled-skills/app-control/tools/app-control-type.ts +12 -0
- package/src/config/bundled-skills/computer-use/SKILL.md +6 -0
- package/src/config/bundled-skills/computer-use/TOOLS.json +67 -43
- package/src/config/bundled-skills/contacts/TOOLS.json +0 -16
- package/src/config/bundled-skills/document/TOOLS.json +0 -8
- package/src/config/bundled-skills/followups/TOOLS.json +0 -12
- package/src/config/bundled-skills/image-studio/SKILL.md +4 -0
- package/src/config/bundled-skills/image-studio/TOOLS.json +0 -4
- package/src/config/bundled-skills/media-processing/TOOLS.json +0 -24
- package/src/config/bundled-skills/messaging/TOOLS.json +0 -40
- package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +4 -3
- package/src/config/bundled-skills/phone-calls/TOOLS.json +0 -12
- package/src/config/bundled-skills/phone-calls/references/TROUBLESHOOTING.md +25 -4
- package/src/config/bundled-skills/playbooks/TOOLS.json +0 -16
- package/src/config/bundled-skills/playbooks/tools/playbook-create.ts +2 -2
- package/src/config/bundled-skills/playbooks/tools/playbook-delete.ts +2 -2
- package/src/config/bundled-skills/playbooks/tools/playbook-list.ts +2 -2
- package/src/config/bundled-skills/playbooks/tools/playbook-update.ts +2 -2
- package/src/config/bundled-skills/schedule/TOOLS.json +14 -14
- package/src/config/bundled-skills/sequences/TOOLS.json +0 -36
- package/src/config/bundled-skills/settings/SKILL.md +4 -0
- package/src/config/bundled-skills/settings/TOOLS.json +0 -12
- package/src/config/bundled-skills/skill-management/SKILL.md +6 -0
- package/src/config/bundled-skills/skill-management/TOOLS.json +0 -8
- package/src/config/bundled-skills/subagent/SKILL.md +6 -2
- package/src/config/bundled-skills/subagent/TOOLS.json +0 -20
- package/src/config/bundled-skills/transcribe/SKILL.md +4 -0
- package/src/config/bundled-skills/transcribe/TOOLS.json +0 -4
- package/src/config/bundled-tool-registry.ts +21 -0
- package/src/config/env-registry.ts +0 -2
- package/src/config/env.ts +19 -20
- package/src/config/feature-flag-registry.json +47 -135
- package/src/config/loader.ts +197 -104
- package/src/config/sanitize-for-transfer.ts +2 -0
- package/src/config/schemas/__tests__/memory-lifecycle.test.ts +80 -0
- package/src/config/schemas/__tests__/memory-v2.test.ts +17 -9
- package/src/config/schemas/call-site-catalog.ts +14 -0
- package/src/config/schemas/calls.ts +0 -9
- package/src/config/schemas/channels.ts +0 -5
- package/src/config/schemas/heartbeat.ts +64 -1
- package/src/config/schemas/ingress.ts +10 -6
- package/src/config/schemas/llm.ts +7 -10
- package/src/config/schemas/memory-lifecycle.ts +90 -24
- package/src/config/schemas/memory-v2.ts +121 -13
- package/src/config/schemas/platform.ts +49 -3
- package/src/config/schemas/services.ts +29 -15
- package/src/config/schemas/skills.ts +0 -6
- package/src/config/seed-inference-profiles.ts +230 -33
- package/src/contacts/contact-store.ts +0 -55
- package/src/contacts/contacts-write.ts +0 -27
- package/src/context/window-manager.ts +1 -2
- package/src/credential-execution/feature-gates.ts +10 -10
- package/src/credential-execution/process-manager.ts +12 -41
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +187 -5
- package/src/daemon/assistant-attachments.ts +4 -4
- package/src/daemon/bootstrap-turn-cleanup.ts +45 -0
- package/src/daemon/config-watcher.ts +89 -60
- package/src/daemon/conversation-agent-loop-handlers.ts +27 -3
- package/src/daemon/conversation-agent-loop.ts +202 -61
- package/src/daemon/conversation-error.ts +87 -15
- package/src/daemon/conversation-lifecycle.ts +9 -4
- package/src/daemon/conversation-process.ts +24 -11
- package/src/daemon/conversation-runtime-assembly.ts +28 -2
- package/src/daemon/conversation-store.ts +2 -2
- package/src/daemon/conversation-surfaces.ts +305 -4
- package/src/daemon/conversation-tool-setup.ts +66 -62
- package/src/daemon/conversation.ts +38 -24
- package/src/daemon/date-context.ts +71 -22
- package/src/daemon/disk-pressure-background-gate.ts +73 -0
- package/src/daemon/disk-pressure-guard.ts +343 -0
- package/src/daemon/disk-pressure-policy.ts +163 -0
- package/src/daemon/doordash-steps.ts +1 -1
- package/src/daemon/handlers/shared.ts +4 -2
- package/src/daemon/handlers/skills.ts +3 -4
- package/src/daemon/host-app-control-proxy.ts +389 -0
- package/src/daemon/host-bash-proxy.ts +117 -82
- package/src/daemon/host-browser-proxy.ts +67 -82
- package/src/daemon/host-cu-proxy.ts +127 -86
- package/src/daemon/host-file-proxy.ts +129 -69
- package/src/daemon/host-proxy-base.ts +294 -0
- package/src/daemon/host-proxy-preactivation.ts +82 -0
- package/src/daemon/host-transfer-proxy.ts +338 -129
- package/src/daemon/lifecycle.ts +194 -145
- package/src/daemon/meet-host-supervisor.ts +4 -4
- package/src/daemon/meet-manifest-loader.ts +0 -1
- package/src/daemon/memory-v2-startup.ts +14 -4
- package/src/daemon/message-protocol.ts +6 -8
- package/src/daemon/message-types/contacts.ts +23 -1
- package/src/daemon/message-types/conversations.ts +15 -8
- package/src/daemon/message-types/disk-pressure.ts +9 -0
- package/src/daemon/message-types/host-app-control.ts +150 -0
- package/src/daemon/message-types/host-bash.ts +4 -0
- package/src/daemon/message-types/host-cu.ts +2 -0
- package/src/daemon/message-types/host-file.ts +4 -0
- package/src/daemon/message-types/host-transfer.ts +3 -0
- package/src/daemon/message-types/messages.ts +3 -0
- package/src/daemon/message-types/schedules.ts +8 -3
- package/src/daemon/message-types/skills.ts +2 -2
- package/src/daemon/process-message.ts +18 -1
- package/src/daemon/profiler-run-store.ts +5 -5
- package/src/daemon/shutdown-handlers.ts +0 -3
- package/src/daemon/tool-setup-types.ts +51 -0
- package/src/daemon/tool-side-effects.ts +1 -1
- package/src/documents/document-store.ts +85 -0
- package/src/events/tool-audit-listener.ts +2 -1
- package/src/filing/filing-service.ts +30 -5
- package/src/heartbeat/__tests__/heartbeat-feed-event.test.ts +24 -23
- package/src/heartbeat/__tests__/heartbeat-run-store.test.ts +252 -0
- package/src/heartbeat/heartbeat-run-store.ts +249 -0
- package/src/heartbeat/heartbeat-service.ts +459 -54
- package/src/home/__tests__/post-connect-feed.test.ts +99 -0
- package/src/home/__tests__/relationship-state-writer.test.ts +11 -9
- package/src/home/__tests__/suggested-prompts.test.ts +89 -0
- package/src/home/feed-scheduler.ts +18 -0
- package/src/home/post-connect-feed.ts +68 -0
- package/src/home/relationship-state-writer.ts +17 -92
- package/src/home/suggested-prompts.ts +46 -10
- package/src/inbound/platform-callback-registration.ts +8 -15
- package/src/inbound/public-ingress-urls.ts +32 -34
- package/src/ipc/__tests__/clients-list-ipc.test.ts +169 -0
- package/src/ipc/__tests__/route-error-envelope.test.ts +80 -0
- package/src/ipc/assistant-server.ts +70 -3
- package/src/ipc/cli-client.ts +32 -1
- package/src/ipc/gateway-client.ts +37 -3
- package/src/live-voice/live-voice-archive.ts +4 -4
- package/src/live-voice/live-voice-metrics.ts +10 -10
- package/src/live-voice/protocol.ts +5 -7
- package/src/mcp/__tests__/mcp-auth-orchestrator.test.ts +304 -0
- package/src/mcp/mcp-auth-orchestrator.ts +213 -0
- package/src/mcp/mcp-auth-state.ts +133 -0
- package/src/mcp/mcp-oauth-provider.ts +19 -0
- package/src/media/image-service.ts +1 -7
- package/src/memory/__tests__/fixtures/memory-v2-activation-fixtures.ts +21 -13
- package/src/memory/__tests__/jobs-store-job-classes.test.ts +24 -0
- package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +52 -22
- package/src/memory/__tests__/memory-v2-activation-log-store.test.ts +0 -6
- package/src/memory/__tests__/memory-v2-concept-frequency.test.ts +272 -0
- package/src/memory/__tests__/qdrant-client-sentinel.test.ts +49 -0
- package/src/memory/__tests__/sparse-tokenize.test.ts +66 -0
- package/src/memory/admin.ts +5 -9
- package/src/memory/anisotropy.test.ts +247 -0
- package/src/memory/anisotropy.ts +443 -0
- package/src/memory/auto-analysis-constants.ts +17 -0
- package/src/memory/auto-analysis-guard.ts +5 -15
- package/src/memory/canonical-guardian-store.ts +7 -7
- package/src/memory/context-search/__tests__/agent-runner-redaction.test.ts +122 -0
- package/src/memory/context-search/agent-protocol.ts +6 -6
- package/src/memory/context-search/agent-runner.ts +51 -9
- package/src/memory/context-search/sources/conversations.ts +2 -11
- package/src/memory/context-search/sources/memory-v2.ts +22 -9
- package/src/memory/context-search/sources/memory.ts +0 -1
- package/src/memory/context-search/types.ts +0 -1
- package/src/memory/conversation-crud.ts +5 -13
- package/src/memory/conversation-key-store.ts +2 -15
- package/src/memory/db-init.ts +6 -0
- package/src/memory/embedding-backend.ts +9 -21
- package/src/memory/embedding-runtime-manager.ts +119 -5
- package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +81 -25
- package/src/memory/graph/conversation-graph-memory.ts +43 -78
- package/src/memory/graph/extraction.ts +1 -3
- package/src/memory/graph/graph-search.test.ts +10 -67
- package/src/memory/graph/graph-search.ts +9 -20
- package/src/memory/graph/retriever.test.ts +6 -0
- package/src/memory/graph/retriever.ts +34 -10
- package/src/memory/graph/tools.ts +1 -1
- package/src/memory/indexer.ts +54 -45
- package/src/memory/job-handlers/backfill.ts +2 -11
- package/src/memory/job-handlers/cleanup.ts +43 -0
- package/src/memory/job-handlers/embedding.ts +6 -8
- package/src/memory/job-handlers/summarization.ts +2 -7
- package/src/memory/jobs/__tests__/embed-concept-page.test.ts +8 -2
- package/src/memory/jobs/embed-concept-page.ts +28 -2
- package/src/memory/jobs/embed-pkb-file.test.ts +2 -2
- package/src/memory/jobs-store.ts +114 -22
- package/src/memory/jobs-worker.ts +193 -106
- package/src/memory/memory-v2-activation-log-store.ts +33 -15
- package/src/memory/memory-v2-concept-frequency.ts +169 -0
- package/src/memory/migrations/237-heartbeat-runs.ts +45 -0
- package/src/memory/migrations/238-schedule-retry-policy.ts +20 -0
- package/src/memory/migrations/239-trace-events-created-at-index.ts +18 -0
- package/src/memory/migrations/index.ts +6 -0
- package/src/memory/migrations/registry.ts +8 -0
- package/src/memory/pkb/pkb-search.test.ts +6 -0
- package/src/memory/pkb/pkb-search.ts +7 -0
- package/src/memory/qdrant-client.ts +49 -32
- package/src/memory/rerank-local.ts +374 -0
- package/src/memory/schema/infrastructure.ts +15 -0
- package/src/memory/search/semantic.ts +13 -67
- package/src/memory/sparse-tokenize.ts +49 -0
- package/src/memory/trace-event-store.ts +1 -17
- package/src/memory/v2/__tests__/activation.test.ts +387 -344
- package/src/memory/v2/__tests__/consolidation-job.test.ts +40 -8
- package/src/memory/v2/__tests__/injection.test.ts +181 -169
- package/src/memory/v2/__tests__/prompts-consolidation.test.ts +61 -2
- package/src/memory/v2/__tests__/qdrant.test.ts +16 -0
- package/src/memory/v2/__tests__/reranker.test.ts +338 -0
- package/src/memory/v2/__tests__/sim.test.ts +154 -188
- package/src/memory/v2/__tests__/skill-store.test.ts +71 -65
- package/src/memory/v2/__tests__/sparse-bm25.test.ts +292 -0
- package/src/memory/v2/__tests__/static-context.test.ts +76 -2
- package/src/memory/v2/activation.ts +213 -239
- package/src/memory/v2/consolidation-job.ts +65 -17
- package/src/memory/v2/constants.ts +7 -0
- package/src/memory/v2/injection.ts +123 -103
- package/src/memory/v2/prompts/consolidation.ts +348 -92
- package/src/memory/v2/qdrant.ts +198 -1
- package/src/memory/v2/reranker.ts +177 -0
- package/src/memory/v2/sim.ts +113 -77
- package/src/memory/v2/skill-content.ts +4 -3
- package/src/memory/v2/skill-store.ts +91 -53
- package/src/memory/v2/sparse-bm25.ts +245 -0
- package/src/memory/v2/static-context.ts +28 -5
- package/src/memory/v2/types.ts +10 -10
- package/src/messaging/providers/gmail/types.ts +0 -49
- package/src/messaging/providers/slack/adapter.ts +1 -31
- package/src/messaging/providers/slack/types.ts +0 -32
- package/src/notifications/README.md +10 -10
- package/src/notifications/broadcaster.ts +1 -1
- package/src/notifications/copy-composer.ts +13 -0
- package/src/notifications/guardian-question-mode.ts +5 -5
- package/src/notifications/signal.ts +4 -0
- package/src/oauth/AGENTS.md +3 -1
- package/src/oauth/__tests__/oauth-connect-state.test.ts +137 -0
- package/src/oauth/connect-orchestrator.ts +6 -0
- package/src/oauth/connection-resolver.test.ts +66 -1
- package/src/oauth/connection-resolver.ts +55 -1
- package/src/oauth/credential-token-resolver.ts +1 -3
- package/src/oauth/manual-token-connection.ts +0 -4
- package/src/oauth/oauth-connect-state.ts +77 -0
- package/src/oauth/seed-providers.ts +58 -1
- package/src/outbound-proxy/index.ts +1 -37
- package/src/outbound-proxy/logging.ts +1 -1
- package/src/outbound-proxy/policy.ts +6 -5
- package/src/outbound-proxy/router.ts +2 -1
- package/src/permissions/approval-policy.test.ts +6 -275
- package/src/permissions/approval-policy.ts +0 -51
- package/src/permissions/checker.test.ts +0 -1
- package/src/permissions/checker.ts +3 -17
- package/src/permissions/gateway-threshold-reader.ts +2 -0
- package/src/permissions/prompter.ts +34 -1
- package/src/permissions/secret-prompter.ts +6 -2
- package/src/plugins/defaults/injectors.ts +35 -2
- package/src/plugins/defaults/memory-retrieval.ts +5 -6
- package/src/plugins/types.ts +7 -0
- package/src/proactive-artifact/aux-message-injector.ts +74 -0
- package/src/proactive-artifact/decision.test.ts +226 -0
- package/src/proactive-artifact/decision.ts +165 -0
- package/src/proactive-artifact/index.ts +7 -0
- package/src/proactive-artifact/job.test.ts +867 -0
- package/src/proactive-artifact/job.ts +352 -0
- package/src/proactive-artifact/message-copy.ts +41 -0
- package/src/proactive-artifact/trigger-state.test.ts +277 -0
- package/src/proactive-artifact/trigger-state.ts +119 -0
- package/src/prompts/bootstrap-cleanup.ts +27 -0
- package/src/prompts/normalize-onboarding.ts +80 -0
- package/src/prompts/persona-resolver.ts +101 -9
- package/src/prompts/system-prompt.ts +23 -24
- package/src/prompts/templates/BOOTSTRAP.md +13 -5
- package/src/prompts/templates/SOUL.md +13 -1
- package/src/providers/__tests__/retry-callsite.test.ts +222 -1
- package/src/providers/model-intents.ts +7 -0
- package/src/providers/openrouter/client.ts +8 -0
- package/src/providers/retry.ts +50 -0
- package/src/providers/speech-to-text/provider-catalog.ts +7 -8
- package/src/providers/types.ts +1 -0
- package/src/runtime/__tests__/agent-wake.test.ts +456 -3
- package/src/runtime/agent-wake.ts +238 -100
- package/src/runtime/assistant-event-hub.ts +151 -99
- package/src/runtime/auth/__tests__/middleware.test.ts +11 -56
- package/src/runtime/auth/__tests__/route-policy.test.ts +64 -0
- package/src/runtime/auth/middleware.ts +0 -96
- package/src/runtime/auth/route-policy.ts +32 -0
- package/src/runtime/auth/same-actor.ts +216 -0
- package/src/runtime/btw-sidechain.ts +2 -3
- package/src/runtime/channel-invite-transport.ts +2 -48
- package/src/runtime/channel-invite-transports/email.ts +1 -1
- package/src/runtime/channel-invite-transports/slack.ts +1 -1
- package/src/runtime/channel-invite-transports/telegram.ts +1 -1
- package/src/runtime/channel-invite-transports/voice.ts +1 -1
- package/src/runtime/channel-invite-transports/whatsapp.ts +1 -1
- package/src/runtime/channel-invite-types.ts +54 -0
- package/src/runtime/channel-readiness-service.ts +32 -13
- package/src/runtime/channel-retry-sweep.ts +65 -1
- package/src/runtime/guardian-reply-router.ts +10 -0
- package/src/runtime/http-server.ts +3 -329
- package/src/runtime/http-types.ts +0 -5
- package/src/runtime/local-actor-identity.ts +52 -11
- package/src/runtime/migrations/__tests__/vbundle-import-parity.test.ts +413 -0
- package/src/runtime/migrations/__tests__/vbundle-import-policy.test.ts +260 -0
- package/src/runtime/migrations/__tests__/vbundle-import-version-compat.test.ts +189 -0
- package/src/runtime/migrations/__tests__/vbundle-streaming-importer.test.ts +153 -1
- package/src/runtime/migrations/__tests__/vbundle-symlink-importer.test.ts +451 -0
- package/src/runtime/migrations/__tests__/vbundle-symlink-streaming-importer.test.ts +0 -0
- package/src/runtime/migrations/__tests__/vbundle-symlink-streaming.test.ts +515 -0
- package/src/runtime/migrations/__tests__/vbundle-symlink-tar.test.ts +437 -0
- package/src/runtime/migrations/__tests__/vbundle-symlink-walker.test.ts +319 -0
- package/src/runtime/migrations/__tests__/vbundle-validator-v1-schema.test.ts +51 -1
- package/src/runtime/migrations/migration-transport.ts +7 -7
- package/src/runtime/migrations/vbundle-builder.ts +327 -60
- package/src/runtime/migrations/vbundle-import-analyzer.ts +4 -4
- package/src/runtime/migrations/vbundle-import-policy.ts +172 -0
- package/src/runtime/migrations/vbundle-importer.ts +245 -68
- package/src/runtime/migrations/vbundle-streaming-importer.ts +326 -35
- package/src/runtime/migrations/vbundle-streaming-validator.ts +157 -4
- package/src/runtime/migrations/vbundle-tar-stream.ts +15 -6
- package/src/runtime/migrations/vbundle-validator.ts +114 -0
- package/src/runtime/pending-interactions.ts +43 -9
- package/src/runtime/routes/__tests__/backup-routes.test.ts +22 -150
- package/src/runtime/routes/__tests__/client-routes.test.ts +155 -0
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +98 -5
- package/src/runtime/routes/__tests__/gateway-log-routes.test.ts +242 -0
- package/src/runtime/routes/__tests__/heartbeat-routes.test.ts +112 -0
- package/src/runtime/routes/approval-interception-types.ts +13 -0
- package/src/runtime/routes/approval-strategies/guardian-text-engine-strategy.ts +1 -1
- package/src/runtime/routes/backup-routes.ts +15 -38
- package/src/runtime/routes/btw-routes.ts +14 -37
- package/src/runtime/routes/client-routes.ts +21 -2
- package/src/runtime/routes/contact-prompt-routes.ts +183 -0
- package/src/runtime/routes/contact-routes.ts +0 -25
- package/src/runtime/routes/conversation-query-routes.ts +36 -1
- package/src/runtime/routes/conversation-routes.ts +65 -39
- package/src/runtime/routes/debug-bash-routes.ts +163 -0
- package/src/runtime/routes/disk-pressure-routes.ts +121 -0
- package/src/runtime/routes/document-pdf-renderer.ts +169 -0
- package/src/runtime/routes/documents-routes.ts +32 -75
- package/src/runtime/routes/errors.ts +19 -4
- package/src/runtime/routes/events-routes.ts +38 -0
- package/src/runtime/routes/gateway-log-routes.ts +79 -0
- package/src/runtime/routes/guardian-approval-interception.ts +2 -8
- package/src/runtime/routes/heartbeat-routes.ts +103 -38
- package/src/runtime/routes/host-app-control-routes.ts +134 -0
- package/src/runtime/routes/host-bash-routes.ts +56 -6
- package/src/runtime/routes/host-browser-routes.ts +108 -13
- package/src/runtime/routes/host-cu-routes.ts +66 -9
- package/src/runtime/routes/host-file-routes.ts +54 -5
- package/src/runtime/routes/host-transfer-routes.ts +122 -19
- package/src/runtime/routes/http-adapter.ts +1 -0
- package/src/runtime/routes/identity-intro-cache.ts +30 -0
- package/src/runtime/routes/identity-routes.ts +21 -180
- package/src/runtime/routes/inbound-message-handler.ts +78 -21
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +0 -7
- package/src/runtime/routes/inbound-stages/edit-intercept.ts +0 -8
- package/src/runtime/routes/inbound-stages/guardian-reply-intercept.ts +3 -0
- package/src/runtime/routes/inbound-stages/transcribe-audio.test.ts +0 -20
- package/src/runtime/routes/inbound-stages/transcribe-audio.ts +5 -13
- package/src/runtime/routes/index.ts +14 -0
- package/src/runtime/routes/mcp-auth-routes.ts +132 -0
- package/src/runtime/routes/memory-item-routes.test.ts +41 -15
- package/src/runtime/routes/memory-item-routes.ts +10 -12
- package/src/runtime/routes/memory-v2-routes.ts +474 -1
- package/src/runtime/routes/migration-routes.ts +96 -0
- package/src/runtime/routes/oauth-connect-routes.ts +153 -0
- package/src/runtime/routes/schedule-routes.ts +7 -0
- package/src/runtime/verification-outbound-actions.ts +4 -4
- package/src/runtime/verification-templates.ts +4 -7
- package/src/schedule/integration-status.ts +66 -2
- package/src/schedule/recurrence-engine.ts +4 -1
- package/src/schedule/retry-backoff.ts +18 -0
- package/src/schedule/retry-policy.ts +82 -0
- package/src/schedule/run-script.ts +37 -5
- package/src/schedule/schedule-recovery.ts +64 -0
- package/src/schedule/schedule-store.ts +106 -2
- package/src/schedule/scheduler-types.ts +25 -0
- package/src/schedule/scheduler.ts +83 -39
- package/src/security/encrypted-store.ts +2 -0
- package/src/security/oauth-callback-registry.ts +8 -0
- package/src/security/secure-keys.ts +55 -0
- package/src/sequence/analytics.ts +5 -5
- package/src/sequence/engine.ts +1 -1
- package/src/skills/catalog-files.ts +2 -8
- package/src/skills/include-graph.ts +5 -5
- package/src/skills/remote-skill-policy.ts +10 -16
- package/src/skills/skill-file-provider.ts +1 -1
- package/src/skills/skill-file-types.ts +13 -0
- package/src/skills/skillssh-audit-types.ts +28 -0
- package/src/skills/skillssh-registry.ts +8 -21
- package/src/subagent/index.ts +1 -7
- package/src/subagent/manager.ts +1 -15
- package/src/tasks/task-runner.ts +0 -1
- package/src/tasks/task-store.ts +0 -3
- package/src/telemetry/types.ts +2 -0
- package/src/telemetry/usage-telemetry-reporter.test.ts +21 -0
- package/src/telemetry/usage-telemetry-reporter.ts +1 -0
- package/src/tools/app-control/skill-proxy-bridge.ts +28 -0
- package/src/tools/apps/executors.ts +56 -69
- package/src/tools/background-tool-registry.ts +17 -3
- package/src/tools/browser/__tests__/browser-status.test.ts +21 -18
- package/src/tools/browser/browser-execution.ts +2 -2
- package/src/tools/browser/cdp-client/__tests__/factory.test.ts +55 -4
- package/src/tools/browser/cdp-client/cdp-inspect/__tests__/ws-transport.test.ts +12 -6
- package/src/tools/browser/cdp-client/factory.ts +23 -24
- package/src/tools/browser/cdp-client/index.ts +1 -14
- package/src/tools/computer-use/definitions.ts +42 -20
- package/src/tools/executor.ts +2 -0
- package/src/tools/host-filesystem/edit.test.ts +151 -0
- package/src/tools/host-filesystem/edit.ts +68 -0
- package/src/tools/host-filesystem/read.test.ts +129 -0
- package/src/tools/host-filesystem/read.ts +68 -0
- package/src/tools/host-filesystem/transfer.test.ts +127 -2
- package/src/tools/host-filesystem/transfer.ts +78 -3
- package/src/tools/host-filesystem/write.test.ts +134 -0
- package/src/tools/host-filesystem/write.ts +68 -0
- package/src/tools/host-terminal/host-shell.ts +66 -1
- package/src/tools/mcp/mcp-tool-factory.ts +2 -1
- package/src/tools/memory/register.test.ts +12 -9
- package/src/tools/memory/register.ts +1 -2
- package/src/tools/provider-tool-name.ts +28 -0
- package/src/tools/registry.ts +30 -9
- package/src/tools/schedule/create.ts +6 -0
- package/src/tools/schedule/list.ts +2 -0
- package/src/tools/schedule/update.ts +10 -0
- package/src/tools/shared/filesystem/file-ops-service.ts +2 -0
- package/src/tools/shared/filesystem/path-policy.ts +25 -1
- package/src/tools/skills/load.ts +0 -32
- package/src/tools/terminal/shell.ts +9 -1
- package/src/tools/tool-approval-handler.ts +32 -11
- package/src/tools/types.ts +28 -2
- package/src/tts/provider-catalog.ts +3 -5
- package/src/usage/pricing.ts +1 -1
- package/src/util/disk-usage.ts +138 -0
- package/src/util/platform.ts +21 -11
- package/src/util/process-liveness.ts +26 -0
- package/src/workspace/hatched-date.ts +86 -0
- package/src/workspace/heartbeat-service.ts +19 -0
- package/src/workspace/migrations/003-seed-device-id.ts +1 -1
- package/src/workspace/migrations/006-services-config.ts +8 -5
- package/src/workspace/migrations/016-extract-feature-flags-to-protected.ts +3 -9
- package/src/workspace/migrations/021-move-signals-to-workspace.ts +4 -10
- package/src/workspace/migrations/022-move-hooks-to-workspace.ts +4 -10
- package/src/workspace/migrations/023-move-config-files-to-workspace.ts +4 -11
- package/src/workspace/migrations/024-move-runtime-files-to-workspace.ts +3 -10
- package/src/workspace/migrations/040-seed-latency-callsite-defaults.ts +3 -2
- package/src/workspace/migrations/050-seed-main-agent-opus-callsite.ts +2 -1
- package/src/workspace/migrations/059-move-pid-to-workspace.ts +3 -8
- package/src/workspace/migrations/061-move-backup-key-to-workspace.ts +3 -8
- package/src/workspace/migrations/065-bump-stale-heartbeat-interval.ts +60 -0
- package/src/workspace/migrations/066-seed-heartbeat-callsite-cost-default.ts +146 -0
- package/src/workspace/migrations/067-release-notes-safe-storage-limits.ts +72 -0
- package/src/workspace/migrations/068-release-notes-local-timezone.ts +65 -0
- package/src/workspace/migrations/AGENTS.md +1 -1
- package/src/workspace/migrations/migrate-to-workspace-volume.ts +4 -10
- package/src/workspace/migrations/registry.ts +8 -0
- package/src/workspace/migrations/utils.ts +21 -0
- package/src/__tests__/conversation-tool-setup-memory-scope.test.ts +0 -167
- package/src/__tests__/host-browser-e2e-cloud.test.ts +0 -443
- package/src/__tests__/host-browser-e2e-self-hosted-capability.test.ts +0 -226
- package/src/__tests__/host-browser-ws-events-e2e.test.ts +0 -427
- package/src/__tests__/twilio-rest.test.ts +0 -34
- package/src/backup/__tests__/backup-key.test.ts +0 -152
- package/src/backup/__tests__/backup-worker.test.ts +0 -782
- package/src/backup/__tests__/offsite-writer.test.ts +0 -641
- package/src/backup/__tests__/stream-crypt.test.ts +0 -228
- package/src/backup/backup-key.ts +0 -137
- package/src/backup/backup-worker.ts +0 -472
- package/src/backup/offsite-writer.ts +0 -222
- package/src/backup/stream-crypt.ts +0 -263
- package/src/daemon/message-types/pairing.ts +0 -58
- package/src/memory/v2/__tests__/skill-qdrant.test.ts +0 -657
- package/src/memory/v2/skill-qdrant.ts +0 -395
- package/src/outbound-proxy/config.ts +0 -20
- package/src/outbound-proxy/health.ts +0 -18
- package/src/outbound-proxy/types.ts +0 -150
- package/src/runtime/capability-tokens.ts +0 -190
- package/src/signals/bash.ts +0 -198
- package/src/signals/mcp-reload.ts +0 -18
|
@@ -14,6 +14,31 @@
|
|
|
14
14
|
|
|
15
15
|
import type { HostProxyCapability, InterfaceId } from "../channels/types.js";
|
|
16
16
|
import type { ServerMessage } from "../daemon/message-protocol.js";
|
|
17
|
+
|
|
18
|
+
// ---------------------------------------------------------------------------
|
|
19
|
+
// Message type → capability inference
|
|
20
|
+
// ---------------------------------------------------------------------------
|
|
21
|
+
|
|
22
|
+
const HOST_PREFIX_TO_CAPABILITY: Record<string, HostProxyCapability> = {
|
|
23
|
+
host_bash: "host_bash",
|
|
24
|
+
host_file: "host_file",
|
|
25
|
+
host_transfer: "host_file", // transfers piggyback on host_file capability
|
|
26
|
+
host_cu: "host_cu",
|
|
27
|
+
host_browser: "host_browser",
|
|
28
|
+
host_app_control: "host_app_control",
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Infer the {@link HostProxyCapability} a message should be targeted at based
|
|
33
|
+
* on its `type` field. Returns `undefined` for message types that are not
|
|
34
|
+
* host-proxy messages (i.e. they should broadcast to all subscribers).
|
|
35
|
+
*/
|
|
36
|
+
export function capabilityForMessageType(
|
|
37
|
+
type: string,
|
|
38
|
+
): HostProxyCapability | undefined {
|
|
39
|
+
const stem = type.replace(/_(request|cancel)$/, "");
|
|
40
|
+
return HOST_PREFIX_TO_CAPABILITY[stem];
|
|
41
|
+
}
|
|
17
42
|
import { emitFeedEvent } from "../home/emit-feed-event.js";
|
|
18
43
|
import { rewriteCommandPreview } from "../home/rewrite-command-preview.js";
|
|
19
44
|
import { redactSecrets } from "../security/secret-scanner.js";
|
|
@@ -22,7 +47,6 @@ import { summarizeToolInput } from "../tools/tool-input-summary.js";
|
|
|
22
47
|
import { getLogger } from "../util/logger.js";
|
|
23
48
|
import type { AssistantEvent } from "./assistant-event.js";
|
|
24
49
|
import { buildAssistantEvent } from "./assistant-event.js";
|
|
25
|
-
import * as pendingInteractions from "./pending-interactions.js";
|
|
26
50
|
|
|
27
51
|
const log = getLogger("assistant-event-hub");
|
|
28
52
|
|
|
@@ -56,18 +80,29 @@ interface BaseSubscriberEntry {
|
|
|
56
80
|
lastActiveAt: Date;
|
|
57
81
|
}
|
|
58
82
|
|
|
59
|
-
|
|
83
|
+
interface ClientEntry extends BaseSubscriberEntry {
|
|
60
84
|
type: "client";
|
|
61
85
|
clientId: string;
|
|
62
86
|
interfaceId: InterfaceId;
|
|
63
87
|
capabilities: HostProxyCapability[];
|
|
88
|
+
machineName?: string;
|
|
89
|
+
/**
|
|
90
|
+
* The verified actor principal id (canonical user identity, parsed from JWT
|
|
91
|
+
* `sub`) of the user that opened this SSE connection, when available.
|
|
92
|
+
*
|
|
93
|
+
* Populated from `AuthContext.actorPrincipalId` at SSE subscription time.
|
|
94
|
+
* Used by host proxies to gate cross-client targeted execution to the same
|
|
95
|
+
* authenticated user identity. May be `undefined` for legacy or
|
|
96
|
+
* service-token connections that have no principal.
|
|
97
|
+
*/
|
|
98
|
+
actorPrincipalId?: string;
|
|
64
99
|
}
|
|
65
100
|
|
|
66
|
-
|
|
101
|
+
interface ProcessEntry extends BaseSubscriberEntry {
|
|
67
102
|
type: "process";
|
|
68
103
|
}
|
|
69
104
|
|
|
70
|
-
|
|
105
|
+
type SubscriberEntry = ClientEntry | ProcessEntry;
|
|
71
106
|
|
|
72
107
|
/** Distributive Omit that preserves union discrimination. */
|
|
73
108
|
type DistributiveOmit<T, K extends PropertyKey> = T extends unknown
|
|
@@ -75,7 +110,7 @@ type DistributiveOmit<T, K extends PropertyKey> = T extends unknown
|
|
|
75
110
|
: never;
|
|
76
111
|
|
|
77
112
|
/** Input shape for `subscribe()` — hub fills `active`, `connectedAt`, `lastActiveAt` and defaults `filter`/`onEvict`. */
|
|
78
|
-
|
|
113
|
+
type SubscriberInput = DistributiveOmit<
|
|
79
114
|
SubscriberEntry,
|
|
80
115
|
"active" | "connectedAt" | "lastActiveAt" | "filter" | "onEvict"
|
|
81
116
|
> & {
|
|
@@ -216,7 +251,12 @@ export class AssistantEventHub {
|
|
|
216
251
|
* Publish an event to all matching subscribers.
|
|
217
252
|
*
|
|
218
253
|
* Matching rules:
|
|
219
|
-
* - if `
|
|
254
|
+
* - if `targetClientId` is set, deliver only to the subscriber with that
|
|
255
|
+
* clientId, bypassing the conversation-id filter entirely (the web-origin
|
|
256
|
+
* event's conversationId differs from the macOS client's subscribed
|
|
257
|
+
* conversation).
|
|
258
|
+
* - if `filter.conversationId` is set (and `targetClientId` is not), the
|
|
259
|
+
* `event.conversationId` must equal it
|
|
220
260
|
* - if `targetCapability` is set, only subscribers whose capabilities include
|
|
221
261
|
* it receive the event; untargeted events go to all
|
|
222
262
|
*
|
|
@@ -225,7 +265,10 @@ export class AssistantEventHub {
|
|
|
225
265
|
*/
|
|
226
266
|
async publish(
|
|
227
267
|
event: AssistantEvent,
|
|
228
|
-
options?: {
|
|
268
|
+
options?: {
|
|
269
|
+
targetCapability?: HostProxyCapability;
|
|
270
|
+
targetClientId?: string;
|
|
271
|
+
},
|
|
229
272
|
): Promise<void> {
|
|
230
273
|
if (event.conversationId) {
|
|
231
274
|
try {
|
|
@@ -236,29 +279,40 @@ export class AssistantEventHub {
|
|
|
236
279
|
}
|
|
237
280
|
|
|
238
281
|
const targetCapability = options?.targetCapability;
|
|
282
|
+
const targetClientId = options?.targetClientId;
|
|
239
283
|
const snapshot = Array.from(this.subscribers);
|
|
240
284
|
const errors: unknown[] = [];
|
|
241
285
|
|
|
242
286
|
for (const entry of snapshot) {
|
|
243
287
|
if (!entry.active) continue;
|
|
244
288
|
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
entry.filter.conversationId != null &&
|
|
250
|
-
entry.filter.conversationId !== event.conversationId
|
|
251
|
-
)
|
|
252
|
-
continue;
|
|
253
|
-
|
|
254
|
-
// Capability targeting: targeted events only go to subscribers that
|
|
255
|
-
// declare the required capability.
|
|
256
|
-
if (targetCapability != null) {
|
|
289
|
+
if (targetClientId != null) {
|
|
290
|
+
// Targeted: bypass conversation filter, deliver only to the named client.
|
|
291
|
+
if (entry.type !== "client" || entry.clientId !== targetClientId)
|
|
292
|
+
continue;
|
|
257
293
|
if (
|
|
258
|
-
|
|
294
|
+
targetCapability != null &&
|
|
259
295
|
!entry.capabilities.includes(targetCapability)
|
|
260
296
|
)
|
|
261
297
|
continue;
|
|
298
|
+
} else {
|
|
299
|
+
// Untargeted: existing conversation-scoped + capability logic.
|
|
300
|
+
if (
|
|
301
|
+
event.conversationId != null &&
|
|
302
|
+
entry.filter.conversationId != null &&
|
|
303
|
+
entry.filter.conversationId !== event.conversationId
|
|
304
|
+
)
|
|
305
|
+
continue;
|
|
306
|
+
|
|
307
|
+
// Capability targeting: targeted events only go to subscribers that
|
|
308
|
+
// declare the required capability.
|
|
309
|
+
if (targetCapability != null) {
|
|
310
|
+
if (
|
|
311
|
+
entry.type !== "client" ||
|
|
312
|
+
!entry.capabilities.includes(targetCapability)
|
|
313
|
+
)
|
|
314
|
+
continue;
|
|
315
|
+
}
|
|
262
316
|
}
|
|
263
317
|
|
|
264
318
|
try {
|
|
@@ -276,6 +330,34 @@ export class AssistantEventHub {
|
|
|
276
330
|
}
|
|
277
331
|
}
|
|
278
332
|
|
|
333
|
+
/**
|
|
334
|
+
* Return the active client subscriber with the given clientId, or
|
|
335
|
+
* `undefined` if no such subscriber exists.
|
|
336
|
+
*/
|
|
337
|
+
getClientById(clientId: string): ClientEntry | undefined {
|
|
338
|
+
for (const entry of this.subscribers) {
|
|
339
|
+
if (
|
|
340
|
+
entry.active &&
|
|
341
|
+
entry.type === "client" &&
|
|
342
|
+
entry.clientId === clientId
|
|
343
|
+
)
|
|
344
|
+
return entry;
|
|
345
|
+
}
|
|
346
|
+
return undefined;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
/**
|
|
350
|
+
* Return the verified actor principal id captured at SSE subscription time
|
|
351
|
+
* for the given client, or `undefined` if the client is unknown or
|
|
352
|
+
* connected without a principal (e.g. legacy/service tokens).
|
|
353
|
+
*
|
|
354
|
+
* Used by host proxies to bind cross-client targeted execution to the same
|
|
355
|
+
* authenticated user identity that opened the target client's SSE stream.
|
|
356
|
+
*/
|
|
357
|
+
getActorPrincipalIdForClient(clientId: string): string | undefined {
|
|
358
|
+
return this.getClientById(clientId)?.actorPrincipalId;
|
|
359
|
+
}
|
|
360
|
+
|
|
279
361
|
/**
|
|
280
362
|
* Returns true when at least one active subscriber would receive the given
|
|
281
363
|
* event based on the same conversation matching rules as publish().
|
|
@@ -338,6 +420,35 @@ export class AssistantEventHub {
|
|
|
338
420
|
return this.listClientsByCapability(capability)[0];
|
|
339
421
|
}
|
|
340
422
|
|
|
423
|
+
/**
|
|
424
|
+
* Return the best client for the given capability using an explicit
|
|
425
|
+
* interface preference order. Among clients that support `capability`,
|
|
426
|
+
* the one whose `interfaceId` appears earliest in `interfacePreference`
|
|
427
|
+
* wins. Within the same interface tier, `lastActiveAt` is the tiebreaker
|
|
428
|
+
* (most recent first). Clients not in the preference list are considered last.
|
|
429
|
+
*
|
|
430
|
+
* Used by {@link HostBrowserProxy} to prefer the Chrome Extension
|
|
431
|
+
* (`chrome-extension`) over the macOS SSE bridge (`macos`) when both are
|
|
432
|
+
* connected, so `chrome.debugger` is used ahead of the localhost:9222 path.
|
|
433
|
+
*/
|
|
434
|
+
getPreferredClientByCapability(
|
|
435
|
+
capability: HostProxyCapability,
|
|
436
|
+
interfacePreference: InterfaceId[],
|
|
437
|
+
): ClientEntry | undefined {
|
|
438
|
+
const clients = this.listClientsByCapability(capability);
|
|
439
|
+
if (clients.length === 0) return undefined;
|
|
440
|
+
// listClientsByCapability returns clients sorted by lastActiveAt desc
|
|
441
|
+
// (most recent first). A stable sort by preference index preserves that
|
|
442
|
+
// ordering within each interface tier.
|
|
443
|
+
return clients.sort((a, b) => {
|
|
444
|
+
const ai = interfacePreference.indexOf(a.interfaceId);
|
|
445
|
+
const bi = interfacePreference.indexOf(b.interfaceId);
|
|
446
|
+
const ea = ai === -1 ? interfacePreference.length : ai;
|
|
447
|
+
const eb = bi === -1 ? interfacePreference.length : bi;
|
|
448
|
+
return ea - eb;
|
|
449
|
+
})[0];
|
|
450
|
+
}
|
|
451
|
+
|
|
341
452
|
/**
|
|
342
453
|
* Return all client subscribers with the given interface type,
|
|
343
454
|
* sorted by `lastActiveAt` descending.
|
|
@@ -372,10 +483,7 @@ export class AssistantEventHub {
|
|
|
372
483
|
disposeClient(clientId: string): number {
|
|
373
484
|
const targets: SubscriberEntry[] = [];
|
|
374
485
|
for (const entry of this.subscribers) {
|
|
375
|
-
if (
|
|
376
|
-
entry.type === "client" &&
|
|
377
|
-
entry.clientId === clientId
|
|
378
|
-
) {
|
|
486
|
+
if (entry.type === "client" && entry.clientId === clientId) {
|
|
379
487
|
targets.push(entry);
|
|
380
488
|
}
|
|
381
489
|
}
|
|
@@ -432,25 +540,27 @@ let _hubChain = Promise.resolve();
|
|
|
432
540
|
* When `conversationId` is omitted, it is auto-extracted from the message
|
|
433
541
|
* payload (if present).
|
|
434
542
|
*
|
|
543
|
+
* Target capability is inferred automatically from the message type — callers
|
|
544
|
+
* never need to specify it. Host-proxy messages (`host_bash_*`,
|
|
545
|
+
* `host_file_*`, `host_transfer_*`, `host_cu_*`, `host_browser_*`) are routed
|
|
546
|
+
* only to subscribers that declare the matching capability; all other messages
|
|
547
|
+
* broadcast to every subscriber.
|
|
548
|
+
*
|
|
435
549
|
* This is the primary entrypoint for emitting events — handlers, routes, and
|
|
436
550
|
* services should call this directly instead of threading a broadcast callback.
|
|
437
551
|
*/
|
|
438
552
|
export function broadcastMessage(
|
|
439
553
|
msg: ServerMessage,
|
|
440
554
|
conversationId?: string,
|
|
441
|
-
options?: {
|
|
555
|
+
options?: { targetClientId?: string },
|
|
442
556
|
): void {
|
|
443
557
|
const resolvedConversationId = conversationId ?? extractConversationId(msg);
|
|
558
|
+
const targetClientId = options?.targetClientId;
|
|
444
559
|
|
|
445
|
-
//
|
|
446
|
-
// regardless of which path triggered the broadcast.
|
|
447
|
-
if (resolvedConversationId) {
|
|
448
|
-
registerPendingInteraction(msg, resolvedConversationId);
|
|
449
|
-
}
|
|
450
|
-
|
|
451
|
-
// Emit feed events for confirmation requests (tool approval prompts).
|
|
560
|
+
// Confirmation-request side effects: feed event + canonical guardian request.
|
|
452
561
|
if (msg.type === "confirmation_request" && resolvedConversationId) {
|
|
453
562
|
void emitConfirmationFeedEvent(msg, resolvedConversationId);
|
|
563
|
+
void createCanonicalRequestForConfirmation(msg, resolvedConversationId);
|
|
454
564
|
}
|
|
455
565
|
|
|
456
566
|
// `conversation_list_invalidated` is a list-level system event — publish
|
|
@@ -460,8 +570,13 @@ export function broadcastMessage(
|
|
|
460
570
|
? undefined
|
|
461
571
|
: resolvedConversationId;
|
|
462
572
|
const event = buildAssistantEvent(msg, scopedConversationId);
|
|
573
|
+
const targetCapability = capabilityForMessageType(msg.type);
|
|
574
|
+
const publishOptions =
|
|
575
|
+
targetCapability != null || targetClientId != null
|
|
576
|
+
? { targetCapability, targetClientId }
|
|
577
|
+
: undefined;
|
|
463
578
|
_hubChain = _hubChain
|
|
464
|
-
.then(() => assistantEventHub.publish(event,
|
|
579
|
+
.then(() => assistantEventHub.publish(event, publishOptions))
|
|
465
580
|
.then(() => {
|
|
466
581
|
// When a conversation title changes, also broadcast an unscoped
|
|
467
582
|
// `conversation_list_invalidated` so every connected client's sidebar
|
|
@@ -495,7 +610,7 @@ function extractConversationId(msg: ServerMessage): string | undefined {
|
|
|
495
610
|
return undefined;
|
|
496
611
|
}
|
|
497
612
|
|
|
498
|
-
// ──
|
|
613
|
+
// ── Canonical guardian request ────────────────────────────────────────────────
|
|
499
614
|
|
|
500
615
|
function resolveCanonicalRequestSourceType(
|
|
501
616
|
sourceChannel: string,
|
|
@@ -505,74 +620,11 @@ function resolveCanonicalRequestSourceType(
|
|
|
505
620
|
return "channel";
|
|
506
621
|
}
|
|
507
622
|
|
|
508
|
-
/**
|
|
509
|
-
* Register pending interactions for request-type messages so approval and
|
|
510
|
-
* host prompts are tracked regardless of which code path broadcasts them.
|
|
511
|
-
*
|
|
512
|
-
* Heavy dependencies (conversation-store, canonical-guardian-store, etc.) are
|
|
513
|
-
* imported lazily so that loading this module during tests doesn't trigger
|
|
514
|
-
* config/data-dir side effects.
|
|
515
|
-
*/
|
|
516
|
-
function registerPendingInteraction(
|
|
517
|
-
msg: ServerMessage,
|
|
518
|
-
conversationId: string,
|
|
519
|
-
): void {
|
|
520
|
-
if (msg.type === "confirmation_request") {
|
|
521
|
-
pendingInteractions.register(msg.requestId, {
|
|
522
|
-
conversationId,
|
|
523
|
-
kind: "confirmation",
|
|
524
|
-
confirmationDetails: {
|
|
525
|
-
toolName: msg.toolName,
|
|
526
|
-
input: msg.input,
|
|
527
|
-
riskLevel: msg.riskLevel,
|
|
528
|
-
executionTarget: msg.executionTarget,
|
|
529
|
-
allowlistOptions: msg.allowlistOptions,
|
|
530
|
-
scopeOptions: msg.scopeOptions,
|
|
531
|
-
persistentDecisionsAllowed: msg.persistentDecisionsAllowed,
|
|
532
|
-
},
|
|
533
|
-
});
|
|
534
|
-
|
|
535
|
-
// Create canonical guardian request asynchronously — heavy deps are
|
|
536
|
-
// imported lazily to avoid pulling in conversation-store (and
|
|
537
|
-
// transitively config/loader → ensureDataDir) at module-load time.
|
|
538
|
-
void createCanonicalRequestForConfirmation(msg, conversationId);
|
|
539
|
-
} else if (msg.type === "secret_request") {
|
|
540
|
-
pendingInteractions.register(msg.requestId, {
|
|
541
|
-
conversationId,
|
|
542
|
-
kind: "secret",
|
|
543
|
-
});
|
|
544
|
-
} else if (msg.type === "host_bash_request") {
|
|
545
|
-
pendingInteractions.register(msg.requestId, {
|
|
546
|
-
conversationId,
|
|
547
|
-
kind: "host_bash",
|
|
548
|
-
});
|
|
549
|
-
} else if (msg.type === "host_browser_request") {
|
|
550
|
-
pendingInteractions.register(msg.requestId, {
|
|
551
|
-
conversationId,
|
|
552
|
-
kind: "host_browser",
|
|
553
|
-
});
|
|
554
|
-
} else if (msg.type === "host_file_request") {
|
|
555
|
-
pendingInteractions.register(msg.requestId, {
|
|
556
|
-
conversationId,
|
|
557
|
-
kind: "host_file",
|
|
558
|
-
});
|
|
559
|
-
} else if (msg.type === "host_cu_request") {
|
|
560
|
-
pendingInteractions.register(msg.requestId, {
|
|
561
|
-
conversationId,
|
|
562
|
-
kind: "host_cu",
|
|
563
|
-
});
|
|
564
|
-
} else if (msg.type === "host_transfer_request") {
|
|
565
|
-
pendingInteractions.register(msg.requestId, {
|
|
566
|
-
conversationId,
|
|
567
|
-
kind: "host_transfer",
|
|
568
|
-
});
|
|
569
|
-
}
|
|
570
|
-
}
|
|
571
623
|
|
|
572
624
|
/**
|
|
573
625
|
* Lazily load heavy dependencies and create a canonical guardian request +
|
|
574
|
-
* bridge for a confirmation_request message.
|
|
575
|
-
*
|
|
626
|
+
* bridge for a confirmation_request message. Called fire-and-forget from
|
|
627
|
+
* broadcastMessage.
|
|
576
628
|
*/
|
|
577
629
|
async function createCanonicalRequestForConfirmation(
|
|
578
630
|
msg: ServerMessage & { type: "confirmation_request" },
|
|
@@ -35,12 +35,6 @@ mock.module("../../../config/env.js", () => ({
|
|
|
35
35
|
|
|
36
36
|
import { DAEMON_INTERNAL_ASSISTANT_ID } from "../../assistant-scope.js";
|
|
37
37
|
import {
|
|
38
|
-
mintHostBrowserCapability,
|
|
39
|
-
resetCapabilityTokenSecretForTests,
|
|
40
|
-
setCapabilityTokenSecretForTests,
|
|
41
|
-
} from "../../capability-tokens.js";
|
|
42
|
-
import {
|
|
43
|
-
authenticateHostBrowserResultRequest,
|
|
44
38
|
authenticateRequest,
|
|
45
39
|
} from "../middleware.js";
|
|
46
40
|
import { initAuthSigningKey, mintToken } from "../token-service.js";
|
|
@@ -272,55 +266,20 @@ describe("authenticateRequest", () => {
|
|
|
272
266
|
});
|
|
273
267
|
|
|
274
268
|
// ---------------------------------------------------------------------------
|
|
275
|
-
//
|
|
276
|
-
//
|
|
277
|
-
//
|
|
278
|
-
// JWT path and emits a 401 like any other invalid token.
|
|
269
|
+
// /v1/host-browser-result auth — exercises authenticateRequest with the
|
|
270
|
+
// same request shape the chrome extension sends. Validates that standard
|
|
271
|
+
// JWT auth applies after the capability-token system was removed.
|
|
279
272
|
// ---------------------------------------------------------------------------
|
|
280
273
|
|
|
281
|
-
describe("
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
beforeEach(() => {
|
|
285
|
-
// Pin the capability-token HMAC secret so mint/verify agree across
|
|
286
|
-
// the test run. The module-level secret cache is reset between
|
|
287
|
-
// tests so dev-bypass flipping doesn't leak stale state.
|
|
288
|
-
setCapabilityTokenSecretForTests(CAPABILITY_SECRET);
|
|
289
|
-
});
|
|
290
|
-
|
|
291
|
-
afterAll(() => {
|
|
292
|
-
resetCapabilityTokenSecretForTests();
|
|
293
|
-
});
|
|
294
|
-
|
|
295
|
-
test("accepts a valid capability token and synthesizes an actor AuthContext", async () => {
|
|
296
|
-
const { token } = mintHostBrowserCapability("guardian-cap-happy");
|
|
297
|
-
const req = new Request("http://localhost/v1/host-browser-result", {
|
|
298
|
-
method: "POST",
|
|
299
|
-
headers: { Authorization: `Bearer ${token}` },
|
|
300
|
-
});
|
|
301
|
-
|
|
302
|
-
const result = await authenticateHostBrowserResultRequest(req);
|
|
303
|
-
expect(result.ok).toBe(true);
|
|
304
|
-
if (result.ok) {
|
|
305
|
-
expect(result.context.principalType).toBe("actor");
|
|
306
|
-
expect(result.context.assistantId).toBe(DAEMON_INTERNAL_ASSISTANT_ID);
|
|
307
|
-
expect(result.context.actorPrincipalId).toBe("guardian-cap-happy");
|
|
308
|
-
expect(result.context.scopeProfile).toBe("actor_client_v1");
|
|
309
|
-
// The synthetic context must carry the scopes the route policy
|
|
310
|
-
// requires — otherwise the router would 403 the POST even though
|
|
311
|
-
// auth succeeded.
|
|
312
|
-
expect(result.context.scopes.has("approval.write")).toBe(true);
|
|
313
|
-
}
|
|
314
|
-
});
|
|
315
|
-
|
|
316
|
-
test("accepts a valid daemon-audience JWT (regression for the legacy path)", async () => {
|
|
274
|
+
describe("authenticateRequest for /v1/host-browser-result", () => {
|
|
275
|
+
test("accepts a valid daemon-audience JWT", async () => {
|
|
317
276
|
const token = mintValidToken({ sub: "actor:self:jwt-principal" });
|
|
318
277
|
const req = new Request("http://localhost/v1/host-browser-result", {
|
|
319
278
|
method: "POST",
|
|
320
279
|
headers: { Authorization: `Bearer ${token}` },
|
|
321
280
|
});
|
|
322
281
|
|
|
323
|
-
const result = await
|
|
282
|
+
const result = await authenticateRequest(req);
|
|
324
283
|
expect(result.ok).toBe(true);
|
|
325
284
|
if (result.ok) {
|
|
326
285
|
expect(result.context.principalType).toBe("actor");
|
|
@@ -334,25 +293,21 @@ describe("authenticateHostBrowserResultRequest", () => {
|
|
|
334
293
|
method: "POST",
|
|
335
294
|
});
|
|
336
295
|
|
|
337
|
-
const result = await
|
|
296
|
+
const result = await authenticateRequest(req);
|
|
338
297
|
expect(result.ok).toBe(false);
|
|
339
298
|
if (!result.ok) {
|
|
340
299
|
expect(result.response.status).toBe(401);
|
|
341
300
|
}
|
|
342
301
|
});
|
|
343
302
|
|
|
344
|
-
test("malformed bearer
|
|
345
|
-
// A bearer that is
|
|
346
|
-
// parseable JWT must fail the JWT path and return 401. This is the
|
|
347
|
-
// primary regression guard against someone accidentally making the
|
|
348
|
-
// capability-token branch "allow-anything" by swallowing
|
|
349
|
-
// verification failures.
|
|
303
|
+
test("malformed bearer returns 401", async () => {
|
|
304
|
+
// A bearer that is not a parseable JWT must return 401.
|
|
350
305
|
const req = new Request("http://localhost/v1/host-browser-result", {
|
|
351
306
|
method: "POST",
|
|
352
307
|
headers: { Authorization: "Bearer not-a-token.xxxxxxxxxxxxx" },
|
|
353
308
|
});
|
|
354
309
|
|
|
355
|
-
const result = await
|
|
310
|
+
const result = await authenticateRequest(req);
|
|
356
311
|
expect(result.ok).toBe(false);
|
|
357
312
|
if (!result.ok) {
|
|
358
313
|
expect(result.response.status).toBe(401);
|
|
@@ -366,7 +321,7 @@ describe("authenticateHostBrowserResultRequest", () => {
|
|
|
366
321
|
method: "POST",
|
|
367
322
|
});
|
|
368
323
|
|
|
369
|
-
const result = await
|
|
324
|
+
const result = await authenticateRequest(req);
|
|
370
325
|
expect(result.ok).toBe(true);
|
|
371
326
|
if (result.ok) {
|
|
372
327
|
// Same synthetic context shape as authenticateRequest's dev
|
|
@@ -214,4 +214,68 @@ describe("enforcePolicy", () => {
|
|
|
214
214
|
const result = enforcePolicy("stt/transcribe", ctx);
|
|
215
215
|
expect(result).toBeNull();
|
|
216
216
|
});
|
|
217
|
+
|
|
218
|
+
// -- internal/oauth/connect/start policy ----------------------------------
|
|
219
|
+
|
|
220
|
+
test("internal/oauth/connect/start is registered as a protected endpoint", () => {
|
|
221
|
+
authDisabled = false;
|
|
222
|
+
const policy = getPolicy("internal/oauth/connect/start");
|
|
223
|
+
expect(policy).toBeDefined();
|
|
224
|
+
expect(policy!.allowedPrincipalTypes).toContain("svc_gateway");
|
|
225
|
+
expect(policy!.allowedPrincipalTypes).not.toContain("actor");
|
|
226
|
+
expect(policy!.requiredScopes).toContain("internal.write");
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
test("internal/oauth/connect/start denies non-svc_gateway principals", () => {
|
|
230
|
+
authDisabled = false;
|
|
231
|
+
const ctx = buildTestContext({
|
|
232
|
+
principalType: "actor",
|
|
233
|
+
scopes: ["internal.write"],
|
|
234
|
+
});
|
|
235
|
+
const result = enforcePolicy("internal/oauth/connect/start", ctx);
|
|
236
|
+
expect(result).not.toBeNull();
|
|
237
|
+
expect(result!.status).toBe(403);
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
test("internal/oauth/connect/start allows svc_gateway with internal.write", () => {
|
|
241
|
+
authDisabled = false;
|
|
242
|
+
const ctx = buildTestContext({
|
|
243
|
+
principalType: "svc_gateway",
|
|
244
|
+
scopes: ["internal.write"],
|
|
245
|
+
});
|
|
246
|
+
const result = enforcePolicy("internal/oauth/connect/start", ctx);
|
|
247
|
+
expect(result).toBeNull();
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
// -- internal/oauth/connect/status policy ---------------------------------
|
|
251
|
+
|
|
252
|
+
test("internal/oauth/connect/status is registered as a protected endpoint", () => {
|
|
253
|
+
authDisabled = false;
|
|
254
|
+
const policy = getPolicy("internal/oauth/connect/status");
|
|
255
|
+
expect(policy).toBeDefined();
|
|
256
|
+
expect(policy!.allowedPrincipalTypes).toContain("svc_gateway");
|
|
257
|
+
expect(policy!.allowedPrincipalTypes).not.toContain("actor");
|
|
258
|
+
expect(policy!.requiredScopes).toContain("internal.write");
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
test("internal/oauth/connect/status denies non-svc_gateway principals", () => {
|
|
262
|
+
authDisabled = false;
|
|
263
|
+
const ctx = buildTestContext({
|
|
264
|
+
principalType: "actor",
|
|
265
|
+
scopes: ["internal.write"],
|
|
266
|
+
});
|
|
267
|
+
const result = enforcePolicy("internal/oauth/connect/status", ctx);
|
|
268
|
+
expect(result).not.toBeNull();
|
|
269
|
+
expect(result!.status).toBe(403);
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
test("internal/oauth/connect/status allows svc_gateway with internal.write", () => {
|
|
273
|
+
authDisabled = false;
|
|
274
|
+
const ctx = buildTestContext({
|
|
275
|
+
principalType: "svc_gateway",
|
|
276
|
+
scopes: ["internal.write"],
|
|
277
|
+
});
|
|
278
|
+
const result = enforcePolicy("internal/oauth/connect/status", ctx);
|
|
279
|
+
expect(result).toBeNull();
|
|
280
|
+
});
|
|
217
281
|
});
|
|
@@ -25,7 +25,6 @@
|
|
|
25
25
|
import { isHttpAuthDisabled } from "../../config/env.js";
|
|
26
26
|
import { getLogger } from "../../util/logger.js";
|
|
27
27
|
import { DAEMON_INTERNAL_ASSISTANT_ID } from "../assistant-scope.js";
|
|
28
|
-
import { verifyHostBrowserCapability } from "../capability-tokens.js";
|
|
29
28
|
import { extractBearerToken } from "../middleware/auth.js";
|
|
30
29
|
import { buildAuthContext } from "./context.js";
|
|
31
30
|
import { resolveScopeProfile } from "./scopes.js";
|
|
@@ -188,99 +187,4 @@ export function authenticateRequest(req: Request): AuthenticateResult {
|
|
|
188
187
|
return { ok: true, context: contextResult.context };
|
|
189
188
|
}
|
|
190
189
|
|
|
191
|
-
// ---------------------------------------------------------------------------
|
|
192
|
-
// Capability-token-aware auth for /v1/host-browser-result
|
|
193
|
-
// ---------------------------------------------------------------------------
|
|
194
190
|
|
|
195
|
-
/**
|
|
196
|
-
* Build a synthetic AuthContext from a verified host_browser capability
|
|
197
|
-
* claim. The resulting context is shaped to look like an
|
|
198
|
-
* `actor_client_v1` actor so downstream route policy (which requires
|
|
199
|
-
* `approval.write`) and `requireBoundGuardian` (which compares
|
|
200
|
-
* `actorPrincipalId` against the bound guardian) both accept it.
|
|
201
|
-
*
|
|
202
|
-
* The capability token already carries its own HMAC-checked expiry, so
|
|
203
|
-
* there is no policy-epoch gate to apply here — we pin `policyEpoch` to
|
|
204
|
-
* `Number.MAX_SAFE_INTEGER` the same way the dev-bypass context does.
|
|
205
|
-
*/
|
|
206
|
-
function buildCapabilityAuthContext(guardianId: string): AuthContext {
|
|
207
|
-
return {
|
|
208
|
-
subject: `actor:${DAEMON_INTERNAL_ASSISTANT_ID}:${guardianId}`,
|
|
209
|
-
principalType: "actor",
|
|
210
|
-
assistantId: DAEMON_INTERNAL_ASSISTANT_ID,
|
|
211
|
-
actorPrincipalId: guardianId,
|
|
212
|
-
scopeProfile: "actor_client_v1",
|
|
213
|
-
scopes: resolveScopeProfile("actor_client_v1"),
|
|
214
|
-
policyEpoch: Number.MAX_SAFE_INTEGER,
|
|
215
|
-
};
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
/**
|
|
219
|
-
* Authenticate a request that is allowed to present either a JWT or a
|
|
220
|
-
* host_browser capability token. This is the auth entry point for
|
|
221
|
-
* `/v1/host-browser-result` POST specifically — the chrome extension
|
|
222
|
-
* stores a capability token (minted by the
|
|
223
|
-
* `/v1/browser-extension-pair` flow) rather than a daemon JWT, so the
|
|
224
|
-
* POST fallback used when the `/v1/browser-relay` WebSocket is
|
|
225
|
-
* unavailable would otherwise 401 through the JWT-only
|
|
226
|
-
* `authenticateRequest` path.
|
|
227
|
-
*
|
|
228
|
-
* Order of operations (mirrors `handleBrowserRelayUpgrade`):
|
|
229
|
-
* 1. Extract the bearer token. Missing header → 401.
|
|
230
|
-
* 2. Try `verifyHostBrowserCapability(token)` first. If it succeeds,
|
|
231
|
-
* derive `guardianId` from the capability claims and synthesize an
|
|
232
|
-
* AuthContext.
|
|
233
|
-
* 3. Otherwise fall through to the standard JWT path so daemon-minted
|
|
234
|
-
* JWTs (gateway-proxied or direct) continue to work as a
|
|
235
|
-
* regression-safe compatibility path.
|
|
236
|
-
*
|
|
237
|
-
* Dev bypass (`isHttpAuthDisabled()`) is honored the same way as
|
|
238
|
-
* `authenticateRequest` — we delegate to it directly to pick up the
|
|
239
|
-
* shared synthetic dev-bypass context.
|
|
240
|
-
*/
|
|
241
|
-
export async function authenticateHostBrowserResultRequest(
|
|
242
|
-
req: Request,
|
|
243
|
-
): Promise<AuthenticateResult> {
|
|
244
|
-
if (isHttpAuthDisabled()) {
|
|
245
|
-
return { ok: true, context: buildDevBypassContext() };
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
const rawToken = extractBearerToken(req);
|
|
249
|
-
if (!rawToken) {
|
|
250
|
-
log.warn(
|
|
251
|
-
{ reason: "missing_token", path: "/v1/host-browser-result" },
|
|
252
|
-
"Host browser result auth denied: missing Authorization header",
|
|
253
|
-
);
|
|
254
|
-
return {
|
|
255
|
-
ok: false,
|
|
256
|
-
response: Response.json(
|
|
257
|
-
{
|
|
258
|
-
error: {
|
|
259
|
-
code: "UNAUTHORIZED",
|
|
260
|
-
message: "Missing Authorization header",
|
|
261
|
-
},
|
|
262
|
-
},
|
|
263
|
-
{ status: 401 },
|
|
264
|
-
),
|
|
265
|
-
};
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
// 1) Capability-token path (self-hosted default). The chrome
|
|
269
|
-
// extension presents the token it received from the native
|
|
270
|
-
// messaging pair flow. We derive `actorPrincipalId` from the
|
|
271
|
-
// capability claims directly — the claims are HMAC-signed by the
|
|
272
|
-
// same daemon so there is no cross-tenant risk.
|
|
273
|
-
const capabilityClaims = await verifyHostBrowserCapability(rawToken);
|
|
274
|
-
if (capabilityClaims) {
|
|
275
|
-
return {
|
|
276
|
-
ok: true,
|
|
277
|
-
context: buildCapabilityAuthContext(capabilityClaims.guardianId),
|
|
278
|
-
};
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
// 2) JWT compatibility path. Fall back to the existing daemon/gateway
|
|
282
|
-
// JWT verification so cloud callers and any legacy self-hosted
|
|
283
|
-
// clients still holding a daemon JWT continue to work. Any 401
|
|
284
|
-
// emitted here already includes the JWT-specific reason.
|
|
285
|
-
return authenticateRequest(req);
|
|
286
|
-
}
|