@vellumai/assistant 0.7.1 → 0.7.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ARCHITECTURE.md +32 -49
- 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/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 +39 -1
- 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/skill-host-contracts/src/assistant-event.ts +9 -0
- 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 +565 -12
- 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 +374 -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 +109 -2
- package/src/__tests__/assistant-event.test.ts +10 -0
- package/src/__tests__/assistant-events-sse-hardening.test.ts +7 -2
- package/src/__tests__/assistant-feature-flags-integration.test.ts +11 -7
- package/src/__tests__/background-shell-host-bash.test.ts +14 -15
- 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-domain.test.ts +0 -2
- package/src/__tests__/call-routes-http.test.ts +0 -2
- package/src/__tests__/channel-readiness-service.test.ts +59 -1
- package/src/__tests__/checker.test.ts +3 -4
- package/src/__tests__/config-loader-backfill.test.ts +90 -155
- 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-set-platform-guard.test.ts +48 -4
- package/src/__tests__/config-watcher-cleanup-throttle.test.ts +2 -2
- package/src/__tests__/config-watcher.test.ts +2 -2
- 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-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-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-slash-commands.test.ts +0 -4
- package/src/__tests__/conversation-surfaces-action-delivery.test.ts +202 -0
- package/src/__tests__/conversation-surfaces-app-control.test.ts +317 -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 +5 -12
- package/src/__tests__/cu-unified-flow.test.ts +185 -23
- package/src/__tests__/daemon-credential-client.test.ts +101 -19
- package/src/__tests__/db-schedule-syntax-migration.test.ts +2 -0
- package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +0 -1
- 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-service.test.ts +718 -1
- package/src/__tests__/helpers/call-route-handler.ts +7 -1
- package/src/__tests__/host-app-control-proxy.test.ts +602 -0
- package/src/__tests__/host-app-control-routes.test.ts +263 -0
- package/src/__tests__/host-bash-proxy.test.ts +246 -47
- package/src/__tests__/host-bash-routes.test.ts +294 -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 +41 -52
- package/src/__tests__/host-cu-routes-targeted.test.ts +300 -0
- package/src/__tests__/host-file-edit-tool.test.ts +47 -1
- package/src/__tests__/host-file-proxy-targeted.test.ts +339 -0
- package/src/__tests__/host-file-proxy.test.ts +37 -43
- package/src/__tests__/host-file-read-tool.test.ts +17 -0
- package/src/__tests__/host-file-routes-targeted.test.ts +262 -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 +583 -0
- package/src/__tests__/host-transfer-proxy.test.ts +121 -22
- package/src/__tests__/host-transfer-routes-targeted.test.ts +447 -0
- package/src/__tests__/http-user-message-parity.test.ts +1 -0
- 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__/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-skill-lifecycle.test.ts +0 -1
- package/src/__tests__/mcp-auth-routes.test.ts +197 -0
- package/src/__tests__/mcp-cli.test.ts +338 -2
- package/src/__tests__/memory-jobs-worker-lanes.test.ts +188 -0
- package/src/__tests__/migration-import-commit-http.test.ts +108 -2
- package/src/__tests__/mock-gateway-ipc.ts +1 -0
- package/src/__tests__/oauth-cli.test.ts +0 -2
- package/src/__tests__/oauth2-gateway-transport.test.ts +0 -1
- package/src/__tests__/persistence-secret-redaction.test.ts +299 -0
- package/src/__tests__/platform-bash-auto-approve.test.ts +5 -9
- package/src/__tests__/prechat-onboarding-contract.test.ts +3 -1
- 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__/public-ingress-urls.test.ts +97 -0
- 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 +10 -6
- package/src/__tests__/sanitize-config-for-transfer.test.ts +24 -2
- package/src/__tests__/schedule-retry.test.ts +715 -0
- package/src/__tests__/script-proxy-mitm-handler.test.ts +1 -1
- package/src/__tests__/secret-ingress-http.test.ts +1 -0
- 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__/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-backfill-installation-id.test.ts +1 -5
- package/src/__tests__/workspace-migration-down-functions.test.ts +8 -8
- package/src/__tests__/workspace-migration-unify-llm-callsite-configs.test.ts +10 -6
- 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/bundler/app-bundler.ts +51 -3
- 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 -1
- package/src/cli/commands/backup.ts +6 -331
- package/src/cli/commands/clients.ts +36 -37
- package/src/cli/commands/contacts.ts +73 -0
- package/src/cli/commands/conversations.ts +2 -5
- package/src/cli/commands/credentials.ts +15 -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 +296 -1
- package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +0 -1
- package/src/cli/commands/platform/__tests__/connect.test.ts +0 -2
- package/src/cli/commands/platform/__tests__/disconnect.test.ts +0 -2
- package/src/cli/commands/platform/__tests__/status.test.ts +13 -15
- package/src/cli/commands/platform/disconnect.ts +5 -4
- package/src/cli/commands/platform/index.ts +0 -18
- package/src/cli/lib/daemon-credential-client.ts +110 -28
- package/src/cli/program.ts +2 -0
- package/src/config/assistant-feature-flags.ts +67 -10
- 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/phone-calls/TOOLS.json +0 -12
- package/src/config/bundled-skills/phone-calls/references/TROUBLESHOOTING.md +19 -4
- package/src/config/bundled-skills/playbooks/TOOLS.json +0 -16
- 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 -12
- package/src/config/feature-flag-registry.json +21 -133
- package/src/config/loader.ts +73 -99
- 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 +7 -4
- package/src/config/schemas/calls.ts +0 -9
- package/src/config/schemas/heartbeat.ts +63 -0
- package/src/config/schemas/ingress.ts +10 -6
- package/src/config/schemas/llm.ts +5 -10
- package/src/config/schemas/memory-lifecycle.ts +77 -24
- package/src/config/schemas/memory-v2.ts +48 -4
- package/src/config/schemas/platform.ts +6 -0
- package/src/config/schemas/services.ts +1 -15
- package/src/config/schemas/skills.ts +0 -6
- package/src/config/seed-inference-profiles.ts +1 -1
- package/src/contacts/contact-store.ts +0 -30
- 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 +126 -5
- package/src/daemon/bootstrap-turn-cleanup.ts +45 -0
- package/src/daemon/config-watcher.ts +4 -3
- package/src/daemon/conversation-agent-loop-handlers.ts +21 -3
- package/src/daemon/conversation-agent-loop.ts +32 -28
- package/src/daemon/conversation-lifecycle.ts +8 -1
- package/src/daemon/conversation-process.ts +16 -11
- package/src/daemon/conversation-runtime-assembly.ts +2 -2
- package/src/daemon/conversation-surfaces.ts +125 -4
- package/src/daemon/conversation-tool-setup.ts +16 -55
- package/src/daemon/conversation.ts +21 -2
- package/src/daemon/doordash-steps.ts +1 -1
- package/src/daemon/handlers/shared.ts +4 -1
- package/src/daemon/host-app-control-proxy.ts +293 -0
- package/src/daemon/host-bash-proxy.ts +84 -74
- package/src/daemon/host-browser-proxy.ts +67 -82
- package/src/daemon/host-cu-proxy.ts +81 -86
- package/src/daemon/host-file-proxy.ts +93 -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 +247 -129
- package/src/daemon/lifecycle.ts +115 -117
- package/src/daemon/message-protocol.ts +3 -8
- package/src/daemon/message-types/contacts.ts +23 -1
- package/src/daemon/message-types/conversations.ts +11 -8
- 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/schedules.ts +8 -3
- package/src/daemon/message-types/skills.ts +2 -2
- package/src/daemon/process-message.ts +18 -1
- 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/events/tool-audit-listener.ts +2 -1
- package/src/heartbeat/__tests__/heartbeat-feed-event.test.ts +15 -7
- package/src/heartbeat/__tests__/heartbeat-run-store.test.ts +216 -0
- package/src/heartbeat/heartbeat-run-store.ts +236 -0
- package/src/heartbeat/heartbeat-service.ts +280 -49
- 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/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/public-ingress-urls.ts +32 -34
- package/src/ipc/__tests__/route-error-envelope.test.ts +80 -0
- package/src/ipc/assistant-server.ts +14 -1
- package/src/ipc/cli-client.ts +32 -1
- package/src/live-voice/live-voice-metrics.ts +10 -10
- 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/memory/__tests__/jobs-store-job-classes.test.ts +24 -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/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 +32 -7
- package/src/memory/context-search/sources/memory-v2.ts +17 -5
- package/src/memory/conversation-crud.ts +1 -1
- package/src/memory/conversation-key-store.ts +2 -15
- package/src/memory/db-init.ts +4 -0
- package/src/memory/embedding-backend.ts +9 -21
- package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +49 -4
- package/src/memory/graph/conversation-graph-memory.ts +1 -24
- package/src/memory/graph/graph-search.ts +8 -0
- package/src/memory/graph/retriever.ts +28 -0
- package/src/memory/graph/tools.ts +1 -1
- 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 +66 -22
- package/src/memory/jobs-worker.ts +112 -63
- package/src/memory/memory-v2-activation-log-store.ts +1 -1
- 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/index.ts +5 -0
- package/src/memory/migrations/registry.ts +8 -0
- package/src/memory/pkb/pkb-search.ts +7 -0
- package/src/memory/qdrant-client.ts +50 -20
- package/src/memory/schema/infrastructure.ts +15 -0
- package/src/memory/search/semantic.ts +7 -0
- package/src/memory/sparse-tokenize.ts +49 -0
- package/src/memory/v2/__tests__/activation.test.ts +77 -95
- package/src/memory/v2/__tests__/injection.test.ts +43 -21
- package/src/memory/v2/__tests__/sim.test.ts +166 -6
- package/src/memory/v2/__tests__/sparse-bm25.test.ts +292 -0
- package/src/memory/v2/__tests__/static-context.test.ts +0 -1
- package/src/memory/v2/activation.ts +69 -88
- package/src/memory/v2/consolidation-job.ts +3 -5
- package/src/memory/v2/constants.ts +7 -0
- package/src/memory/v2/injection.ts +86 -53
- package/src/memory/v2/prompts/consolidation.ts +312 -91
- package/src/memory/v2/qdrant.ts +99 -1
- package/src/memory/v2/sim.ts +126 -16
- package/src/memory/v2/skill-qdrant.ts +12 -3
- package/src/memory/v2/skill-store.ts +16 -1
- package/src/memory/v2/sparse-bm25.ts +245 -0
- package/src/memory/v2/static-context.ts +6 -5
- 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/guardian-question-mode.ts +5 -5
- package/src/oauth/connect-orchestrator.ts +4 -0
- package/src/oauth/credential-token-resolver.ts +1 -3
- package/src/oauth/manual-token-connection.ts +0 -4
- 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/prompts/bootstrap-cleanup.ts +27 -0
- package/src/prompts/system-prompt.ts +3 -18
- package/src/prompts/templates/SOUL.md +13 -1
- package/src/providers/speech-to-text/provider-catalog.ts +7 -8
- package/src/runtime/assistant-event-hub.ts +118 -96
- package/src/runtime/assistant-event.ts +1 -0
- package/src/runtime/auth/__tests__/middleware.test.ts +11 -56
- package/src/runtime/auth/middleware.ts +0 -96
- package/src/runtime/auth/route-policy.ts +19 -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/http-server.ts +3 -329
- package/src/runtime/http-types.ts +0 -5
- 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 +35 -9
- package/src/runtime/routes/__tests__/backup-routes.test.ts +22 -150
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +98 -0
- 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 +1 -0
- package/src/runtime/routes/contact-prompt-routes.ts +183 -0
- package/src/runtime/routes/conversation-query-routes.ts +36 -1
- package/src/runtime/routes/conversation-routes.ts +30 -13
- package/src/runtime/routes/document-pdf-renderer.ts +165 -0
- package/src/runtime/routes/documents-routes.ts +30 -0
- package/src/runtime/routes/errors.ts +19 -4
- package/src/runtime/routes/events-routes.ts +12 -6
- 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 +36 -6
- package/src/runtime/routes/host-browser-routes.ts +108 -13
- package/src/runtime/routes/host-cu-routes.ts +44 -14
- package/src/runtime/routes/host-file-routes.ts +33 -10
- package/src/runtime/routes/host-transfer-routes.ts +64 -24
- 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 +15 -43
- package/src/runtime/routes/inbound-message-handler.ts +1 -9
- 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/transcribe-audio.test.ts +0 -20
- package/src/runtime/routes/inbound-stages/transcribe-audio.ts +5 -13
- package/src/runtime/routes/index.ts +8 -0
- package/src/runtime/routes/mcp-auth-routes.ts +132 -0
- package/src/runtime/routes/memory-item-routes.ts +10 -12
- package/src/runtime/routes/memory-v2-routes.ts +441 -1
- package/src/runtime/routes/migration-routes.ts +96 -0
- package/src/runtime/routes/schedule-routes.ts +7 -0
- 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/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 +63 -38
- package/src/security/oauth-callback-registry.ts +8 -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 +5 -5
- 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/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/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.ts +26 -0
- package/src/tools/host-filesystem/read.ts +26 -0
- package/src/tools/host-filesystem/transfer.ts +31 -1
- package/src/tools/host-filesystem/write.ts +26 -0
- package/src/tools/host-terminal/host-shell.ts +58 -0
- 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/tool-approval-handler.ts +1 -5
- package/src/tools/types.ts +4 -0
- package/src/usage/pricing.ts +1 -1
- package/src/workspace/hatched-date.ts +86 -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/AGENTS.md +1 -1
- package/src/workspace/migrations/migrate-to-workspace-volume.ts +4 -10
- package/src/workspace/migrations/utils.ts +21 -0
- 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/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/mcp-reload.ts +0 -18
|
@@ -1,263 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Streaming AES-256-GCM file encryption/decryption for backup bundles.
|
|
3
|
-
*
|
|
4
|
-
* The on-disk format is:
|
|
5
|
-
*
|
|
6
|
-
* [12-byte IV][ciphertext...][16-byte GCM auth tag]
|
|
7
|
-
*
|
|
8
|
-
* Both encrypt and decrypt use Node streams so peak memory stays bounded
|
|
9
|
-
* regardless of input size. This is important for backup archives which may
|
|
10
|
-
* run to many gigabytes on larger workspaces.
|
|
11
|
-
*
|
|
12
|
-
* The key must be exactly 32 bytes (AES-256). The IV is randomly generated
|
|
13
|
-
* per call, which is required for GCM semantic security — never reuse an
|
|
14
|
-
* IV with the same key.
|
|
15
|
-
*/
|
|
16
|
-
|
|
17
|
-
import {
|
|
18
|
-
createCipheriv,
|
|
19
|
-
createDecipheriv,
|
|
20
|
-
randomBytes,
|
|
21
|
-
} from "node:crypto";
|
|
22
|
-
import {
|
|
23
|
-
createReadStream,
|
|
24
|
-
createWriteStream,
|
|
25
|
-
} from "node:fs";
|
|
26
|
-
import { open, rename, stat, unlink } from "node:fs/promises";
|
|
27
|
-
import { Readable, Writable } from "node:stream";
|
|
28
|
-
import { pipeline } from "node:stream/promises";
|
|
29
|
-
|
|
30
|
-
// ---------------------------------------------------------------------------
|
|
31
|
-
// Constants
|
|
32
|
-
// ---------------------------------------------------------------------------
|
|
33
|
-
|
|
34
|
-
/** Size of the AES-GCM initialization vector prefix, in bytes. */
|
|
35
|
-
export const ENCRYPTED_HEADER_SIZE = 12;
|
|
36
|
-
|
|
37
|
-
/** Size of the AES-GCM authentication tag suffix, in bytes. */
|
|
38
|
-
export const GCM_TAG_SIZE = 16;
|
|
39
|
-
|
|
40
|
-
const ALGORITHM = "aes-256-gcm";
|
|
41
|
-
const KEY_LENGTH = 32;
|
|
42
|
-
|
|
43
|
-
// ---------------------------------------------------------------------------
|
|
44
|
-
// Helpers
|
|
45
|
-
// ---------------------------------------------------------------------------
|
|
46
|
-
|
|
47
|
-
function assertKey(key: Buffer): void {
|
|
48
|
-
if (key.length !== KEY_LENGTH) {
|
|
49
|
-
throw new Error("Backup encryption key must be 32 bytes");
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
async function safeUnlink(path: string): Promise<void> {
|
|
54
|
-
try {
|
|
55
|
-
await unlink(path);
|
|
56
|
-
} catch {
|
|
57
|
-
// best-effort cleanup — swallow ENOENT and other errors
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
function tempPath(outputPath: string): string {
|
|
62
|
-
return `${outputPath}.tmp.${process.pid}.${randomBytes(4).toString("hex")}`;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
// ---------------------------------------------------------------------------
|
|
66
|
-
// Encrypt
|
|
67
|
-
// ---------------------------------------------------------------------------
|
|
68
|
-
|
|
69
|
-
/**
|
|
70
|
-
* Stream-encrypt `inputPath` to `outputPath` using AES-256-GCM.
|
|
71
|
-
*
|
|
72
|
-
* Produces `[IV (12 bytes)][ciphertext][auth tag (16 bytes)]` in the output.
|
|
73
|
-
* Writes to a temp file and atomically renames on success; unlinks the temp
|
|
74
|
-
* file on any error so failed writes don't leave partial bundles behind.
|
|
75
|
-
*/
|
|
76
|
-
export async function encryptFile(
|
|
77
|
-
inputPath: string,
|
|
78
|
-
outputPath: string,
|
|
79
|
-
key: Buffer,
|
|
80
|
-
): Promise<void> {
|
|
81
|
-
assertKey(key);
|
|
82
|
-
|
|
83
|
-
const iv = randomBytes(ENCRYPTED_HEADER_SIZE);
|
|
84
|
-
const cipher = createCipheriv(ALGORITHM, key, iv);
|
|
85
|
-
|
|
86
|
-
const tmp = tempPath(outputPath);
|
|
87
|
-
const writeStream = createWriteStream(tmp);
|
|
88
|
-
|
|
89
|
-
try {
|
|
90
|
-
// Write IV first so decrypt can read it without knowing the ciphertext size.
|
|
91
|
-
await new Promise<void>((resolve, reject) => {
|
|
92
|
-
writeStream.write(iv, (err) => (err ? reject(err) : resolve()));
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
// Stream plaintext through the cipher into the output.
|
|
96
|
-
const readStream = createReadStream(inputPath);
|
|
97
|
-
await pipeline(readStream, cipher, writeStream, { end: false });
|
|
98
|
-
|
|
99
|
-
// Append the auth tag after the ciphertext body.
|
|
100
|
-
const tag = cipher.getAuthTag();
|
|
101
|
-
await new Promise<void>((resolve, reject) => {
|
|
102
|
-
writeStream.write(tag, (err) => (err ? reject(err) : resolve()));
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
await new Promise<void>((resolve, reject) => {
|
|
106
|
-
writeStream.end((err?: Error | null) => (err ? reject(err) : resolve()));
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
await rename(tmp, outputPath);
|
|
110
|
-
} catch (err) {
|
|
111
|
-
// Make sure the write stream is closed before we try to unlink the temp file.
|
|
112
|
-
writeStream.destroy();
|
|
113
|
-
await safeUnlink(tmp);
|
|
114
|
-
throw err;
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
// ---------------------------------------------------------------------------
|
|
119
|
-
// Decrypt
|
|
120
|
-
// ---------------------------------------------------------------------------
|
|
121
|
-
|
|
122
|
-
/**
|
|
123
|
-
* Stream-decrypt `inputPath` to `outputPath`. Expects the on-disk format
|
|
124
|
-
* produced by `encryptFile`: `[IV][ciphertext][auth tag]`.
|
|
125
|
-
*
|
|
126
|
-
* Reads the IV and auth tag via positional reads, then streams only the
|
|
127
|
-
* ciphertext body through the decipher. Atomic tmp + rename semantics.
|
|
128
|
-
*/
|
|
129
|
-
export async function decryptFile(
|
|
130
|
-
inputPath: string,
|
|
131
|
-
outputPath: string,
|
|
132
|
-
key: Buffer,
|
|
133
|
-
): Promise<void> {
|
|
134
|
-
assertKey(key);
|
|
135
|
-
|
|
136
|
-
const info = await stat(inputPath);
|
|
137
|
-
const totalSize = info.size;
|
|
138
|
-
const minSize = ENCRYPTED_HEADER_SIZE + GCM_TAG_SIZE;
|
|
139
|
-
if (totalSize < minSize) {
|
|
140
|
-
throw new Error(
|
|
141
|
-
`Encrypted file is too small: ${totalSize} bytes (need at least ${minSize})`,
|
|
142
|
-
);
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
// Read IV (first 12 bytes) and auth tag (last 16 bytes) via positional reads.
|
|
146
|
-
const iv = Buffer.alloc(ENCRYPTED_HEADER_SIZE);
|
|
147
|
-
const tag = Buffer.alloc(GCM_TAG_SIZE);
|
|
148
|
-
const fh = await open(inputPath, "r");
|
|
149
|
-
try {
|
|
150
|
-
await fh.read(iv, 0, ENCRYPTED_HEADER_SIZE, 0);
|
|
151
|
-
await fh.read(tag, 0, GCM_TAG_SIZE, totalSize - GCM_TAG_SIZE);
|
|
152
|
-
} finally {
|
|
153
|
-
await fh.close();
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
const decipher = createDecipheriv(ALGORITHM, key, iv);
|
|
157
|
-
decipher.setAuthTag(tag);
|
|
158
|
-
|
|
159
|
-
const ciphertextStart = ENCRYPTED_HEADER_SIZE;
|
|
160
|
-
const ciphertextEnd = totalSize - GCM_TAG_SIZE - 1; // createReadStream end is inclusive
|
|
161
|
-
const hasCiphertext = ciphertextEnd >= ciphertextStart;
|
|
162
|
-
|
|
163
|
-
const tmp = tempPath(outputPath);
|
|
164
|
-
const writeStream = createWriteStream(tmp);
|
|
165
|
-
|
|
166
|
-
try {
|
|
167
|
-
const ciphertextStream = hasCiphertext
|
|
168
|
-
? createReadStream(inputPath, {
|
|
169
|
-
start: ciphertextStart,
|
|
170
|
-
end: ciphertextEnd,
|
|
171
|
-
})
|
|
172
|
-
: Readable.from([]);
|
|
173
|
-
|
|
174
|
-
// pipeline consumes the ciphertext, pushes it through the decipher, and
|
|
175
|
-
// calls decipher.final() at the end — which is where auth tag verification
|
|
176
|
-
// happens. A bad tag surfaces here as a thrown error.
|
|
177
|
-
await pipeline(ciphertextStream, decipher, writeStream);
|
|
178
|
-
|
|
179
|
-
await rename(tmp, outputPath);
|
|
180
|
-
} catch (err) {
|
|
181
|
-
writeStream.destroy();
|
|
182
|
-
await safeUnlink(tmp);
|
|
183
|
-
throw err;
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
// ---------------------------------------------------------------------------
|
|
188
|
-
// Verify
|
|
189
|
-
// ---------------------------------------------------------------------------
|
|
190
|
-
|
|
191
|
-
/**
|
|
192
|
-
* Verify that `path` is a valid AES-256-GCM encrypted bundle for `key`.
|
|
193
|
-
*
|
|
194
|
-
* Streams the ciphertext through the decipher into a null sink and relies on
|
|
195
|
-
* `decipher.final()` to either succeed (tag matches) or throw (tamper / wrong
|
|
196
|
-
* key). No scratch file is written, so a full or read-only tmpdir cannot
|
|
197
|
-
* cause a healthy backup to be reported as invalid.
|
|
198
|
-
*
|
|
199
|
-
* Returns `true` if the bundle authenticates, `false` on a cryptographic
|
|
200
|
-
* failure (bad auth tag, wrong key, truncated/short input). Filesystem errors
|
|
201
|
-
* on the *source* file (ENOENT, EACCES, EIO, …) are rethrown so callers can
|
|
202
|
-
* distinguish tamper from transient I/O.
|
|
203
|
-
*/
|
|
204
|
-
export async function verifyEncryptedFile(
|
|
205
|
-
path: string,
|
|
206
|
-
key: Buffer,
|
|
207
|
-
): Promise<boolean> {
|
|
208
|
-
assertKey(key);
|
|
209
|
-
|
|
210
|
-
const info = await stat(path);
|
|
211
|
-
const totalSize = info.size;
|
|
212
|
-
const minSize = ENCRYPTED_HEADER_SIZE + GCM_TAG_SIZE;
|
|
213
|
-
if (totalSize < minSize) {
|
|
214
|
-
// Too short to contain an IV + tag — not a valid bundle.
|
|
215
|
-
return false;
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
const iv = Buffer.alloc(ENCRYPTED_HEADER_SIZE);
|
|
219
|
-
const tag = Buffer.alloc(GCM_TAG_SIZE);
|
|
220
|
-
const fh = await open(path, "r");
|
|
221
|
-
try {
|
|
222
|
-
await fh.read(iv, 0, ENCRYPTED_HEADER_SIZE, 0);
|
|
223
|
-
await fh.read(tag, 0, GCM_TAG_SIZE, totalSize - GCM_TAG_SIZE);
|
|
224
|
-
} finally {
|
|
225
|
-
await fh.close();
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
const decipher = createDecipheriv(ALGORITHM, key, iv);
|
|
229
|
-
decipher.setAuthTag(tag);
|
|
230
|
-
|
|
231
|
-
const ciphertextStart = ENCRYPTED_HEADER_SIZE;
|
|
232
|
-
const ciphertextEnd = totalSize - GCM_TAG_SIZE - 1;
|
|
233
|
-
const hasCiphertext = ciphertextEnd >= ciphertextStart;
|
|
234
|
-
const ciphertextStream = hasCiphertext
|
|
235
|
-
? createReadStream(path, { start: ciphertextStart, end: ciphertextEnd })
|
|
236
|
-
: Readable.from([]);
|
|
237
|
-
|
|
238
|
-
// Discard-only sink — verification never touches scratch disk.
|
|
239
|
-
const nullSink = new Writable({
|
|
240
|
-
write(_chunk, _encoding, cb) {
|
|
241
|
-
cb();
|
|
242
|
-
},
|
|
243
|
-
});
|
|
244
|
-
|
|
245
|
-
try {
|
|
246
|
-
await pipeline(ciphertextStream, decipher, nullSink);
|
|
247
|
-
return true;
|
|
248
|
-
} catch (err) {
|
|
249
|
-
if (isFilesystemError(err)) {
|
|
250
|
-
throw err;
|
|
251
|
-
}
|
|
252
|
-
return false;
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
// Node errno exceptions surface as uppercase `E`-prefixed codes (ENOENT,
|
|
257
|
-
// EACCES, ENOSPC, EIO, EROFS, …). Crypto errors use `ERR_*` codes or no code
|
|
258
|
-
// at all, so the regex rules them out.
|
|
259
|
-
function isFilesystemError(err: unknown): boolean {
|
|
260
|
-
if (!err || typeof err !== "object") return false;
|
|
261
|
-
const code = (err as { code?: unknown }).code;
|
|
262
|
-
return typeof code === "string" && /^E[A-Z]+$/.test(code);
|
|
263
|
-
}
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
// Pairing approval and approved-device management types.
|
|
2
|
-
|
|
3
|
-
// === Client → Server ===
|
|
4
|
-
|
|
5
|
-
export interface PairingApprovalResponse {
|
|
6
|
-
type: "pairing_approval_response";
|
|
7
|
-
pairingRequestId: string;
|
|
8
|
-
decision: "approve_once" | "always_allow" | "deny";
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export interface ApprovedDevicesList {
|
|
12
|
-
type: "approved_devices_list";
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export interface ApprovedDeviceRemove {
|
|
16
|
-
type: "approved_device_remove";
|
|
17
|
-
hashedDeviceId: string;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export interface ApprovedDevicesClear {
|
|
21
|
-
type: "approved_devices_clear";
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
// === Server → Client ===
|
|
25
|
-
|
|
26
|
-
export interface PairingApprovalRequest {
|
|
27
|
-
type: "pairing_approval_request";
|
|
28
|
-
pairingRequestId: string;
|
|
29
|
-
deviceId: string;
|
|
30
|
-
deviceName: string;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export interface ApprovedDevicesListResponse {
|
|
34
|
-
type: "approved_devices_list_response";
|
|
35
|
-
devices: Array<{
|
|
36
|
-
hashedDeviceId: string;
|
|
37
|
-
deviceName: string;
|
|
38
|
-
lastPairedAt: number;
|
|
39
|
-
}>;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
export interface ApprovedDeviceRemoveResponse {
|
|
43
|
-
type: "approved_device_remove_response";
|
|
44
|
-
success: boolean;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
// --- Domain-level union aliases (consumed by the barrel file) ---
|
|
48
|
-
|
|
49
|
-
export type _PairingClientMessages =
|
|
50
|
-
| PairingApprovalResponse
|
|
51
|
-
| ApprovedDevicesList
|
|
52
|
-
| ApprovedDeviceRemove
|
|
53
|
-
| ApprovedDevicesClear;
|
|
54
|
-
|
|
55
|
-
export type _PairingServerMessages =
|
|
56
|
-
| PairingApprovalRequest
|
|
57
|
-
| ApprovedDevicesListResponse
|
|
58
|
-
| ApprovedDeviceRemoveResponse;
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Configuration for the standalone proxy sidecar server.
|
|
3
|
-
*
|
|
4
|
-
* All values are sourced from environment variables with sensible defaults.
|
|
5
|
-
* Invalid values cause the process to exit with a descriptive error so
|
|
6
|
-
* misconfigurations are caught immediately at startup.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
export interface SidecarConfig {
|
|
10
|
-
/** Port the proxy server listens on. */
|
|
11
|
-
port: number;
|
|
12
|
-
/** Host address to bind to. */
|
|
13
|
-
host: string;
|
|
14
|
-
/** Port for the health/readiness HTTP server. */
|
|
15
|
-
healthPort: number;
|
|
16
|
-
/** Optional CA directory for MITM interception (contains ca.pem / ca-key.pem). */
|
|
17
|
-
caDir: string | null;
|
|
18
|
-
/** Log level for the sidecar process. */
|
|
19
|
-
logLevel: "debug" | "info" | "warn" | "error";
|
|
20
|
-
}
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Health / readiness HTTP server for the proxy sidecar.
|
|
3
|
-
*
|
|
4
|
-
* Exposes two endpoints on a separate control port:
|
|
5
|
-
* GET /healthz - Liveness probe. Returns 200 whenever the process is alive.
|
|
6
|
-
* GET /readyz - Readiness probe. Returns 200 only when the proxy server
|
|
7
|
-
* is listening and ready to accept connections.
|
|
8
|
-
*
|
|
9
|
-
* All other paths return 404. Non-GET methods return 405.
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
export interface HealthServerOptions {
|
|
13
|
-
/**
|
|
14
|
-
* Callback that returns `true` when the proxy server is ready to accept
|
|
15
|
-
* connections. The readiness probe delegates to this function.
|
|
16
|
-
*/
|
|
17
|
-
isReady: () => boolean;
|
|
18
|
-
}
|
|
@@ -1,150 +0,0 @@
|
|
|
1
|
-
/** How a credential value is injected into an outbound proxied request. */
|
|
2
|
-
export type CredentialInjectionType = "header" | "query";
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Describes where and how to inject a credential into proxied requests
|
|
6
|
-
* matching a specific host pattern.
|
|
7
|
-
*/
|
|
8
|
-
export interface CredentialInjectionTemplate {
|
|
9
|
-
/** Glob pattern for matching request hosts (e.g. "*.fal.ai"). */
|
|
10
|
-
hostPattern: string;
|
|
11
|
-
/** Where the credential value is injected. */
|
|
12
|
-
injectionType: CredentialInjectionType;
|
|
13
|
-
/** Header name when injectionType is 'header' (e.g. "Authorization"). */
|
|
14
|
-
headerName?: string;
|
|
15
|
-
/** Prefix prepended to the secret value (e.g. "Key ", "Bearer "). */
|
|
16
|
-
valuePrefix?: string;
|
|
17
|
-
/** Query parameter name when injectionType is 'query'. */
|
|
18
|
-
queryParamName?: string;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
/** Unique identifier for a proxy session. */
|
|
22
|
-
export type ProxySessionId = string;
|
|
23
|
-
|
|
24
|
-
export type ProxySessionStatus = "starting" | "active" | "stopping" | "stopped";
|
|
25
|
-
|
|
26
|
-
export interface ProxySession {
|
|
27
|
-
id: ProxySessionId;
|
|
28
|
-
conversationId: string;
|
|
29
|
-
credentialIds: string[];
|
|
30
|
-
status: ProxySessionStatus;
|
|
31
|
-
createdAt: Date;
|
|
32
|
-
/** Ephemeral port assigned once the session starts listening. */
|
|
33
|
-
port: number | null;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export interface ProxySessionConfig {
|
|
37
|
-
/** How long (ms) an idle session stays alive before auto-stopping. */
|
|
38
|
-
idleTimeoutMs: number;
|
|
39
|
-
/** Maximum concurrent sessions per conversation. */
|
|
40
|
-
maxSessionsPerConversation: number;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
export interface ProxyEnvVars {
|
|
44
|
-
HTTP_PROXY: string;
|
|
45
|
-
HTTPS_PROXY: string;
|
|
46
|
-
NO_PROXY: string;
|
|
47
|
-
NODE_EXTRA_CA_CERTS?: string;
|
|
48
|
-
/** Combined CA bundle (system roots + proxy CA) for non-Node TLS clients (curl, Python, etc.). */
|
|
49
|
-
SSL_CERT_FILE?: string;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
// ---------------------------------------------------------------------------
|
|
53
|
-
// Policy engine types
|
|
54
|
-
// ---------------------------------------------------------------------------
|
|
55
|
-
|
|
56
|
-
/** A single credential matched -- inject it. */
|
|
57
|
-
export interface PolicyDecisionMatched {
|
|
58
|
-
kind: "matched";
|
|
59
|
-
credentialId: string;
|
|
60
|
-
template: CredentialInjectionTemplate;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
/** Multiple credentials match -- caller must disambiguate. */
|
|
64
|
-
export interface PolicyDecisionAmbiguous {
|
|
65
|
-
kind: "ambiguous";
|
|
66
|
-
candidates: Array<{
|
|
67
|
-
credentialId: string;
|
|
68
|
-
template: CredentialInjectionTemplate;
|
|
69
|
-
}>;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
/** No credential matches the target host/path. */
|
|
73
|
-
export interface PolicyDecisionMissing {
|
|
74
|
-
kind: "missing";
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
/** No credential_ids were requested -- pass-through. */
|
|
78
|
-
export interface PolicyDecisionUnauthenticated {
|
|
79
|
-
kind: "unauthenticated";
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
// ---------------------------------------------------------------------------
|
|
83
|
-
// Approval hook outcomes -- structured data for triggering permission prompts.
|
|
84
|
-
// ---------------------------------------------------------------------------
|
|
85
|
-
|
|
86
|
-
/** Context about the outbound request target, used to build permission prompts. */
|
|
87
|
-
export interface RequestTargetContext {
|
|
88
|
-
hostname: string;
|
|
89
|
-
port: number | null;
|
|
90
|
-
path: string;
|
|
91
|
-
/** The protocol scheme of the original request ('http' or 'https'). */
|
|
92
|
-
scheme: "http" | "https";
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
/**
|
|
96
|
-
* The target host matches a known credential template pattern, but the
|
|
97
|
-
* session has no credential bound for it. The UI should prompt the user
|
|
98
|
-
* to bind or create a credential.
|
|
99
|
-
*/
|
|
100
|
-
export interface PolicyDecisionAskMissingCredential {
|
|
101
|
-
kind: "ask_missing_credential";
|
|
102
|
-
target: RequestTargetContext;
|
|
103
|
-
/** Host patterns from the known registry that matched the target. */
|
|
104
|
-
matchingPatterns: string[];
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
/**
|
|
108
|
-
* The request doesn't match any known credential template and the session
|
|
109
|
-
* has no credentials. The UI should prompt the user to allow or deny the
|
|
110
|
-
* unauthenticated request.
|
|
111
|
-
*/
|
|
112
|
-
export interface PolicyDecisionAskUnauthenticated {
|
|
113
|
-
kind: "ask_unauthenticated";
|
|
114
|
-
target: RequestTargetContext;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
export type PolicyDecision =
|
|
118
|
-
| PolicyDecisionMatched
|
|
119
|
-
| PolicyDecisionAmbiguous
|
|
120
|
-
| PolicyDecisionMissing
|
|
121
|
-
| PolicyDecisionUnauthenticated
|
|
122
|
-
| PolicyDecisionAskMissingCredential
|
|
123
|
-
| PolicyDecisionAskUnauthenticated;
|
|
124
|
-
|
|
125
|
-
// ---------------------------------------------------------------------------
|
|
126
|
-
// Proxy approval callback -- wires policy "ask" decisions to the UI prompter.
|
|
127
|
-
// ---------------------------------------------------------------------------
|
|
128
|
-
|
|
129
|
-
/**
|
|
130
|
-
* Payload passed to the approval callback when the policy engine emits an
|
|
131
|
-
* `ask_missing_credential` or `ask_unauthenticated` decision. Contains
|
|
132
|
-
* enough context for the prompter to build a meaningful confirmation dialog.
|
|
133
|
-
*/
|
|
134
|
-
export interface ProxyApprovalRequest {
|
|
135
|
-
/** The policy decision that triggered the approval prompt. */
|
|
136
|
-
decision:
|
|
137
|
-
| PolicyDecisionAskMissingCredential
|
|
138
|
-
| PolicyDecisionAskUnauthenticated;
|
|
139
|
-
/** The proxy session ID that originated the request. */
|
|
140
|
-
sessionId: ProxySessionId;
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
/**
|
|
144
|
-
* Callback signature for proxy approval prompts. The proxy service calls
|
|
145
|
-
* this when an outbound request requires user confirmation. Returns `true`
|
|
146
|
-
* if the user approves, `false` if denied.
|
|
147
|
-
*/
|
|
148
|
-
export type ProxyApprovalCallback = (
|
|
149
|
-
request: ProxyApprovalRequest,
|
|
150
|
-
) => Promise<boolean>;
|
|
@@ -1,190 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Capability token verification for scoped, short-lived tokens issued to the
|
|
3
|
-
* chrome extension (and other thin clients).
|
|
4
|
-
*
|
|
5
|
-
* Both minting and verification are owned by the gateway
|
|
6
|
-
* (`gateway/src/auth/capability-tokens.ts`). The daemon delegates
|
|
7
|
-
* verification to the gateway via IPC so it never needs to read the
|
|
8
|
-
* HMAC secret from the filesystem.
|
|
9
|
-
*
|
|
10
|
-
* Test-only helpers (`mintHostBrowserCapability`,
|
|
11
|
-
* `setCapabilityTokenSecretForTests`, `resetCapabilityTokenSecretForTests`)
|
|
12
|
-
* implement the same HMAC logic in-process so assistant tests can create
|
|
13
|
-
* and verify tokens without a live gateway.
|
|
14
|
-
*/
|
|
15
|
-
|
|
16
|
-
import { createHmac, randomBytes, timingSafeEqual } from "node:crypto";
|
|
17
|
-
|
|
18
|
-
import { ipcCall } from "../ipc/gateway-client.js";
|
|
19
|
-
import { getLogger } from "../util/logger.js";
|
|
20
|
-
|
|
21
|
-
const log = getLogger("capability-tokens");
|
|
22
|
-
|
|
23
|
-
// ---------------------------------------------------------------------------
|
|
24
|
-
// Types (mirror the gateway's types for consumer convenience)
|
|
25
|
-
// ---------------------------------------------------------------------------
|
|
26
|
-
|
|
27
|
-
/** Capability identifiers that can be bound to a capability token. */
|
|
28
|
-
export type Capability = "host_browser_command";
|
|
29
|
-
|
|
30
|
-
/** Claims encoded in the signed payload. */
|
|
31
|
-
export interface CapabilityClaims {
|
|
32
|
-
capability: Capability;
|
|
33
|
-
guardianId: string;
|
|
34
|
-
/** 16-byte random nonce, hex-encoded. Prevents replay across fresh mints. */
|
|
35
|
-
nonce: string;
|
|
36
|
-
/** ms-since-epoch expiry. */
|
|
37
|
-
expiresAt: number;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/** A freshly-minted capability token and its absolute expiry. */
|
|
41
|
-
export interface CapabilityToken {
|
|
42
|
-
token: string;
|
|
43
|
-
expiresAt: number;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
// ---------------------------------------------------------------------------
|
|
47
|
-
// In-process HMAC helpers (shared between test mint/verify and IPC verify)
|
|
48
|
-
// ---------------------------------------------------------------------------
|
|
49
|
-
|
|
50
|
-
let _testSecret: Buffer | undefined;
|
|
51
|
-
|
|
52
|
-
function base64urlEncode(buf: Buffer): string {
|
|
53
|
-
return buf
|
|
54
|
-
.toString("base64")
|
|
55
|
-
.replace(/\+/g, "-")
|
|
56
|
-
.replace(/\//g, "_")
|
|
57
|
-
.replace(/=+$/, "");
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
function base64urlDecode(s: string): Buffer {
|
|
61
|
-
const pad = s.length % 4 === 0 ? 0 : 4 - (s.length % 4);
|
|
62
|
-
const b64 = s.replace(/-/g, "+").replace(/_/g, "/") + "=".repeat(pad);
|
|
63
|
-
return Buffer.from(b64, "base64");
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
function sign(payload: string, secret: Buffer): string {
|
|
67
|
-
return base64urlEncode(createHmac("sha256", secret).update(payload).digest());
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
// ---------------------------------------------------------------------------
|
|
71
|
-
// Verify (production: gateway IPC, test: in-process)
|
|
72
|
-
// ---------------------------------------------------------------------------
|
|
73
|
-
|
|
74
|
-
/**
|
|
75
|
-
* Verify a capability token.
|
|
76
|
-
*
|
|
77
|
-
* In production, delegates to the gateway via IPC. In tests (when a
|
|
78
|
-
* secret has been injected via `setCapabilityTokenSecretForTests`),
|
|
79
|
-
* verifies in-process so tests don't need a live gateway.
|
|
80
|
-
*
|
|
81
|
-
* Returns the decoded claims on success or null on any failure.
|
|
82
|
-
*/
|
|
83
|
-
export async function verifyHostBrowserCapability(
|
|
84
|
-
token: string,
|
|
85
|
-
): Promise<CapabilityClaims | null> {
|
|
86
|
-
if (typeof token !== "string" || token.length === 0) return null;
|
|
87
|
-
|
|
88
|
-
// Test path: in-process verification with the injected secret.
|
|
89
|
-
if (_testSecret) {
|
|
90
|
-
return verifyInProcess(token, _testSecret);
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
// Production path: delegate to the gateway.
|
|
94
|
-
try {
|
|
95
|
-
const result = await ipcCall("verify_capability_token", { token });
|
|
96
|
-
if (!result || typeof result !== "object") return null;
|
|
97
|
-
|
|
98
|
-
const claims = result as Record<string, unknown>;
|
|
99
|
-
if (claims.valid === false) return null;
|
|
100
|
-
if (claims.capability !== "host_browser_command") return null;
|
|
101
|
-
if (
|
|
102
|
-
typeof claims.guardianId !== "string" ||
|
|
103
|
-
claims.guardianId.length === 0
|
|
104
|
-
) {
|
|
105
|
-
return null;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
return claims as unknown as CapabilityClaims;
|
|
109
|
-
} catch (err) {
|
|
110
|
-
log.warn({ err }, "Failed to verify capability token via gateway IPC");
|
|
111
|
-
return null;
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
function verifyInProcess(
|
|
116
|
-
token: string,
|
|
117
|
-
secret: Buffer,
|
|
118
|
-
): CapabilityClaims | null {
|
|
119
|
-
const dot = token.indexOf(".");
|
|
120
|
-
if (dot < 0) return null;
|
|
121
|
-
const payload = token.slice(0, dot);
|
|
122
|
-
const sig = token.slice(dot + 1);
|
|
123
|
-
if (!payload || !sig) return null;
|
|
124
|
-
|
|
125
|
-
const expected = sign(payload, secret);
|
|
126
|
-
const a = Buffer.from(sig, "utf8");
|
|
127
|
-
const b = Buffer.from(expected, "utf8");
|
|
128
|
-
if (a.length !== b.length) return null;
|
|
129
|
-
if (!timingSafeEqual(a, b)) return null;
|
|
130
|
-
|
|
131
|
-
let claims: CapabilityClaims;
|
|
132
|
-
try {
|
|
133
|
-
claims = JSON.parse(
|
|
134
|
-
base64urlDecode(payload).toString("utf8"),
|
|
135
|
-
) as CapabilityClaims;
|
|
136
|
-
} catch {
|
|
137
|
-
return null;
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
if (!claims || typeof claims !== "object") return null;
|
|
141
|
-
if (claims.capability !== "host_browser_command") return null;
|
|
142
|
-
if (typeof claims.guardianId !== "string" || claims.guardianId.length === 0) {
|
|
143
|
-
return null;
|
|
144
|
-
}
|
|
145
|
-
if (typeof claims.expiresAt !== "number" || claims.expiresAt <= Date.now()) {
|
|
146
|
-
return null;
|
|
147
|
-
}
|
|
148
|
-
return claims;
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
// ---------------------------------------------------------------------------
|
|
152
|
-
// Test-only helpers
|
|
153
|
-
// ---------------------------------------------------------------------------
|
|
154
|
-
|
|
155
|
-
/**
|
|
156
|
-
* Mint a capability token in-process. Test-only — production minting is
|
|
157
|
-
* done by the gateway.
|
|
158
|
-
*/
|
|
159
|
-
export function mintHostBrowserCapability(
|
|
160
|
-
guardianId: string,
|
|
161
|
-
ttlMs: number = 30 * 60 * 1000,
|
|
162
|
-
): CapabilityToken {
|
|
163
|
-
const secret = _testSecret;
|
|
164
|
-
if (!secret) {
|
|
165
|
-
throw new Error(
|
|
166
|
-
"capability token secret not set — call setCapabilityTokenSecretForTests() first",
|
|
167
|
-
);
|
|
168
|
-
}
|
|
169
|
-
const expiresAt = Date.now() + ttlMs;
|
|
170
|
-
const nonce = randomBytes(16).toString("hex");
|
|
171
|
-
const claims: CapabilityClaims = {
|
|
172
|
-
capability: "host_browser_command",
|
|
173
|
-
guardianId,
|
|
174
|
-
nonce,
|
|
175
|
-
expiresAt,
|
|
176
|
-
};
|
|
177
|
-
const payload = base64urlEncode(Buffer.from(JSON.stringify(claims), "utf8"));
|
|
178
|
-
const sig = sign(payload, secret);
|
|
179
|
-
return { token: `${payload}.${sig}`, expiresAt };
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
/** Inject a deterministic secret for tests. */
|
|
183
|
-
export function setCapabilityTokenSecretForTests(secret: Buffer): void {
|
|
184
|
-
_testSecret = secret;
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
/** Reset the test secret. */
|
|
188
|
-
export function resetCapabilityTokenSecretForTests(): void {
|
|
189
|
-
_testSecret = undefined;
|
|
190
|
-
}
|