@vellumai/assistant 0.6.5 → 0.7.0
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/AGENTS.md +29 -1
- package/ARCHITECTURE.md +60 -53
- package/Dockerfile +25 -3
- package/README.md +8 -10
- package/__tests__/permissions/gateway-threshold-reader.test.ts +277 -0
- package/bun.lock +306 -119
- package/docs/architecture/integrations.md +32 -39
- package/docs/architecture/memory.md +26 -120
- package/docs/architecture/security.md +22 -36
- package/docs/browser-use-architecture-phase2.md +63 -20
- package/docs/credential-execution-service.md +7 -5
- package/docs/plugins.md +761 -0
- package/docs/skills.md +10 -10
- package/docs/stt-provider-onboarding.md +17 -45
- package/examples/plugins/echo/README.md +132 -0
- package/examples/plugins/echo/bun.lock +25 -0
- package/examples/plugins/echo/package.json +17 -0
- package/examples/plugins/echo/register.ts +187 -0
- package/knip.json +8 -22
- package/node_modules/@vellumai/ces-client/bun.lock +33 -0
- package/node_modules/@vellumai/ces-client/package.json +25 -0
- package/node_modules/@vellumai/ces-client/src/__tests__/ces-client.test.ts +631 -0
- package/node_modules/@vellumai/ces-client/src/__tests__/package-boundary.test.ts +138 -0
- package/node_modules/@vellumai/ces-client/src/credential-rpc.ts +13 -0
- package/node_modules/@vellumai/ces-client/src/http-credentials.ts +296 -0
- package/node_modules/@vellumai/ces-client/src/http-log-export.ts +111 -0
- package/node_modules/@vellumai/ces-client/src/index.ts +43 -0
- package/node_modules/@vellumai/ces-client/src/rpc-client.ts +445 -0
- package/node_modules/@vellumai/credential-storage/src/__tests__/package-boundary.test.ts +32 -6
- package/node_modules/@vellumai/egress-proxy/src/__tests__/package-boundary.test.ts +32 -1
- package/node_modules/@vellumai/egress-proxy/src/types.ts +19 -0
- package/node_modules/@vellumai/gateway-client/bun.lock +39 -0
- package/node_modules/@vellumai/gateway-client/package.json +23 -0
- package/node_modules/@vellumai/gateway-client/src/__tests__/gateway-client.test.ts +343 -0
- package/node_modules/@vellumai/gateway-client/src/__tests__/package-boundary.test.ts +140 -0
- package/node_modules/@vellumai/gateway-client/src/http-delivery.ts +422 -0
- package/node_modules/@vellumai/gateway-client/src/index.ts +35 -0
- package/node_modules/@vellumai/gateway-client/src/ipc-client.ts +331 -0
- package/node_modules/@vellumai/gateway-client/src/types.ts +131 -0
- package/node_modules/@vellumai/gateway-client/tsconfig.json +20 -0
- package/node_modules/@vellumai/{ces-contracts → service-contracts}/bun.lock +1 -1
- package/node_modules/@vellumai/{ces-contracts → service-contracts}/package.json +4 -2
- package/node_modules/@vellumai/{ces-contracts → service-contracts}/src/__tests__/contracts.test.ts +5 -1
- package/node_modules/@vellumai/service-contracts/src/__tests__/package-boundary.test.ts +155 -0
- package/node_modules/@vellumai/service-contracts/src/credential-rpc.ts +23 -0
- package/node_modules/@vellumai/service-contracts/src/index.ts +25 -0
- package/node_modules/@vellumai/{ces-contracts/src/index.ts → service-contracts/src/transport.ts} +6 -28
- package/node_modules/@vellumai/service-contracts/src/trust-rules.ts +116 -0
- package/node_modules/@vellumai/service-contracts/tsconfig.json +20 -0
- package/node_modules/@vellumai/skill-host-contracts/__tests__/client.test.ts +891 -0
- package/node_modules/@vellumai/skill-host-contracts/bun.lock +24 -0
- package/node_modules/@vellumai/skill-host-contracts/package.json +18 -0
- package/node_modules/@vellumai/skill-host-contracts/src/assistant-event.ts +91 -0
- package/node_modules/@vellumai/skill-host-contracts/src/client.ts +1348 -0
- package/node_modules/@vellumai/skill-host-contracts/src/index.ts +6 -0
- package/node_modules/@vellumai/skill-host-contracts/src/runtime-mode.ts +11 -0
- package/node_modules/@vellumai/skill-host-contracts/src/server-message.ts +32 -0
- package/node_modules/@vellumai/skill-host-contracts/src/skill-host.ts +333 -0
- package/node_modules/@vellumai/skill-host-contracts/src/tool-types.ts +444 -0
- package/node_modules/@vellumai/skill-host-contracts/tsconfig.json +20 -0
- package/node_modules/@vellumai/skill-host-contracts/tsconfig.test.json +12 -0
- package/openapi.yaml +3135 -692
- package/package.json +13 -7
- package/scripts/check-circular-deps.ts +80 -0
- package/scripts/generate-openapi.ts +24 -7
- package/{src/memory/graph/inspect.ts → scripts/memory-inspect.ts} +28 -28
- package/src/__tests__/access-request-decision.test.ts +2 -11
- package/src/__tests__/acp-session.test.ts +4 -150
- package/src/__tests__/actor-token-service.test.ts +17 -678
- package/src/__tests__/agent-loop-callsite-precedence.test.ts +2 -6
- package/src/__tests__/agent-loop-override-profile.test.ts +404 -0
- package/src/__tests__/agent-loop-thinking.test.ts +4 -4
- package/src/__tests__/agent-wake-override-profile.test.ts +261 -0
- package/src/__tests__/always-loaded-tools-guard.test.ts +2 -1
- package/src/__tests__/anthropic-provider.test.ts +127 -15
- package/src/__tests__/app-compiler.test.ts +57 -0
- package/src/__tests__/app-routes-csp.test.ts +106 -55
- package/src/__tests__/approval-cascade.test.ts +10 -357
- package/src/__tests__/approval-conversation-turn.test.ts +3 -8
- package/src/__tests__/approval-hardcoded-copy-guard.test.ts +1 -1
- package/src/__tests__/approval-primitive.test.ts +2 -1
- package/src/__tests__/approval-routes-http.test.ts +34 -451
- package/src/__tests__/assistant-events-sse-hardening.test.ts +73 -80
- package/src/__tests__/assistant-id-boundary-guard.test.ts +0 -3
- package/src/__tests__/attachment-upload-trusted-source.test.ts +139 -0
- package/src/__tests__/attachments-store.test.ts +46 -1
- package/src/__tests__/audit-log-rotation.test.ts +2 -1
- package/src/__tests__/auto-analysis-end-to-end.test.ts +9 -20
- package/src/__tests__/avatar-generator.test.ts +4 -2
- package/src/__tests__/background-shell-bash.test.ts +227 -0
- package/src/__tests__/background-shell-host-bash.test.ts +474 -0
- package/src/__tests__/background-tool-registry.test.ts +145 -0
- package/src/__tests__/background-tool-routes.test.ts +175 -0
- package/src/__tests__/btw-routes.test.ts +147 -183
- package/src/__tests__/bundled-asset.test.ts +6 -6
- package/src/__tests__/call-controller.test.ts +15 -2
- package/src/__tests__/call-conversation-messages.test.ts +2 -1
- package/src/__tests__/call-domain.test.ts +2 -2
- package/src/__tests__/call-pointer-messages.test.ts +11 -13
- package/src/__tests__/call-recovery.test.ts +2 -1
- package/src/__tests__/call-routes-http.test.ts +3 -14
- package/src/__tests__/call-store.test.ts +2 -1
- package/src/__tests__/cancel-resolves-conversation-key.test.ts +31 -62
- package/src/__tests__/canonical-guardian-store.test.ts +2 -2
- package/src/__tests__/catalog-cache.test.ts +69 -0
- package/src/__tests__/catalog-files.test.ts +0 -26
- package/src/__tests__/ces-rpc-credential-backend.test.ts +1 -1
- package/src/__tests__/channel-approval-routes.test.ts +79 -49
- package/src/__tests__/channel-approval.test.ts +9 -7
- package/src/__tests__/channel-approvals.test.ts +9 -180
- package/src/__tests__/channel-delivery-store.test.ts +11 -10
- package/src/__tests__/channel-guardian.test.ts +14 -25
- package/src/__tests__/channel-readiness-service.test.ts +8 -6
- package/src/__tests__/channel-reply-delivery.test.ts +3 -19
- package/src/__tests__/channel-retry-sweep.test.ts +2 -5
- package/src/__tests__/checker.test.ts +447 -3806
- package/src/__tests__/circuit-breaker-pipeline.test.ts +406 -0
- package/src/__tests__/cli-memory-v2-reembed-skills.test.ts +208 -0
- package/src/__tests__/cli.test.ts +1 -38
- package/src/__tests__/compaction-events.test.ts +500 -0
- package/src/__tests__/compaction-pipeline.test.ts +210 -0
- package/src/__tests__/compaction-strip-metadata-clear.test.ts +181 -0
- package/src/__tests__/compaction-timeout-recovery.test.ts +262 -0
- package/src/__tests__/config-managed-gemini-defaults.test.ts +3 -7
- package/src/__tests__/config-model-image-provider.test.ts +109 -0
- package/src/__tests__/config-schema-cmd.test.ts +1 -1
- package/src/__tests__/config-schema.test.ts +25 -203
- package/src/__tests__/config-watcher-cleanup-throttle.test.ts +0 -4
- package/src/__tests__/confirmation-request-guardian-bridge.test.ts +4 -25
- package/src/__tests__/contact-store-user-file.test.ts +2 -1
- package/src/__tests__/contacts-tools.test.ts +71 -18
- package/src/__tests__/contacts-write.test.ts +6 -61
- package/src/__tests__/context-overflow-policy.test.ts +7 -7
- package/src/__tests__/context-search-agent-protocol.test.ts +230 -0
- package/src/__tests__/context-search-agent-runner.test.ts +998 -0
- package/src/__tests__/context-search-conversations-source.test.ts +320 -0
- package/src/__tests__/context-search-fanout.test.ts +380 -0
- package/src/__tests__/context-search-memory-source.test.ts +311 -0
- package/src/__tests__/context-search-pkb-source.test.ts +444 -0
- package/src/__tests__/context-search-types.test.ts +95 -0
- package/src/__tests__/context-search-workspace-source.test.ts +545 -0
- package/src/__tests__/context-window-manager.test.ts +380 -4
- package/src/__tests__/conversation-abort-tool-results.test.ts +14 -2
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +631 -0
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +41 -32
- package/src/__tests__/conversation-agent-loop.test.ts +54 -143
- package/src/__tests__/conversation-analysis-routes.test.ts +60 -82
- package/src/__tests__/conversation-attachments.test.ts +9 -20
- package/src/__tests__/conversation-attention-store.test.ts +2 -1
- package/src/__tests__/conversation-attention-telegram.test.ts +4 -2
- package/src/__tests__/conversation-clear-safety.test.ts +53 -95
- package/src/__tests__/conversation-confirmation-signals.test.ts +7 -40
- package/src/__tests__/conversation-crud-inference-profile.test.ts +54 -0
- package/src/__tests__/conversation-delete-schedule-cleanup.test.ts +63 -157
- package/src/__tests__/conversation-disk-view-integration.test.ts +2 -2
- package/src/__tests__/conversation-disk-view.test.ts +5 -4
- package/src/__tests__/conversation-fork-crud.test.ts +26 -55
- package/src/__tests__/conversation-fork-route.test.ts +5 -74
- package/src/__tests__/conversation-history-web-search.test.ts +1 -0
- package/src/__tests__/conversation-inference-profile-list.test.ts +128 -0
- package/src/__tests__/conversation-inference-profile-route.test.ts +216 -0
- package/src/__tests__/conversation-init.benchmark.test.ts +4 -95
- package/src/__tests__/conversation-key-store-disk-view.test.ts +2 -1
- package/src/__tests__/conversation-lifecycle.test.ts +0 -1
- package/src/__tests__/conversation-list-source.test.ts +2 -2
- package/src/__tests__/conversation-load-history-repair.test.ts +0 -1
- package/src/__tests__/conversation-pairing.test.ts +174 -11
- package/src/__tests__/conversation-pre-run-repair.test.ts +137 -294
- package/src/__tests__/conversation-process-callsite.test.ts +3 -1
- package/src/__tests__/conversation-provider-retry-repair.test.ts +22 -8
- package/src/__tests__/conversation-queue.test.ts +30 -47
- package/src/__tests__/conversation-routes-disk-view.test.ts +131 -103
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +80 -55
- package/src/__tests__/conversation-routes-slash-commands.test.ts +83 -12
- package/src/__tests__/conversation-runtime-assembly.test.ts +196 -194
- package/src/__tests__/conversation-runtime-workspace.test.ts +23 -38
- package/src/__tests__/conversation-seed-composer.test.ts +2 -2
- package/src/__tests__/conversation-slash-commands.test.ts +6 -43
- package/src/__tests__/conversation-slash-queue.test.ts +7 -3
- package/src/__tests__/conversation-slash-unknown.test.ts +25 -3
- package/src/__tests__/conversation-speed-override.test.ts +6 -2
- package/src/__tests__/conversation-starter-routes.test.ts +177 -55
- package/src/__tests__/conversation-starters-cadence.test.ts +2 -2
- package/src/__tests__/conversation-store.test.ts +2 -375
- package/src/__tests__/conversation-title-service.test.ts +116 -0
- package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +42 -3
- package/src/__tests__/conversation-tool-setup-memory-scope.test.ts +6 -6
- package/src/__tests__/conversation-unread-route.test.ts +1 -1
- package/src/__tests__/conversation-usage.test.ts +3 -2
- package/src/__tests__/conversation-wipe.test.ts +2 -103
- package/src/__tests__/conversation-workspace-cache-state.test.ts +4 -2
- package/src/__tests__/conversation-workspace-injection.test.ts +3 -1
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +4 -2
- package/src/__tests__/conversations-defer-cli.test.ts +150 -0
- package/src/__tests__/credential-execution-admin-cli.test.ts +1 -1
- package/src/__tests__/credential-execution-api-key-propagation.test.ts +2 -2
- package/src/__tests__/credential-execution-approval-bridge.test.ts +22 -289
- package/src/__tests__/credential-execution-client.test.ts +1 -1
- package/src/__tests__/credential-execution-managed-contract.test.ts +1 -1
- package/src/__tests__/credential-health-service.test.ts +78 -9
- package/src/__tests__/credential-security-invariants.test.ts +16 -2
- package/src/__tests__/credentials-cli.test.ts +45 -21
- package/src/__tests__/daemon-credential-client.test.ts +23 -108
- package/src/__tests__/db-acp-history.test.ts +284 -0
- package/src/__tests__/db-activation-state.test.ts +240 -0
- package/src/__tests__/db-conversation-fork-lineage-migration.test.ts +2 -1
- package/src/__tests__/db-conversation-inference-profile-migration.test.ts +248 -0
- package/src/__tests__/db-llm-request-log-provider-migration.test.ts +2 -1
- package/src/__tests__/db-memory-graph-event-date-repair.test.ts +116 -0
- package/src/__tests__/db-rename-inference-profile-snake-case-migration.test.ts +132 -0
- package/src/__tests__/db-schedule-syntax-migration.test.ts +2 -0
- package/src/__tests__/delete-propagation.test.ts +3 -2
- package/src/__tests__/deterministic-verification-control-plane.test.ts +39 -32
- package/src/__tests__/dm-backfill.test.ts +3 -2
- package/src/__tests__/edit-propagation.test.ts +5 -7
- package/src/__tests__/embedding-managed-proxy-selection.test.ts +1 -1
- package/src/__tests__/empty-response-pipeline.test.ts +305 -0
- package/src/__tests__/events-client-registration.test.ts +297 -0
- package/src/__tests__/file-write-tool.test.ts +2 -4
- package/src/__tests__/filing-service.test.ts +144 -17
- package/src/__tests__/first-greeting.test.ts +247 -5
- package/src/__tests__/followup-tools.test.ts +2 -1
- package/src/__tests__/gateway-client-managed-outbound.test.ts +8 -12
- package/src/__tests__/gateway-only-enforcement.test.ts +2 -6
- package/src/__tests__/gateway-only-guard.test.ts +4 -3
- package/src/__tests__/gemini-provider.test.ts +276 -10
- package/src/__tests__/graph-extraction-event-date.test.ts +30 -0
- package/src/__tests__/guardian-action-conversation-turn.test.ts +2 -1
- package/src/__tests__/guardian-action-followup-executor.test.ts +2 -2
- package/src/__tests__/guardian-action-followup-store.test.ts +2 -1
- package/src/__tests__/guardian-action-grant-mint-consume.test.ts +9 -9
- package/src/__tests__/guardian-action-late-reply.test.ts +2 -1
- package/src/__tests__/guardian-action-store.test.ts +2 -1
- package/src/__tests__/guardian-action-sweep.test.ts +9 -8
- package/src/__tests__/guardian-binding-drift-heal.test.ts +2 -1
- package/src/__tests__/guardian-decision-primitive-canonical.test.ts +21 -118
- package/src/__tests__/guardian-dispatch.test.ts +14 -11
- package/src/__tests__/guardian-grant-minting.test.ts +9 -15
- package/src/__tests__/guardian-outbound-http.test.ts +71 -106
- package/src/__tests__/guardian-principal-id-roundtrip.test.ts +2 -2
- package/src/__tests__/guardian-routing-invariants.test.ts +34 -90
- package/src/__tests__/guardian-routing-state.test.ts +14 -22
- package/src/__tests__/guardian-verification-voice-binding.test.ts +1 -2
- package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +253 -0
- package/src/__tests__/handlers-user-message-approval-consumption.test.ts +8 -4
- package/src/__tests__/headless-browser-mode.test.ts +57 -0
- package/src/__tests__/heartbeat-service.test.ts +39 -21
- package/src/__tests__/helpers/call-route-handler.ts +72 -0
- package/src/__tests__/helpers/channel-test-adapter.ts +161 -0
- package/src/__tests__/helpers/gateway-classify-mock.ts +67 -0
- package/src/__tests__/helpers/mock-logger.ts +36 -0
- package/src/__tests__/history-repair-pipeline.test.ts +399 -0
- package/src/__tests__/home-state-routes.test.ts +10 -31
- package/src/__tests__/host-browser-e2e-cloud.test.ts +309 -1
- package/src/__tests__/host-browser-e2e-self-hosted-capability.test.ts +12 -2
- package/src/__tests__/host-browser-routes.test.ts +36 -91
- package/src/__tests__/host-browser-ws-events-e2e.test.ts +10 -2
- package/src/__tests__/host-proxy-interface.test.ts +38 -4
- package/src/__tests__/host-shell-tool.test.ts +2 -4
- package/src/__tests__/host-transfer-pending-interactions.test.ts +160 -0
- package/src/__tests__/host-transfer-proxy.test.ts +733 -0
- package/src/__tests__/http-conversation-lineage.test.ts +3 -2
- package/src/__tests__/http-user-message-parity.test.ts +20 -11
- package/src/__tests__/image-credentials.test.ts +137 -0
- package/src/__tests__/image-service-dispatcher.test.ts +186 -0
- package/src/__tests__/inbound-invite-redemption.test.ts +3 -2
- package/src/__tests__/injector-chain.test.ts +525 -0
- package/src/__tests__/inline-skill-load-permissions.test.ts +41 -206
- package/src/__tests__/install-skill-routing.test.ts +1 -1
- package/src/__tests__/intent-routing.test.ts +0 -26
- package/src/__tests__/invite-redemption-service.test.ts +2 -1
- package/src/__tests__/invite-routes-http.test.ts +80 -12
- package/src/__tests__/jobs-store-qdrant-breaker.test.ts +2 -1
- package/src/__tests__/jobs-store-upsert-debounced.test.ts +2 -1
- package/src/__tests__/lifecycle-memory-v2-seed.test.ts +157 -0
- package/src/__tests__/list-messages-attachments.test.ts +52 -55
- package/src/__tests__/list-messages-page-latest.test.ts +283 -0
- package/src/__tests__/list-messages-tool-merge.test.ts +16 -17
- package/src/__tests__/llm-call-pipeline.test.ts +284 -0
- package/src/__tests__/llm-context-normalization.test.ts +69 -4
- package/src/__tests__/llm-context-route-provider.test.ts +39 -113
- package/src/__tests__/llm-request-log-turn-query.test.ts +2 -1
- package/src/__tests__/llm-resolver.test.ts +211 -0
- package/src/__tests__/llm-schema.test.ts +56 -0
- package/src/__tests__/llm-usage-store.test.ts +2 -1
- package/src/__tests__/log-export-workspace.test.ts +28 -17
- package/src/__tests__/mcp-abort-signal.test.ts +2 -3
- package/src/__tests__/mcp-client-auth.test.ts +2 -3
- package/src/__tests__/media-generate-image.test.ts +119 -13
- package/src/__tests__/memory-admin-recall.test.ts +221 -0
- package/src/__tests__/memory-recall-log-store.test.ts +2 -1
- package/src/__tests__/memory-retrieval-pipeline.test.ts +399 -0
- package/src/__tests__/memory-upsert-concurrency.test.ts +3 -1
- package/src/__tests__/migration-cross-version-compatibility.test.ts +14 -13
- package/src/__tests__/migration-export-http.test.ts +17 -17
- package/src/__tests__/migration-export-to-gcs.test.ts +491 -0
- package/src/__tests__/migration-import-commit-http.test.ts +16 -16
- package/src/__tests__/migration-import-from-gcs.test.ts +533 -0
- package/src/__tests__/migration-import-from-url.test.ts +21 -91
- package/src/__tests__/migration-import-preflight-http.test.ts +13 -13
- package/src/__tests__/migration-jobs-status.test.ts +164 -0
- package/src/__tests__/migration-validate-http.test.ts +48 -83
- package/src/__tests__/mock-gateway-ipc.ts +32 -62
- package/src/__tests__/model-intents.test.ts +16 -1
- package/src/__tests__/nl-approval-parser.test.ts +13 -17
- package/src/__tests__/non-member-access-request.test.ts +13 -5
- package/src/__tests__/notification-broadcaster.test.ts +3 -3
- package/src/__tests__/notification-decision-strategy.test.ts +0 -11
- package/src/__tests__/notification-guardian-path.test.ts +15 -8
- package/src/__tests__/notification-schedule-notify-dedup.test.ts +109 -0
- package/src/__tests__/notification-telegram-adapter.test.ts +57 -55
- package/src/__tests__/oauth-apps-routes.test.ts +77 -123
- package/src/__tests__/oauth-cli.test.ts +28 -13
- package/src/__tests__/oauth-connect-orchestrator.test.ts +4 -13
- package/src/__tests__/oauth-provider-profiles.test.ts +1 -1
- package/src/__tests__/oauth-provider-serializer.test.ts +6 -4
- package/src/__tests__/oauth-provider-visibility.test.ts +6 -6
- package/src/__tests__/oauth-providers-routes.test.ts +81 -103
- package/src/__tests__/oauth-store.test.ts +44 -77
- package/src/__tests__/oauth2-gateway-transport.test.ts +6 -3
- package/src/__tests__/onboarding-template-contract.test.ts +16 -64
- package/src/__tests__/openai-image-service.test.ts +368 -0
- package/src/__tests__/openai-provider.test.ts +105 -6
- package/src/__tests__/openai-responses-provider.test.ts +146 -4
- package/src/__tests__/openrouter-provider-only.test.ts +22 -4
- package/src/__tests__/overflow-reduce-pipeline.test.ts +671 -0
- package/src/__tests__/permission-types.test.ts +3 -18
- package/src/__tests__/persist-onboarding-artifacts.test.ts +266 -0
- package/src/__tests__/persistence-pipeline.test.ts +378 -0
- package/src/__tests__/pipeline-runner.test.ts +565 -0
- package/src/__tests__/platform-bash-auto-approve.test.ts +27 -20
- package/src/__tests__/platform.test.ts +10 -59
- package/src/__tests__/playbook-execution.test.ts +2 -1
- package/src/__tests__/playbook-tools.test.ts +2 -1
- package/src/__tests__/plugin-bootstrap.test.ts +529 -0
- package/src/__tests__/plugin-registry.test.ts +303 -0
- package/src/__tests__/plugin-route-contribution.test.ts +294 -0
- package/src/__tests__/plugin-skill-contribution.test.ts +367 -0
- package/src/__tests__/plugin-tool-contribution.test.ts +292 -0
- package/src/__tests__/plugin-types.test.ts +320 -0
- package/src/__tests__/pricing.test.ts +195 -14
- package/src/__tests__/profiler-routes.test.ts +112 -177
- package/src/__tests__/provider-send-message-override-profile.test.ts +223 -0
- package/src/__tests__/proxy-approval-callback.test.ts +6 -493
- package/src/__tests__/qdrant-collection-migration.test.ts +7 -7
- package/src/__tests__/reaction-persistence.test.ts +4 -2
- package/src/__tests__/rebuild-index-graph-nodes.test.ts +1 -1
- package/src/__tests__/recording-handler.test.ts +0 -2
- package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +1 -0
- package/src/__tests__/registry.test.ts +1 -2
- package/src/__tests__/relay-server.test.ts +19 -4
- package/src/__tests__/require-fresh-approval.test.ts +19 -168
- package/src/__tests__/resolve-trust-class.test.ts +2 -1
- package/src/__tests__/retry-thinking-tool-choice.test.ts +19 -7
- package/src/__tests__/retry-verbosity-normalization.test.ts +139 -0
- package/src/__tests__/runtime-attachment-metadata.test.ts +26 -6
- package/src/__tests__/runtime-events-sse-parity.test.ts +12 -13
- package/src/__tests__/runtime-events-sse.test.ts +13 -21
- package/src/__tests__/schedule-routes.test.ts +304 -77
- package/src/__tests__/schedule-store.test.ts +119 -1
- package/src/__tests__/schedule-tools.test.ts +2 -1
- package/src/__tests__/scheduler-recurrence.test.ts +16 -71
- package/src/__tests__/scheduler-reuse-conversation.test.ts +12 -51
- package/src/__tests__/scheduler-wake.test.ts +356 -0
- package/src/__tests__/scoped-approval-grants.test.ts +2 -1
- package/src/__tests__/scoped-grant-security-matrix.test.ts +2 -1
- package/src/__tests__/secret-detection-handler.test.ts +2 -19
- package/src/__tests__/secret-ingress-http.test.ts +38 -21
- package/src/__tests__/secret-routes-managed-proxy.test.ts +46 -102
- package/src/__tests__/secret-scanner-executor.test.ts +1 -2
- package/src/__tests__/send-endpoint-busy.test.ts +38 -25
- package/src/__tests__/sequence-store.test.ts +2 -1
- package/src/__tests__/server-history-render.test.ts +2 -2
- package/src/__tests__/service-contracts-import-guard.test.ts +185 -0
- package/src/__tests__/set-permission-mode.test.ts +0 -10
- package/src/__tests__/settings-routes.test.ts +35 -68
- package/src/__tests__/skill-boundary-guard.test.ts +105 -0
- package/src/__tests__/skill-load-inline-command.test.ts +2 -2
- package/src/__tests__/skill-load-inline-includes.test.ts +2 -2
- package/src/__tests__/skill-runtime-path.test.ts +64 -0
- package/src/__tests__/skills-file-content-endpoint.test.ts +0 -2
- package/src/__tests__/slack-inbound-verification.test.ts +11 -2
- package/src/__tests__/slack-messaging-token-resolution.test.ts +1 -3
- package/src/__tests__/slack-reaction-approvals.test.ts +4 -4
- package/src/__tests__/slack-share-routes.test.ts +37 -72
- package/src/__tests__/subagent-call-site-routing.test.ts +79 -0
- package/src/__tests__/subagent-fork-spawn.test.ts +20 -28
- package/src/__tests__/subagent-notify-parent.test.ts +6 -29
- package/src/__tests__/subagent-role-registry.test.ts +3 -3
- package/src/__tests__/subagent-spawn-tool-fork.test.ts +52 -104
- package/src/__tests__/subagent-tools.test.ts +0 -1
- package/src/__tests__/suggestion-routes.test.ts +149 -57
- package/src/__tests__/task-compiler.test.ts +2 -1
- package/src/__tests__/task-management-tools.test.ts +2 -1
- package/src/__tests__/task-memory-cleanup.test.ts +3 -1
- package/src/__tests__/task-scheduler.test.ts +5 -16
- package/src/__tests__/telegram-config.test.ts +0 -1
- package/src/__tests__/terminal-tools.test.ts +5 -314
- package/src/__tests__/thread-backfill.test.ts +3 -2
- package/src/__tests__/title-generate-pipeline.test.ts +224 -0
- package/src/__tests__/token-estimate-pipeline.test.ts +484 -0
- package/src/__tests__/tool-approval-handler.test.ts +21 -63
- package/src/__tests__/tool-audit-listener.test.ts +3 -3
- package/src/__tests__/tool-domain-event-publisher.test.ts +3 -3
- package/src/__tests__/tool-error-pipeline.test.ts +244 -0
- package/src/__tests__/tool-execute-pipeline.test.ts +429 -0
- package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +61 -4
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +28 -56
- package/src/__tests__/tool-executor.test.ts +434 -1604
- package/src/__tests__/tool-grant-request-escalation.test.ts +90 -311
- package/src/__tests__/tool-result-truncate-pipeline.test.ts +356 -0
- package/src/__tests__/tool-result-truncation.test.ts +0 -110
- package/src/__tests__/trust-context-guards.test.ts +1 -1
- package/src/__tests__/trusted-contact-approval-notifier.test.ts +7 -15
- package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +178 -354
- package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +3 -2
- package/src/__tests__/trusted-contact-multichannel.test.ts +3 -2
- package/src/__tests__/trusted-contact-verification.test.ts +2 -1
- package/src/__tests__/turn-boundary-resolution.test.ts +2 -1
- package/src/__tests__/twilio-routes.test.ts +25 -66
- package/src/__tests__/usage-cache-backfill-migration.test.ts +3 -7
- package/src/__tests__/usage-routes.test.ts +73 -90
- package/src/__tests__/user-plugin-loader.test.ts +233 -0
- package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +2 -2
- package/src/__tests__/verification-control-plane-policy.test.ts +95 -14
- package/src/__tests__/voice-ingress-preflight.test.ts +5 -5
- package/src/__tests__/voice-invite-redemption.test.ts +2 -1
- package/src/__tests__/voice-scoped-grant-consumer.test.ts +3 -3
- package/src/__tests__/voice-session-bridge.test.ts +285 -106
- package/src/__tests__/volume-security-guard.test.ts +0 -2
- package/src/__tests__/workspace-migration-009-backfill-conversation-disk-view.test.ts +2 -1
- package/src/__tests__/workspace-migration-013-repair-conversation-disk-view.test.ts +3 -1
- package/src/__tests__/workspace-migration-028-recover-conversations-from-disk-view.test.ts +2 -1
- package/src/__tests__/workspace-migration-045-release-notes-meet-avatar.test.ts +1 -1
- package/src/__tests__/workspace-migration-046-seed-conversation-starters-callsite.test.ts +185 -0
- package/src/__tests__/workspace-migration-049-release-notes-default-sonnet.test.ts +100 -0
- package/src/__tests__/workspace-migration-050-seed-main-agent-opus-callsite.test.ts +171 -0
- package/src/__tests__/workspace-migration-051-seed-conversation-summarization-callsite.test.ts +252 -0
- package/src/__tests__/workspace-migration-052-seed-default-inference-profiles.test.ts +260 -0
- package/src/__tests__/workspace-migration-053-release-notes-acp-codex.test.ts +225 -0
- package/src/__tests__/workspace-migration-054-seed-recall-callsite.test.ts +235 -0
- package/src/__tests__/workspace-migration-055-release-notes-agentic-recall.test.ts +128 -0
- package/src/__tests__/workspace-migration-057-repair-stale-gemini-model-ids.test.ts +232 -0
- package/src/__tests__/workspace-migration-acp-sessions-ui.test.ts +144 -0
- package/src/__tests__/workspace-migration-drop-user-md.test.ts +1 -1
- package/src/__tests__/workspace-migration-memory-v2-init.test.ts +274 -0
- package/src/__tests__/workspace-migration-remove-hooks.test.ts +99 -0
- package/src/__tests__/workspace-policy.test.ts +21 -3
- package/src/acp/__tests__/client-handler.test.ts +64 -0
- package/src/acp/__tests__/helpers/acp-config-stub.ts +62 -0
- package/src/acp/__tests__/helpers/which-stub.ts +45 -0
- package/src/acp/__tests__/session-manager-persistence.test.ts +366 -0
- package/src/acp/__tests__/session-manager-startup.test.ts +159 -0
- package/src/acp/__tests__/session-manager.test.ts +83 -0
- package/src/acp/client-handler.ts +23 -139
- package/src/acp/resolve-agent.test.ts +291 -0
- package/src/acp/resolve-agent.ts +176 -0
- package/src/acp/session-manager.ts +166 -7
- package/src/acp/types.ts +2 -50
- package/src/agent/loop.ts +365 -104
- package/src/agent/message-types.ts +0 -2
- package/src/approvals/AGENTS.md +1 -1
- package/src/approvals/__tests__/guardian-feed-event.test.ts +296 -0
- package/src/approvals/approval-primitive.ts +3 -20
- package/src/approvals/guardian-decision-primitive.ts +37 -68
- package/src/approvals/guardian-request-resolvers.ts +109 -103
- package/src/avatar/character-components.ts +6 -6
- package/src/{config/bundled-skills/settings/tools → avatar}/identity-avatar.ts +1 -1
- package/src/backup/__tests__/backup-worker.test.ts +2 -15
- package/src/backup/__tests__/paths.test.ts +3 -2
- package/src/backup/backup-worker.ts +3 -24
- package/src/backup/paths.ts +2 -18
- package/src/backup/restore.ts +7 -11
- package/src/browser/__tests__/operations.test.ts +0 -35
- package/src/browser/operations.ts +1 -47
- package/src/bundler/app-compiler.ts +84 -1
- package/src/bundler/package-resolver.ts +2 -6
- package/src/calls/active-call-lease.ts +1 -1
- package/src/calls/call-constants.ts +1 -1
- package/src/calls/call-controller.ts +1 -5
- package/src/calls/call-domain.ts +14 -14
- package/src/calls/call-pointer-messages.ts +4 -9
- package/src/calls/call-state.ts +2 -2
- package/src/calls/call-store.ts +2 -1
- package/src/calls/guardian-action-sweep.ts +9 -25
- package/src/calls/guardian-dispatch.ts +1 -20
- package/src/calls/media-stream-audio-transcode.ts +2 -41
- package/src/calls/media-stream-server.ts +2 -3
- package/src/calls/media-stream-stt-session.ts +1 -3
- package/src/calls/relay-access-wait.ts +5 -8
- package/src/calls/relay-server.ts +15 -18
- package/src/calls/relay-setup-router.ts +2 -2
- package/src/calls/relay-verification.ts +4 -4
- package/src/calls/twilio-rest.ts +1 -1
- package/src/calls/twilio-routes.ts +160 -78
- package/src/calls/voice-control-protocol.ts +10 -10
- package/src/calls/voice-ingress-preflight.ts +2 -2
- package/src/calls/voice-session-bridge.ts +137 -42
- package/src/channels/__tests__/types.test.ts +28 -6
- package/src/channels/permission-profiles.ts +2 -72
- package/src/channels/types.ts +48 -30
- package/src/cli/AGENTS.md +1 -0
- package/src/cli/__tests__/notifications.test.ts +92 -214
- package/src/cli/commands/__tests__/attachment.test.ts +14 -8
- package/src/cli/commands/__tests__/backup.test.ts +4 -15
- package/src/cli/commands/__tests__/browser.test.ts +36 -31
- package/src/cli/commands/__tests__/cache.test.ts +23 -18
- package/src/cli/commands/__tests__/image-generation.test.ts +255 -35
- package/src/cli/commands/__tests__/inference-send.test.ts +12 -0
- package/src/cli/commands/__tests__/memory-v2.test.ts +396 -0
- package/src/cli/commands/__tests__/task.test.ts +36 -35
- package/src/cli/commands/__tests__/trust.test.ts +602 -0
- package/src/cli/commands/__tests__/tts-synthesize.test.ts +12 -0
- package/src/cli/commands/__tests__/ui-confirm.test.ts +14 -14
- package/src/cli/commands/__tests__/ui.test.ts +17 -17
- package/src/cli/commands/__tests__/watchers.test.ts +29 -29
- package/src/cli/commands/__tests__/webhooks.test.ts +544 -0
- package/src/cli/commands/attachment.ts +12 -8
- package/src/cli/commands/auth.ts +1 -1
- package/src/cli/commands/avatar.ts +192 -9
- package/src/cli/commands/backup.ts +16 -46
- package/src/cli/commands/browser.ts +52 -4
- package/src/cli/commands/cache.ts +7 -5
- package/src/cli/commands/channel-verification-sessions.ts +6 -6
- package/src/cli/commands/clients.ts +137 -0
- package/src/cli/commands/completions.ts +3 -10
- package/src/cli/commands/contacts.ts +10 -10
- package/src/cli/commands/conversations-defer.ts +364 -0
- package/src/cli/commands/conversations-import.ts +2 -3
- package/src/cli/commands/conversations.ts +115 -57
- package/src/cli/commands/credential-execution.ts +1 -1
- package/src/cli/commands/credentials.ts +139 -5
- package/src/cli/commands/default-action.ts +1 -1
- package/src/cli/commands/domain.ts +2 -2
- package/src/cli/commands/email.ts +7 -7
- package/src/cli/commands/image-generation.ts +33 -34
- package/src/cli/commands/keys.ts +2 -2
- package/src/cli/commands/mcp.ts +1 -1
- package/src/cli/commands/memory-v2.ts +343 -0
- package/src/cli/commands/memory.ts +8 -8
- package/src/cli/commands/notifications.ts +87 -121
- package/src/cli/commands/oauth/__tests__/connect.test.ts +23 -5
- package/src/cli/commands/oauth/__tests__/disconnect.test.ts +1 -1
- package/src/cli/commands/oauth/__tests__/mode.test.ts +1 -1
- package/src/cli/commands/oauth/__tests__/providers-register.test.ts +1 -1
- package/src/cli/commands/oauth/__tests__/providers-update.test.ts +1 -1
- package/src/cli/commands/oauth/__tests__/status.test.ts +1 -1
- package/src/cli/commands/oauth/__tests__/token.test.ts +1 -1
- package/src/cli/commands/oauth/connect.ts +4 -4
- package/src/cli/commands/oauth/providers.ts +176 -8
- package/src/cli/commands/oauth/shared.ts +29 -2
- package/src/cli/commands/oauth/status.ts +46 -36
- package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +0 -6
- package/src/cli/commands/platform/__tests__/connect.test.ts +23 -11
- package/src/cli/commands/platform/__tests__/disconnect.test.ts +22 -10
- package/src/cli/commands/platform/__tests__/status.test.ts +22 -10
- package/src/cli/commands/platform/connect.ts +3 -3
- package/src/cli/commands/platform/disconnect.ts +4 -6
- package/src/cli/commands/platform/index.ts +12 -10
- package/src/cli/commands/routes.ts +7 -1
- package/src/cli/commands/sequence.ts +7 -7
- package/src/cli/commands/skills.ts +189 -84
- package/src/cli/commands/task.ts +12 -10
- package/src/cli/commands/trust.ts +460 -162
- package/src/cli/commands/ui.ts +3 -3
- package/src/cli/commands/usage.ts +10 -5
- package/src/cli/commands/watchers.ts +8 -8
- package/src/cli/commands/webhooks.ts +270 -0
- package/src/cli/lib/daemon-avatar-client.ts +37 -0
- package/src/cli/lib/daemon-credential-client.ts +27 -189
- package/src/cli/lib/ipc-params.ts +22 -0
- package/src/cli/program.ts +29 -29
- package/src/cli.ts +1 -61
- package/src/config/__tests__/backup-schema.test.ts +7 -2
- package/src/config/acp-defaults.test.ts +57 -0
- package/src/config/acp-defaults.ts +40 -0
- package/src/config/acp-schema.ts +1 -1
- package/src/config/assistant-feature-flags.ts +18 -142
- package/src/config/bundled-skills/acp/SKILL.md +44 -16
- package/src/config/bundled-skills/acp/TOOLS.json +45 -1
- package/src/config/bundled-skills/{screen-watch/tools/start-screen-watch.ts → acp/tools/acp-list-agents.ts} +2 -2
- package/src/config/bundled-skills/acp/tools/acp-steer.ts +12 -0
- package/src/config/bundled-skills/app-builder/SKILL.md +2 -2
- package/src/config/bundled-skills/app-builder/references/WIDGETS.md +10 -10
- package/src/config/bundled-skills/contacts/tools/contact-merge.ts +66 -87
- package/src/config/bundled-skills/contacts/tools/contact-search.ts +25 -51
- package/src/config/bundled-skills/contacts/tools/contact-upsert.ts +31 -44
- package/src/config/bundled-skills/image-studio/SKILL.md +2 -1
- package/src/config/bundled-skills/image-studio/TOOLS.json +2 -1
- package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +23 -39
- package/src/config/bundled-skills/media-processing/__tests__/cost-tracker.test.ts +6 -6
- package/src/config/bundled-skills/media-processing/services/reduce.ts +0 -13
- package/src/config/bundled-skills/messaging/SKILL.md +3 -3
- package/src/config/bundled-skills/messaging/tools/__tests__/messaging-feed-events.test.ts +207 -0
- package/src/config/bundled-skills/messaging/tools/gmail-mime-helpers.ts +1 -1
- package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +1 -1
- package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +12 -0
- package/src/config/bundled-skills/messaging/tools/messaging-send.ts +58 -0
- package/src/config/bundled-skills/playbooks/tools/playbook-create.ts +1 -1
- package/src/config/bundled-skills/playbooks/tools/playbook-list.ts +1 -1
- package/src/config/bundled-skills/playbooks/tools/playbook-update.ts +1 -1
- package/src/config/bundled-skills/schedule/SKILL.md +8 -3
- package/src/config/bundled-skills/schedule/TOOLS.json +15 -7
- package/src/config/bundled-skills/schedule/references/SCRIPT_MODE_PATTERNS.md +59 -0
- package/src/config/bundled-skills/settings/SKILL.md +2 -17
- package/src/config/bundled-skills/settings/TOOLS.json +0 -56
- package/src/config/bundled-skills/subagent/SKILL.md +2 -0
- package/src/config/bundled-tool-registry.ts +4 -21
- package/src/config/env.ts +7 -8
- package/src/config/feature-flag-registry.json +25 -17
- package/src/config/llm-resolver.ts +51 -33
- package/src/config/loader.ts +12 -15
- package/src/config/schema.ts +22 -70
- package/src/config/schemas/__tests__/filing.test.ts +58 -0
- package/src/config/schemas/__tests__/memory-v2.test.ts +186 -0
- package/src/config/schemas/backup.ts +1 -1
- package/src/config/schemas/conversations.ts +16 -0
- package/src/config/schemas/filing.ts +12 -0
- package/src/config/schemas/host-browser.ts +2 -2
- package/src/config/schemas/inference.ts +0 -2
- package/src/config/schemas/ingress.ts +1 -1
- package/src/config/schemas/llm.ts +51 -10
- package/src/config/schemas/memory-storage.ts +1 -1
- package/src/config/schemas/memory-v2.ts +176 -0
- package/src/config/schemas/memory.ts +2 -0
- package/src/config/schemas/security.ts +0 -60
- package/src/config/schemas/services.ts +46 -7
- package/src/config/schemas/tts.ts +11 -0
- package/src/config/skill-state.ts +6 -2
- package/src/config/skills.ts +95 -6
- package/src/config/types.ts +0 -41
- package/src/contacts/contact-store.ts +2 -2
- package/src/contacts/contacts-write.ts +0 -38
- package/src/contacts/types.ts +8 -10
- package/src/context/__tests__/compact-prompt.test.ts +27 -9
- package/src/context/prompts/compact.md +26 -12
- package/src/context/token-estimator.ts +1 -1
- package/src/context/tool-result-truncation.ts +4 -64
- package/src/context/window-manager.ts +191 -17
- package/src/credential-execution/approval-bridge.ts +7 -69
- package/src/credential-execution/client.ts +17 -422
- package/src/credential-execution/feature-gates.ts +1 -2
- package/src/credential-execution/managed-catalog.ts +1 -1
- package/src/credential-health/credential-health-service.ts +20 -7
- package/src/daemon/__tests__/conversation-feed-event.test.ts +304 -0
- package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +4 -12
- package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +1 -1
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +14 -15
- package/src/daemon/__tests__/daemon-skill-host.test.ts +272 -0
- package/src/daemon/__tests__/meet-host-supervisor.test.ts +587 -0
- package/src/daemon/__tests__/meet-manifest-loader.test.ts +463 -0
- package/src/daemon/approval-generators.ts +2 -14
- package/src/daemon/classifier.ts +0 -106
- package/src/daemon/config-watcher.ts +14 -56
- package/src/daemon/connection-policy.ts +0 -14
- package/src/daemon/context-overflow-policy.ts +4 -13
- package/src/daemon/conversation-agent-loop-handlers.ts +120 -28
- package/src/daemon/conversation-agent-loop.ts +1113 -701
- package/src/daemon/conversation-attachments.ts +5 -81
- package/src/daemon/conversation-error.ts +9 -5
- package/src/daemon/conversation-history.ts +11 -20
- package/src/daemon/conversation-launch.ts +1 -1
- package/src/daemon/conversation-lifecycle.ts +37 -19
- package/src/daemon/conversation-messaging.ts +1 -1
- package/src/daemon/conversation-notifiers.ts +3 -111
- package/src/daemon/conversation-process.ts +23 -20
- package/src/daemon/conversation-runtime-assembly.ts +530 -471
- package/src/daemon/conversation-slash.ts +4 -160
- package/src/daemon/conversation-store.ts +368 -0
- package/src/daemon/conversation-surfaces.ts +5 -4
- package/src/daemon/conversation-tool-setup.ts +49 -161
- package/src/daemon/conversation.ts +126 -217
- package/src/daemon/daemon-control.ts +3 -3
- package/src/daemon/daemon-skill-host.ts +262 -0
- package/src/daemon/external-plugins-bootstrap.ts +532 -0
- package/src/daemon/first-greeting.ts +191 -14
- package/src/daemon/handlers/config-channels.ts +2 -2
- package/src/daemon/handlers/config-embeddings.ts +1 -1
- package/src/daemon/handlers/config-ingress.ts +24 -2
- package/src/daemon/handlers/config-model.test.ts +17 -0
- package/src/daemon/handlers/config-model.ts +18 -52
- package/src/daemon/handlers/config-telegram.ts +6 -53
- package/src/daemon/handlers/config-voice.ts +1 -1
- package/src/daemon/handlers/conversations.ts +22 -156
- package/src/daemon/handlers/recording.ts +1 -1
- package/src/daemon/handlers/shared.ts +34 -35
- package/src/daemon/handlers/skills.ts +20 -24
- package/src/daemon/host-transfer-proxy.ts +500 -0
- package/src/daemon/lifecycle.ts +56 -326
- package/src/daemon/meet-host-startup.ts +51 -0
- package/src/daemon/meet-host-supervisor.ts +781 -0
- package/src/daemon/meet-manifest-loader.ts +410 -0
- package/src/daemon/memory-v2-startup.ts +35 -0
- package/src/daemon/message-protocol.ts +4 -7
- package/src/daemon/message-types/acp.ts +1 -0
- package/src/daemon/message-types/computer-use.ts +2 -34
- package/src/daemon/message-types/conversations.ts +65 -2
- package/src/daemon/message-types/host-transfer.ts +41 -0
- package/src/daemon/message-types/integrations.ts +6 -0
- package/src/daemon/message-types/messages.ts +26 -14
- package/src/daemon/message-types/schedules.ts +1 -0
- package/src/daemon/message-types/settings.ts +0 -6
- package/src/daemon/message-types/shared.ts +5 -2
- package/src/daemon/message-types/subagents.ts +2 -1
- package/src/daemon/message-types/workspace.ts +0 -2
- package/src/daemon/pkb-reminder-builder.test.ts +13 -12
- package/src/daemon/pkb-reminder-builder.ts +8 -16
- package/src/daemon/process-message.ts +616 -0
- package/src/daemon/providers-setup.ts +14 -6
- package/src/daemon/server.ts +79 -1272
- package/src/daemon/shutdown-handlers.ts +3 -13
- package/src/daemon/startup-error.ts +1 -1
- package/src/daemon/tool-side-effects.ts +14 -56
- package/src/daemon/trust-context.ts +32 -0
- package/src/daemon/wake-target-adapter.ts +223 -0
- package/src/email/feature-gate.ts +1 -1
- package/src/events/domain-events.ts +1 -8
- package/src/events/tool-audit-listener.ts +2 -8
- package/src/events/tool-metrics-listener.ts +1 -4
- package/src/filing/filing-service.ts +194 -54
- package/src/followups/followup-store.ts +3 -71
- package/src/heartbeat/__tests__/heartbeat-feed-event.test.ts +228 -0
- package/src/heartbeat/heartbeat-service.ts +52 -8
- package/src/home/__tests__/feed-population-integration.test.ts +312 -0
- package/src/home/__tests__/phase5-exit-criteria.test.ts +18 -1
- package/src/home/__tests__/rollup-producer.test.ts +67 -2
- package/src/home/assistant-feed-authoring.ts +8 -1
- package/src/home/emit-feed-event.ts +7 -0
- package/src/home/feed-types.ts +42 -3
- package/src/home/relationship-state-writer.ts +1 -1
- package/src/home/rewrite-command-preview.ts +66 -0
- package/src/home/rewrite-feed-title.ts +58 -0
- package/src/home/rollup-producer.ts +16 -3
- package/src/inbound/platform-callback-registration.ts +1 -17
- package/src/ipc/__tests__/attachment-ipc.test.ts +128 -66
- package/src/ipc/__tests__/browser-ipc.test.ts +75 -51
- package/src/ipc/__tests__/cache-ipc.test.ts +52 -107
- package/src/ipc/__tests__/cli-ipc.test.ts +9 -6
- package/src/ipc/__tests__/skill-server-bidirectional.test.ts +254 -0
- package/src/ipc/__tests__/skill-server.test.ts +182 -0
- package/src/ipc/__tests__/socket-path.test.ts +44 -37
- package/src/ipc/__tests__/ui-request-route.test.ts +241 -216
- package/src/ipc/__tests__/watcher-ipc.test.ts +33 -33
- package/src/ipc/assistant-server.ts +450 -0
- package/src/ipc/cli-client.ts +3 -3
- package/src/ipc/gateway-client.test.ts +131 -0
- package/src/ipc/gateway-client.ts +98 -120
- package/src/ipc/ipc-framing.ts +281 -0
- package/src/ipc/routes/__tests__/memory-v2-backfill.test.ts +152 -0
- package/src/ipc/routes/__tests__/memory-v2-validate.test.ts +219 -0
- package/src/ipc/routes/db-proxy.ts +73 -0
- package/src/ipc/routes/route-adapter.ts +32 -0
- package/src/ipc/routes/trust-rules.test.ts +218 -0
- package/src/ipc/skill-ipc-types.ts +13 -0
- package/src/ipc/skill-routes/__tests__/config.test.ts +146 -0
- package/src/ipc/skill-routes/__tests__/events-ipc.test.ts +402 -0
- package/src/ipc/skill-routes/__tests__/identity.test.ts +81 -0
- package/src/ipc/skill-routes/__tests__/log.test.ts +133 -0
- package/src/ipc/skill-routes/__tests__/memory.test.ts +178 -0
- package/src/ipc/skill-routes/__tests__/platform.test.ts +111 -0
- package/src/ipc/skill-routes/__tests__/providers.test.ts +265 -0
- package/src/ipc/skill-routes/__tests__/registries.test.ts +361 -0
- package/src/ipc/skill-routes/config.ts +47 -0
- package/src/ipc/skill-routes/events.ts +131 -0
- package/src/ipc/skill-routes/identity.ts +34 -0
- package/src/ipc/skill-routes/index.ts +37 -0
- package/src/ipc/skill-routes/log.ts +40 -0
- package/src/ipc/skill-routes/memory.ts +76 -0
- package/src/ipc/skill-routes/platform.ts +39 -0
- package/src/ipc/skill-routes/providers.ts +163 -0
- package/src/ipc/skill-routes/registries.ts +393 -0
- package/src/ipc/skill-server.ts +771 -0
- package/src/ipc/skill-socket-path.ts +20 -0
- package/src/ipc/socket-cleanup.ts +92 -0
- package/src/ipc/socket-path.ts +55 -48
- package/src/live-voice/__tests__/live-voice-agent-turn.test.ts +374 -0
- package/src/live-voice/__tests__/live-voice-archive.test.ts +525 -0
- package/src/live-voice/__tests__/live-voice-events.test.ts +473 -0
- package/src/live-voice/__tests__/live-voice-integration.test.ts +359 -0
- package/src/live-voice/__tests__/live-voice-metrics.test.ts +179 -0
- package/src/live-voice/__tests__/live-voice-session-manager.test.ts +349 -0
- package/src/live-voice/__tests__/live-voice-stt.test.ts +244 -0
- package/src/live-voice/__tests__/live-voice-tts-session.test.ts +337 -0
- package/src/live-voice/__tests__/live-voice-tts.test.ts +337 -0
- package/src/live-voice/__tests__/protocol.test.ts +295 -0
- package/src/live-voice/__tests__/runtime-websocket-shell.test.ts +421 -0
- package/src/live-voice/live-voice-archive.ts +758 -0
- package/src/live-voice/live-voice-metrics.ts +472 -0
- package/src/live-voice/live-voice-session-manager.ts +222 -0
- package/src/live-voice/live-voice-session.ts +1144 -0
- package/src/live-voice/live-voice-tts.ts +260 -0
- package/src/live-voice/protocol.ts +524 -0
- package/src/mcp/client.ts +2 -2
- package/src/media/app-icon-generator.ts +23 -46
- package/src/media/avatar-router.ts +26 -41
- package/src/media/gemini-image-service.ts +8 -41
- package/src/media/image-credentials.ts +73 -0
- package/src/media/image-service.ts +85 -0
- package/src/media/openai-image-service.ts +131 -0
- package/src/media/types.ts +46 -0
- package/src/memory/__tests__/auto-analysis-enqueue.test.ts +4 -28
- package/src/memory/__tests__/auto-analysis-guard.test.ts +2 -2
- package/src/memory/__tests__/conversation-analyze-job.test.ts +7 -62
- package/src/memory/__tests__/conversation-group-migration.test.ts +2 -2
- package/src/memory/__tests__/find-analysis-conversation.test.ts +2 -1
- package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +235 -0
- package/src/memory/admin.ts +65 -7
- package/src/memory/app-git-service.ts +0 -14
- package/src/memory/attachments-store.ts +14 -16
- package/src/memory/auto-analysis-enqueue.ts +2 -17
- package/src/memory/canonical-guardian-store.ts +2 -1
- package/src/memory/channel-verification-sessions.ts +1 -1
- package/src/memory/checkpoints.ts +1 -1
- package/src/memory/context-search/agent-protocol.ts +424 -0
- package/src/memory/context-search/agent-runner.ts +1295 -0
- package/src/memory/context-search/format.ts +160 -0
- package/src/memory/context-search/limits.ts +106 -0
- package/src/memory/context-search/search.ts +387 -0
- package/src/memory/context-search/sources/conversations.ts +278 -0
- package/src/memory/context-search/sources/memory.ts +90 -0
- package/src/memory/context-search/sources/pkb.ts +468 -0
- package/src/memory/context-search/sources/workspace.ts +1255 -0
- package/src/memory/context-search/types.ts +49 -0
- package/src/memory/conversation-analyze-job.ts +3 -24
- package/src/memory/conversation-attention-store.ts +1 -1
- package/src/memory/conversation-bootstrap.ts +1 -1
- package/src/memory/conversation-crud.ts +117 -145
- package/src/memory/conversation-directories.ts +1 -11
- package/src/memory/conversation-display-order-migration.ts +11 -2
- package/src/memory/conversation-group-migration.ts +20 -4
- package/src/memory/conversation-key-store.ts +3 -4
- package/src/memory/conversation-queries.ts +69 -29
- package/src/memory/conversation-starter-validation.ts +88 -0
- package/src/memory/conversation-starters-cadence.ts +1 -1
- package/src/memory/conversation-title-service.ts +27 -1
- package/src/memory/db-init.ts +22 -4
- package/src/memory/db-maintenance.ts +1 -1
- package/src/memory/delivery-channels.ts +1 -14
- package/src/memory/delivery-crud.ts +2 -32
- package/src/memory/delivery-status.ts +1 -1
- package/src/memory/embedding-gemini.test.ts +44 -5
- package/src/memory/embedding-gemini.ts +6 -1
- package/src/memory/external-conversation-store.ts +1 -1
- package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +412 -0
- package/src/memory/graph/__tests__/handle-remember-v2.test.ts +225 -0
- package/src/memory/graph/bootstrap.test.ts +277 -0
- package/src/memory/graph/bootstrap.ts +10 -6
- package/src/memory/graph/capability-seed.ts +3 -3
- package/src/memory/graph/compaction.ts +1 -1
- package/src/memory/graph/consolidation.ts +13 -10
- package/src/memory/graph/conversation-graph-memory.ts +151 -1
- package/src/memory/graph/decay.ts +1 -1
- package/src/memory/graph/extraction.ts +63 -23
- package/src/memory/graph/graph-memory-state-store.ts +1 -1
- package/src/memory/graph/graph-search.test.ts +95 -2
- package/src/memory/graph/graph-search.ts +22 -7
- package/src/memory/graph/image-ref-utils.ts +1 -1
- package/src/memory/graph/retriever.test.ts +158 -4
- package/src/memory/graph/retriever.ts +27 -8
- package/src/memory/graph/store.test.ts +2 -1
- package/src/memory/graph/store.ts +1 -1
- package/src/memory/graph/tool-handlers.ts +73 -247
- package/src/memory/graph/tools.ts +35 -53
- package/src/memory/group-crud.ts +1 -2
- package/src/memory/guardian-action-store.ts +2 -1
- package/src/memory/guardian-approvals.ts +1 -1
- package/src/memory/guardian-rate-limits.ts +1 -1
- package/src/memory/indexer.ts +43 -17
- package/src/memory/invite-store.ts +1 -1
- package/src/memory/job-handlers/backfill.ts +1 -1
- package/src/memory/job-handlers/cleanup.ts +2 -1
- package/src/memory/job-handlers/conversation-starters.ts +18 -10
- package/src/memory/job-handlers/embedding.test.ts +2 -1
- package/src/memory/job-handlers/embedding.ts +1 -1
- package/src/memory/job-handlers/index-maintenance.ts +1 -1
- package/src/memory/job-handlers/summarization.ts +3 -3
- package/src/memory/job-utils.ts +3 -3
- package/src/memory/jobs/__tests__/embed-concept-page.test.ts +362 -0
- package/src/memory/jobs/embed-concept-page.ts +210 -0
- package/src/memory/jobs/embed-pkb-file.test.ts +2 -1
- package/src/memory/jobs-store.ts +10 -2
- package/src/memory/jobs-worker.ts +58 -5
- package/src/memory/lifecycle-events-store.ts +1 -1
- package/src/memory/llm-request-log-store.ts +1 -1
- package/src/memory/llm-usage-store.ts +1 -1
- package/src/memory/media-store.ts +1 -1
- package/src/memory/memory-recall-log-store.ts +1 -1
- package/src/memory/migrations/038-actor-token-records.ts +3 -0
- package/src/memory/migrations/039-actor-refresh-token-records.ts +3 -0
- package/src/memory/migrations/041-approval-prompt-ts-tracker.ts +26 -0
- package/src/memory/migrations/149-oauth-tables.ts +1 -0
- package/src/memory/migrations/223-schedule-script-column.ts +11 -0
- package/src/memory/migrations/224-oauth-providers-managed-service-is-paid.ts +24 -0
- package/src/memory/migrations/225-oauth-providers-available-scopes.ts +13 -0
- package/src/memory/migrations/226-schedule-wake-conversation-id.ts +11 -0
- package/src/memory/migrations/227-add-conversation-inference-profile.ts +18 -0
- package/src/memory/migrations/228-rename-inference-profile-snake-case.ts +27 -0
- package/src/memory/migrations/229-delete-private-conversations.test.ts +1087 -0
- package/src/memory/migrations/229-delete-private-conversations.ts +210 -0
- package/src/memory/migrations/230-acp-session-history.ts +41 -0
- package/src/memory/migrations/231-repair-memory-graph-event-dates.ts +128 -0
- package/src/memory/migrations/232-activation-state.ts +38 -0
- package/src/memory/migrations/index.ts +14 -0
- package/src/memory/migrations/registry.ts +7 -0
- package/src/memory/pkb/pkb-index.test.ts +5 -5
- package/src/memory/pkb/pkb-reconcile.test.ts +5 -5
- package/src/memory/pkb/pkb-search.test.ts +148 -7
- package/src/memory/pkb/pkb-search.ts +65 -30
- package/src/memory/published-pages-store.ts +1 -1
- package/src/memory/qdrant-client.test.ts +60 -0
- package/src/memory/qdrant-client.ts +25 -0
- package/src/memory/schema/acp.ts +30 -0
- package/src/memory/schema/conversations.ts +1 -1
- package/src/memory/schema/index.ts +1 -0
- package/src/memory/schema/infrastructure.ts +2 -32
- package/src/memory/schema/memory-graph.ts +36 -14
- package/src/memory/schema/oauth.ts +4 -1
- package/src/memory/scoped-approval-grants.ts +2 -1
- package/src/memory/search/semantic.ts +2 -2
- package/src/memory/shared-app-links-store.ts +2 -1
- package/src/memory/tool-usage-store.ts +1 -1
- package/src/memory/trace-event-store.ts +2 -1
- package/src/memory/turn-events-store.ts +1 -1
- package/src/memory/v2/__tests__/activation-store.test.ts +202 -0
- package/src/memory/v2/__tests__/activation.test.ts +956 -0
- package/src/memory/v2/__tests__/backfill-jobs.test.ts +610 -0
- package/src/memory/v2/__tests__/consolidation-job.test.ts +395 -0
- package/src/memory/v2/__tests__/edges.test.ts +435 -0
- package/src/memory/v2/__tests__/injection.test.ts +792 -0
- package/src/memory/v2/__tests__/migration.test.ts +812 -0
- package/src/memory/v2/__tests__/page-store.test.ts +334 -0
- package/src/memory/v2/__tests__/qdrant.test.ts +438 -0
- package/src/memory/v2/__tests__/sim.test.ts +549 -0
- package/src/memory/v2/__tests__/skill-content.test.ts +85 -0
- package/src/memory/v2/__tests__/skill-qdrant.test.ts +657 -0
- package/src/memory/v2/__tests__/skill-store.test.ts +351 -0
- package/src/memory/v2/__tests__/sweep-job.test.ts +441 -0
- package/src/memory/v2/activation-store.ts +109 -0
- package/src/memory/v2/activation.ts +490 -0
- package/src/memory/v2/backfill-jobs.ts +442 -0
- package/src/memory/v2/consolidation-job.ts +304 -0
- package/src/memory/v2/edges.ts +217 -0
- package/src/memory/v2/injection.ts +307 -0
- package/src/memory/v2/migration.ts +654 -0
- package/src/memory/v2/now-text.ts +38 -0
- package/src/memory/v2/page-store.ts +245 -0
- package/src/memory/v2/prompts/consolidation.ts +185 -0
- package/src/memory/v2/prompts/sweep.ts +56 -0
- package/src/memory/v2/qdrant.ts +342 -0
- package/src/memory/v2/sim.ts +206 -0
- package/src/memory/v2/skill-content.ts +42 -0
- package/src/memory/v2/skill-qdrant.ts +395 -0
- package/src/memory/v2/skill-store.ts +128 -0
- package/src/memory/v2/sweep-job.ts +298 -0
- package/src/memory/v2/types.ts +116 -0
- package/src/memory/validation.ts +1 -1
- package/src/messaging/providers/index.ts +262 -0
- package/src/messaging/providers/slack/api.ts +242 -0
- package/src/messaging/providers/slack/message-metadata.ts +1 -1
- package/src/messaging/providers/slack/render-transcript.test.ts +77 -29
- package/src/messaging/providers/slack/render-transcript.ts +58 -0
- package/src/messaging/providers/slack/send.ts +383 -0
- package/src/messaging/providers/telegram-bot/adapter.ts +4 -42
- package/src/messaging/providers/telegram-bot/api.ts +253 -0
- package/src/messaging/providers/telegram-bot/client.ts +17 -58
- package/src/messaging/providers/telegram-bot/send.ts +232 -0
- package/src/messaging/providers/whatsapp/adapter.ts +4 -36
- package/src/messaging/providers/whatsapp/api.ts +319 -0
- package/src/messaging/providers/whatsapp/client.ts +4 -48
- package/src/messaging/providers/whatsapp/send.ts +209 -0
- package/src/notifications/adapters/slack.ts +5 -23
- package/src/notifications/adapters/telegram.ts +8 -29
- package/src/notifications/conversation-candidates.ts +1 -1
- package/src/notifications/conversation-pairing.ts +78 -19
- package/src/notifications/conversation-seed-composer.ts +12 -6
- package/src/notifications/copy-composer.ts +1 -6
- package/src/notifications/decision-engine.ts +1 -1
- package/src/notifications/decisions-store.ts +1 -1
- package/src/notifications/deliveries-store.ts +2 -1
- package/src/notifications/deterministic-checks.ts +1 -1
- package/src/notifications/emit-signal.ts +1 -1
- package/src/notifications/events-store.ts +1 -13
- package/src/notifications/preferences-store.ts +1 -1
- package/src/notifications/signal.ts +1 -11
- package/src/oauth/AGENTS.md +1 -1
- package/src/oauth/__tests__/identity-verifier.test.ts +2 -1
- package/src/oauth/connect-orchestrator.ts +8 -34
- package/src/oauth/connect-types.ts +6 -10
- package/src/oauth/connection-resolver.ts +11 -2
- package/src/oauth/manual-token-connection.ts +23 -0
- package/src/oauth/oauth-store.ts +32 -15
- package/src/oauth/provider-serializer.ts +6 -1
- package/src/oauth/seed-providers.ts +56 -108
- package/src/outbound-proxy/http-forwarder.ts +9 -0
- package/src/outbound-proxy/index.ts +0 -1
- package/src/permissions/approval-policy.test.ts +398 -106
- package/src/permissions/approval-policy.ts +134 -108
- package/src/permissions/checker.test.ts +632 -0
- package/src/permissions/checker.ts +280 -345
- package/src/permissions/gateway-threshold-reader.ts +177 -0
- package/src/permissions/ipc-risk-types.ts +95 -0
- package/src/permissions/prompter.ts +8 -9
- package/src/permissions/risk-types.ts +24 -153
- package/src/permissions/types.ts +19 -47
- package/src/permissions/workspace-policy.ts +10 -7
- package/src/playbooks/playbook-compiler.ts +1 -1
- package/src/plugins/defaults/circuit-breaker.ts +146 -0
- package/src/plugins/defaults/compaction.ts +145 -0
- package/src/plugins/defaults/empty-response.ts +126 -0
- package/src/plugins/defaults/history-repair.ts +85 -0
- package/src/plugins/defaults/index.ts +116 -0
- package/src/plugins/defaults/injectors.ts +488 -0
- package/src/plugins/defaults/llm-call.ts +79 -0
- package/src/plugins/defaults/memory-retrieval.ts +221 -0
- package/src/plugins/defaults/overflow-reduce.ts +185 -0
- package/src/plugins/defaults/persistence.ts +129 -0
- package/src/plugins/defaults/title-generate.ts +95 -0
- package/src/plugins/defaults/token-estimate.ts +103 -0
- package/src/plugins/defaults/tool-error.ts +126 -0
- package/src/plugins/defaults/tool-execute.ts +89 -0
- package/src/plugins/defaults/tool-result-truncate.ts +88 -0
- package/src/plugins/pipeline.ts +316 -0
- package/src/plugins/plugin-skill-contributions.ts +292 -0
- package/src/plugins/registry.ts +301 -0
- package/src/plugins/types.ts +1133 -0
- package/src/plugins/user-loader.ts +203 -0
- package/src/prompts/__tests__/system-prompt-memory-v2.test.ts +197 -0
- package/src/prompts/persona-resolver.ts +2 -4
- package/src/prompts/system-prompt.ts +39 -0
- package/src/prompts/templates/BOOTSTRAP.md +27 -77
- package/src/prompts/templates/SOUL.md +3 -1
- package/src/providers/__tests__/provider-env-vars.test.ts +0 -21
- package/src/providers/__tests__/retry-callsite.test.ts +3 -6
- package/src/providers/anthropic/client.ts +71 -19
- package/src/providers/call-site-routing.ts +7 -3
- package/src/providers/fireworks/client.ts +3 -0
- package/src/providers/gemini/client.ts +96 -22
- package/src/providers/managed-proxy/context.ts +0 -12
- package/src/providers/model-catalog.ts +123 -25
- package/src/providers/model-intents.ts +6 -7
- package/src/providers/openai/chat-completions-provider.ts +37 -7
- package/src/providers/openai/responses-provider.ts +39 -4
- package/src/providers/openrouter/client.ts +9 -6
- package/src/providers/provider-env-vars.ts +4 -12
- package/src/providers/provider-send-message.ts +16 -11
- package/src/providers/registry.ts +1 -1
- package/src/providers/retry.ts +52 -23
- package/src/providers/speech-to-text/deepgram-realtime.test.ts +61 -0
- package/src/providers/speech-to-text/deepgram-realtime.ts +57 -0
- package/src/providers/speech-to-text/openai-whisper-stream.ts +1 -1
- package/src/providers/speech-to-text/openai-whisper.ts +3 -6
- package/src/providers/speech-to-text/provider-catalog.ts +75 -0
- package/src/providers/speech-to-text/xai-realtime.test.ts +72 -4
- package/src/providers/speech-to-text/xai-realtime.ts +39 -14
- package/src/providers/speech-to-text/xai.ts +5 -5
- package/src/providers/thinking-config.ts +34 -0
- package/src/providers/types.ts +22 -10
- package/src/runtime/AGENTS.md +27 -17
- package/src/runtime/__tests__/agent-wake.test.ts +33 -9
- package/src/runtime/__tests__/client-registry.test.ts +271 -0
- package/src/runtime/__tests__/interactive-ui.test.ts +157 -246
- package/src/runtime/access-request-helper.ts +9 -20
- package/src/runtime/actor-trust-resolver.ts +2 -2
- package/src/runtime/agent-wake.ts +174 -68
- package/src/runtime/approval-conversation-turn.ts +2 -15
- package/src/runtime/approval-message-composer.ts +11 -60
- package/src/runtime/assistant-event.ts +18 -66
- package/src/runtime/auth/__tests__/guard-tests.test.ts +6 -30
- package/src/runtime/auth/__tests__/middleware.test.ts +10 -10
- package/src/runtime/auth/__tests__/route-policy.test.ts +0 -8
- package/src/runtime/auth/context.ts +9 -0
- package/src/runtime/auth/middleware.ts +4 -4
- package/src/runtime/auth/route-policy.ts +195 -4
- package/src/runtime/auth/token-service.ts +1 -100
- package/src/runtime/capability-tokens.ts +89 -313
- package/src/runtime/channel-approval-types.ts +1 -6
- package/src/runtime/channel-approvals.ts +7 -79
- package/src/runtime/channel-readiness-service.ts +2 -2
- package/src/runtime/channel-reply-delivery.ts +2 -8
- package/src/runtime/channel-retry-sweep.ts +20 -17
- package/src/runtime/client-registry.ts +254 -0
- package/src/runtime/confirmation-request-guardian-bridge.ts +2 -7
- package/src/runtime/gateway-client.ts +37 -378
- package/src/runtime/guardian-action-grant-minter.ts +2 -3
- package/src/runtime/guardian-action-message-composer.ts +11 -52
- package/src/runtime/guardian-action-service.ts +19 -7
- package/src/runtime/guardian-decision-types.ts +4 -65
- package/src/runtime/guardian-reply-router.ts +10 -19
- package/src/runtime/guardian-vellum-migration.ts +5 -64
- package/src/runtime/http-errors.ts +3 -0
- package/src/runtime/http-router.ts +50 -7
- package/src/runtime/http-server.ts +345 -1041
- package/src/runtime/http-types.ts +15 -100
- package/src/runtime/interactive-ui-types.ts +145 -0
- package/src/runtime/interactive-ui.ts +38 -196
- package/src/runtime/invite-redemption-service.ts +1 -1
- package/src/runtime/invite-redemption-templates.ts +1 -1
- package/src/runtime/local-actor-identity.ts +13 -43
- package/src/runtime/message-composer-types.ts +134 -0
- package/src/runtime/middleware/rate-limiter.ts +1 -1
- package/src/runtime/middleware/request-logger.ts +5 -2
- package/src/runtime/migrations/__tests__/job-registry.test.ts +346 -0
- package/src/runtime/migrations/__tests__/vbundle-tar-stream.test.ts +16 -0
- package/src/runtime/migrations/job-registry.ts +281 -0
- package/src/runtime/migrations/vbundle-builder.ts +4 -26
- package/src/runtime/migrations/vbundle-importer.ts +1 -1
- package/src/runtime/migrations/vbundle-streaming-importer.ts +0 -13
- package/src/runtime/migrations/vbundle-tar-stream.ts +11 -3
- package/src/runtime/nl-approval-parser.ts +16 -21
- package/src/runtime/pending-interactions.ts +29 -12
- package/src/runtime/routes/__tests__/acp-routes.test.ts +395 -0
- package/src/runtime/routes/__tests__/backup-routes.test.ts +204 -320
- package/src/runtime/routes/__tests__/home-feed-routes.test.ts +72 -4
- package/src/runtime/routes/__tests__/stt-routes.test.ts +182 -223
- package/src/runtime/routes/__tests__/suggest-trust-rule-routes.test.ts +230 -0
- package/src/{ipc/__tests__/task-ipc.test.ts → runtime/routes/__tests__/task-routes.test.ts} +116 -96
- package/src/runtime/routes/__tests__/tts-routes.test.ts +185 -289
- package/src/runtime/routes/access-request-decision.ts +25 -50
- package/src/runtime/routes/acp-routes.test.ts +371 -0
- package/src/runtime/routes/acp-routes.ts +392 -166
- package/src/runtime/routes/app-management-routes.ts +464 -660
- package/src/runtime/routes/app-routes.ts +192 -177
- package/src/runtime/routes/approval-prompt-ts-tracker.ts +51 -31
- package/src/runtime/routes/approval-routes.ts +133 -434
- package/src/runtime/routes/approval-strategies/guardian-callback-strategy.ts +24 -84
- package/src/runtime/routes/approval-strategies/guardian-text-engine-strategy.ts +3 -10
- package/src/runtime/routes/attachment-routes.ts +409 -253
- package/src/runtime/routes/audio-routes.ts +51 -18
- package/src/runtime/routes/avatar-routes.ts +82 -75
- package/src/runtime/routes/background-tool-routes.ts +94 -0
- package/src/runtime/routes/backup-routes.ts +154 -336
- package/src/runtime/routes/brain-graph-routes.ts +83 -110
- package/src/runtime/routes/browser-routes.ts +141 -0
- package/src/runtime/routes/btw-routes.ts +62 -106
- package/src/runtime/routes/cache-routes.ts +96 -0
- package/src/runtime/routes/call-routes.ts +208 -247
- package/src/runtime/routes/canonical-guardian-expiry-sweep.ts +1 -1
- package/src/runtime/routes/channel-delivery-routes.ts +25 -27
- package/src/runtime/routes/channel-readiness-routes.ts +83 -120
- package/src/runtime/routes/channel-route-definitions.ts +62 -0
- package/src/runtime/routes/channel-route-shared.ts +14 -18
- package/src/runtime/routes/channel-verification-routes.ts +207 -187
- package/src/runtime/routes/client-routes.ts +48 -0
- package/src/runtime/routes/contact-routes.ts +533 -407
- package/src/runtime/routes/conversation-analysis-routes.ts +48 -49
- package/src/runtime/routes/conversation-attention-routes.ts +55 -67
- package/src/runtime/routes/conversation-list-routes.ts +265 -0
- package/src/runtime/routes/conversation-management-routes.ts +626 -715
- package/src/runtime/routes/conversation-query-routes.ts +510 -460
- package/src/runtime/routes/conversation-routes.ts +652 -457
- package/src/runtime/routes/conversation-starter-routes.ts +121 -71
- package/src/runtime/routes/credential-prompt-routes.ts +124 -0
- package/src/runtime/routes/debug-routes.ts +34 -39
- package/src/runtime/routes/defer-routes.ts +230 -0
- package/src/runtime/routes/diagnostics-routes.ts +79 -70
- package/src/runtime/routes/documents-routes.ts +117 -106
- package/src/runtime/routes/errors.ts +132 -0
- package/src/runtime/routes/events-routes.ts +97 -58
- package/src/runtime/routes/filing-routes.ts +65 -78
- package/src/runtime/routes/global-search-routes.ts +51 -57
- package/src/runtime/routes/group-routes.ts +199 -181
- package/src/runtime/routes/guardian-action-routes.ts +103 -169
- package/src/runtime/routes/guardian-approval-interception.ts +27 -58
- package/src/runtime/routes/guardian-approval-prompt.ts +10 -21
- package/src/runtime/routes/guardian-approval-reply-helpers.ts +2 -6
- package/src/runtime/routes/guardian-expiry-sweep.ts +19 -36
- package/src/runtime/routes/heartbeat-routes.ts +194 -209
- package/src/runtime/routes/home-feed-routes.ts +85 -187
- package/src/runtime/routes/home-state-routes.ts +27 -24
- package/src/runtime/routes/host-bash-routes.ts +42 -52
- package/src/runtime/routes/host-browser-routes.ts +38 -69
- package/src/runtime/routes/host-cu-routes.ts +74 -70
- package/src/runtime/routes/host-file-routes.ts +50 -60
- package/src/runtime/routes/host-transfer-routes.ts +220 -0
- package/src/runtime/routes/http-adapter.ts +172 -0
- package/src/runtime/routes/identity-routes.ts +83 -79
- package/src/runtime/routes/inbound-conversation.ts +11 -18
- package/src/runtime/routes/inbound-message-handler.ts +162 -123
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +79 -138
- package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +2 -3
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +54 -90
- package/src/runtime/routes/inbound-stages/bootstrap-intercept.ts +25 -50
- package/src/runtime/routes/inbound-stages/edit-intercept.ts +7 -7
- package/src/runtime/routes/inbound-stages/escalation-intercept.ts +5 -5
- package/src/runtime/routes/inbound-stages/guardian-activation-intercept.test.ts +5 -6
- package/src/runtime/routes/inbound-stages/guardian-activation-intercept.ts +14 -24
- package/src/runtime/routes/inbound-stages/guardian-reply-intercept.ts +3 -10
- package/src/runtime/routes/inbound-stages/secret-ingress-check.ts +4 -4
- package/src/runtime/routes/inbound-stages/transcribe-audio.ts +3 -3
- package/src/runtime/routes/inbound-stages/verification-intercept.ts +19 -26
- package/src/runtime/routes/index.ts +197 -0
- package/src/runtime/routes/integrations/slack/__tests__/channel.test.ts +25 -32
- package/src/runtime/routes/integrations/slack/__tests__/share.test.ts +22 -31
- package/src/runtime/routes/integrations/slack/channel.ts +69 -66
- package/src/runtime/routes/integrations/slack/share.ts +49 -58
- package/src/runtime/routes/integrations/telegram.ts +91 -74
- package/src/runtime/routes/integrations/twilio.ts +163 -240
- package/src/runtime/routes/integrations/vercel.ts +57 -54
- package/src/runtime/routes/interface-routes.ts +43 -0
- package/src/runtime/routes/internal-oauth-routes.ts +56 -0
- package/src/runtime/routes/internal-twilio-routes.ts +46 -0
- package/src/runtime/routes/llm-context-normalization.ts +4 -2
- package/src/runtime/routes/log-export/workspace-allowlist.ts +1 -1
- package/src/runtime/routes/log-export-routes.ts +90 -100
- package/src/runtime/routes/memory-item-routes.test.ts +153 -175
- package/src/runtime/routes/memory-item-routes.ts +243 -323
- package/src/runtime/routes/memory-v2-routes.ts +193 -0
- package/src/runtime/routes/migration-rollback-routes.ts +167 -212
- package/src/runtime/routes/migration-routes.ts +877 -377
- package/src/runtime/routes/notification-routes.ts +199 -70
- package/src/runtime/routes/oauth-apps.ts +254 -251
- package/src/runtime/routes/oauth-providers.ts +66 -57
- package/src/runtime/routes/playground/__tests__/force-compact.test.ts +224 -0
- package/src/runtime/routes/playground/__tests__/guard.test.ts +60 -0
- package/src/runtime/routes/playground/__tests__/inject-failures.test.ts +250 -0
- package/src/runtime/routes/playground/__tests__/reset-circuit.test.ts +195 -0
- package/src/runtime/routes/playground/__tests__/seed-conversation.test.ts +159 -0
- package/src/runtime/routes/playground/__tests__/seeded-conversations.test.ts +207 -0
- package/src/runtime/routes/playground/__tests__/state.test.ts +175 -0
- package/src/runtime/routes/playground/conversation-not-found.ts +27 -0
- package/src/runtime/routes/playground/force-compact.ts +60 -0
- package/src/runtime/routes/playground/guard.ts +36 -0
- package/src/runtime/routes/playground/helpers.ts +103 -0
- package/src/runtime/routes/playground/index.ts +18 -0
- package/src/runtime/routes/playground/inject-failures.ts +143 -0
- package/src/runtime/routes/playground/reset-circuit.ts +89 -0
- package/src/runtime/routes/playground/seed-conversation.ts +113 -0
- package/src/runtime/routes/playground/seeded-conversations.ts +74 -0
- package/src/runtime/routes/playground/state.ts +77 -0
- package/src/runtime/routes/profiler-routes.ts +132 -167
- package/src/runtime/routes/ps-routes.ts +120 -0
- package/src/runtime/routes/recording-routes.ts +197 -258
- package/src/runtime/routes/rename-conversation-routes.ts +89 -0
- package/src/runtime/routes/schedule-routes.ts +284 -207
- package/src/runtime/routes/secret-routes.ts +219 -265
- package/src/runtime/routes/secrets-deps.ts +24 -0
- package/src/runtime/routes/settings-routes.ts +361 -441
- package/src/runtime/routes/skills-routes.ts +434 -469
- package/src/runtime/routes/stt-routes.ts +196 -206
- package/src/runtime/routes/subagents-routes.ts +125 -141
- package/src/runtime/routes/suggest-trust-rule-routes.ts +244 -0
- package/src/runtime/routes/surface-action-routes.ts +135 -190
- package/src/runtime/routes/surface-content-routes.ts +84 -118
- package/src/runtime/routes/task-routes.ts +354 -0
- package/src/runtime/routes/telemetry-routes.ts +33 -49
- package/src/runtime/routes/trace-event-routes.ts +55 -74
- package/src/runtime/routes/trust-rules-routes.ts +147 -239
- package/src/runtime/routes/tts-routes.ts +187 -169
- package/src/runtime/routes/types.ts +139 -0
- package/src/{ipc/routes/ui-request.ts → runtime/routes/ui-request-routes.ts} +23 -17
- package/src/runtime/routes/upgrade-broadcast-routes.ts +156 -197
- package/src/runtime/routes/usage-routes.ts +143 -169
- package/src/runtime/routes/user-routes.ts +102 -18
- package/src/runtime/routes/wake-conversation-routes.ts +49 -0
- package/src/{ipc/routes/watcher.ts → runtime/routes/watcher-routes.ts} +84 -39
- package/src/runtime/routes/wipe-conversation-routes.ts +89 -0
- package/src/runtime/routes/work-items-routes.test.ts +10 -20
- package/src/runtime/routes/work-items-routes.ts +418 -433
- package/src/runtime/routes/workspace-commit-routes.ts +30 -61
- package/src/runtime/routes/workspace-routes.test.ts +254 -381
- package/src/runtime/routes/workspace-routes.ts +238 -246
- package/src/runtime/runtime-mode.ts +8 -1
- package/src/runtime/services/__tests__/analyze-conversation.test.ts +80 -118
- package/src/runtime/services/analyze-conversation.ts +14 -41
- package/src/runtime/services/conversation-serializer.ts +181 -0
- package/src/runtime/skill-route-registry.ts +75 -15
- package/src/runtime/trust-context-resolver.ts +3 -2
- package/src/runtime/verification-outbound-actions.ts +13 -49
- package/src/schedule/run-script.ts +68 -0
- package/src/schedule/schedule-store.ts +70 -2
- package/src/schedule/scheduler.ts +149 -8
- package/src/security/ces-credential-client.ts +32 -169
- package/src/security/ces-rpc-credential-backend.ts +1 -1
- package/src/security/credential-backend.ts +6 -6
- package/src/security/oauth-completion-page.ts +1 -1
- package/src/security/oauth2.ts +3 -6
- package/src/sequence/analytics.ts +1 -1
- package/src/sequence/guardrails.ts +3 -3
- package/src/sequence/store.ts +2 -1
- package/src/signals/bash.ts +1 -1
- package/src/signals/event-stream.ts +1 -1
- package/src/skills/catalog-cache.ts +19 -5
- package/src/skills/catalog-files.ts +0 -5
- package/src/skills/catalog-install.ts +28 -18
- package/src/skills/category-inference.ts +0 -11
- package/src/skills/clawhub.ts +2 -2
- package/src/skills/managed-store.ts +2 -2
- package/src/skills/remote-skill-policy.ts +6 -7
- package/src/subagent/index.ts +2 -6
- package/src/subagent/manager.ts +27 -23
- package/src/subagent/types.ts +9 -0
- package/src/tasks/SPEC.md +2 -2
- package/src/tasks/task-compiler.ts +1 -1
- package/src/tasks/task-runner.ts +2 -22
- package/src/tasks/task-store.ts +1 -1
- package/src/tools/acp/list-agents.test.ts +115 -0
- package/src/tools/acp/list-agents.ts +31 -0
- package/src/tools/acp/spawn.test.ts +379 -0
- package/src/tools/acp/spawn.ts +142 -62
- package/src/tools/acp/steer.test.ts +101 -0
- package/src/tools/acp/steer.ts +38 -0
- package/src/tools/background-tool-registry.ts +98 -0
- package/src/tools/browser/__tests__/browser-status.test.ts +189 -0
- package/src/tools/browser/browser-execution.ts +122 -26
- package/src/tools/browser/browser-manager.ts +1 -8
- package/src/tools/browser/cdp-client/__tests__/extension-cdp-client.test.ts +230 -0
- package/src/tools/browser/cdp-client/__tests__/factory.test.ts +146 -3
- package/src/tools/browser/cdp-client/accessibility-snapshot.ts +1 -1
- package/src/tools/browser/cdp-client/cdp-inspect/discovery.ts +3 -1
- package/src/tools/browser/cdp-client/extension-cdp-client.ts +54 -3
- package/src/tools/browser/cdp-client/factory.ts +15 -4
- package/src/tools/browser/cdp-client/types.ts +4 -1
- package/src/tools/computer-use/definitions.ts +1 -1
- package/src/tools/credential-execution/make-authenticated-request.ts +2 -2
- package/src/tools/credential-execution/manage-secure-command-tool.ts +1 -1
- package/src/tools/credential-execution/run-authenticated-command.ts +2 -2
- package/src/tools/credentials/broker-types.ts +2 -1
- package/src/tools/document/editor-template.ts +1 -1
- package/src/tools/execution-timeout.ts +1 -1
- package/src/tools/executor.ts +123 -76
- package/src/tools/host-filesystem/transfer.test.ts +268 -0
- package/src/tools/host-filesystem/transfer.ts +234 -0
- package/src/tools/host-terminal/host-shell.ts +189 -11
- package/src/tools/mcp/mcp-tool-factory.ts +1 -1
- package/src/tools/memory/register.test.ts +161 -1
- package/src/tools/memory/register.ts +19 -34
- package/src/tools/network/script-proxy/session-manager.ts +37 -1
- package/src/tools/permission-checker.ts +103 -255
- package/src/tools/policy-context.ts +5 -8
- package/src/tools/registry.ts +156 -4
- package/src/tools/schedule/create.ts +23 -8
- package/src/tools/schedule/update.ts +3 -1
- package/src/tools/secret-detection-handler.ts +13 -154
- package/src/tools/shared/shell-output.ts +4 -1
- package/src/tools/side-effects.ts +2 -2
- package/src/tools/skills/execute.ts +1 -1
- package/src/tools/subagent/spawn.ts +35 -11
- package/src/tools/system/avatar-generator.ts +6 -2
- package/src/tools/terminal/safe-env.ts +9 -1
- package/src/tools/terminal/shell.ts +161 -31
- package/src/tools/tool-approval-handler.ts +4 -70
- package/src/tools/tool-input-summary.ts +10 -0
- package/src/tools/types.ts +157 -151
- package/src/tools/ui-surface/definitions.ts +2 -2
- package/src/util/debounce.ts +0 -21
- package/src/util/errors.ts +0 -8
- package/src/util/log-redact.ts +0 -1
- package/src/util/platform.ts +85 -119
- package/src/util/pricing.ts +135 -9
- package/src/watcher/engine.ts +42 -20
- package/src/watcher/watcher-store.ts +2 -1
- package/src/work-items/work-item-store.ts +1 -1
- package/src/workspace/git-service.ts +1 -6
- package/src/workspace/migrations/006-services-config.ts +11 -4
- package/src/workspace/migrations/017-seed-persona-dirs.ts +1 -1
- package/src/workspace/migrations/019-scope-journal-to-guardian.ts +1 -1
- package/src/workspace/migrations/022-move-hooks-to-workspace.ts +2 -3
- package/src/workspace/migrations/028-recover-conversations-from-disk-view.ts +1 -1
- package/src/workspace/migrations/031-drop-user-md.ts +1 -1
- package/src/workspace/migrations/041-backfill-google-gmail-settings-scope.ts +3 -4
- package/src/workspace/migrations/045-release-notes-meet-avatar.ts +3 -4
- package/src/workspace/migrations/046-seed-conversation-starters-callsite.ts +108 -0
- package/src/workspace/migrations/047-remove-watch-callsites.ts +54 -0
- package/src/workspace/migrations/048-remove-workspace-hooks.ts +81 -0
- package/src/workspace/migrations/049-release-notes-default-sonnet.ts +80 -0
- package/src/workspace/migrations/050-seed-main-agent-opus-callsite.ts +86 -0
- package/src/workspace/migrations/051-seed-conversation-summarization-callsite.ts +128 -0
- package/src/workspace/migrations/052-seed-default-inference-profiles.ts +150 -0
- package/src/workspace/migrations/053-release-notes-acp-codex.ts +107 -0
- package/src/workspace/migrations/054-seed-recall-callsite.ts +102 -0
- package/src/workspace/migrations/055-release-notes-agentic-recall.ts +63 -0
- package/src/workspace/migrations/056-release-notes-inference-profile-reordering.ts +65 -0
- package/src/workspace/migrations/057-repair-stale-gemini-model-ids.ts +98 -0
- package/src/workspace/migrations/058-release-notes-acp-sessions-ui.ts +71 -0
- package/src/workspace/migrations/059-move-pid-to-workspace.ts +53 -0
- package/src/workspace/migrations/060-memory-v2-init.ts +53 -0
- package/src/workspace/migrations/rebuild-conversation-disk-view.ts +1 -1
- package/src/workspace/migrations/registry.ts +30 -0
- package/src/workspace/migrations/runner.ts +2 -2
- package/src/workspace/provider-commit-message-generator.ts +1 -1
- package/tsconfig.json +1 -1
- package/hook-templates/debug-prompt-logger/hook.json +0 -7
- package/hook-templates/debug-prompt-logger/run.sh +0 -66
- package/node_modules/@vellumai/ces-contracts/src/__tests__/trust-rules.test.ts +0 -471
- package/node_modules/@vellumai/ces-contracts/src/trust-rules.ts +0 -436
- package/src/__tests__/cli-command-risk-guard.test.ts +0 -368
- package/src/__tests__/compaction-circuit-breaker.test.ts +0 -336
- package/src/__tests__/config-watcher-feature-flags.test.ts +0 -211
- package/src/__tests__/context-overflow-approval.test.ts +0 -156
- package/src/__tests__/conversation-approval-overrides.test.ts +0 -207
- package/src/__tests__/conversation-host-access-routes.test.ts +0 -229
- package/src/__tests__/conversation-tool-setup-batch-authorized.test.ts +0 -226
- package/src/__tests__/conversation-tool-setup-side-effect-flag.test.ts +0 -167
- package/src/__tests__/ephemeral-permissions.test.ts +0 -474
- package/src/__tests__/extension-id-sync-guard.test.ts +0 -241
- package/src/__tests__/hooks-blocking.test.ts +0 -178
- package/src/__tests__/hooks-cli.test.ts +0 -182
- package/src/__tests__/hooks-config.test.ts +0 -108
- package/src/__tests__/hooks-discovery.test.ts +0 -211
- package/src/__tests__/hooks-integration.test.ts +0 -196
- package/src/__tests__/hooks-manager.test.ts +0 -226
- package/src/__tests__/hooks-runner.test.ts +0 -175
- package/src/__tests__/hooks-settings.test.ts +0 -160
- package/src/__tests__/hooks-templates.test.ts +0 -169
- package/src/__tests__/hooks-ts-runner.test.ts +0 -170
- package/src/__tests__/hooks-watch.test.ts +0 -112
- package/src/__tests__/host-browser-e2e-self-hosted.test.ts +0 -374
- package/src/__tests__/native-host-marker-sync-guard.test.ts +0 -157
- package/src/__tests__/notification-schedule-dedup.test.ts +0 -213
- package/src/__tests__/oauth-scope-policy.test.ts +0 -180
- package/src/__tests__/pairing-concurrent.test.ts +0 -84
- package/src/__tests__/pairing-routes.test.ts +0 -181
- package/src/__tests__/parser.test.ts +0 -595
- package/src/__tests__/permission-checker-host-gate.test.ts +0 -512
- package/src/__tests__/permission-controls-v2-flag.test.ts +0 -55
- package/src/__tests__/permission-mode.test.ts +0 -89
- package/src/__tests__/provider-env-vars-scope.test.ts +0 -52
- package/src/__tests__/risk-classifier-parity.test.ts +0 -230
- package/src/__tests__/send-notification-tool.test.ts +0 -83
- package/src/__tests__/shell-identity.test.ts +0 -370
- package/src/__tests__/shell-parser-fuzz.test.ts +0 -629
- package/src/__tests__/shell-parser-property.test.ts +0 -936
- package/src/__tests__/starter-bundle.test.ts +0 -173
- package/src/__tests__/stt-catalog-parity.test.ts +0 -282
- package/src/__tests__/task-runner.test.ts +0 -224
- package/src/__tests__/tool-executor-shell-integration.test.ts +0 -357
- package/src/__tests__/trust-store-pattern-matches.test.ts +0 -29
- package/src/__tests__/trust-store.test.ts +0 -2013
- package/src/__tests__/v2-consent-policy.test.ts +0 -103
- package/src/browser/identifiers.ts +0 -51
- package/src/cli/commands/shotgun.ts +0 -266
- package/src/cli/db.ts +0 -1
- package/src/config/bundled-skills/conversations/SKILL.md +0 -20
- package/src/config/bundled-skills/conversations/TOOLS.json +0 -23
- package/src/config/bundled-skills/conversations/tools/rename-conversation.ts +0 -88
- package/src/config/bundled-skills/heartbeat/SKILL.md +0 -43
- package/src/config/bundled-skills/notifications/SKILL.md +0 -40
- package/src/config/bundled-skills/notifications/TOOLS.json +0 -80
- package/src/config/bundled-skills/notifications/tools/send-notification.ts +0 -152
- package/src/config/bundled-skills/notifications/tools/shared.ts +0 -13
- package/src/config/bundled-skills/screen-watch/SKILL.md +0 -27
- package/src/config/bundled-skills/screen-watch/TOOLS.json +0 -35
- package/src/config/bundled-skills/settings/tools/avatar-get.ts +0 -40
- package/src/config/bundled-skills/settings/tools/avatar-remove.ts +0 -64
- package/src/config/bundled-skills/settings/tools/avatar-update.ts +0 -88
- package/src/config/bundled-skills/skills-catalog/SKILL.md +0 -84
- package/src/daemon/__tests__/lifecycle-startup-ordering.test.ts +0 -127
- package/src/daemon/approved-devices-store.ts +0 -110
- package/src/daemon/context-overflow-approval.ts +0 -52
- package/src/daemon/external-skills-bootstrap.ts +0 -41
- package/src/daemon/message-types/trust.ts +0 -71
- package/src/daemon/pairing-store.ts +0 -229
- package/src/daemon/watch-handler.ts +0 -399
- package/src/hooks/cli.ts +0 -253
- package/src/hooks/config.ts +0 -100
- package/src/hooks/discovery.ts +0 -135
- package/src/hooks/manager.ts +0 -179
- package/src/hooks/runner.ts +0 -117
- package/src/hooks/templates.ts +0 -77
- package/src/hooks/types.ts +0 -75
- package/src/ipc/cli-server.ts +0 -252
- package/src/ipc/routes/attachment.ts +0 -114
- package/src/ipc/routes/browser-context.ts +0 -61
- package/src/ipc/routes/browser.ts +0 -96
- package/src/ipc/routes/cache.ts +0 -96
- package/src/ipc/routes/index.ts +0 -21
- package/src/ipc/routes/task-queue.ts +0 -226
- package/src/ipc/routes/task.ts +0 -173
- package/src/ipc/routes/wake-conversation.ts +0 -19
- package/src/memory/db.ts +0 -23
- package/src/oauth/scope-policy.ts +0 -89
- package/src/permissions/bash-risk-classifier.test.ts +0 -1208
- package/src/permissions/bash-risk-classifier.ts +0 -707
- package/src/permissions/command-registry.test.ts +0 -535
- package/src/permissions/command-registry.ts +0 -825
- package/src/permissions/defaults.ts +0 -313
- package/src/permissions/file-risk-classifier.test.ts +0 -535
- package/src/permissions/file-risk-classifier.ts +0 -274
- package/src/permissions/permission-mode.ts +0 -24
- package/src/permissions/shell-identity.ts +0 -337
- package/src/permissions/skill-risk-classifier.test.ts +0 -311
- package/src/permissions/skill-risk-classifier.ts +0 -214
- package/src/permissions/trust-client.ts +0 -359
- package/src/permissions/trust-store-interface.ts +0 -100
- package/src/permissions/trust-store.ts +0 -1330
- package/src/permissions/v2-consent-policy.ts +0 -87
- package/src/permissions/web-risk-classifier.test.ts +0 -170
- package/src/permissions/web-risk-classifier.ts +0 -89
- package/src/runtime/__tests__/browser-extension-pair-routes.test.ts +0 -715
- package/src/runtime/__tests__/capability-tokens.test.ts +0 -258
- package/src/runtime/actor-refresh-token-store.ts +0 -156
- package/src/runtime/actor-token-store.ts +0 -207
- package/src/runtime/auth/__tests__/credential-service.test.ts +0 -264
- package/src/runtime/auth/credential-service.ts +0 -352
- package/src/runtime/conversation-approval-overrides.ts +0 -86
- package/src/runtime/gateway-internal-client.ts +0 -94
- package/src/runtime/routes/browser-extension-pair-routes.ts +0 -556
- package/src/runtime/routes/channel-routes.ts +0 -112
- package/src/runtime/routes/contact-routes.test.ts +0 -298
- package/src/runtime/routes/guardian-bootstrap-routes.ts +0 -175
- package/src/runtime/routes/guardian-refresh-routes.ts +0 -79
- package/src/runtime/routes/invite-routes.ts +0 -280
- package/src/runtime/routes/pairing-routes.ts +0 -431
- package/src/runtime/routes/watch-routes.ts +0 -156
- package/src/runtime/services/__tests__/analyze-deps-singleton.test.ts +0 -67
- package/src/runtime/services/analyze-deps-singleton.ts +0 -32
- package/src/signals/shotgun.ts +0 -203
- package/src/tasks/ephemeral-permissions.ts +0 -55
- package/src/tools/terminal/parser.ts +0 -623
- package/src/tools/watch/screen-watch.ts +0 -144
- package/src/tools/watch/watch-state.ts +0 -142
- package/src/types/qrcode.d.ts +0 -13
- package/src/util/network-info.ts +0 -55
- /package/node_modules/@vellumai/{ces-contracts → ces-client}/tsconfig.json +0 -0
- /package/node_modules/@vellumai/{ces-contracts → service-contracts}/src/__tests__/grants.test.ts +0 -0
- /package/node_modules/@vellumai/{ces-contracts → service-contracts}/src/error.ts +0 -0
- /package/node_modules/@vellumai/{ces-contracts → service-contracts}/src/grants.ts +0 -0
- /package/node_modules/@vellumai/{ces-contracts → service-contracts}/src/handles.ts +0 -0
- /package/node_modules/@vellumai/{ces-contracts → service-contracts}/src/rendering.ts +0 -0
- /package/node_modules/@vellumai/{ces-contracts → service-contracts}/src/rpc.ts +0 -0
|
@@ -23,7 +23,6 @@ import { z } from "zod";
|
|
|
23
23
|
import { invalidateConfigCache } from "../../config/loader.js";
|
|
24
24
|
import { getDb, resetDb } from "../../memory/db-connection.js";
|
|
25
25
|
import { validateMigrationState } from "../../memory/migrations/validate-migration-state.js";
|
|
26
|
-
import { clearCache as clearTrustCache } from "../../permissions/trust-store.js";
|
|
27
26
|
import { credentialKey } from "../../security/credential-key.js";
|
|
28
27
|
import {
|
|
29
28
|
bulkSetSecureKeysAsync,
|
|
@@ -41,12 +40,14 @@ import {
|
|
|
41
40
|
getWorkspaceDir,
|
|
42
41
|
getWorkspaceHooksDir,
|
|
43
42
|
} from "../../util/platform.js";
|
|
44
|
-
import { httpError } from "../http-errors.js";
|
|
45
|
-
import type { RouteDefinition } from "../http-router.js";
|
|
46
43
|
import {
|
|
47
44
|
validateGcsSignedUrl,
|
|
48
45
|
type ValidateGcsSignedUrlOptions,
|
|
49
46
|
} from "../migrations/gcs-signed-url.js";
|
|
47
|
+
import {
|
|
48
|
+
JobAlreadyInProgressError,
|
|
49
|
+
migrationJobs,
|
|
50
|
+
} from "../migrations/job-registry.js";
|
|
50
51
|
import { streamExportVBundle } from "../migrations/vbundle-builder.js";
|
|
51
52
|
import {
|
|
52
53
|
analyzeImport,
|
|
@@ -60,6 +61,15 @@ import {
|
|
|
60
61
|
} from "../migrations/vbundle-importer.js";
|
|
61
62
|
import { streamCommitImport } from "../migrations/vbundle-streaming-importer.js";
|
|
62
63
|
import { validateVBundle } from "../migrations/vbundle-validator.js";
|
|
64
|
+
import {
|
|
65
|
+
BadGatewayError,
|
|
66
|
+
BadRequestError,
|
|
67
|
+
InternalError,
|
|
68
|
+
NotFoundError,
|
|
69
|
+
RouteError,
|
|
70
|
+
} from "./errors.js";
|
|
71
|
+
import type { RouteDefinition, RouteHandlerArgs } from "./types.js";
|
|
72
|
+
import { RouteResponse } from "./types.js";
|
|
63
73
|
|
|
64
74
|
/**
|
|
65
75
|
* CES account prefix for platform-identity (`vellum:*`) credentials. Entries
|
|
@@ -139,60 +149,24 @@ const log = getLogger("migration-routes");
|
|
|
139
149
|
* 400: Standard error envelope for missing/empty body
|
|
140
150
|
* 422: Standard error envelope for completely unparseable input
|
|
141
151
|
*/
|
|
142
|
-
export async function handleMigrationValidate(
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
if (contentType.includes("multipart/form-data")) {
|
|
148
|
-
try {
|
|
149
|
-
const formData = await req.formData();
|
|
150
|
-
const file = formData.get("file");
|
|
151
|
-
if (!file || !(file instanceof Blob)) {
|
|
152
|
-
return httpError(
|
|
153
|
-
"BAD_REQUEST",
|
|
154
|
-
'Multipart upload requires a "file" field',
|
|
155
|
-
400,
|
|
156
|
-
);
|
|
157
|
-
}
|
|
158
|
-
fileData = new Uint8Array(await file.arrayBuffer());
|
|
159
|
-
} catch (err) {
|
|
160
|
-
log.error({ err }, "Failed to parse multipart form data");
|
|
161
|
-
return httpError("BAD_REQUEST", "Invalid multipart form data", 400);
|
|
162
|
-
}
|
|
163
|
-
} else {
|
|
164
|
-
// Treat as raw binary body
|
|
165
|
-
try {
|
|
166
|
-
const arrayBuffer = await req.arrayBuffer();
|
|
167
|
-
fileData = new Uint8Array(arrayBuffer);
|
|
168
|
-
} catch (err) {
|
|
169
|
-
log.error({ err }, "Failed to read request body");
|
|
170
|
-
return httpError("BAD_REQUEST", "Failed to read request body", 400);
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
if (!fileData || fileData.length === 0) {
|
|
175
|
-
return httpError(
|
|
176
|
-
"BAD_REQUEST",
|
|
177
|
-
"Request body is empty — a .vbundle file is required",
|
|
178
|
-
400,
|
|
179
|
-
);
|
|
180
|
-
}
|
|
152
|
+
export async function handleMigrationValidate({
|
|
153
|
+
rawBody,
|
|
154
|
+
headers,
|
|
155
|
+
}: RouteHandlerArgs) {
|
|
156
|
+
const fileData = await extractFileData(rawBody, headers);
|
|
181
157
|
|
|
182
158
|
try {
|
|
183
159
|
const result = validateVBundle(fileData);
|
|
184
160
|
|
|
185
|
-
return
|
|
161
|
+
return {
|
|
186
162
|
is_valid: result.is_valid,
|
|
187
163
|
errors: result.errors,
|
|
188
164
|
...(result.manifest ? { manifest: result.manifest } : {}),
|
|
189
|
-
}
|
|
165
|
+
};
|
|
190
166
|
} catch (err) {
|
|
191
167
|
log.error({ err }, "Unexpected error during vbundle validation");
|
|
192
|
-
|
|
193
|
-
"INTERNAL_ERROR",
|
|
168
|
+
throw new InternalError(
|
|
194
169
|
err instanceof Error ? err.message : "Unexpected validation error",
|
|
195
|
-
500,
|
|
196
170
|
);
|
|
197
171
|
}
|
|
198
172
|
}
|
|
@@ -214,21 +188,11 @@ export async function handleMigrationValidate(req: Request): Promise<Response> {
|
|
|
214
188
|
*
|
|
215
189
|
* Auth: Requires settings.write scope. Allowed for actor, svc_gateway, svc_daemon, local.
|
|
216
190
|
*/
|
|
217
|
-
export async function handleMigrationExport(
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
if (contentType.includes("application/json")) {
|
|
223
|
-
try {
|
|
224
|
-
const body = (await req.json()) as Record<string, unknown>;
|
|
225
|
-
if (typeof body.description === "string") {
|
|
226
|
-
description = body.description;
|
|
227
|
-
}
|
|
228
|
-
} catch (err) {
|
|
229
|
-
log.warn({ err }, "Failed to parse export request body — using defaults");
|
|
230
|
-
}
|
|
231
|
-
}
|
|
191
|
+
export async function handleMigrationExport({
|
|
192
|
+
body,
|
|
193
|
+
}: RouteHandlerArgs): Promise<RouteResponse> {
|
|
194
|
+
const description =
|
|
195
|
+
typeof body?.description === "string" ? body.description : undefined;
|
|
232
196
|
|
|
233
197
|
let cleanup: (() => Promise<void>) | undefined;
|
|
234
198
|
|
|
@@ -255,9 +219,6 @@ export async function handleMigrationExport(req: Request): Promise<Response> {
|
|
|
255
219
|
}
|
|
256
220
|
|
|
257
221
|
const result = await streamExportVBundle({
|
|
258
|
-
// hooksDir is intentionally omitted — hooks now live under workspace/hooks/
|
|
259
|
-
// and are included in the workspace walk. Passing hooksDir separately would
|
|
260
|
-
// export them twice (once as workspace/hooks/... and again as hooks/...).
|
|
261
222
|
workspaceDir: getWorkspaceDir(),
|
|
262
223
|
source: "runtime-export",
|
|
263
224
|
description,
|
|
@@ -295,30 +256,282 @@ export async function handleMigrationExport(req: Request): Promise<Response> {
|
|
|
295
256
|
cleanup = undefined;
|
|
296
257
|
});
|
|
297
258
|
|
|
298
|
-
const
|
|
299
|
-
|
|
300
|
-
return new
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
"X-Vbundle-Manifest-Sha256": manifest.manifest_sha256,
|
|
308
|
-
"X-Vbundle-Credentials-Included": String(credentials.length),
|
|
309
|
-
},
|
|
259
|
+
const streamBody = Readable.toWeb(fileStream) as unknown as ReadableStream;
|
|
260
|
+
|
|
261
|
+
return new RouteResponse(streamBody, {
|
|
262
|
+
"Content-Type": "application/octet-stream",
|
|
263
|
+
"Content-Disposition": `attachment; filename="${filename}"`,
|
|
264
|
+
"Content-Length": String(size),
|
|
265
|
+
"X-Vbundle-Schema-Version": manifest.schema_version,
|
|
266
|
+
"X-Vbundle-Manifest-Sha256": manifest.manifest_sha256,
|
|
267
|
+
"X-Vbundle-Credentials-Included": String(credentials.length),
|
|
310
268
|
});
|
|
311
269
|
} catch (err) {
|
|
312
270
|
await cleanup?.();
|
|
313
271
|
log.error({ err }, "Failed to build export bundle");
|
|
314
|
-
|
|
315
|
-
"INTERNAL_ERROR",
|
|
272
|
+
throw new InternalError(
|
|
316
273
|
err instanceof Error ? err.message : "Unexpected export error",
|
|
317
|
-
500,
|
|
318
274
|
);
|
|
319
275
|
}
|
|
320
276
|
}
|
|
321
277
|
|
|
278
|
+
// ---------------------------------------------------------------------------
|
|
279
|
+
// POST /v1/migrations/export-to-gcs — async export streamed to a signed URL
|
|
280
|
+
// ---------------------------------------------------------------------------
|
|
281
|
+
|
|
282
|
+
/** 60 minutes — matches the URL-body import fetch deadline. */
|
|
283
|
+
const EXPORT_TO_GCS_PUT_TIMEOUT_MS = 60 * 60 * 1000;
|
|
284
|
+
|
|
285
|
+
const MigrationExportToGcsBody = z.object({
|
|
286
|
+
upload_url: z.string().url(),
|
|
287
|
+
description: z.string().optional(),
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* Collected credentials plus a warning marker if the credential store was
|
|
292
|
+
* unreachable. The caller surfaces the warning in logs; production callers
|
|
293
|
+
* fail closed on errors (a thrown exception → 500) to avoid shipping a
|
|
294
|
+
* bundle with partial credentials. An unreachable store is NOT an error —
|
|
295
|
+
* `handleMigrationExport` treats that case as "export without credentials".
|
|
296
|
+
*/
|
|
297
|
+
interface CollectedCredentials {
|
|
298
|
+
credentials: Array<{ account: string; value: string }>;
|
|
299
|
+
unreachable: boolean;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/**
|
|
303
|
+
* Mirror of the credential-collection block inside `handleMigrationExport`.
|
|
304
|
+
* Factored out so the new async export-to-gcs handler can share the exact
|
|
305
|
+
* same behavior. Throws if the credential store raises an unexpected error —
|
|
306
|
+
* the caller translates that into a 500 (fail closed on credential errors).
|
|
307
|
+
*/
|
|
308
|
+
async function collectExportCredentials(): Promise<CollectedCredentials> {
|
|
309
|
+
const credentialList = await listSecureKeysAsync();
|
|
310
|
+
if (credentialList.unreachable) {
|
|
311
|
+
log.warn(
|
|
312
|
+
"Credential store is unreachable — export will not include credentials",
|
|
313
|
+
);
|
|
314
|
+
return { credentials: [], unreachable: true };
|
|
315
|
+
}
|
|
316
|
+
const credentials: Array<{ account: string; value: string }> = [];
|
|
317
|
+
for (const account of credentialList.accounts) {
|
|
318
|
+
const result = await getSecureKeyResultAsync(account);
|
|
319
|
+
if (result.unreachable) {
|
|
320
|
+
log.warn(
|
|
321
|
+
{ account },
|
|
322
|
+
"Credential store unreachable when reading credential — skipping",
|
|
323
|
+
);
|
|
324
|
+
} else if (result.value != null) {
|
|
325
|
+
credentials.push({ account, value: result.value });
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
return { credentials, unreachable: false };
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
/**
|
|
332
|
+
* POST /v1/migrations/export-to-gcs
|
|
333
|
+
*
|
|
334
|
+
* Starts an async export job that streams a freshly-built .vbundle archive
|
|
335
|
+
* to a GCS signed PUT URL. Returns `202 Accepted` with a `job_id` the caller
|
|
336
|
+
* can poll via the job-status endpoint; the bundle upload runs in the
|
|
337
|
+
* background via `migrationJobs`.
|
|
338
|
+
*
|
|
339
|
+
* Request body (JSON):
|
|
340
|
+
* { upload_url: string, description?: string }
|
|
341
|
+
*
|
|
342
|
+
* Responses:
|
|
343
|
+
* 202: { job_id, status: "pending", type: "export" }
|
|
344
|
+
* 400: { error: { code: "invalid_upload_url", reason } } — URL failed
|
|
345
|
+
* `validateGcsSignedUrl` (scheme/host/signature/traversal).
|
|
346
|
+
* 409: { error: { code: "export_in_progress", job_id } } — another export
|
|
347
|
+
* job is already pending or running.
|
|
348
|
+
* 500: Standard error envelope for credential-collection failures or
|
|
349
|
+
* other unexpected errors before the job is enqueued.
|
|
350
|
+
*
|
|
351
|
+
* Terminal job state (surfaced via the job-status endpoint once poll lands):
|
|
352
|
+
* result: { size, sha256, schemaVersion, credentialsIncluded }
|
|
353
|
+
* error.code = "upload_failed" with `upstreamStatus` on non-2xx PUT
|
|
354
|
+
* error.code = "fetch_failed" on transport errors from the PUT itself.
|
|
355
|
+
*
|
|
356
|
+
* Auth: settings.write scope (matches `migrations/export`).
|
|
357
|
+
*/
|
|
358
|
+
export async function handleMigrationExportToGcs({
|
|
359
|
+
body,
|
|
360
|
+
}: RouteHandlerArgs) {
|
|
361
|
+
// ── 1. Parse JSON body ────────────────────────────────────────────────
|
|
362
|
+
const parsed = MigrationExportToGcsBody.safeParse(body);
|
|
363
|
+
if (!parsed.success) {
|
|
364
|
+
throw new BadRequestError(
|
|
365
|
+
"Request body must be { upload_url: string, description?: string } with a valid URL",
|
|
366
|
+
);
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
// ── 2. Validate the upload URL. Never log `parsed.data.upload_url`.
|
|
370
|
+
const validated = validateGcsSignedUrl(
|
|
371
|
+
parsed.data.upload_url,
|
|
372
|
+
urlValidatorOptions,
|
|
373
|
+
);
|
|
374
|
+
if (!validated.ok) {
|
|
375
|
+
log.warn(
|
|
376
|
+
{ reason: validated.reason },
|
|
377
|
+
"Rejected migration export-to-gcs upload URL",
|
|
378
|
+
);
|
|
379
|
+
throw new RouteError(
|
|
380
|
+
`Invalid upload URL: ${validated.reason}`,
|
|
381
|
+
"invalid_upload_url",
|
|
382
|
+
400,
|
|
383
|
+
);
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
log.info(
|
|
387
|
+
{ host: validated.host, path: validated.path },
|
|
388
|
+
"migration export to GCS starting",
|
|
389
|
+
);
|
|
390
|
+
|
|
391
|
+
// ── 3. Collect credentials up front. Fail closed → 500.
|
|
392
|
+
let collected: CollectedCredentials;
|
|
393
|
+
try {
|
|
394
|
+
collected = await collectExportCredentials();
|
|
395
|
+
} catch (err) {
|
|
396
|
+
log.error({ err }, "Failed to collect credentials for export-to-gcs");
|
|
397
|
+
throw new InternalError(
|
|
398
|
+
err instanceof Error ? err.message : "Failed to collect credentials",
|
|
399
|
+
);
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
const description = parsed.data.description;
|
|
403
|
+
const uploadUrl = parsed.data.upload_url;
|
|
404
|
+
|
|
405
|
+
// ── 4. Enqueue the job. The runner captures the collected credentials.
|
|
406
|
+
let job;
|
|
407
|
+
try {
|
|
408
|
+
job = migrationJobs.startJob("export", async () => {
|
|
409
|
+
let cleanup: (() => Promise<void>) | undefined;
|
|
410
|
+
try {
|
|
411
|
+
const result = await streamExportVBundle({
|
|
412
|
+
workspaceDir: getWorkspaceDir(),
|
|
413
|
+
source: "runtime-export",
|
|
414
|
+
description,
|
|
415
|
+
credentials: collected.credentials,
|
|
416
|
+
checkpoint: () => {
|
|
417
|
+
const dbPath = getDbPath();
|
|
418
|
+
try {
|
|
419
|
+
const db = new Database(dbPath);
|
|
420
|
+
try {
|
|
421
|
+
db.exec("PRAGMA wal_checkpoint(TRUNCATE)");
|
|
422
|
+
} finally {
|
|
423
|
+
db.close();
|
|
424
|
+
}
|
|
425
|
+
} catch (err) {
|
|
426
|
+
log.warn(
|
|
427
|
+
{ err },
|
|
428
|
+
"WAL checkpoint failed — exporting without checkpoint",
|
|
429
|
+
);
|
|
430
|
+
}
|
|
431
|
+
},
|
|
432
|
+
});
|
|
433
|
+
|
|
434
|
+
cleanup = result.cleanup;
|
|
435
|
+
const { tempPath, size, manifest } = result;
|
|
436
|
+
|
|
437
|
+
// Stream the temp file to GCS via PUT. Using Node's ReadableStream
|
|
438
|
+
// bridge keeps peak memory bounded — we do NOT load the archive
|
|
439
|
+
// into memory.
|
|
440
|
+
const fileStream = createReadStream(tempPath);
|
|
441
|
+
const webBody = Readable.toWeb(
|
|
442
|
+
fileStream,
|
|
443
|
+
) as unknown as ReadableStream<Uint8Array>;
|
|
444
|
+
|
|
445
|
+
let response: Response;
|
|
446
|
+
try {
|
|
447
|
+
response = await fetch(uploadUrl, {
|
|
448
|
+
method: "PUT",
|
|
449
|
+
body: webBody,
|
|
450
|
+
// `duplex: "half"` is required when sending a streaming body
|
|
451
|
+
// via fetch in Node/Bun — without it the platform rejects the
|
|
452
|
+
// request as "duplex option is required when body is a
|
|
453
|
+
// ReadableStream".
|
|
454
|
+
duplex: "half",
|
|
455
|
+
// `validateGcsSignedUrl` only vets the initial URL. If the
|
|
456
|
+
// upstream responds with a 3xx, default fetch would follow
|
|
457
|
+
// the redirect and PUT bytes to an attacker-controlled host.
|
|
458
|
+
// Refuse redirects so the signed URL's origin is the only
|
|
459
|
+
// destination for the export archive.
|
|
460
|
+
redirect: "error",
|
|
461
|
+
headers: {
|
|
462
|
+
"Content-Type": "application/octet-stream",
|
|
463
|
+
"Content-Length": String(size),
|
|
464
|
+
},
|
|
465
|
+
signal: AbortSignal.timeout(EXPORT_TO_GCS_PUT_TIMEOUT_MS),
|
|
466
|
+
} as RequestInit & { duplex: "half" });
|
|
467
|
+
} catch (err) {
|
|
468
|
+
// Transport-level fetch failures (DNS, reset, abort) — tag them
|
|
469
|
+
// with the fetch-body marker so the registry maps them to
|
|
470
|
+
// `error.code = "fetch_failed"` and logs stay consistent with
|
|
471
|
+
// the import URL path.
|
|
472
|
+
const wrapped = err instanceof Error ? err : new Error(String(err));
|
|
473
|
+
tagFetchBodyError(wrapped as NodeJS.ErrnoException);
|
|
474
|
+
(wrapped as { code?: string }).code = "fetch_failed";
|
|
475
|
+
throw wrapped;
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
if (!response.ok) {
|
|
479
|
+
// Drain so the socket is released promptly. Ignore drain errors.
|
|
480
|
+
try {
|
|
481
|
+
await response.body?.cancel();
|
|
482
|
+
} catch {
|
|
483
|
+
/* best-effort */
|
|
484
|
+
}
|
|
485
|
+
const uploadErr = new Error(
|
|
486
|
+
`Upload to GCS failed with status ${response.status}`,
|
|
487
|
+
);
|
|
488
|
+
(uploadErr as { code?: string }).code = "upload_failed";
|
|
489
|
+
(uploadErr as { upstreamStatus?: number }).upstreamStatus =
|
|
490
|
+
response.status;
|
|
491
|
+
throw uploadErr;
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
return {
|
|
495
|
+
size,
|
|
496
|
+
sha256: manifest.manifest_sha256,
|
|
497
|
+
schemaVersion: manifest.schema_version,
|
|
498
|
+
credentialsIncluded: collected.credentials.length,
|
|
499
|
+
};
|
|
500
|
+
} finally {
|
|
501
|
+
// Mirror the raw-bytes export cleanup pattern: the stream's
|
|
502
|
+
// `close` listener is the happy-path cleanup in that handler, but
|
|
503
|
+
// here we keep everything in the async block, so a finally is the
|
|
504
|
+
// right place to evict the temp file regardless of outcome.
|
|
505
|
+
if (cleanup) {
|
|
506
|
+
try {
|
|
507
|
+
await cleanup();
|
|
508
|
+
} catch (err) {
|
|
509
|
+
log.warn({ err }, "Failed to clean up export-to-gcs temp file");
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
});
|
|
514
|
+
} catch (err) {
|
|
515
|
+
if (err instanceof JobAlreadyInProgressError) {
|
|
516
|
+
throw new RouteError(
|
|
517
|
+
`Export already in progress: ${err.existingJobId}`,
|
|
518
|
+
"export_in_progress",
|
|
519
|
+
409,
|
|
520
|
+
);
|
|
521
|
+
}
|
|
522
|
+
log.error({ err }, "Unexpected error while enqueueing export-to-gcs job");
|
|
523
|
+
throw new InternalError(
|
|
524
|
+
err instanceof Error ? err.message : "Unexpected export-to-gcs error",
|
|
525
|
+
);
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
return {
|
|
529
|
+
job_id: job.id,
|
|
530
|
+
status: "pending" as const,
|
|
531
|
+
type: "export" as const,
|
|
532
|
+
};
|
|
533
|
+
}
|
|
534
|
+
|
|
322
535
|
/**
|
|
323
536
|
* Extract file data from a request body, supporting both raw binary
|
|
324
537
|
* and multipart form data uploads.
|
|
@@ -326,42 +539,43 @@ export async function handleMigrationExport(req: Request): Promise<Response> {
|
|
|
326
539
|
* Shared between validate and import-preflight handlers.
|
|
327
540
|
*/
|
|
328
541
|
async function extractFileData(
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
542
|
+
rawBody: Uint8Array | undefined,
|
|
543
|
+
headers: Record<string, string> | undefined,
|
|
544
|
+
): Promise<Uint8Array> {
|
|
545
|
+
const contentType = headers?.["content-type"] ?? "";
|
|
332
546
|
|
|
333
547
|
if (contentType.includes("multipart/form-data")) {
|
|
548
|
+
if (!rawBody) {
|
|
549
|
+
throw new BadRequestError("Request body is empty");
|
|
550
|
+
}
|
|
334
551
|
try {
|
|
335
|
-
const
|
|
552
|
+
const syntheticReq = new Request("http://localhost", {
|
|
553
|
+
method: "POST",
|
|
554
|
+
headers: { "content-type": contentType },
|
|
555
|
+
body: rawBody.buffer as ArrayBuffer,
|
|
556
|
+
});
|
|
557
|
+
const formData = await syntheticReq.formData();
|
|
336
558
|
const file = formData.get("file");
|
|
337
559
|
if (!file || !(file instanceof Blob)) {
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
'Multipart upload requires a "file" field',
|
|
342
|
-
400,
|
|
343
|
-
),
|
|
344
|
-
};
|
|
560
|
+
throw new BadRequestError(
|
|
561
|
+
'Multipart upload requires a "file" field',
|
|
562
|
+
);
|
|
345
563
|
}
|
|
346
|
-
return
|
|
564
|
+
return new Uint8Array(await file.arrayBuffer());
|
|
347
565
|
} catch (err) {
|
|
566
|
+
if (err instanceof BadRequestError) throw err;
|
|
348
567
|
log.error({ err }, "Failed to parse multipart form data");
|
|
349
|
-
|
|
350
|
-
error: httpError("BAD_REQUEST", "Invalid multipart form data", 400),
|
|
351
|
-
};
|
|
568
|
+
throw new BadRequestError("Invalid multipart form data");
|
|
352
569
|
}
|
|
353
570
|
}
|
|
354
571
|
|
|
355
|
-
//
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
log.error({ err }, "Failed to read request body");
|
|
361
|
-
return {
|
|
362
|
-
error: httpError("BAD_REQUEST", "Failed to read request body", 400),
|
|
363
|
-
};
|
|
572
|
+
// Raw binary body — already provided as rawBody by the adapter
|
|
573
|
+
if (!rawBody || rawBody.length === 0) {
|
|
574
|
+
throw new BadRequestError(
|
|
575
|
+
"Request body is empty — a .vbundle file is required",
|
|
576
|
+
);
|
|
364
577
|
}
|
|
578
|
+
return rawBody;
|
|
365
579
|
}
|
|
366
580
|
|
|
367
581
|
/**
|
|
@@ -390,35 +604,23 @@ async function extractFileData(
|
|
|
390
604
|
*
|
|
391
605
|
* Auth: Requires settings.write scope. Allowed for actor, svc_gateway, svc_daemon, local.
|
|
392
606
|
*/
|
|
393
|
-
export async function handleMigrationImportPreflight(
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
return extracted.error;
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
const fileData = extracted.data;
|
|
402
|
-
if (fileData.length === 0) {
|
|
403
|
-
return httpError(
|
|
404
|
-
"BAD_REQUEST",
|
|
405
|
-
"Request body is empty — a .vbundle file is required",
|
|
406
|
-
400,
|
|
407
|
-
);
|
|
408
|
-
}
|
|
607
|
+
export async function handleMigrationImportPreflight({
|
|
608
|
+
rawBody,
|
|
609
|
+
headers,
|
|
610
|
+
}: RouteHandlerArgs) {
|
|
611
|
+
const fileData = await extractFileData(rawBody, headers);
|
|
409
612
|
|
|
410
613
|
try {
|
|
411
|
-
// Step 1: Validate the bundle
|
|
412
614
|
const validationResult = validateVBundle(fileData);
|
|
413
615
|
|
|
414
616
|
if (!validationResult.is_valid || !validationResult.manifest) {
|
|
415
|
-
return
|
|
617
|
+
return {
|
|
416
618
|
can_import: false,
|
|
417
619
|
validation: {
|
|
418
620
|
is_valid: false,
|
|
419
621
|
errors: validationResult.errors,
|
|
420
622
|
},
|
|
421
|
-
}
|
|
623
|
+
};
|
|
422
624
|
}
|
|
423
625
|
|
|
424
626
|
const pathResolver = new DefaultPathResolver(
|
|
@@ -426,18 +628,14 @@ export async function handleMigrationImportPreflight(
|
|
|
426
628
|
getWorkspaceHooksDir(),
|
|
427
629
|
);
|
|
428
630
|
|
|
429
|
-
|
|
631
|
+
return analyzeImport({
|
|
430
632
|
manifest: validationResult.manifest,
|
|
431
633
|
pathResolver,
|
|
432
634
|
});
|
|
433
|
-
|
|
434
|
-
return Response.json(report);
|
|
435
635
|
} catch (err) {
|
|
436
636
|
log.error({ err }, "Unexpected error during import preflight analysis");
|
|
437
|
-
|
|
438
|
-
"INTERNAL_ERROR",
|
|
637
|
+
throw new InternalError(
|
|
439
638
|
err instanceof Error ? err.message : "Unexpected import preflight error",
|
|
440
|
-
500,
|
|
441
639
|
);
|
|
442
640
|
}
|
|
443
641
|
}
|
|
@@ -480,31 +678,18 @@ export async function handleMigrationImportPreflight(
|
|
|
480
678
|
*
|
|
481
679
|
* Auth: Requires settings.write scope. Allowed for actor, svc_gateway, svc_daemon, local.
|
|
482
680
|
*/
|
|
483
|
-
export async function handleMigrationImport(
|
|
681
|
+
export async function handleMigrationImport(
|
|
682
|
+
args: RouteHandlerArgs,
|
|
683
|
+
): Promise<unknown> {
|
|
684
|
+
const { body, rawBody, headers } = args;
|
|
484
685
|
// JSON body means the caller is asking us to fetch the bundle from a
|
|
485
|
-
// signed URL and stream it through the importer.
|
|
486
|
-
|
|
487
|
-
// the whole point of supporting URL-based imports for large bundles.
|
|
488
|
-
//
|
|
489
|
-
// Raw-bytes path (octet-stream / multipart) is untouched below.
|
|
490
|
-
const contentType = req.headers.get("content-type") ?? "";
|
|
686
|
+
// signed URL and stream it through the importer.
|
|
687
|
+
const contentType = headers?.["content-type"] ?? "";
|
|
491
688
|
if (contentType.includes("application/json")) {
|
|
492
|
-
return handleMigrationImportFromUrl(
|
|
493
|
-
}
|
|
494
|
-
|
|
495
|
-
const extracted = await extractFileData(req);
|
|
496
|
-
if ("error" in extracted) {
|
|
497
|
-
return extracted.error;
|
|
689
|
+
return handleMigrationImportFromUrl(body);
|
|
498
690
|
}
|
|
499
691
|
|
|
500
|
-
const fileData =
|
|
501
|
-
if (fileData.length === 0) {
|
|
502
|
-
return httpError(
|
|
503
|
-
"BAD_REQUEST",
|
|
504
|
-
"Request body is empty — a .vbundle file is required",
|
|
505
|
-
400,
|
|
506
|
-
);
|
|
507
|
-
}
|
|
692
|
+
const fileData = await extractFileData(rawBody, headers);
|
|
508
693
|
|
|
509
694
|
try {
|
|
510
695
|
// Validate the bundle before closing the DB to avoid an unnecessary
|
|
@@ -513,11 +698,11 @@ export async function handleMigrationImport(req: Request): Promise<Response> {
|
|
|
513
698
|
// (avoids holding two copies of decompressed data in memory).
|
|
514
699
|
const validation = validateVBundle(fileData);
|
|
515
700
|
if (!validation.is_valid) {
|
|
516
|
-
return
|
|
701
|
+
return {
|
|
517
702
|
success: false,
|
|
518
703
|
reason: "validation_failed",
|
|
519
704
|
errors: validation.errors,
|
|
520
|
-
}
|
|
705
|
+
};
|
|
521
706
|
}
|
|
522
707
|
|
|
523
708
|
const pathResolver = new DefaultPathResolver(
|
|
@@ -538,7 +723,7 @@ export async function handleMigrationImport(req: Request): Promise<Response> {
|
|
|
538
723
|
});
|
|
539
724
|
|
|
540
725
|
if (!result.ok) {
|
|
541
|
-
|
|
726
|
+
throwImportCommitFailure(result);
|
|
542
727
|
}
|
|
543
728
|
|
|
544
729
|
// Import credentials from the bundle into CES (non-blocking — failures
|
|
@@ -561,9 +746,8 @@ export async function handleMigrationImport(req: Request): Promise<Response> {
|
|
|
561
746
|
// if Django's post-hatch provisioning raced with the import.
|
|
562
747
|
await reconcileVellumMetadataFromCes(result.report);
|
|
563
748
|
|
|
564
|
-
// Invalidate in-process
|
|
749
|
+
// Invalidate in-process config cache so imported settings.json takes effect
|
|
565
750
|
invalidateConfigCache();
|
|
566
|
-
clearTrustCache();
|
|
567
751
|
|
|
568
752
|
// Check whether the imported database contains migration checkpoints from
|
|
569
753
|
// a newer version. This is non-blocking — the import has already
|
|
@@ -571,19 +755,18 @@ export async function handleMigrationImport(req: Request): Promise<Response> {
|
|
|
571
755
|
// not be fully compatible with this daemon's schema.
|
|
572
756
|
appendNewerMigrationWarningsIfAny(result.report);
|
|
573
757
|
|
|
574
|
-
return
|
|
758
|
+
return importCommitSuccessResult(result.report, credentialsImported);
|
|
575
759
|
} catch (err) {
|
|
576
760
|
log.error({ err }, "Unexpected error during import commit");
|
|
577
|
-
|
|
578
|
-
"INTERNAL_ERROR",
|
|
761
|
+
throw new InternalError(
|
|
579
762
|
err instanceof Error ? err.message : "Unexpected import error",
|
|
580
|
-
500,
|
|
581
763
|
);
|
|
582
764
|
}
|
|
583
765
|
}
|
|
584
766
|
|
|
585
767
|
// ---------------------------------------------------------------------------
|
|
586
|
-
// URL-body
|
|
768
|
+
// GCS URL import pipeline — shared by the URL-body branch of
|
|
769
|
+
// POST /v1/migrations/import and POST /v1/migrations/import-from-gcs.
|
|
587
770
|
// ---------------------------------------------------------------------------
|
|
588
771
|
|
|
589
772
|
/** 60 minutes — matches the gateway's upstream fetch deadline. */
|
|
@@ -591,6 +774,8 @@ const URL_FETCH_TIMEOUT_MS = 60 * 60 * 1000;
|
|
|
591
774
|
|
|
592
775
|
const MigrationImportUrlBody = z.object({ url: z.string().min(1) });
|
|
593
776
|
|
|
777
|
+
const MigrationImportFromGcsBody = z.object({ bundle_url: z.string().url() });
|
|
778
|
+
|
|
594
779
|
/**
|
|
595
780
|
* Marker attached to errors that originate from the upstream HTTP body
|
|
596
781
|
* stream (peer reset, abort mid-stream, DNS/transport failure after
|
|
@@ -646,43 +831,98 @@ export function _setUrlImportValidatorOptionsForTests(
|
|
|
646
831
|
}
|
|
647
832
|
|
|
648
833
|
/**
|
|
649
|
-
*
|
|
650
|
-
*
|
|
651
|
-
*
|
|
652
|
-
*
|
|
653
|
-
*
|
|
654
|
-
*
|
|
834
|
+
* Successful outcome of `runGcsImport`. Mirrors the wire shape produced by
|
|
835
|
+
* `importCommitSuccessResponse` (report fields spread at the top level, with
|
|
836
|
+
* an optional `credentialsImported` summary alongside) so the same value can
|
|
837
|
+
* be serialized directly as a Response body OR stashed as an async-job
|
|
838
|
+
* `result` — both the sync endpoint and the async job-status endpoint then
|
|
839
|
+
* hand the CLI a single, identical `ImportResponse`-compatible shape.
|
|
655
840
|
*/
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
try {
|
|
660
|
-
rawBody = await req.json();
|
|
661
|
-
} catch (err) {
|
|
662
|
-
log.warn(
|
|
663
|
-
{ err: err instanceof Error ? err.message : String(err) },
|
|
664
|
-
"Failed to parse JSON body on migration import URL request",
|
|
665
|
-
);
|
|
666
|
-
return httpError("BAD_REQUEST", "Invalid JSON body", 400);
|
|
667
|
-
}
|
|
841
|
+
export interface ImportSummary extends ImportCommitReport {
|
|
842
|
+
credentialsImported?: CredentialImportSummary;
|
|
843
|
+
}
|
|
668
844
|
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
845
|
+
/**
|
|
846
|
+
* Structured error thrown by `runGcsImport`. Carries the information needed
|
|
847
|
+
* to reconstruct the URL-body handler's legacy Response shapes and for the
|
|
848
|
+
* async-job registry to map to `error.code`/`upstreamStatus`.
|
|
849
|
+
*/
|
|
850
|
+
interface GcsImportErrorInit {
|
|
851
|
+
code:
|
|
852
|
+
| "invalid_url"
|
|
853
|
+
| "fetch_failed"
|
|
854
|
+
| "validation_failed"
|
|
855
|
+
| "extraction_failed"
|
|
856
|
+
| "write_failed";
|
|
857
|
+
message: string;
|
|
858
|
+
upstreamStatus?: number;
|
|
859
|
+
reason?: string;
|
|
860
|
+
errors?: Array<{ code: string; message: string; path?: string }>;
|
|
861
|
+
partial_report?: ImportCommitReport;
|
|
862
|
+
}
|
|
863
|
+
|
|
864
|
+
class GcsImportError extends Error {
|
|
865
|
+
public readonly code: GcsImportErrorInit["code"];
|
|
866
|
+
public readonly upstreamStatus?: number;
|
|
867
|
+
public readonly reason?: string;
|
|
868
|
+
public readonly errors?: GcsImportErrorInit["errors"];
|
|
869
|
+
public readonly partial_report?: ImportCommitReport;
|
|
870
|
+
|
|
871
|
+
constructor(init: GcsImportErrorInit) {
|
|
872
|
+
super(init.message);
|
|
873
|
+
this.name = "GcsImportError";
|
|
874
|
+
this.code = init.code;
|
|
875
|
+
if (init.upstreamStatus !== undefined) {
|
|
876
|
+
this.upstreamStatus = init.upstreamStatus;
|
|
877
|
+
}
|
|
878
|
+
if (init.reason !== undefined) {
|
|
879
|
+
this.reason = init.reason;
|
|
880
|
+
}
|
|
881
|
+
if (init.errors !== undefined) {
|
|
882
|
+
this.errors = init.errors;
|
|
883
|
+
}
|
|
884
|
+
if (init.partial_report !== undefined) {
|
|
885
|
+
this.partial_report = init.partial_report;
|
|
886
|
+
}
|
|
676
887
|
}
|
|
888
|
+
}
|
|
677
889
|
|
|
678
|
-
|
|
679
|
-
|
|
890
|
+
/**
|
|
891
|
+
* Fetch a .vbundle from a signed GCS URL and commit it via the streaming
|
|
892
|
+
* importer. On success, returns an `ImportSummary` the caller can serialize
|
|
893
|
+
* into a Response or stash as an async-job `result`. On failure, throws a
|
|
894
|
+
* `GcsImportError`:
|
|
895
|
+
*
|
|
896
|
+
* - `invalid_url` → URL failed `validateGcsSignedUrl` (pre-fetch).
|
|
897
|
+
* - `fetch_failed` → upstream fetch error, non-2xx response, missing
|
|
898
|
+
* body, OR a mid-stream body teardown tagged via
|
|
899
|
+
* `kFetchBodyError`. `upstreamStatus` is populated
|
|
900
|
+
* for non-2xx responses.
|
|
901
|
+
* - `validation_failed` → the bundle failed schema/structural validation
|
|
902
|
+
* inside `streamCommitImport`; `errors` carries
|
|
903
|
+
* the per-issue list.
|
|
904
|
+
* - `extraction_failed` → bundle extraction threw (malformed archive, hash
|
|
905
|
+
* mismatch, etc.) that was NOT an upstream tear-
|
|
906
|
+
* down. `reason` carries the importer's string.
|
|
907
|
+
* - `write_failed` → post-extraction disk write error; `partial_report`
|
|
908
|
+
* is attached when the importer produced one.
|
|
909
|
+
*
|
|
910
|
+
* The signed URL is never echoed into errors or logs — only the extracted
|
|
911
|
+
* `host`/`path` are.
|
|
912
|
+
*/
|
|
913
|
+
export async function runGcsImport(
|
|
914
|
+
url: string,
|
|
915
|
+
_correlationId?: string,
|
|
916
|
+
): Promise<ImportSummary> {
|
|
917
|
+
// ── 1. Validate the URL (defense-in-depth; never log the raw URL).
|
|
918
|
+
const validated = validateGcsSignedUrl(url, urlValidatorOptions);
|
|
680
919
|
if (!validated.ok) {
|
|
681
|
-
// `reason` is a stable enum string and safe to include. The raw URL is
|
|
682
|
-
// not — it may contain a live signature. Callers get the reason so they
|
|
683
|
-
// can correct the URL without leaking anything into observability.
|
|
684
920
|
log.warn({ reason: validated.reason }, "Rejected migration import URL");
|
|
685
|
-
|
|
921
|
+
throw new GcsImportError({
|
|
922
|
+
code: "invalid_url",
|
|
923
|
+
message: `Invalid URL: ${validated.reason}`,
|
|
924
|
+
reason: validated.reason,
|
|
925
|
+
});
|
|
686
926
|
}
|
|
687
927
|
|
|
688
928
|
log.info(
|
|
@@ -692,10 +932,10 @@ async function handleMigrationImportFromUrl(req: Request): Promise<Response> {
|
|
|
692
932
|
|
|
693
933
|
const startedAt = Date.now();
|
|
694
934
|
|
|
695
|
-
// ──
|
|
935
|
+
// ── 2. Fetch the URL ──────────────────────────────────────────────────
|
|
696
936
|
let upstream: Response;
|
|
697
937
|
try {
|
|
698
|
-
upstream = await fetch(
|
|
938
|
+
upstream = await fetch(url, {
|
|
699
939
|
signal: AbortSignal.timeout(URL_FETCH_TIMEOUT_MS),
|
|
700
940
|
// SSRF guard: `validateGcsSignedUrl` only vetted the initial URL.
|
|
701
941
|
// Default fetch behavior follows 3xx responses, which would let a
|
|
@@ -713,10 +953,10 @@ async function handleMigrationImportFromUrl(req: Request): Promise<Response> {
|
|
|
713
953
|
},
|
|
714
954
|
"Failed to fetch migration import URL",
|
|
715
955
|
);
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
);
|
|
956
|
+
throw new GcsImportError({
|
|
957
|
+
code: "fetch_failed",
|
|
958
|
+
message: err instanceof Error ? err.message : String(err),
|
|
959
|
+
});
|
|
720
960
|
}
|
|
721
961
|
|
|
722
962
|
if (!upstream.ok) {
|
|
@@ -734,14 +974,11 @@ async function handleMigrationImportFromUrl(req: Request): Promise<Response> {
|
|
|
734
974
|
} catch {
|
|
735
975
|
/* best effort */
|
|
736
976
|
}
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
},
|
|
743
|
-
{ status: 502 },
|
|
744
|
-
);
|
|
977
|
+
throw new GcsImportError({
|
|
978
|
+
code: "fetch_failed",
|
|
979
|
+
message: `Upstream fetch returned ${upstream.status}`,
|
|
980
|
+
upstreamStatus: upstream.status,
|
|
981
|
+
});
|
|
745
982
|
}
|
|
746
983
|
|
|
747
984
|
if (!upstream.body) {
|
|
@@ -749,13 +986,13 @@ async function handleMigrationImportFromUrl(req: Request): Promise<Response> {
|
|
|
749
986
|
{ host: validated.host, path: validated.path },
|
|
750
987
|
"Migration import URL fetch returned no body",
|
|
751
988
|
);
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
);
|
|
989
|
+
throw new GcsImportError({
|
|
990
|
+
code: "fetch_failed",
|
|
991
|
+
message: "Upstream fetch returned no body",
|
|
992
|
+
});
|
|
756
993
|
}
|
|
757
994
|
|
|
758
|
-
// ──
|
|
995
|
+
// ── 3. Stream the response through the importer ──────────────────────
|
|
759
996
|
// Convert the WHATWG ReadableStream from fetch() into a Node Readable so
|
|
760
997
|
// the tar-stream / gunzip / hash-verifier pipeline inside
|
|
761
998
|
// streamCommitImport can consume it via `.pipe()`.
|
|
@@ -767,8 +1004,8 @@ async function handleMigrationImportFromUrl(req: Request): Promise<Response> {
|
|
|
767
1004
|
// from the upstream HTTP body (peer reset, abort mid-stream, etc.) with a
|
|
768
1005
|
// known symbol. When that tagged error surfaces out of
|
|
769
1006
|
// streamCommitImport's gunzip/tar pipeline, we can distinguish it from a
|
|
770
|
-
// legitimate bundle-format failure and map it to
|
|
771
|
-
// of
|
|
1007
|
+
// legitimate bundle-format failure and map it to `fetch_failed` instead
|
|
1008
|
+
// of `extraction_failed` — matching the OpenAPI contract for the URL
|
|
772
1009
|
// body shape. We also propagate errors from the wrapper back to the
|
|
773
1010
|
// upstream stream so its underlying connection is torn down cleanly.
|
|
774
1011
|
//
|
|
@@ -784,7 +1021,7 @@ async function handleMigrationImportFromUrl(req: Request): Promise<Response> {
|
|
|
784
1021
|
// `taggedSource`. The subsequent `close` on `upstreamNodeStream` is then a
|
|
785
1022
|
// cascaded effect of our own teardown, NOT a real upstream failure — so
|
|
786
1023
|
// we must NOT tag it as a fetch-body error, or local validation /
|
|
787
|
-
// extraction errors would be masked as
|
|
1024
|
+
// extraction errors would be masked as fetch_failed.
|
|
788
1025
|
let localTeardownInitiated = false;
|
|
789
1026
|
upstreamNodeStream.on("end", () => {
|
|
790
1027
|
upstreamEnded = true;
|
|
@@ -811,6 +1048,19 @@ async function handleMigrationImportFromUrl(req: Request): Promise<Response> {
|
|
|
811
1048
|
taggedSource.destroy(err);
|
|
812
1049
|
});
|
|
813
1050
|
upstreamNodeStream.pipe(taggedSource);
|
|
1051
|
+
// Absorb stream errors on `taggedSource`. `streamCommitImport` does
|
|
1052
|
+
// several `await`s (workspace recovery, temp-dir mkdir) before
|
|
1053
|
+
// `parseVBundleStream(source)` attaches its own `source.on('error')`
|
|
1054
|
+
// listener. If the upstream socket is destroyed during that window,
|
|
1055
|
+
// the `upstreamNodeStream.on('close')` handler above calls
|
|
1056
|
+
// `taggedSource.destroy(err)` with no listener attached yet and the
|
|
1057
|
+
// error surfaces as unhandled. We don't need to act on it here — the
|
|
1058
|
+
// `kFetchBodyTornDown` flag has already been latched on the stream,
|
|
1059
|
+
// and the post-import branch below (`wasFetchBodyTornDown(taggedSource)`)
|
|
1060
|
+
// maps the failure to `fetch_failed`. Register this absorber
|
|
1061
|
+
// unconditionally so there is always at least one `'error'` listener
|
|
1062
|
+
// on the wrapper for the lifetime of the stream.
|
|
1063
|
+
taggedSource.on("error", () => {});
|
|
814
1064
|
// Propagate wrapper teardown back to the upstream fetch body. When the
|
|
815
1065
|
// streaming importer hits a validation/extraction error, it destroys
|
|
816
1066
|
// `source` (which is `taggedSource`). Without this listener the
|
|
@@ -820,8 +1070,8 @@ async function handleMigrationImportFromUrl(req: Request): Promise<Response> {
|
|
|
820
1070
|
// (malformed bundle, hash mismatch, size cap, etc.). We set
|
|
821
1071
|
// `localTeardownInitiated` BEFORE destroying upstream so the resulting
|
|
822
1072
|
// cascaded `close` on `upstreamNodeStream` isn't misclassified as a real
|
|
823
|
-
// upstream failure (which would return
|
|
824
|
-
//
|
|
1073
|
+
// upstream failure (which would return fetch_failed and mask the actual
|
|
1074
|
+
// validation error).
|
|
825
1075
|
taggedSource.on("close", () => {
|
|
826
1076
|
if (!upstreamNodeStream.destroyed) {
|
|
827
1077
|
localTeardownInitiated = true;
|
|
@@ -870,10 +1120,10 @@ async function handleMigrationImportFromUrl(req: Request): Promise<Response> {
|
|
|
870
1120
|
},
|
|
871
1121
|
"Upstream body stream failed mid-import",
|
|
872
1122
|
);
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
);
|
|
1123
|
+
throw new GcsImportError({
|
|
1124
|
+
code: "fetch_failed",
|
|
1125
|
+
message: err instanceof Error ? err.message : String(err),
|
|
1126
|
+
});
|
|
877
1127
|
}
|
|
878
1128
|
log.error(
|
|
879
1129
|
{
|
|
@@ -883,11 +1133,10 @@ async function handleMigrationImportFromUrl(req: Request): Promise<Response> {
|
|
|
883
1133
|
},
|
|
884
1134
|
"streamCommitImport threw during URL-body import",
|
|
885
1135
|
);
|
|
886
|
-
|
|
887
|
-
"
|
|
888
|
-
err instanceof Error ? err.message : "Unexpected import error",
|
|
889
|
-
|
|
890
|
-
);
|
|
1136
|
+
throw new GcsImportError({
|
|
1137
|
+
code: "extraction_failed",
|
|
1138
|
+
message: err instanceof Error ? err.message : "Unexpected import error",
|
|
1139
|
+
});
|
|
891
1140
|
}
|
|
892
1141
|
|
|
893
1142
|
if (!result.ok) {
|
|
@@ -905,10 +1154,10 @@ async function handleMigrationImportFromUrl(req: Request): Promise<Response> {
|
|
|
905
1154
|
},
|
|
906
1155
|
"Upstream body stream failed mid-import (detected via result)",
|
|
907
1156
|
);
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
);
|
|
1157
|
+
throw new GcsImportError({
|
|
1158
|
+
code: "fetch_failed",
|
|
1159
|
+
message: "Upstream body stream failed mid-import",
|
|
1160
|
+
});
|
|
912
1161
|
}
|
|
913
1162
|
log.warn(
|
|
914
1163
|
{
|
|
@@ -918,7 +1167,28 @@ async function handleMigrationImportFromUrl(req: Request): Promise<Response> {
|
|
|
918
1167
|
},
|
|
919
1168
|
"streamCommitImport returned failure during URL-body import",
|
|
920
1169
|
);
|
|
921
|
-
|
|
1170
|
+
if (result.reason === "validation_failed") {
|
|
1171
|
+
throw new GcsImportError({
|
|
1172
|
+
code: "validation_failed",
|
|
1173
|
+
message: "Bundle validation failed",
|
|
1174
|
+
reason: result.reason,
|
|
1175
|
+
errors: result.errors,
|
|
1176
|
+
});
|
|
1177
|
+
}
|
|
1178
|
+
if (result.reason === "extraction_failed") {
|
|
1179
|
+
throw new GcsImportError({
|
|
1180
|
+
code: "extraction_failed",
|
|
1181
|
+
message: result.message,
|
|
1182
|
+
reason: result.reason,
|
|
1183
|
+
});
|
|
1184
|
+
}
|
|
1185
|
+
// write_failed
|
|
1186
|
+
throw new GcsImportError({
|
|
1187
|
+
code: "write_failed",
|
|
1188
|
+
message: result.message,
|
|
1189
|
+
reason: result.reason,
|
|
1190
|
+
partial_report: result.partial_report,
|
|
1191
|
+
});
|
|
922
1192
|
}
|
|
923
1193
|
|
|
924
1194
|
// Merge any warnings accumulated by the credential-import callback into
|
|
@@ -952,7 +1222,136 @@ async function handleMigrationImportFromUrl(req: Request): Promise<Response> {
|
|
|
952
1222
|
"Migration import from URL complete",
|
|
953
1223
|
);
|
|
954
1224
|
|
|
955
|
-
return
|
|
1225
|
+
return credentialsImported
|
|
1226
|
+
? { ...result.report, credentialsImported }
|
|
1227
|
+
: { ...result.report };
|
|
1228
|
+
}
|
|
1229
|
+
|
|
1230
|
+
/**
|
|
1231
|
+
* Handle a JSON `{ "url": "..." }` body on POST /v1/migrations/import.
|
|
1232
|
+
*
|
|
1233
|
+
* Thin wrapper around `runGcsImport` that preserves the legacy synchronous
|
|
1234
|
+
* Response shapes. `handleMigrationImportFromGcs` below uses the same helper
|
|
1235
|
+
* asynchronously via the migration-job registry.
|
|
1236
|
+
*/
|
|
1237
|
+
async function handleMigrationImportFromUrl(
|
|
1238
|
+
body: Record<string, unknown> | undefined,
|
|
1239
|
+
): Promise<unknown> {
|
|
1240
|
+
const parsed = MigrationImportUrlBody.safeParse(body);
|
|
1241
|
+
if (!parsed.success) {
|
|
1242
|
+
throw new BadRequestError(
|
|
1243
|
+
"Request body must be { url: string } with a non-empty url",
|
|
1244
|
+
);
|
|
1245
|
+
}
|
|
1246
|
+
|
|
1247
|
+
try {
|
|
1248
|
+
const summary = await runGcsImport(parsed.data.url);
|
|
1249
|
+
const { credentialsImported, ...report } = summary;
|
|
1250
|
+
return importCommitSuccessResult(report, credentialsImported);
|
|
1251
|
+
} catch (err) {
|
|
1252
|
+
throwGcsImportError(err);
|
|
1253
|
+
}
|
|
1254
|
+
}
|
|
1255
|
+
|
|
1256
|
+
/**
|
|
1257
|
+
* Map a `runGcsImport` error (or any other thrown value) to a thrown
|
|
1258
|
+
* RouteError subclass or a plain-object error body. Always throws —
|
|
1259
|
+
* callers should invoke this in a catch block.
|
|
1260
|
+
*/
|
|
1261
|
+
function throwGcsImportError(err: unknown): never {
|
|
1262
|
+
if (err instanceof GcsImportError) {
|
|
1263
|
+
if (err.code === "invalid_url") {
|
|
1264
|
+
throw new BadRequestError(err.message);
|
|
1265
|
+
}
|
|
1266
|
+
if (err.code === "fetch_failed") {
|
|
1267
|
+
throw new BadGatewayError(
|
|
1268
|
+
err.upstreamStatus
|
|
1269
|
+
? `Upstream fetch returned ${err.upstreamStatus}`
|
|
1270
|
+
: err.message,
|
|
1271
|
+
);
|
|
1272
|
+
}
|
|
1273
|
+
if (err.code === "validation_failed") {
|
|
1274
|
+
// Validation failure is not an HTTP error — return structured body
|
|
1275
|
+
// with 200 (same as raw-bytes validate path).
|
|
1276
|
+
throw new BadRequestError(
|
|
1277
|
+
JSON.stringify({
|
|
1278
|
+
success: false,
|
|
1279
|
+
reason: "validation_failed",
|
|
1280
|
+
errors: err.errors ?? [],
|
|
1281
|
+
}),
|
|
1282
|
+
);
|
|
1283
|
+
}
|
|
1284
|
+
if (err.code === "extraction_failed") {
|
|
1285
|
+
throw new InternalError(err.message);
|
|
1286
|
+
}
|
|
1287
|
+
// write_failed
|
|
1288
|
+
throw new InternalError(err.message);
|
|
1289
|
+
}
|
|
1290
|
+
|
|
1291
|
+
log.error({ err }, "Unexpected error from runGcsImport");
|
|
1292
|
+
throw new InternalError(
|
|
1293
|
+
err instanceof Error ? err.message : "Unexpected import error",
|
|
1294
|
+
);
|
|
1295
|
+
}
|
|
1296
|
+
|
|
1297
|
+
/**
|
|
1298
|
+
* POST /v1/migrations/import-from-gcs
|
|
1299
|
+
*
|
|
1300
|
+
* Kick off an async bundle import from a signed GCS URL. Returns 202 with a
|
|
1301
|
+
* `job_id` the caller can poll via `GET /v1/migrations/jobs/:job_id`
|
|
1302
|
+
* (PR 4). 409 if another import is already pending or running.
|
|
1303
|
+
*
|
|
1304
|
+
* Auth: Requires settings.write scope. Allowed for actor, svc_gateway, svc_daemon, local.
|
|
1305
|
+
*/
|
|
1306
|
+
export async function handleMigrationImportFromGcs({
|
|
1307
|
+
body,
|
|
1308
|
+
}: RouteHandlerArgs) {
|
|
1309
|
+
const parsed = MigrationImportFromGcsBody.safeParse(body);
|
|
1310
|
+
if (!parsed.success) {
|
|
1311
|
+
throw new BadRequestError(
|
|
1312
|
+
"Request body must be { bundle_url: string } with a valid URL",
|
|
1313
|
+
);
|
|
1314
|
+
}
|
|
1315
|
+
|
|
1316
|
+
const { bundle_url } = parsed.data;
|
|
1317
|
+
|
|
1318
|
+
// Synchronously validate the GCS URL before consuming the single
|
|
1319
|
+
// in-flight import slot.
|
|
1320
|
+
const validated = validateGcsSignedUrl(bundle_url, urlValidatorOptions);
|
|
1321
|
+
if (!validated.ok) {
|
|
1322
|
+
log.warn(
|
|
1323
|
+
{ reason: validated.reason },
|
|
1324
|
+
"Rejected migration import-from-gcs bundle URL",
|
|
1325
|
+
);
|
|
1326
|
+
throw new RouteError(
|
|
1327
|
+
`Invalid bundle URL: ${validated.reason}`,
|
|
1328
|
+
"invalid_bundle_url",
|
|
1329
|
+
400,
|
|
1330
|
+
);
|
|
1331
|
+
}
|
|
1332
|
+
|
|
1333
|
+
try {
|
|
1334
|
+
const job = migrationJobs.startJob("import", async (jobRecord) =>
|
|
1335
|
+
runGcsImport(bundle_url, jobRecord.id),
|
|
1336
|
+
);
|
|
1337
|
+
return {
|
|
1338
|
+
job_id: job.id,
|
|
1339
|
+
status: "pending" as const,
|
|
1340
|
+
type: "import" as const,
|
|
1341
|
+
};
|
|
1342
|
+
} catch (err) {
|
|
1343
|
+
if (err instanceof JobAlreadyInProgressError) {
|
|
1344
|
+
throw new RouteError(
|
|
1345
|
+
`Import already in progress: ${err.existingJobId}`,
|
|
1346
|
+
"import_in_progress",
|
|
1347
|
+
409,
|
|
1348
|
+
);
|
|
1349
|
+
}
|
|
1350
|
+
log.error({ err }, "Unexpected error scheduling import-from-gcs job");
|
|
1351
|
+
throw new InternalError(
|
|
1352
|
+
err instanceof Error ? err.message : "Unexpected import error",
|
|
1353
|
+
);
|
|
1354
|
+
}
|
|
956
1355
|
}
|
|
957
1356
|
|
|
958
1357
|
// ---------------------------------------------------------------------------
|
|
@@ -1081,178 +1480,279 @@ function appendNewerMigrationWarningsIfAny(report: ImportCommitReport): void {
|
|
|
1081
1480
|
}
|
|
1082
1481
|
|
|
1083
1482
|
/**
|
|
1084
|
-
* Build a success
|
|
1085
|
-
* are spread at the top level, with an optional `credentialsImported`
|
|
1086
|
-
* summary alongside.
|
|
1483
|
+
* Build a success result from an ImportCommitReport.
|
|
1087
1484
|
*/
|
|
1088
|
-
function
|
|
1485
|
+
function importCommitSuccessResult(
|
|
1089
1486
|
report: ImportCommitReport,
|
|
1090
1487
|
credentialsImported: CredentialImportSummary | undefined,
|
|
1091
|
-
):
|
|
1092
|
-
return
|
|
1488
|
+
): unknown {
|
|
1489
|
+
return {
|
|
1093
1490
|
...report,
|
|
1094
1491
|
...(credentialsImported ? { credentialsImported } : {}),
|
|
1095
|
-
}
|
|
1492
|
+
};
|
|
1096
1493
|
}
|
|
1097
1494
|
|
|
1098
1495
|
/**
|
|
1099
|
-
* Map an `ImportCommitResult` failure to
|
|
1100
|
-
*
|
|
1101
|
-
*
|
|
1496
|
+
* Map an `ImportCommitResult` failure to a thrown error or a plain-object
|
|
1497
|
+
* error body. Status codes and body shapes are part of the public contract
|
|
1498
|
+
* and must remain stable.
|
|
1102
1499
|
*/
|
|
1103
|
-
function
|
|
1500
|
+
function throwImportCommitFailure(
|
|
1104
1501
|
result: Extract<ImportCommitResult, { ok: false }>,
|
|
1105
|
-
):
|
|
1502
|
+
): never {
|
|
1106
1503
|
if (result.reason === "validation_failed") {
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1504
|
+
// Validation failure uses 400 — structured body with error details
|
|
1505
|
+
throw new BadRequestError(
|
|
1506
|
+
JSON.stringify({
|
|
1507
|
+
success: false,
|
|
1508
|
+
reason: "validation_failed",
|
|
1509
|
+
errors: result.errors,
|
|
1510
|
+
}),
|
|
1511
|
+
);
|
|
1112
1512
|
}
|
|
1113
1513
|
|
|
1114
1514
|
if (result.reason === "extraction_failed") {
|
|
1115
|
-
|
|
1116
|
-
{
|
|
1117
|
-
success: false,
|
|
1118
|
-
reason: "extraction_failed",
|
|
1119
|
-
message: result.message,
|
|
1120
|
-
},
|
|
1121
|
-
{ status: 500 },
|
|
1122
|
-
);
|
|
1515
|
+
throw new InternalError(result.message);
|
|
1123
1516
|
}
|
|
1124
1517
|
|
|
1125
1518
|
// write_failed
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1519
|
+
throw new InternalError(result.message);
|
|
1520
|
+
}
|
|
1521
|
+
|
|
1522
|
+
// ---------------------------------------------------------------------------
|
|
1523
|
+
// GET /v1/migrations/jobs/:job_id
|
|
1524
|
+
// ---------------------------------------------------------------------------
|
|
1525
|
+
|
|
1526
|
+
/**
|
|
1527
|
+
* GET /v1/migrations/jobs/:job_id
|
|
1528
|
+
*
|
|
1529
|
+
* Returns the current status of a migration job tracked by
|
|
1530
|
+
* `MigrationJobRegistry`. The response shape is a discriminated union on
|
|
1531
|
+
* `status`:
|
|
1532
|
+
*
|
|
1533
|
+
* - `{ job_id, type, status: "processing" }`
|
|
1534
|
+
* Covers both the internal `pending` and `running` states — collapsed
|
|
1535
|
+
* into a single wire value to match the platform's transport shape used
|
|
1536
|
+
* by `ExportStatusProcessingSerializer` / `ImportStatusProcessingSerializer`.
|
|
1537
|
+
* - `{ job_id, type, status: "complete", result }`
|
|
1538
|
+
* - `{ job_id, type, status: "failed", error, error_code, upstream_status? }`
|
|
1539
|
+
*
|
|
1540
|
+
* 404 `{ error: { code: "job_not_found" } }` when no job matches the id.
|
|
1541
|
+
*/
|
|
1542
|
+
export async function handleMigrationJobStatus({
|
|
1543
|
+
pathParams,
|
|
1544
|
+
}: RouteHandlerArgs) {
|
|
1545
|
+
const jobId = pathParams?.job_id;
|
|
1546
|
+
if (!jobId) {
|
|
1547
|
+
throw new BadRequestError("Missing job_id path parameter");
|
|
1548
|
+
}
|
|
1549
|
+
|
|
1550
|
+
const job = migrationJobs.getJob(jobId);
|
|
1551
|
+
if (job === null) {
|
|
1552
|
+
throw new NotFoundError("Job not found");
|
|
1553
|
+
}
|
|
1554
|
+
|
|
1555
|
+
if (job.status === "complete") {
|
|
1556
|
+
return {
|
|
1557
|
+
job_id: job.id,
|
|
1558
|
+
type: job.type,
|
|
1559
|
+
status: "complete",
|
|
1560
|
+
result: job.result,
|
|
1561
|
+
};
|
|
1562
|
+
}
|
|
1563
|
+
|
|
1564
|
+
if (job.status === "failed") {
|
|
1565
|
+
const error = job.error;
|
|
1566
|
+
const result: Record<string, unknown> = {
|
|
1567
|
+
job_id: job.id,
|
|
1568
|
+
type: job.type,
|
|
1569
|
+
status: "failed",
|
|
1570
|
+
error: error?.message ?? "unknown",
|
|
1571
|
+
error_code: error?.code ?? "unknown",
|
|
1572
|
+
};
|
|
1573
|
+
if (error?.upstreamStatus !== undefined) {
|
|
1574
|
+
result.upstream_status = error.upstreamStatus;
|
|
1575
|
+
}
|
|
1576
|
+
return result;
|
|
1577
|
+
}
|
|
1578
|
+
|
|
1579
|
+
// pending or running — collapse to the platform's "processing" wire value.
|
|
1580
|
+
return {
|
|
1581
|
+
job_id: job.id,
|
|
1582
|
+
type: job.type,
|
|
1583
|
+
status: "processing",
|
|
1584
|
+
};
|
|
1137
1585
|
}
|
|
1138
1586
|
|
|
1139
1587
|
// ---------------------------------------------------------------------------
|
|
1140
1588
|
// Route definitions
|
|
1141
1589
|
// ---------------------------------------------------------------------------
|
|
1142
1590
|
|
|
1143
|
-
export
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1591
|
+
export const ROUTES: RouteDefinition[] = [
|
|
1592
|
+
{
|
|
1593
|
+
operationId: "migrations_validate_post",
|
|
1594
|
+
endpoint: "migrations/validate",
|
|
1595
|
+
method: "POST",
|
|
1596
|
+
summary: "Validate a .vbundle archive",
|
|
1597
|
+
description:
|
|
1598
|
+
"Upload a .vbundle archive for validation. Accepts raw binary or multipart form data.",
|
|
1599
|
+
tags: ["migrations"],
|
|
1600
|
+
responseBody: z.object({
|
|
1601
|
+
is_valid: z.boolean(),
|
|
1602
|
+
errors: z.array(z.unknown()),
|
|
1603
|
+
manifest: z.object({}).passthrough(),
|
|
1604
|
+
}),
|
|
1605
|
+
handler: handleMigrationValidate,
|
|
1606
|
+
},
|
|
1607
|
+
{
|
|
1608
|
+
operationId: "migrations_export_post",
|
|
1609
|
+
endpoint: "migrations/export",
|
|
1610
|
+
method: "POST",
|
|
1611
|
+
summary: "Export a .vbundle archive",
|
|
1612
|
+
description:
|
|
1613
|
+
"Generate and download a .vbundle archive of the assistant's data. Optional JSON body for metadata.",
|
|
1614
|
+
tags: ["migrations"],
|
|
1615
|
+
requestBody: z.object({
|
|
1616
|
+
description: z.string().describe("Human-readable export description"),
|
|
1617
|
+
}),
|
|
1618
|
+
handler: handleMigrationExport,
|
|
1619
|
+
},
|
|
1620
|
+
{
|
|
1621
|
+
operationId: "migrations_importpreflight_post",
|
|
1622
|
+
endpoint: "migrations/import-preflight",
|
|
1623
|
+
method: "POST",
|
|
1624
|
+
summary: "Dry-run import analysis",
|
|
1625
|
+
description:
|
|
1626
|
+
"Validate a .vbundle archive and return a report of what would change on import without modifying data.",
|
|
1627
|
+
tags: ["migrations"],
|
|
1628
|
+
responseBody: z.object({
|
|
1629
|
+
can_import: z.boolean(),
|
|
1630
|
+
summary: z.object({}).passthrough(),
|
|
1631
|
+
files: z.array(z.unknown()),
|
|
1632
|
+
conflicts: z.array(z.unknown()),
|
|
1633
|
+
manifest: z.object({}).passthrough(),
|
|
1634
|
+
}),
|
|
1635
|
+
handler: handleMigrationImportPreflight,
|
|
1636
|
+
},
|
|
1637
|
+
{
|
|
1638
|
+
operationId: "migrations_import_post",
|
|
1639
|
+
endpoint: "migrations/import",
|
|
1640
|
+
method: "POST",
|
|
1641
|
+
summary: "Import a .vbundle archive",
|
|
1642
|
+
description:
|
|
1643
|
+
"Commit a .vbundle archive import to disk — destructive. Accepts the bundle as raw bytes (application/octet-stream), multipart/form-data, or a JSON body with `{ url }` carrying a signed URL the daemon fetches.",
|
|
1644
|
+
tags: ["migrations"],
|
|
1645
|
+
requestBody: z.object({
|
|
1646
|
+
url: z
|
|
1647
|
+
.string()
|
|
1648
|
+
.url()
|
|
1649
|
+
.describe(
|
|
1650
|
+
"A signed GCS URL pointing to the .vbundle archive (JSON body path only).",
|
|
1651
|
+
),
|
|
1652
|
+
}),
|
|
1653
|
+
additionalResponses: {
|
|
1654
|
+
"502": {
|
|
1655
|
+
description:
|
|
1656
|
+
"Upstream fetch failed (URL body only).",
|
|
1657
|
+
},
|
|
1158
1658
|
},
|
|
1159
|
-
{
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1659
|
+
responseBody: z.object({
|
|
1660
|
+
success: z.boolean(),
|
|
1661
|
+
summary: z.object({}).passthrough(),
|
|
1662
|
+
files: z.array(z.unknown()),
|
|
1663
|
+
manifest: z.object({}).passthrough(),
|
|
1664
|
+
warnings: z.array(z.unknown()),
|
|
1665
|
+
}),
|
|
1666
|
+
handler: handleMigrationImport,
|
|
1667
|
+
},
|
|
1668
|
+
{
|
|
1669
|
+
operationId: "migrations_exporttogcs_post",
|
|
1670
|
+
endpoint: "migrations/export-to-gcs",
|
|
1671
|
+
method: "POST",
|
|
1672
|
+
summary: "Start an async export streamed to a GCS signed URL",
|
|
1673
|
+
description:
|
|
1674
|
+
"Kick off a background export job that PUTs a freshly-built .vbundle archive to the supplied GCS signed URL. Returns 202 with a job_id the caller can poll via the job-status endpoint. Fails fast with 409 if another export job is already pending or running.",
|
|
1675
|
+
tags: ["migrations"],
|
|
1676
|
+
requestBody: z.object({
|
|
1677
|
+
upload_url: z
|
|
1678
|
+
.string()
|
|
1679
|
+
.url()
|
|
1680
|
+
.describe("Signed GCS PUT URL that receives the exported bundle."),
|
|
1681
|
+
description: z
|
|
1682
|
+
.string()
|
|
1683
|
+
.optional()
|
|
1684
|
+
.describe("Human-readable export description."),
|
|
1685
|
+
}),
|
|
1686
|
+
responseStatus: "202",
|
|
1687
|
+
responseBody: z.object({
|
|
1688
|
+
job_id: z.string(),
|
|
1689
|
+
status: z.literal("pending"),
|
|
1690
|
+
type: z.literal("export"),
|
|
1691
|
+
}),
|
|
1692
|
+
handler: handleMigrationExportToGcs,
|
|
1693
|
+
},
|
|
1694
|
+
{
|
|
1695
|
+
operationId: "migrations_importfromgcs_post",
|
|
1696
|
+
endpoint: "migrations/import-from-gcs",
|
|
1697
|
+
method: "POST",
|
|
1698
|
+
summary: "Start an async .vbundle import from a signed GCS URL",
|
|
1699
|
+
description:
|
|
1700
|
+
"Schedule a background import job that fetches the bundle at `bundle_url` and streams it through the importer. Returns 202 with a `job_id`; poll `GET /v1/migrations/jobs/{job_id}` for status. 409 if another import is already in flight.",
|
|
1701
|
+
tags: ["migrations"],
|
|
1702
|
+
requestBody: z.object({
|
|
1703
|
+
bundle_url: z.string().url(),
|
|
1704
|
+
}),
|
|
1705
|
+
responseStatus: "202",
|
|
1706
|
+
responseBody: z.object({
|
|
1707
|
+
job_id: z.string(),
|
|
1708
|
+
status: z.literal("pending"),
|
|
1709
|
+
type: z.literal("import"),
|
|
1710
|
+
}),
|
|
1711
|
+
additionalResponses: {
|
|
1712
|
+
"409": {
|
|
1713
|
+
description:
|
|
1714
|
+
"Another import job is already pending or running.",
|
|
1715
|
+
},
|
|
1170
1716
|
},
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1717
|
+
handler: handleMigrationImportFromGcs,
|
|
1718
|
+
},
|
|
1719
|
+
{
|
|
1720
|
+
operationId: "migrations_jobs_by_job_id_get",
|
|
1721
|
+
endpoint: "migrations/jobs/:job_id",
|
|
1722
|
+
method: "GET",
|
|
1723
|
+
summary: "Get migration job status",
|
|
1724
|
+
description:
|
|
1725
|
+
"Return the current status of an async migration job (export or import). The response discriminates on `status`: `processing` (pending or running), `complete` (with `result`), or `failed` (with `error`, `error_code`, optional `upstream_status`).",
|
|
1726
|
+
tags: ["migrations"],
|
|
1727
|
+
pathParams: [
|
|
1728
|
+
{ name: "job_id", description: "The migration job ID to query." },
|
|
1729
|
+
],
|
|
1730
|
+
responseBody: z.discriminatedUnion("status", [
|
|
1731
|
+
z.object({
|
|
1732
|
+
job_id: z.string(),
|
|
1733
|
+
type: z.enum(["export", "import"]),
|
|
1734
|
+
status: z.literal("processing"),
|
|
1184
1735
|
}),
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
type: "string",
|
|
1199
|
-
format: "binary",
|
|
1200
|
-
description: "Raw .vbundle archive bytes.",
|
|
1201
|
-
},
|
|
1202
|
-
},
|
|
1203
|
-
{
|
|
1204
|
-
contentType: "multipart/form-data",
|
|
1205
|
-
schema: {
|
|
1206
|
-
type: "object",
|
|
1207
|
-
properties: {
|
|
1208
|
-
file: {
|
|
1209
|
-
type: "string",
|
|
1210
|
-
format: "binary",
|
|
1211
|
-
description: "The .vbundle archive uploaded as a file field.",
|
|
1212
|
-
},
|
|
1213
|
-
},
|
|
1214
|
-
required: ["file"],
|
|
1215
|
-
},
|
|
1216
|
-
},
|
|
1217
|
-
{
|
|
1218
|
-
contentType: "application/json",
|
|
1219
|
-
schema: {
|
|
1220
|
-
type: "object",
|
|
1221
|
-
properties: {
|
|
1222
|
-
url: {
|
|
1223
|
-
type: "string",
|
|
1224
|
-
format: "uri",
|
|
1225
|
-
description:
|
|
1226
|
-
"A signed GCS URL pointing to the .vbundle archive. The daemon fetches the URL and streams the body through the importer.",
|
|
1227
|
-
},
|
|
1228
|
-
},
|
|
1229
|
-
required: ["url"],
|
|
1230
|
-
},
|
|
1231
|
-
},
|
|
1232
|
-
],
|
|
1233
|
-
additionalResponses: {
|
|
1234
|
-
"502": {
|
|
1235
|
-
description:
|
|
1236
|
-
"Upstream fetch failed (URL body only). Body shape: { success: false, reason: 'fetch_failed', upstream_status?: number }.",
|
|
1237
|
-
schema: {
|
|
1238
|
-
type: "object",
|
|
1239
|
-
properties: {
|
|
1240
|
-
success: { type: "boolean" },
|
|
1241
|
-
reason: { type: "string", enum: ["fetch_failed"] },
|
|
1242
|
-
upstream_status: { type: "integer" },
|
|
1243
|
-
},
|
|
1244
|
-
required: ["success", "reason"],
|
|
1245
|
-
},
|
|
1246
|
-
},
|
|
1247
|
-
},
|
|
1248
|
-
responseBody: z.object({
|
|
1249
|
-
success: z.boolean(),
|
|
1250
|
-
summary: z.object({}).passthrough(),
|
|
1251
|
-
files: z.array(z.unknown()),
|
|
1252
|
-
manifest: z.object({}).passthrough(),
|
|
1253
|
-
warnings: z.array(z.unknown()),
|
|
1736
|
+
z.object({
|
|
1737
|
+
job_id: z.string(),
|
|
1738
|
+
type: z.enum(["export", "import"]),
|
|
1739
|
+
status: z.literal("complete"),
|
|
1740
|
+
result: z.unknown(),
|
|
1741
|
+
}),
|
|
1742
|
+
z.object({
|
|
1743
|
+
job_id: z.string(),
|
|
1744
|
+
type: z.enum(["export", "import"]),
|
|
1745
|
+
status: z.literal("failed"),
|
|
1746
|
+
error: z.string(),
|
|
1747
|
+
error_code: z.string(),
|
|
1748
|
+
upstream_status: z.number().int().optional(),
|
|
1254
1749
|
}),
|
|
1255
|
-
|
|
1750
|
+
]),
|
|
1751
|
+
additionalResponses: {
|
|
1752
|
+
"404": {
|
|
1753
|
+
description: "No job matches the given id.",
|
|
1754
|
+
},
|
|
1256
1755
|
},
|
|
1257
|
-
|
|
1258
|
-
}
|
|
1756
|
+
handler: handleMigrationJobStatus,
|
|
1757
|
+
},
|
|
1758
|
+
];
|