@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
|
@@ -22,11 +22,9 @@ import { randomBytes } from "node:crypto";
|
|
|
22
22
|
import {
|
|
23
23
|
existsSync,
|
|
24
24
|
mkdirSync,
|
|
25
|
-
readdirSync,
|
|
26
25
|
rmSync,
|
|
27
26
|
writeFileSync,
|
|
28
27
|
} from "node:fs";
|
|
29
|
-
import { open } from "node:fs/promises";
|
|
30
28
|
import { tmpdir } from "node:os";
|
|
31
29
|
import { join } from "node:path";
|
|
32
30
|
import { afterEach, beforeEach, describe, expect, test } from "bun:test";
|
|
@@ -40,7 +38,6 @@ import type {
|
|
|
40
38
|
} from "../../runtime/migrations/vbundle-importer.js";
|
|
41
39
|
import type { ManifestType } from "../../runtime/migrations/vbundle-validator.js";
|
|
42
40
|
import { restoreFromSnapshot, verifySnapshot } from "../restore.js";
|
|
43
|
-
import { ENCRYPTED_HEADER_SIZE, encryptFile } from "../stream-crypt.js";
|
|
44
41
|
|
|
45
42
|
// ---------------------------------------------------------------------------
|
|
46
43
|
// Fixtures
|
|
@@ -161,26 +158,6 @@ function makeStubCommitImpl(): {
|
|
|
161
158
|
return { commitImpl, calls };
|
|
162
159
|
}
|
|
163
160
|
|
|
164
|
-
/** Throwing stub used to verify temp-file cleanup on commit failure. */
|
|
165
|
-
function makeThrowingCommitImpl(): (
|
|
166
|
-
options: ImportCommitOptions,
|
|
167
|
-
) => ImportCommitResult {
|
|
168
|
-
return () => {
|
|
169
|
-
throw new Error("simulated commit failure");
|
|
170
|
-
};
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
/**
|
|
174
|
-
* Snapshot the OS temp directory so tests can later verify that nothing
|
|
175
|
-
* matching `vellum-restore-*.vbundle` was left behind. Restricting the
|
|
176
|
-
* search to that prefix avoids racing with unrelated processes.
|
|
177
|
-
*/
|
|
178
|
-
function listRestoreTempArtifacts(): string[] {
|
|
179
|
-
return readdirSync(tmpdir()).filter((name) =>
|
|
180
|
-
name.startsWith("vellum-restore-"),
|
|
181
|
-
);
|
|
182
|
-
}
|
|
183
|
-
|
|
184
161
|
// ---------------------------------------------------------------------------
|
|
185
162
|
// Tests
|
|
186
163
|
// ---------------------------------------------------------------------------
|
|
@@ -189,7 +166,7 @@ describe("verifySnapshot", () => {
|
|
|
189
166
|
test("plaintext: returns valid:true and the manifest for a well-formed bundle", async () => {
|
|
190
167
|
const { path, manifest } = writeTinyPlaintextBundle("plain.vbundle");
|
|
191
168
|
|
|
192
|
-
const result = await verifySnapshot(path
|
|
169
|
+
const result = await verifySnapshot(path);
|
|
193
170
|
|
|
194
171
|
expect(result.valid).toBe(true);
|
|
195
172
|
expect(result.manifest).toBeDefined();
|
|
@@ -199,66 +176,19 @@ describe("verifySnapshot", () => {
|
|
|
199
176
|
expect(result.manifest?.contents.length).toBe(3);
|
|
200
177
|
});
|
|
201
178
|
|
|
202
|
-
test("encrypted
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
const key = randomBytes(32);
|
|
206
|
-
await encryptFile(plainPath, encPath, key);
|
|
207
|
-
|
|
208
|
-
const before = listRestoreTempArtifacts();
|
|
209
|
-
const result = await verifySnapshot(encPath, { key });
|
|
210
|
-
const after = listRestoreTempArtifacts();
|
|
211
|
-
|
|
212
|
-
expect(result.valid).toBe(true);
|
|
213
|
-
expect(result.manifest).toBeDefined();
|
|
214
|
-
// The decrypted temp file must be cleaned up after verification.
|
|
215
|
-
expect(after.length).toBe(before.length);
|
|
216
|
-
});
|
|
217
|
-
|
|
218
|
-
test("encrypted with no key throws the typed error", async () => {
|
|
219
|
-
const { path: plainPath } = writeTinyPlaintextBundle("plain.vbundle");
|
|
179
|
+
test("encrypted path is rejected with a gateway redirect error", async () => {
|
|
180
|
+
// Write a dummy file with .vbundle.enc extension — the content doesn't
|
|
181
|
+
// matter because the rejection is based purely on file extension.
|
|
220
182
|
const encPath = join(TEST_DIR, "plain.vbundle.enc");
|
|
221
|
-
|
|
222
|
-
await encryptFile(plainPath, encPath, key);
|
|
223
|
-
|
|
224
|
-
await expect(verifySnapshot(encPath, {})).rejects.toThrow(
|
|
225
|
-
"Encrypted snapshot requires a decryption key",
|
|
226
|
-
);
|
|
227
|
-
});
|
|
228
|
-
|
|
229
|
-
test("corrupt ciphertext: returns valid:false with the decrypt error", async () => {
|
|
230
|
-
const { path: plainPath } = writeTinyPlaintextBundle("plain.vbundle");
|
|
231
|
-
const encPath = join(TEST_DIR, "plain.vbundle.enc");
|
|
232
|
-
const key = randomBytes(32);
|
|
233
|
-
await encryptFile(plainPath, encPath, key);
|
|
234
|
-
|
|
235
|
-
// Flip a byte inside the ciphertext body — auth tag verification fails.
|
|
236
|
-
const flipOffset = ENCRYPTED_HEADER_SIZE + 4;
|
|
237
|
-
const fh = await open(encPath, "r+");
|
|
238
|
-
try {
|
|
239
|
-
const one = Buffer.alloc(1);
|
|
240
|
-
await fh.read(one, 0, 1, flipOffset);
|
|
241
|
-
one[0] = one[0] ^ 0xff;
|
|
242
|
-
await fh.write(one, 0, 1, flipOffset);
|
|
243
|
-
} finally {
|
|
244
|
-
await fh.close();
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
const before = listRestoreTempArtifacts();
|
|
248
|
-
const result = await verifySnapshot(encPath, { key });
|
|
249
|
-
const after = listRestoreTempArtifacts();
|
|
183
|
+
writeFileSync(encPath, "dummy encrypted content");
|
|
250
184
|
|
|
185
|
+
const result = await verifySnapshot(encPath);
|
|
251
186
|
expect(result.valid).toBe(false);
|
|
252
|
-
expect(result.error).
|
|
253
|
-
expect(result.manifest).toBeUndefined();
|
|
254
|
-
// Even on failure, the decrypted temp file must be cleaned up.
|
|
255
|
-
expect(after.length).toBe(before.length);
|
|
187
|
+
expect(result.error).toMatch(/gateway/i);
|
|
256
188
|
});
|
|
257
189
|
|
|
258
190
|
test("corrupt manifest: returns valid:false with the validation error", async () => {
|
|
259
|
-
// Build a valid bundle, then
|
|
260
|
-
// We tamper at the plaintext bundle level so encryption succeeds but
|
|
261
|
-
// validateVBundle catches the bad manifest.
|
|
191
|
+
// Build a valid bundle, then tamper bytes in the middle
|
|
262
192
|
const { archive } = buildVBundle({
|
|
263
193
|
files: [
|
|
264
194
|
{ path: "data/db/assistant.db", data: new Uint8Array() },
|
|
@@ -270,9 +200,6 @@ describe("verifySnapshot", () => {
|
|
|
270
200
|
...defaultV1Options(),
|
|
271
201
|
});
|
|
272
202
|
|
|
273
|
-
// Flip a few bytes in the middle of the gzipped archive — this almost
|
|
274
|
-
// always corrupts the gzip stream itself or the embedded manifest JSON,
|
|
275
|
-
// both of which are validation failures (NOT decryption failures).
|
|
276
203
|
const tampered = Buffer.from(archive);
|
|
277
204
|
const tamperOffset = Math.floor(tampered.length / 2);
|
|
278
205
|
tampered[tamperOffset] = tampered[tamperOffset] ^ 0xff;
|
|
@@ -281,7 +208,7 @@ describe("verifySnapshot", () => {
|
|
|
281
208
|
const path = join(TEST_DIR, "corrupt.vbundle");
|
|
282
209
|
writeFileSync(path, tampered);
|
|
283
210
|
|
|
284
|
-
const result = await verifySnapshot(path
|
|
211
|
+
const result = await verifySnapshot(path);
|
|
285
212
|
|
|
286
213
|
expect(result.valid).toBe(false);
|
|
287
214
|
expect(result.error).toBeDefined();
|
|
@@ -309,53 +236,22 @@ describe("restoreFromSnapshot", () => {
|
|
|
309
236
|
|
|
310
237
|
expect(calls.length).toBe(1);
|
|
311
238
|
const passed = calls[0].options;
|
|
312
|
-
// The wrapper should pass the pre-validated manifest + entries so
|
|
313
|
-
// commitImport doesn't re-validate.
|
|
314
239
|
expect(passed.preValidatedManifest?.checksum).toBe(manifest.checksum);
|
|
315
240
|
expect(passed.preValidatedEntries).toBeDefined();
|
|
316
241
|
expect(passed.preValidatedEntries?.has("manifest.json")).toBe(true);
|
|
317
242
|
expect(passed.preValidatedEntries?.has("workspace/notes/hello.txt")).toBe(
|
|
318
243
|
true,
|
|
319
244
|
);
|
|
320
|
-
// archiveData must be the actual bundle bytes.
|
|
321
245
|
expect(passed.archiveData).toBeInstanceOf(Uint8Array);
|
|
322
246
|
expect(passed.archiveData.length).toBeGreaterThan(0);
|
|
323
247
|
|
|
324
|
-
// Public result is shaped correctly.
|
|
325
248
|
expect(result.manifest.checksum).toBe(manifest.checksum);
|
|
326
249
|
expect(result.restoredFiles).toBe(3);
|
|
327
250
|
});
|
|
328
251
|
|
|
329
|
-
test("encrypted
|
|
330
|
-
const { path: plainPath, manifest } =
|
|
331
|
-
writeTinyPlaintextBundle("plain.vbundle");
|
|
252
|
+
test("encrypted path is rejected with a gateway redirect error", async () => {
|
|
332
253
|
const encPath = join(TEST_DIR, "plain.vbundle.enc");
|
|
333
|
-
|
|
334
|
-
await encryptFile(plainPath, encPath, key);
|
|
335
|
-
|
|
336
|
-
const { commitImpl, calls } = makeStubCommitImpl();
|
|
337
|
-
|
|
338
|
-
const before = listRestoreTempArtifacts();
|
|
339
|
-
const result = await restoreFromSnapshot(encPath, {
|
|
340
|
-
key,
|
|
341
|
-
pathResolver: NULL_RESOLVER,
|
|
342
|
-
commitImpl,
|
|
343
|
-
});
|
|
344
|
-
const after = listRestoreTempArtifacts();
|
|
345
|
-
|
|
346
|
-
expect(calls.length).toBe(1);
|
|
347
|
-
expect(result.manifest.checksum).toBe(manifest.checksum);
|
|
348
|
-
expect(result.restoredFiles).toBe(3);
|
|
349
|
-
|
|
350
|
-
// Decrypted temp file must be cleaned up after the call.
|
|
351
|
-
expect(after.length).toBe(before.length);
|
|
352
|
-
});
|
|
353
|
-
|
|
354
|
-
test("encrypted with no key throws the typed error", async () => {
|
|
355
|
-
const { path: plainPath } = writeTinyPlaintextBundle("plain.vbundle");
|
|
356
|
-
const encPath = join(TEST_DIR, "plain.vbundle.enc");
|
|
357
|
-
const key = randomBytes(32);
|
|
358
|
-
await encryptFile(plainPath, encPath, key);
|
|
254
|
+
writeFileSync(encPath, "dummy encrypted content");
|
|
359
255
|
|
|
360
256
|
const { commitImpl, calls } = makeStubCommitImpl();
|
|
361
257
|
|
|
@@ -364,34 +260,12 @@ describe("restoreFromSnapshot", () => {
|
|
|
364
260
|
pathResolver: NULL_RESOLVER,
|
|
365
261
|
commitImpl,
|
|
366
262
|
}),
|
|
367
|
-
).rejects.toThrow(
|
|
263
|
+
).rejects.toThrow(/gateway/i);
|
|
368
264
|
|
|
369
265
|
expect(calls.length).toBe(0);
|
|
370
266
|
});
|
|
371
267
|
|
|
372
|
-
test("temp decrypted file is cleaned up after a commit failure", async () => {
|
|
373
|
-
const { path: plainPath } = writeTinyPlaintextBundle("plain.vbundle");
|
|
374
|
-
const encPath = join(TEST_DIR, "plain.vbundle.enc");
|
|
375
|
-
const key = randomBytes(32);
|
|
376
|
-
await encryptFile(plainPath, encPath, key);
|
|
377
|
-
|
|
378
|
-
const before = listRestoreTempArtifacts();
|
|
379
|
-
await expect(
|
|
380
|
-
restoreFromSnapshot(encPath, {
|
|
381
|
-
key,
|
|
382
|
-
pathResolver: NULL_RESOLVER,
|
|
383
|
-
commitImpl: makeThrowingCommitImpl(),
|
|
384
|
-
}),
|
|
385
|
-
).rejects.toThrow("simulated commit failure");
|
|
386
|
-
const after = listRestoreTempArtifacts();
|
|
387
|
-
|
|
388
|
-
expect(after.length).toBe(before.length);
|
|
389
|
-
});
|
|
390
|
-
|
|
391
268
|
test("credentials in a bundle are ignored and not surfaced to the caller", async () => {
|
|
392
|
-
// Older bundles (or a shared vbundle format) may include `credentials/*`
|
|
393
|
-
// entries. Backup restore explicitly drops them — credentials live in
|
|
394
|
-
// the OS keychain / CES and are not part of the backup round trip.
|
|
395
269
|
const { archive, manifest } = buildVBundle({
|
|
396
270
|
files: [
|
|
397
271
|
{ path: "data/db/assistant.db", data: new Uint8Array() },
|
|
@@ -416,14 +290,11 @@ describe("restoreFromSnapshot", () => {
|
|
|
416
290
|
commitImpl,
|
|
417
291
|
});
|
|
418
292
|
|
|
419
|
-
// The restore result must not expose a `credentials` field — the public
|
|
420
|
-
// type only has `manifest` and `restoredFiles`.
|
|
421
293
|
expect(result.manifest.checksum).toBe(manifest.checksum);
|
|
422
294
|
expect("credentials" in result).toBe(false);
|
|
423
295
|
});
|
|
424
296
|
|
|
425
297
|
test("validation failure: throws with the validation error message", async () => {
|
|
426
|
-
// Write garbage to a .vbundle path — gzip decompression will fail.
|
|
427
298
|
const path = join(TEST_DIR, "garbage.vbundle");
|
|
428
299
|
writeFileSync(path, Buffer.from("not a real bundle"));
|
|
429
300
|
|
|
@@ -436,14 +307,10 @@ describe("restoreFromSnapshot", () => {
|
|
|
436
307
|
}),
|
|
437
308
|
).rejects.toThrow(/Snapshot failed validation/);
|
|
438
309
|
|
|
439
|
-
// commitImpl must NOT have been called when validation fails.
|
|
440
310
|
expect(calls.length).toBe(0);
|
|
441
311
|
});
|
|
442
312
|
|
|
443
313
|
test("resetDbImpl runs before commitImpl and is skipped when validation fails", async () => {
|
|
444
|
-
// Happy path: resetDb must be called, and must be called BEFORE the
|
|
445
|
-
// commit step so the SQLite handle is released before assistant.db is
|
|
446
|
-
// overwritten on disk.
|
|
447
314
|
const { path } = writeTinyPlaintextBundle("plain.vbundle");
|
|
448
315
|
const order: string[] = [];
|
|
449
316
|
const { commitImpl } = makeStubCommitImpl();
|
|
@@ -462,9 +329,6 @@ describe("restoreFromSnapshot", () => {
|
|
|
462
329
|
|
|
463
330
|
expect(order).toEqual(["reset", "commit"]);
|
|
464
331
|
|
|
465
|
-
// Failure path: when validation fails, resetDb must NOT be invoked —
|
|
466
|
-
// there's no reason to close the DB singleton if we're not going to
|
|
467
|
-
// overwrite anything on disk.
|
|
468
332
|
const garbagePath = join(TEST_DIR, "garbage-for-reset.vbundle");
|
|
469
333
|
writeFileSync(garbagePath, Buffer.from("not a real bundle"));
|
|
470
334
|
let resetCallsOnInvalid = 0;
|
|
@@ -485,8 +349,6 @@ describe("restoreFromSnapshot", () => {
|
|
|
485
349
|
test("commit returning a write_failed result is surfaced as an error", async () => {
|
|
486
350
|
const { path } = writeTinyPlaintextBundle("plain.vbundle");
|
|
487
351
|
|
|
488
|
-
// Stub that simulates a write failure (the importer returns this for
|
|
489
|
-
// disk errors like permission denied or partial bundle writes).
|
|
490
352
|
const failingCommit = (_opts: ImportCommitOptions): ImportCommitResult => ({
|
|
491
353
|
ok: false,
|
|
492
354
|
reason: "write_failed",
|
|
@@ -500,6 +362,44 @@ describe("restoreFromSnapshot", () => {
|
|
|
500
362
|
}),
|
|
501
363
|
).rejects.toThrow(/disk full/);
|
|
502
364
|
});
|
|
365
|
+
|
|
366
|
+
test("version-incompatible bundle short-circuits before resetDbImpl and commitImpl", async () => {
|
|
367
|
+
// Bundle declares it requires runtime 99.0.0+, but the test process is
|
|
368
|
+
// far below that. The restore wrapper must pre-check compat before the
|
|
369
|
+
// DB close/reopen cycle and skip both resetDbImpl and commitImpl.
|
|
370
|
+
const incompatPath = join(TEST_DIR, "incompat.vbundle");
|
|
371
|
+
const { archive } = buildVBundle({
|
|
372
|
+
files: [
|
|
373
|
+
{ path: "data/db/assistant.db", data: new Uint8Array() },
|
|
374
|
+
{
|
|
375
|
+
path: "workspace/notes/hello.txt",
|
|
376
|
+
data: new TextEncoder().encode("hello"),
|
|
377
|
+
},
|
|
378
|
+
],
|
|
379
|
+
...defaultV1Options(),
|
|
380
|
+
compatibility: {
|
|
381
|
+
min_runtime_version: "99.0.0",
|
|
382
|
+
max_runtime_version: null,
|
|
383
|
+
},
|
|
384
|
+
});
|
|
385
|
+
writeFileSync(incompatPath, archive);
|
|
386
|
+
|
|
387
|
+
const { commitImpl, calls } = makeStubCommitImpl();
|
|
388
|
+
let resetCalls = 0;
|
|
389
|
+
|
|
390
|
+
await expect(
|
|
391
|
+
restoreFromSnapshot(incompatPath, {
|
|
392
|
+
pathResolver: NULL_RESOLVER,
|
|
393
|
+
commitImpl,
|
|
394
|
+
resetDbImpl: () => {
|
|
395
|
+
resetCalls += 1;
|
|
396
|
+
},
|
|
397
|
+
}),
|
|
398
|
+
).rejects.toThrow(/Snapshot restore failed.*99\.0\.0/);
|
|
399
|
+
|
|
400
|
+
expect(resetCalls).toBe(0);
|
|
401
|
+
expect(calls.length).toBe(0);
|
|
402
|
+
});
|
|
503
403
|
});
|
|
504
404
|
|
|
505
405
|
describe("snapshot path detection", () => {
|
|
@@ -507,7 +407,7 @@ describe("snapshot path detection", () => {
|
|
|
507
407
|
const path = join(TEST_DIR, "missing.vbundle");
|
|
508
408
|
expect(existsSync(path)).toBe(false);
|
|
509
409
|
|
|
510
|
-
const result = await verifySnapshot(path
|
|
410
|
+
const result = await verifySnapshot(path);
|
|
511
411
|
|
|
512
412
|
expect(result.valid).toBe(false);
|
|
513
413
|
expect(result.error).toBeDefined();
|
package/src/backup/paths.ts
CHANGED
|
@@ -1,12 +1,9 @@
|
|
|
1
1
|
import { homedir, userInfo } from "node:os";
|
|
2
2
|
import { dirname, isAbsolute, join } from "node:path";
|
|
3
3
|
|
|
4
|
-
import {
|
|
5
|
-
getBackupDirOverride,
|
|
6
|
-
getBackupKeyPathOverride,
|
|
7
|
-
} from "../config/env-registry.js";
|
|
4
|
+
import { getBackupDirOverride } from "../config/env-registry.js";
|
|
8
5
|
import type { BackupDestination } from "../config/schema.js";
|
|
9
|
-
|
|
6
|
+
|
|
10
7
|
|
|
11
8
|
/**
|
|
12
9
|
* Returns the backup root directory. Respects the `VELLUM_BACKUP_DIR`
|
|
@@ -133,19 +130,6 @@ export function resolveOffsiteDestinations(
|
|
|
133
130
|
return override;
|
|
134
131
|
}
|
|
135
132
|
|
|
136
|
-
/**
|
|
137
|
-
* Returns the path to the backup encryption key file.
|
|
138
|
-
*
|
|
139
|
-
* The `VELLUM_BACKUP_KEY_PATH` env var can override this for containerized
|
|
140
|
-
* deployments where the key must live on a persistent volume.
|
|
141
|
-
*
|
|
142
|
-
* TODO: The backup key is a credential and should eventually be managed by the
|
|
143
|
-
* gateway (behind IPC), not stored on the daemon's filesystem.
|
|
144
|
-
*/
|
|
145
|
-
export function getBackupKeyPath(): string {
|
|
146
|
-
return getBackupKeyPathOverride() ?? join(getWorkspaceDir(), ".backup.key");
|
|
147
|
-
}
|
|
148
|
-
|
|
149
133
|
/**
|
|
150
134
|
* Formats a backup filename from a date. Encrypted backups get a `.vbundle.enc`
|
|
151
135
|
* suffix; plaintext backups get `.vbundle`. Timestamp components are in UTC to
|