@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
package/src/backup/restore.ts
CHANGED
|
@@ -1,116 +1,56 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* High-level helpers for restoring and verifying backup snapshots
|
|
3
|
-
* by the backup pipeline.
|
|
2
|
+
* High-level helpers for restoring and verifying backup snapshots.
|
|
4
3
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
4
|
+
* Only plaintext `.vbundle` files are supported directly. Encrypted
|
|
5
|
+
* `.vbundle.enc` files must be restored through the gateway, which owns the
|
|
6
|
+
* backup encryption key (ATL-397).
|
|
8
7
|
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* For encrypted snapshots, this module decrypts to a temporary file under the
|
|
14
|
-
* OS temp directory, runs validation, and then either commits the import or
|
|
15
|
-
* just reports validation status. The temp file is always cleaned up — on
|
|
16
|
-
* success and on failure — via a `try { ... } finally { unlink }` block.
|
|
17
|
-
*
|
|
18
|
-
* Restore is intentionally a thin wrapper around the existing
|
|
19
|
-
* `commitImport` flow in `runtime/migrations/vbundle-importer.ts`. That
|
|
20
|
-
* function handles bundle validation, workspace clearing, per-file
|
|
21
|
-
* backup-before-overwrite, and writing files to disk.
|
|
8
|
+
* Restore is a thin wrapper around `commitImport` in
|
|
9
|
+
* `runtime/migrations/vbundle-importer.ts`, which handles bundle validation,
|
|
10
|
+
* workspace clearing, per-file backup-before-overwrite, and writing files.
|
|
22
11
|
*
|
|
23
12
|
* `restoreFromSnapshot` closes the live SQLite singleton via `resetDb()`
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
* `handleMigrationImport` and ensures both the HTTP restore path and any
|
|
27
|
-
* in-process CLI caller get the reset for free. Tests can inject a fake via
|
|
28
|
-
* `opts.resetDbImpl`.
|
|
29
|
-
*
|
|
30
|
-
* `commitImport` does NOT invalidate cached config. Callers are responsible
|
|
31
|
-
* for calling `invalidateConfigCache()` AFTER a successful restore so the
|
|
32
|
-
* daemon re-reads the restored `config.json` instead of serving stale
|
|
33
|
-
* in-process caches. A daemon restart is the simplest recovery path.
|
|
13
|
+
* before the commit step so the daemon's DB handle is released before
|
|
14
|
+
* `assistant.db` is overwritten on disk.
|
|
34
15
|
*
|
|
35
16
|
* Credentials are intentionally excluded from backups — they live in the OS
|
|
36
|
-
* keychain / CES and are not restored by this path.
|
|
37
|
-
* integrations after a restore.
|
|
17
|
+
* keychain / CES and are not restored by this path.
|
|
38
18
|
*/
|
|
39
19
|
|
|
40
|
-
import {
|
|
41
|
-
import { readFile, unlink } from "node:fs/promises";
|
|
42
|
-
import { tmpdir } from "node:os";
|
|
43
|
-
import { join } from "node:path";
|
|
20
|
+
import { readFile } from "node:fs/promises";
|
|
44
21
|
|
|
45
22
|
import { resetDb } from "../memory/db-connection.js";
|
|
46
23
|
import type { PathResolver } from "../runtime/migrations/vbundle-import-analyzer.js";
|
|
24
|
+
import {
|
|
25
|
+
evaluateRuntimeCompatibility,
|
|
26
|
+
formatRuntimeCompatibilityMessage,
|
|
27
|
+
} from "../runtime/migrations/vbundle-import-policy.js";
|
|
47
28
|
import { commitImport } from "../runtime/migrations/vbundle-importer.js";
|
|
48
29
|
import type { ManifestType } from "../runtime/migrations/vbundle-validator.js";
|
|
49
30
|
import { validateVBundle } from "../runtime/migrations/vbundle-validator.js";
|
|
50
|
-
import {
|
|
31
|
+
import { APP_VERSION } from "../version.js";
|
|
51
32
|
|
|
52
33
|
// ---------------------------------------------------------------------------
|
|
53
34
|
// Public types
|
|
54
35
|
// ---------------------------------------------------------------------------
|
|
55
36
|
|
|
56
|
-
/**
|
|
57
|
-
* Optional injection point for the underlying commit function. Tests pass a
|
|
58
|
-
* fake here to avoid running the destructive `commitImport` flow against the
|
|
59
|
-
* live workspace. Production callers should leave this unset so the real
|
|
60
|
-
* importer is used.
|
|
61
|
-
*/
|
|
62
37
|
type CommitImpl = typeof commitImport;
|
|
63
38
|
|
|
64
39
|
interface RestoreOptions {
|
|
65
|
-
/** AES-256 decryption key. Required for `.vbundle.enc` snapshots. */
|
|
66
|
-
key?: Buffer;
|
|
67
|
-
/**
|
|
68
|
-
* Resolver that maps archive paths (e.g. `workspace/config.json`) to
|
|
69
|
-
* absolute disk paths. Required by the underlying `commitImport` flow.
|
|
70
|
-
*/
|
|
71
40
|
pathResolver: PathResolver;
|
|
72
|
-
/**
|
|
73
|
-
* Absolute path to the workspace directory. When set and the bundle
|
|
74
|
-
* contains `workspace/` entries, `commitImport` clears the workspace
|
|
75
|
-
* before writing to ensure an exact-match restore.
|
|
76
|
-
*/
|
|
77
41
|
workspaceDir?: string;
|
|
78
|
-
/**
|
|
79
|
-
* Optional override for the underlying commit function. Tests inject a
|
|
80
|
-
* fake to avoid mutating disk; production callers should leave this unset.
|
|
81
|
-
*/
|
|
82
42
|
commitImpl?: CommitImpl;
|
|
83
|
-
/**
|
|
84
|
-
* Optional override for the DB-reset hook. Invoked immediately before
|
|
85
|
-
* `commitImpl` so the live SQLite singleton is closed before
|
|
86
|
-
* `assistant.db` is overwritten. Tests inject a spy; production callers
|
|
87
|
-
* should leave this unset so the real `resetDb` is used.
|
|
88
|
-
*/
|
|
89
43
|
resetDbImpl?: () => void;
|
|
90
44
|
}
|
|
91
45
|
|
|
92
46
|
export interface RestoreResult {
|
|
93
|
-
/** Manifest from the bundle that was restored. */
|
|
94
47
|
manifest: ManifestType;
|
|
95
|
-
/** Number of files written (or skipped) by the underlying commit. */
|
|
96
48
|
restoredFiles: number;
|
|
97
49
|
}
|
|
98
50
|
|
|
99
|
-
interface VerifyOptions {
|
|
100
|
-
/** AES-256 decryption key. Required for `.vbundle.enc` snapshots. */
|
|
101
|
-
key?: Buffer;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
51
|
export interface VerifyResult {
|
|
105
|
-
/** True iff the bundle decrypts (when applicable) and validates. */
|
|
106
52
|
valid: boolean;
|
|
107
|
-
/** Manifest from the bundle when `valid` is true. */
|
|
108
53
|
manifest?: ManifestType;
|
|
109
|
-
/**
|
|
110
|
-
* Human-readable error message when `valid` is false. Populated for
|
|
111
|
-
* validation failures, decryption failures, and missing-file errors.
|
|
112
|
-
* Always undefined when `valid` is true.
|
|
113
|
-
*/
|
|
114
54
|
error?: string;
|
|
115
55
|
}
|
|
116
56
|
|
|
@@ -118,201 +58,137 @@ export interface VerifyResult {
|
|
|
118
58
|
// Internal helpers
|
|
119
59
|
// ---------------------------------------------------------------------------
|
|
120
60
|
|
|
121
|
-
/** Returns true if the snapshot path indicates an encrypted bundle. */
|
|
122
61
|
function isEncryptedSnapshot(snapshotPath: string): boolean {
|
|
123
62
|
return snapshotPath.endsWith(".vbundle.enc");
|
|
124
63
|
}
|
|
125
64
|
|
|
126
|
-
/** Build a unique temp path for a decrypted bundle. */
|
|
127
|
-
function makeDecryptedTempPath(): string {
|
|
128
|
-
return join(tmpdir(), `vellum-restore-${randomUUID()}.vbundle`);
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
/**
|
|
132
|
-
* Resolve `snapshotPath` to a path that holds plaintext `.vbundle` bytes.
|
|
133
|
-
*
|
|
134
|
-
* For plaintext snapshots, this just returns `{ path: snapshotPath }`. For
|
|
135
|
-
* encrypted snapshots, it decrypts to a fresh temp file and returns
|
|
136
|
-
* `{ path: tmpPath, tmpPath }` so the caller can clean up afterwards.
|
|
137
|
-
*
|
|
138
|
-
* Throws when an encrypted bundle has no key, when `decryptFile` fails
|
|
139
|
-
* (bad key, tampered ciphertext, truncated file), or on any I/O error.
|
|
140
|
-
*/
|
|
141
|
-
async function materializePlaintext(
|
|
142
|
-
snapshotPath: string,
|
|
143
|
-
key: Buffer | undefined,
|
|
144
|
-
): Promise<{ path: string; tmpPath: string | null }> {
|
|
145
|
-
if (!isEncryptedSnapshot(snapshotPath)) {
|
|
146
|
-
return { path: snapshotPath, tmpPath: null };
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
if (!key) {
|
|
150
|
-
throw new Error("Encrypted snapshot requires a decryption key");
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
const tmpPath = makeDecryptedTempPath();
|
|
154
|
-
await decryptFile(snapshotPath, tmpPath, key);
|
|
155
|
-
return { path: tmpPath, tmpPath };
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
/** Best-effort temp file cleanup — swallows ENOENT and other errors. */
|
|
159
|
-
async function safeUnlink(path: string | null): Promise<void> {
|
|
160
|
-
if (!path) return;
|
|
161
|
-
try {
|
|
162
|
-
await unlink(path);
|
|
163
|
-
} catch {
|
|
164
|
-
// Best-effort — temp file may already be gone.
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
|
|
168
65
|
// ---------------------------------------------------------------------------
|
|
169
66
|
// Public API
|
|
170
67
|
// ---------------------------------------------------------------------------
|
|
171
68
|
|
|
172
69
|
/**
|
|
173
|
-
* Restore a backup snapshot into the workspace.
|
|
174
|
-
*
|
|
175
|
-
* Auto-detects encryption from the file extension. Encrypted snapshots
|
|
176
|
-
* (`.vbundle.enc`) decrypt to a temp file under `tmpdir()` before
|
|
177
|
-
* validation; the temp file is unlinked in a `finally` block so it never
|
|
178
|
-
* lingers, even on validation or commit failure.
|
|
70
|
+
* Restore a plaintext backup snapshot into the workspace.
|
|
179
71
|
*
|
|
180
|
-
*
|
|
181
|
-
*
|
|
182
|
-
* Tests can pass `opts.commitImpl` to substitute a fake without mutating
|
|
183
|
-
* the live workspace.
|
|
72
|
+
* Encrypted `.vbundle.enc` snapshots are rejected — use the gateway's
|
|
73
|
+
* restore endpoint for those.
|
|
184
74
|
*/
|
|
185
75
|
export async function restoreFromSnapshot(
|
|
186
76
|
snapshotPath: string,
|
|
187
77
|
opts: RestoreOptions,
|
|
188
78
|
): Promise<RestoreResult> {
|
|
79
|
+
if (isEncryptedSnapshot(snapshotPath)) {
|
|
80
|
+
throw new Error(
|
|
81
|
+
"Encrypted snapshot restore must go through the gateway, which owns the backup key. " +
|
|
82
|
+
"Use the gateway's restore endpoint instead.",
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
|
|
189
86
|
const {
|
|
190
|
-
key,
|
|
191
87
|
pathResolver,
|
|
192
88
|
workspaceDir,
|
|
193
89
|
commitImpl = commitImport,
|
|
194
90
|
resetDbImpl = resetDb,
|
|
195
91
|
} = opts;
|
|
196
92
|
|
|
197
|
-
|
|
198
|
-
try {
|
|
199
|
-
const materialized = await materializePlaintext(snapshotPath, key);
|
|
200
|
-
tmpPath = materialized.tmpPath;
|
|
201
|
-
|
|
202
|
-
// Read plaintext bytes for validation + commit. validateVBundle takes
|
|
203
|
-
// raw bytes (Uint8Array) — file paths are not part of its API.
|
|
204
|
-
const fileData = await readFile(materialized.path);
|
|
93
|
+
const fileData = await readFile(snapshotPath);
|
|
205
94
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
95
|
+
const validation = validateVBundle(fileData);
|
|
96
|
+
if (!validation.is_valid || !validation.manifest || !validation.entries) {
|
|
97
|
+
const summary = validation.errors
|
|
98
|
+
.map((e) => `${e.code}: ${e.message}`)
|
|
99
|
+
.join("; ");
|
|
100
|
+
throw new Error(`Snapshot failed validation: ${summary}`);
|
|
101
|
+
}
|
|
213
102
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
103
|
+
// Pre-check runtime-version compat before the DB close/reopen cycle.
|
|
104
|
+
// commitImport runs the same gate as defense-in-depth for callers that
|
|
105
|
+
// don't pre-check; we run it here too so an incompatible bundle short-
|
|
106
|
+
// circuits before resetDbImpl().
|
|
107
|
+
const compatResult = evaluateRuntimeCompatibility(
|
|
108
|
+
validation.manifest.compatibility,
|
|
109
|
+
APP_VERSION,
|
|
110
|
+
);
|
|
111
|
+
if (!compatResult.ok) {
|
|
112
|
+
throw new Error(
|
|
113
|
+
`Snapshot restore failed: ${formatRuntimeCompatibilityMessage(
|
|
114
|
+
compatResult.bundle_compat,
|
|
115
|
+
compatResult.runtime_version,
|
|
116
|
+
)}`,
|
|
117
|
+
);
|
|
118
|
+
}
|
|
220
119
|
|
|
221
|
-
|
|
222
|
-
archiveData: fileData,
|
|
223
|
-
pathResolver,
|
|
224
|
-
preValidatedManifest: validation.manifest,
|
|
225
|
-
preValidatedEntries: validation.entries,
|
|
226
|
-
workspaceDir,
|
|
227
|
-
});
|
|
120
|
+
resetDbImpl();
|
|
228
121
|
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
122
|
+
const commitResult = commitImpl({
|
|
123
|
+
archiveData: fileData,
|
|
124
|
+
pathResolver,
|
|
125
|
+
preValidatedManifest: validation.manifest,
|
|
126
|
+
preValidatedEntries: validation.entries,
|
|
127
|
+
workspaceDir,
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
if (!commitResult.ok) {
|
|
131
|
+
let message: string;
|
|
132
|
+
switch (commitResult.reason) {
|
|
133
|
+
case "validation_failed":
|
|
134
|
+
message = commitResult.errors
|
|
135
|
+
.map((e) => `${e.code}: ${e.message}`)
|
|
136
|
+
.join("; ");
|
|
137
|
+
break;
|
|
138
|
+
case "extraction_failed":
|
|
139
|
+
case "write_failed":
|
|
140
|
+
message = commitResult.message;
|
|
141
|
+
break;
|
|
142
|
+
case "version_incompatible":
|
|
143
|
+
message = formatRuntimeCompatibilityMessage(
|
|
144
|
+
commitResult.bundle_compat,
|
|
145
|
+
commitResult.runtime_version,
|
|
146
|
+
);
|
|
147
|
+
break;
|
|
245
148
|
}
|
|
246
|
-
|
|
247
|
-
return {
|
|
248
|
-
manifest: commitResult.report.manifest,
|
|
249
|
-
restoredFiles: commitResult.report.summary.total_files,
|
|
250
|
-
};
|
|
251
|
-
} finally {
|
|
252
|
-
await safeUnlink(tmpPath);
|
|
149
|
+
throw new Error(`Snapshot restore failed: ${message}`);
|
|
253
150
|
}
|
|
151
|
+
|
|
152
|
+
return {
|
|
153
|
+
manifest: commitResult.report.manifest,
|
|
154
|
+
restoredFiles: commitResult.report.summary.total_files,
|
|
155
|
+
};
|
|
254
156
|
}
|
|
255
157
|
|
|
256
158
|
/**
|
|
257
159
|
* Verify a backup snapshot without restoring it.
|
|
258
160
|
*
|
|
259
|
-
*
|
|
260
|
-
*
|
|
261
|
-
* `validateVBundle` checks the importer would run, but never touches the
|
|
262
|
-
* workspace.
|
|
263
|
-
*
|
|
264
|
-
* Does NOT throw on validation or decryption failure — those are returned
|
|
265
|
-
* as `{ valid: false, error: ... }`. Only the missing-key precondition
|
|
266
|
-
* for encrypted bundles throws, since that is a programmer error.
|
|
161
|
+
* Only plaintext `.vbundle` files are supported. Encrypted snapshots must be
|
|
162
|
+
* verified through the gateway.
|
|
267
163
|
*/
|
|
268
164
|
export async function verifySnapshot(
|
|
269
165
|
snapshotPath: string,
|
|
270
|
-
opts: VerifyOptions,
|
|
271
166
|
): Promise<VerifyResult> {
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
167
|
+
if (isEncryptedSnapshot(snapshotPath)) {
|
|
168
|
+
return {
|
|
169
|
+
valid: false,
|
|
170
|
+
error:
|
|
171
|
+
"Encrypted snapshot verification must go through the gateway, which owns the backup key.",
|
|
172
|
+
};
|
|
278
173
|
}
|
|
279
174
|
|
|
280
|
-
let
|
|
175
|
+
let fileData: Uint8Array;
|
|
281
176
|
try {
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
// callers (e.g. snapshot list health checks) get a uniform shape.
|
|
290
|
-
return {
|
|
291
|
-
valid: false,
|
|
292
|
-
error: err instanceof Error ? err.message : String(err),
|
|
293
|
-
};
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
let fileData: Uint8Array;
|
|
297
|
-
try {
|
|
298
|
-
fileData = await readFile(plaintextPath);
|
|
299
|
-
} catch (err) {
|
|
300
|
-
return {
|
|
301
|
-
valid: false,
|
|
302
|
-
error: err instanceof Error ? err.message : String(err),
|
|
303
|
-
};
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
const validation = validateVBundle(fileData);
|
|
307
|
-
if (!validation.is_valid || !validation.manifest) {
|
|
308
|
-
const summary = validation.errors
|
|
309
|
-
.map((e) => `${e.code}: ${e.message}`)
|
|
310
|
-
.join("; ");
|
|
311
|
-
return { valid: false, error: summary };
|
|
312
|
-
}
|
|
177
|
+
fileData = await readFile(snapshotPath);
|
|
178
|
+
} catch (err) {
|
|
179
|
+
return {
|
|
180
|
+
valid: false,
|
|
181
|
+
error: err instanceof Error ? err.message : String(err),
|
|
182
|
+
};
|
|
183
|
+
}
|
|
313
184
|
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
185
|
+
const validation = validateVBundle(fileData);
|
|
186
|
+
if (!validation.is_valid || !validation.manifest) {
|
|
187
|
+
const summary = validation.errors
|
|
188
|
+
.map((e) => `${e.code}: ${e.message}`)
|
|
189
|
+
.join("; ");
|
|
190
|
+
return { valid: false, error: summary };
|
|
317
191
|
}
|
|
192
|
+
|
|
193
|
+
return { valid: true, manifest: validation.manifest };
|
|
318
194
|
}
|
|
@@ -17,6 +17,7 @@ import JSZip from "jszip";
|
|
|
17
17
|
import { getApp, getAppDirPath, isMultifileApp } from "../memory/app-store.js";
|
|
18
18
|
import { computeContentId } from "../util/content-id.js";
|
|
19
19
|
import { getLogger } from "../util/logger.js";
|
|
20
|
+
import { APP_VERSION } from "../version.js";
|
|
20
21
|
import { compileApp } from "./app-compiler.js";
|
|
21
22
|
import type { SigningCallback } from "./bundle-signer.js";
|
|
22
23
|
import { signBundle } from "./bundle-signer.js";
|
|
@@ -25,7 +26,6 @@ import { serializeManifest } from "./manifest.js";
|
|
|
25
26
|
|
|
26
27
|
const bundlerLog = getLogger("app-bundler");
|
|
27
28
|
|
|
28
|
-
import { APP_VERSION } from "../version.js";
|
|
29
29
|
const PACKAGE_VERSION = APP_VERSION;
|
|
30
30
|
|
|
31
31
|
const MAX_BUNDLE_SIZE_BYTES = 25 * 1024 * 1024; // 25 MB
|
|
@@ -37,6 +37,45 @@ export interface BundleResult {
|
|
|
37
37
|
iconImageBase64?: string;
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
+
function isDefaultMainScaffold(source: string): boolean {
|
|
41
|
+
const normalized = source.replace(/\s+/g, " ").trim();
|
|
42
|
+
return (
|
|
43
|
+
normalized.startsWith(
|
|
44
|
+
`import { render } from 'preact'; function App() { return <div>{"Hello, `,
|
|
45
|
+
) &&
|
|
46
|
+
normalized.endsWith(
|
|
47
|
+
`!"}</div>; } render(<App />, document.getElementById('app')!);`,
|
|
48
|
+
)
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function assertMultifileSourceReady(
|
|
53
|
+
app: { name: string },
|
|
54
|
+
appDir: string,
|
|
55
|
+
): void {
|
|
56
|
+
const srcIndexPath = join(appDir, "src", "index.html");
|
|
57
|
+
const srcMainPath = join(appDir, "src", "main.tsx");
|
|
58
|
+
const missing = [
|
|
59
|
+
!existsSync(srcIndexPath) ? "src/index.html" : null,
|
|
60
|
+
!existsSync(srcMainPath) ? "src/main.tsx" : null,
|
|
61
|
+
].filter((value): value is string => value !== null);
|
|
62
|
+
|
|
63
|
+
if (missing.length > 0) {
|
|
64
|
+
throw new Error(
|
|
65
|
+
`App "${app.name}" is a multi-file TSX app but is missing ${missing.join(
|
|
66
|
+
" and ",
|
|
67
|
+
)}. Write source files under src/ and call app_refresh before sharing.`,
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const mainSource = readFileSync(srcMainPath, "utf-8");
|
|
72
|
+
if (isDefaultMainScaffold(mainSource)) {
|
|
73
|
+
throw new Error(
|
|
74
|
+
`App "${app.name}" still has the default src/main.tsx scaffold. Write the real multi-file TSX source and call app_refresh before sharing.`,
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
40
79
|
/**
|
|
41
80
|
* Package an app into a .vellum zip archive.
|
|
42
81
|
*
|
|
@@ -82,6 +121,8 @@ export async function packageApp(
|
|
|
82
121
|
const appDir = getAppDirPath(appId);
|
|
83
122
|
|
|
84
123
|
if (multifile) {
|
|
124
|
+
assertMultifileSourceReady(app, appDir);
|
|
125
|
+
|
|
85
126
|
// Multi-file TSX app: compile src/ -> dist/
|
|
86
127
|
const compileResult = await compileApp(appDir);
|
|
87
128
|
if (!compileResult.ok) {
|
|
@@ -97,8 +138,15 @@ export async function packageApp(
|
|
|
97
138
|
}
|
|
98
139
|
|
|
99
140
|
const distDir = join(appDir, "dist");
|
|
100
|
-
const
|
|
101
|
-
const
|
|
141
|
+
const distIndexPath = join(distDir, "index.html");
|
|
142
|
+
const distMainPath = join(distDir, "main.js");
|
|
143
|
+
if (!existsSync(distIndexPath) || !existsSync(distMainPath)) {
|
|
144
|
+
throw new Error(
|
|
145
|
+
`Compilation for app "${app.name}" did not produce dist/index.html and dist/main.js. Check src/index.html and src/main.tsx, then call app_refresh.`,
|
|
146
|
+
);
|
|
147
|
+
}
|
|
148
|
+
const indexHtml = await readFile(distIndexPath, "utf-8");
|
|
149
|
+
const mainJs = await readFile(distMainPath);
|
|
102
150
|
|
|
103
151
|
compiledFiles.push({ name: "index.html", data: Buffer.from(indexHtml) });
|
|
104
152
|
compiledFiles.push({ name: "main.js", data: mainJs });
|
|
@@ -14,10 +14,6 @@ import {
|
|
|
14
14
|
findGuardianForChannel,
|
|
15
15
|
listGuardianChannels,
|
|
16
16
|
} from "../contacts/contact-store.js";
|
|
17
|
-
import {
|
|
18
|
-
touchContactInteraction,
|
|
19
|
-
upsertContactChannel,
|
|
20
|
-
} from "../contacts/contacts-write.js";
|
|
21
17
|
import { getAssistantName } from "../daemon/identity-helpers.js";
|
|
22
18
|
import type { ServerMessage } from "../daemon/message-protocol.js";
|
|
23
19
|
import { getCanonicalGuardianRequest } from "../memory/canonical-guardian-store.js";
|
|
@@ -615,13 +611,6 @@ export class RelayConnection {
|
|
|
615
611
|
this.startNameCapture(outcome.assistantId, outcome.fromNumber);
|
|
616
612
|
return;
|
|
617
613
|
case "verification":
|
|
618
|
-
if (
|
|
619
|
-
resolved.actorTrust.memberRecord &&
|
|
620
|
-
(resolved.actorTrust.trustClass === "guardian" ||
|
|
621
|
-
resolved.actorTrust.trustClass === "trusted_contact")
|
|
622
|
-
) {
|
|
623
|
-
touchContactInteraction(resolved.actorTrust.memberRecord.channel.id);
|
|
624
|
-
}
|
|
625
614
|
if (this.controller && resolved.actorTrust.trustClass !== "unknown") {
|
|
626
615
|
this.controller.setTrustContext(
|
|
627
616
|
toTrustContext(resolved.actorTrust, msg.from),
|
|
@@ -631,15 +620,6 @@ export class RelayConnection {
|
|
|
631
620
|
return;
|
|
632
621
|
case "normal_call":
|
|
633
622
|
if (outcome.isInbound) {
|
|
634
|
-
if (
|
|
635
|
-
resolved.actorTrust.memberRecord &&
|
|
636
|
-
(resolved.actorTrust.trustClass === "guardian" ||
|
|
637
|
-
resolved.actorTrust.trustClass === "trusted_contact")
|
|
638
|
-
) {
|
|
639
|
-
touchContactInteraction(
|
|
640
|
-
resolved.actorTrust.memberRecord.channel.id,
|
|
641
|
-
);
|
|
642
|
-
}
|
|
643
623
|
if (this.controller && resolved.actorTrust.trustClass !== "unknown") {
|
|
644
624
|
this.controller.setTrustContext(
|
|
645
625
|
toTrustContext(resolved.actorTrust, msg.from),
|
|
@@ -796,8 +776,6 @@ export class RelayConnection {
|
|
|
796
776
|
private continueCallAfterTrustedContactActivation(params: {
|
|
797
777
|
assistantId: string;
|
|
798
778
|
fromNumber: string;
|
|
799
|
-
callerName?: string;
|
|
800
|
-
skipMemberActivation?: boolean;
|
|
801
779
|
activationReason?:
|
|
802
780
|
| "invite_redeemed"
|
|
803
781
|
| "access_approved"
|
|
@@ -805,25 +783,10 @@ export class RelayConnection {
|
|
|
805
783
|
friendName?: string;
|
|
806
784
|
guardianName?: string;
|
|
807
785
|
}): void {
|
|
808
|
-
const { assistantId, fromNumber
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
upsertContactChannel({
|
|
813
|
-
sourceChannel: "phone",
|
|
814
|
-
externalUserId: fromNumber,
|
|
815
|
-
externalChatId: fromNumber,
|
|
816
|
-
displayName: callerName,
|
|
817
|
-
status: "active",
|
|
818
|
-
policy: "allow",
|
|
819
|
-
});
|
|
820
|
-
} catch (err) {
|
|
821
|
-
log.error(
|
|
822
|
-
{ err, callSessionId: this.callSessionId },
|
|
823
|
-
"Failed to activate voice caller as trusted contact",
|
|
824
|
-
);
|
|
825
|
-
}
|
|
826
|
-
}
|
|
786
|
+
const { assistantId, fromNumber } = params;
|
|
787
|
+
|
|
788
|
+
// Contact activation is handled by the gateway — the assistant no
|
|
789
|
+
// longer writes contact/channel records on inbound voice calls.
|
|
827
790
|
|
|
828
791
|
const updatedTrust = resolveActorTrust({
|
|
829
792
|
assistantId,
|
|
@@ -1411,7 +1374,6 @@ export class RelayConnection {
|
|
|
1411
1374
|
this.continueCallAfterTrustedContactActivation({
|
|
1412
1375
|
assistantId,
|
|
1413
1376
|
fromNumber,
|
|
1414
|
-
callerName: callerName ?? undefined,
|
|
1415
1377
|
activationReason: "access_approved",
|
|
1416
1378
|
});
|
|
1417
1379
|
|
|
@@ -1594,8 +1556,6 @@ export class RelayConnection {
|
|
|
1594
1556
|
this.continueCallAfterTrustedContactActivation({
|
|
1595
1557
|
assistantId: this.inviteRedemptionAssistantId,
|
|
1596
1558
|
fromNumber: this.inviteRedemptionFromNumber,
|
|
1597
|
-
callerName: this.inviteRedemptionFriendName ?? undefined,
|
|
1598
|
-
skipMemberActivation: true,
|
|
1599
1559
|
activationReason: "invite_redeemed",
|
|
1600
1560
|
friendName: this.inviteRedemptionFriendName ?? undefined,
|
|
1601
1561
|
guardianName: this.inviteRedemptionGuardianName ?? undefined,
|
|
@@ -1,8 +1,4 @@
|
|
|
1
1
|
import { loadConfig } from "../config/loader.js";
|
|
2
|
-
import {
|
|
3
|
-
getPublicBaseUrl,
|
|
4
|
-
getTwilioRelayUrl,
|
|
5
|
-
} from "../inbound/public-ingress-urls.js";
|
|
6
2
|
import { credentialKey } from "../security/credential-key.js";
|
|
7
3
|
import { getSecureKeyAsync } from "../security/secure-keys.js";
|
|
8
4
|
import { ConfigError } from "../util/errors.js";
|
|
@@ -14,8 +10,6 @@ export interface TwilioConfig {
|
|
|
14
10
|
accountSid: string;
|
|
15
11
|
authToken: string;
|
|
16
12
|
phoneNumber: string;
|
|
17
|
-
webhookBaseUrl: string;
|
|
18
|
-
wssBaseUrl: string;
|
|
19
13
|
}
|
|
20
14
|
|
|
21
15
|
/**
|
|
@@ -39,19 +33,10 @@ export function resolveTwilioPhoneNumber(): string {
|
|
|
39
33
|
}
|
|
40
34
|
|
|
41
35
|
export async function getTwilioConfig(): Promise<TwilioConfig> {
|
|
42
|
-
const
|
|
43
|
-
const accountSid = config.twilio?.accountSid || "";
|
|
36
|
+
const accountSid = loadConfig().twilio?.accountSid || "";
|
|
44
37
|
const authToken =
|
|
45
38
|
(await getSecureKeyAsync(credentialKey("twilio", "auth_token"))) || "";
|
|
46
39
|
const phoneNumber = resolveTwilioPhoneNumber();
|
|
47
|
-
const webhookBaseUrl = getPublicBaseUrl(config);
|
|
48
|
-
|
|
49
|
-
let wssBaseUrl: string;
|
|
50
|
-
try {
|
|
51
|
-
wssBaseUrl = getTwilioRelayUrl(config);
|
|
52
|
-
} catch {
|
|
53
|
-
wssBaseUrl = "";
|
|
54
|
-
}
|
|
55
40
|
|
|
56
41
|
if (!accountSid || !authToken) {
|
|
57
42
|
throw new ConfigError(
|
|
@@ -64,5 +49,5 @@ export async function getTwilioConfig(): Promise<TwilioConfig> {
|
|
|
64
49
|
|
|
65
50
|
log.debug("Twilio config loaded successfully");
|
|
66
51
|
|
|
67
|
-
return { accountSid, authToken, phoneNumber
|
|
52
|
+
return { accountSid, authToken, phoneNumber };
|
|
68
53
|
}
|