@vellumai/assistant 0.5.6 → 0.5.8
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/.env.example +16 -2
- package/ARCHITECTURE.md +6 -75
- package/Dockerfile +3 -2
- package/README.md +0 -2
- package/bun.lock +0 -414
- package/docker-entrypoint.sh +9 -0
- package/docs/architecture/keychain-broker.md +45 -240
- package/docs/architecture/memory.md +13 -11
- package/docs/architecture/security.md +0 -17
- package/docs/credential-execution-service.md +2 -2
- package/node_modules/@vellumai/ces-contracts/package.json +1 -0
- package/node_modules/@vellumai/ces-contracts/src/error.ts +1 -1
- package/node_modules/@vellumai/ces-contracts/src/grants.ts +1 -1
- package/node_modules/@vellumai/ces-contracts/src/handles.ts +1 -1
- package/node_modules/@vellumai/ces-contracts/src/index.ts +1 -1
- package/node_modules/@vellumai/ces-contracts/src/rpc.ts +120 -1
- package/node_modules/@vellumai/credential-storage/package.json +1 -0
- package/node_modules/@vellumai/egress-proxy/package.json +1 -0
- package/package.json +2 -3
- package/src/__tests__/actor-token-service.test.ts +0 -114
- package/src/__tests__/approval-cascade.test.ts +0 -1
- package/src/__tests__/assistant-feature-flags-integration.test.ts +30 -29
- package/src/__tests__/browser-fill-credential.test.ts +1 -1
- package/src/__tests__/browser-skill-endstate.test.ts +6 -5
- package/src/__tests__/btw-routes.test.ts +0 -39
- package/src/__tests__/call-controller.test.ts +0 -1
- package/src/__tests__/call-domain.test.ts +0 -128
- package/src/__tests__/ces-rpc-credential-backend.test.ts +199 -0
- package/src/__tests__/ces-startup-timeout.test.ts +40 -0
- package/src/__tests__/channel-approval-routes.test.ts +0 -5
- package/src/__tests__/channel-readiness-service.test.ts +1 -60
- package/src/__tests__/checker.test.ts +4 -2
- package/src/__tests__/cli-command-risk-guard.test.ts +112 -0
- package/src/__tests__/config-schema-cmd.test.ts +0 -2
- package/src/__tests__/config-schema.test.ts +3 -1
- package/src/__tests__/conversation-abort-tool-results.test.ts +0 -1
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +0 -2
- package/src/__tests__/conversation-agent-loop.test.ts +2 -4
- package/src/__tests__/conversation-attention-telegram.test.ts +0 -5
- package/src/__tests__/conversation-confirmation-signals.test.ts +0 -1
- package/src/__tests__/conversation-error.test.ts +15 -1
- package/src/__tests__/conversation-init.benchmark.test.ts +0 -2
- package/src/__tests__/conversation-messaging-secret-redirect.test.ts +1 -1
- package/src/__tests__/conversation-pre-run-repair.test.ts +0 -1
- package/src/__tests__/conversation-provider-retry-repair.test.ts +0 -1
- package/src/__tests__/conversation-queue.test.ts +0 -1
- package/src/__tests__/conversation-skill-tools.test.ts +0 -54
- package/src/__tests__/conversation-slash-queue.test.ts +0 -1
- package/src/__tests__/conversation-slash-unknown.test.ts +0 -1
- package/src/__tests__/conversation-title-service.test.ts +87 -0
- package/src/__tests__/conversation-workspace-injection.test.ts +0 -1
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +0 -1
- package/src/__tests__/credential-execution-client.test.ts +5 -2
- package/src/__tests__/credential-execution-feature-gates.test.ts +59 -30
- package/src/__tests__/credential-execution-managed-contract.test.ts +35 -20
- package/src/__tests__/credential-security-e2e.test.ts +1 -67
- package/src/__tests__/credential-security-invariants.test.ts +6 -50
- package/src/__tests__/credentials-cli.test.ts +82 -3
- package/src/__tests__/daemon-credential-client.test.ts +123 -0
- package/src/__tests__/db-migration-rollback.test.ts +2015 -1
- package/src/__tests__/deterministic-verification-control-plane.test.ts +1 -0
- package/src/__tests__/docker-signing-key-bootstrap.test.ts +34 -143
- package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +6 -4
- package/src/__tests__/gateway-client-managed-outbound.test.ts +79 -1
- package/src/__tests__/guardian-routing-state.test.ts +0 -5
- package/src/__tests__/host-shell-tool.test.ts +6 -7
- package/src/__tests__/http-user-message-parity.test.ts +3 -103
- package/src/__tests__/inbound-invite-redemption.test.ts +0 -4
- package/src/__tests__/inline-skill-load-permissions.test.ts +6 -8
- package/src/__tests__/intent-routing.test.ts +0 -13
- package/src/__tests__/jobs-store-qdrant-breaker.test.ts +178 -0
- package/src/__tests__/journal-context.test.ts +335 -0
- package/src/__tests__/keychain-broker-client.test.ts +161 -22
- package/src/__tests__/memory-context-benchmark.benchmark.test.ts +0 -3
- package/src/__tests__/memory-jobs-worker-backoff.test.ts +150 -0
- package/src/__tests__/memory-lifecycle-e2e.test.ts +70 -25
- package/src/__tests__/memory-recall-quality.test.ts +48 -17
- package/src/__tests__/memory-regressions.test.ts +408 -363
- package/src/__tests__/memory-retrieval.benchmark.test.ts +0 -3
- package/src/__tests__/migration-export-http.test.ts +2 -2
- package/src/__tests__/migration-import-commit-http.test.ts +2 -2
- package/src/__tests__/migration-import-preflight-http.test.ts +2 -2
- package/src/__tests__/migration-validate-http.test.ts +2 -2
- package/src/__tests__/non-member-access-request.test.ts +2 -7
- package/src/__tests__/notification-decision-fallback.test.ts +4 -0
- package/src/__tests__/notification-decision-identity.test.ts +4 -0
- package/src/__tests__/notification-decision-strategy.test.ts +71 -0
- package/src/__tests__/oauth-cli.test.ts +5 -1
- package/src/__tests__/permission-types.test.ts +1 -0
- package/src/__tests__/provider-commit-message-generator.test.ts +0 -37
- package/src/__tests__/provider-error-scenarios.test.ts +0 -267
- package/src/__tests__/provider-managed-proxy-integration.test.ts +5 -6
- package/src/__tests__/provider-streaming.benchmark.test.ts +2 -81
- package/src/__tests__/qdrant-manager.test.ts +28 -2
- package/src/__tests__/registry.test.ts +0 -6
- package/src/__tests__/relay-server.test.ts +1 -2
- package/src/__tests__/runtime-attachment-metadata.test.ts +0 -4
- package/src/__tests__/script-proxy-injection-runtime.test.ts +1 -1
- package/src/__tests__/secret-onetime-send.test.ts +1 -1
- package/src/__tests__/secret-routes-managed-proxy.test.ts +0 -4
- package/src/__tests__/secure-keys.test.ts +95 -272
- package/src/__tests__/shell-identity.test.ts +96 -6
- package/src/__tests__/skill-feature-flags-integration.test.ts +22 -14
- package/src/__tests__/skill-feature-flags.test.ts +46 -45
- package/src/__tests__/skill-load-feature-flag.test.ts +7 -10
- package/src/__tests__/skill-load-inline-command.test.ts +8 -12
- package/src/__tests__/skill-load-inline-includes.test.ts +6 -10
- package/src/__tests__/skill-load-tool.test.ts +0 -2
- package/src/__tests__/skill-memory.test.ts +17 -3
- package/src/__tests__/skill-projection-feature-flag.test.ts +33 -29
- package/src/__tests__/skills.test.ts +0 -2
- package/src/__tests__/slack-inbound-verification.test.ts +0 -4
- package/src/__tests__/stale-approval-dedup.test.ts +171 -0
- package/src/__tests__/stt-hints.test.ts +437 -0
- package/src/__tests__/suggestion-routes.test.ts +1 -32
- package/src/__tests__/system-prompt.test.ts +0 -1
- package/src/__tests__/task-memory-cleanup.test.ts +14 -0
- package/src/__tests__/tool-executor-shell-integration.test.ts +5 -3
- package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +0 -5
- package/src/__tests__/trusted-contact-multichannel.test.ts +0 -4
- package/src/__tests__/twilio-routes-twiml.test.ts +139 -1
- package/src/__tests__/update-bulletin.test.ts +0 -2
- package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +6 -9
- package/src/__tests__/voice-quality.test.ts +58 -0
- package/src/__tests__/voice-scoped-grant-consumer.test.ts +0 -7
- package/src/__tests__/workspace-migration-015-migrate-credentials-to-keychain.test.ts +252 -0
- package/src/__tests__/workspace-migration-016-migrate-credentials-from-keychain.test.ts +220 -0
- package/src/__tests__/workspace-migration-down-functions.test.ts +1009 -0
- package/src/__tests__/workspace-migrations-runner.test.ts +114 -0
- package/src/acp/agent-process.ts +9 -1
- package/src/agent/loop.ts +1 -1
- package/src/approvals/guardian-request-resolvers.ts +164 -38
- package/src/calls/__tests__/tts-text-sanitizer.test.ts +254 -0
- package/src/calls/audio-store.test.ts +97 -0
- package/src/calls/audio-store.ts +205 -0
- package/src/calls/call-controller.ts +90 -8
- package/src/calls/call-domain.ts +3 -0
- package/src/calls/call-store.ts +10 -3
- package/src/calls/fish-audio-client.ts +129 -0
- package/src/calls/relay-server.ts +27 -0
- package/src/calls/stt-hints.ts +189 -0
- package/src/calls/tts-text-sanitizer.ts +61 -0
- package/src/calls/twilio-routes.ts +34 -5
- package/src/calls/types.ts +1 -0
- package/src/calls/voice-ingress-preflight.ts +0 -42
- package/src/calls/voice-quality.ts +38 -5
- package/src/calls/voice-session-bridge.ts +7 -12
- package/src/cli/commands/avatar.ts +2 -2
- package/src/cli/commands/config.ts +1 -4
- package/src/cli/commands/credentials.ts +128 -82
- package/src/cli/commands/doctor.ts +2 -2
- package/src/cli/commands/keys.ts +7 -7
- package/src/cli/commands/memory.ts +1 -1
- package/src/cli/commands/oauth/connections.ts +11 -29
- package/src/cli/commands/oauth/index.ts +7 -0
- package/src/cli/commands/oauth/platform.ts +525 -0
- package/src/cli/commands/platform.ts +3 -3
- package/src/cli/lib/daemon-credential-client.ts +284 -0
- package/src/cli.ts +1 -1
- package/src/config/assistant-feature-flags.ts +186 -5
- package/src/config/bundled-skills/AGENTS.md +34 -0
- package/src/config/bundled-skills/acp/SKILL.md +10 -0
- package/src/config/bundled-skills/app-builder/SKILL.md +0 -4
- package/src/config/bundled-skills/messaging/SKILL.md +5 -5
- package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +2 -2
- package/src/config/bundled-skills/phone-calls/TOOLS.json +4 -0
- package/src/config/bundled-skills/playbooks/tools/playbook-create.ts +1 -0
- package/src/config/bundled-skills/playbooks/tools/playbook-update.ts +1 -0
- package/src/config/bundled-skills/settings/SKILL.md +15 -2
- package/src/config/bundled-skills/settings/TOOLS.json +47 -2
- package/src/config/bundled-skills/settings/tools/avatar-remove.ts +59 -0
- package/src/config/bundled-skills/settings/tools/avatar-update.ts +80 -0
- package/src/config/bundled-skills/settings/tools/voice-config-update.ts +42 -0
- package/src/config/bundled-skills/slack/SKILL.md +1 -1
- package/src/config/bundled-tool-registry.ts +5 -11
- package/src/config/defaults.ts +0 -2
- package/src/config/env-registry.ts +5 -5
- package/src/config/env.ts +21 -14
- package/src/config/feature-flag-registry.json +49 -9
- package/src/config/loader.ts +106 -42
- package/src/config/schema.ts +9 -29
- package/src/config/schemas/calls.ts +30 -0
- package/src/config/schemas/fish-audio.ts +39 -0
- package/src/config/schemas/inference.ts +2 -2
- package/src/config/schemas/journal.ts +16 -0
- package/src/config/schemas/memory-processing.ts +2 -2
- package/src/config/schemas/security.ts +0 -4
- package/src/config/types.ts +1 -1
- package/src/contacts/contact-store.ts +39 -0
- package/src/contacts/types.ts +2 -0
- package/src/credential-execution/approval-bridge.ts +1 -0
- package/src/credential-execution/executable-discovery.ts +28 -4
- package/src/credential-execution/feature-gates.ts +16 -0
- package/src/credential-execution/process-manager.ts +38 -0
- package/src/credential-execution/startup-timeout.ts +36 -0
- package/src/daemon/approval-generators.ts +3 -9
- package/src/daemon/assistant-attachments.ts +9 -0
- package/src/daemon/config-watcher.ts +5 -0
- package/src/daemon/conversation-error.ts +13 -1
- package/src/daemon/conversation-memory.ts +1 -2
- package/src/daemon/conversation-process.ts +18 -1
- package/src/daemon/conversation-surfaces.ts +30 -1
- package/src/daemon/conversation-tool-setup.ts +0 -105
- package/src/daemon/conversation.ts +21 -1
- package/src/daemon/guardian-action-generators.ts +3 -9
- package/src/daemon/handlers/config-vercel.ts +92 -0
- package/src/daemon/handlers/skills.ts +2 -15
- package/src/daemon/install-symlink.ts +195 -0
- package/src/daemon/lifecycle.ts +234 -51
- package/src/daemon/message-types/conversations.ts +4 -4
- package/src/daemon/message-types/diagnostics.ts +3 -22
- package/src/daemon/message-types/messages.ts +0 -2
- package/src/daemon/message-types/upgrades.ts +8 -0
- package/src/daemon/server.ts +32 -95
- package/src/events/domain-events.ts +2 -1
- package/src/inbound/platform-callback-registration.ts +3 -3
- package/src/instrument.ts +8 -5
- package/src/memory/app-store.ts +31 -0
- package/src/memory/conversation-title-service.ts +50 -1
- package/src/memory/db-init.ts +16 -0
- package/src/memory/indexer.ts +19 -10
- package/src/memory/items-extractor.ts +328 -321
- package/src/memory/job-handlers/conversation-starters.ts +4 -1
- package/src/memory/job-handlers/summarization.ts +26 -16
- package/src/memory/jobs-store.ts +63 -6
- package/src/memory/jobs-worker.ts +31 -7
- package/src/memory/journal-memory.ts +214 -0
- package/src/memory/migrations/001-job-deferrals.ts +19 -0
- package/src/memory/migrations/004-entity-relation-dedup.ts +10 -0
- package/src/memory/migrations/005-fingerprint-scope-unique.ts +76 -0
- package/src/memory/migrations/006-scope-salted-fingerprints.ts +50 -0
- package/src/memory/migrations/007-assistant-id-to-self.ts +10 -0
- package/src/memory/migrations/008-remove-assistant-id-columns.ts +34 -0
- package/src/memory/migrations/009-llm-usage-events-drop-assistant-id.ts +26 -0
- package/src/memory/migrations/014-backfill-inbox-thread-state.ts +10 -0
- package/src/memory/migrations/015-drop-active-search-index.ts +17 -0
- package/src/memory/migrations/019-notification-tables-schema-migration.ts +12 -0
- package/src/memory/migrations/020-rename-macos-ios-channel-to-vellum.ts +121 -0
- package/src/memory/migrations/024-embedding-vector-blob.ts +74 -0
- package/src/memory/migrations/026a-embeddings-nullable-vector-json.ts +82 -0
- package/src/memory/migrations/036-normalize-phone-identities.ts +11 -0
- package/src/memory/migrations/116-messages-fts.ts +106 -1
- package/src/memory/migrations/126-backfill-guardian-principal-id.ts +52 -0
- package/src/memory/migrations/127-guardian-principal-id-not-null.ts +77 -0
- package/src/memory/migrations/134-contacts-notes-column.ts +13 -0
- package/src/memory/migrations/135-backfill-contact-interaction-stats.ts +20 -0
- package/src/memory/migrations/136-drop-assistant-id-columns.ts +52 -0
- package/src/memory/migrations/140-backfill-usage-cache-accounting.ts +13 -0
- package/src/memory/migrations/141-rename-verification-table.ts +54 -0
- package/src/memory/migrations/142-rename-verification-session-id-column.ts +25 -0
- package/src/memory/migrations/143-rename-guardian-verification-values.ts +35 -0
- package/src/memory/migrations/144-rename-voice-to-phone.ts +136 -0
- package/src/memory/migrations/145-drop-accounts-table.ts +32 -0
- package/src/memory/migrations/147-migrate-reminders-to-schedules.ts +14 -1
- package/src/memory/migrations/148-drop-reminders-table.ts +35 -1
- package/src/memory/migrations/150-oauth-apps-client-secret-path.ts +69 -1
- package/src/memory/migrations/162-guardian-timestamps-epoch-ms.ts +290 -0
- package/src/memory/migrations/169-rename-gmail-provider-key-to-google.ts +51 -1
- package/src/memory/migrations/174-rename-thread-starters-table.ts +47 -1
- package/src/memory/migrations/176-drop-capability-card-state.ts +13 -0
- package/src/memory/migrations/180-backfill-inline-attachments-to-disk.ts +16 -0
- package/src/memory/migrations/181-rename-thread-starters-checkpoints.ts +28 -1
- package/src/memory/migrations/190-call-session-skip-disclosure.ts +15 -0
- package/src/memory/migrations/191-backfill-audio-attachment-mime-types.ts +64 -0
- package/src/memory/migrations/192-contacts-user-file-column.ts +15 -0
- package/src/memory/migrations/193-add-source-type-columns.ts +81 -0
- package/src/memory/migrations/index.ts +5 -0
- package/src/memory/migrations/registry.ts +98 -0
- package/src/memory/migrations/validate-migration-state.ts +137 -11
- package/src/memory/qdrant-circuit-breaker.ts +9 -0
- package/src/memory/qdrant-manager.ts +64 -7
- package/src/memory/retriever.test.ts +37 -25
- package/src/memory/retriever.ts +24 -49
- package/src/memory/schema/calls.ts +1 -0
- package/src/memory/schema/contacts.ts +1 -0
- package/src/memory/schema/memory-core.ts +2 -0
- package/src/memory/search/formatting.ts +7 -44
- package/src/memory/search/staleness.ts +4 -0
- package/src/memory/search/tier-classifier.ts +10 -2
- package/src/memory/search/types.ts +2 -5
- package/src/memory/task-memory-cleanup.ts +4 -3
- package/src/notifications/adapters/slack.ts +168 -6
- package/src/notifications/broadcaster.ts +1 -0
- package/src/notifications/copy-composer.ts +59 -2
- package/src/notifications/decision-engine.ts +4 -1
- package/src/notifications/signal.ts +2 -0
- package/src/notifications/types.ts +2 -0
- package/src/oauth/connection-resolver.ts +6 -4
- package/src/permissions/checker.ts +0 -38
- package/src/permissions/shell-identity.ts +76 -22
- package/src/permissions/types.ts +4 -2
- package/src/platform/client.ts +35 -7
- package/src/prompts/journal-context.ts +133 -0
- package/src/prompts/persona-resolver.ts +194 -0
- package/src/prompts/system-prompt.ts +44 -4
- package/src/prompts/templates/SOUL.md +10 -0
- package/src/prompts/templates/users/default.md +1 -0
- package/src/providers/provider-send-message.ts +3 -32
- package/src/providers/registry.ts +29 -179
- package/src/providers/types.ts +1 -1
- package/src/runtime/access-request-helper.ts +4 -0
- package/src/runtime/auth/__tests__/credential-service.test.ts +0 -1
- package/src/runtime/auth/__tests__/external-assistant-id.test.ts +13 -68
- package/src/runtime/auth/__tests__/guard-tests.test.ts +9 -50
- package/src/runtime/auth/external-assistant-id.ts +13 -59
- package/src/runtime/auth/route-policy.ts +17 -1
- package/src/runtime/auth/token-service.ts +43 -138
- package/src/runtime/channel-readiness-service.ts +1 -16
- package/src/runtime/gateway-client.ts +47 -4
- package/src/runtime/guardian-decision-types.ts +45 -4
- package/src/runtime/http-server.ts +31 -3
- package/src/runtime/middleware/error-handler.ts +1 -9
- package/src/runtime/routes/access-request-decision.ts +2 -2
- package/src/runtime/routes/app-management-routes.ts +2 -1
- package/src/runtime/routes/approval-strategies/guardian-callback-strategy.ts +219 -30
- package/src/runtime/routes/approval-strategies/guardian-text-engine-strategy.ts +37 -14
- package/src/runtime/routes/audio-routes.ts +40 -0
- package/src/runtime/routes/btw-routes.ts +0 -17
- package/src/runtime/routes/channel-readiness-routes.ts +9 -4
- package/src/runtime/routes/conversation-query-routes.ts +63 -1
- package/src/runtime/routes/conversation-routes.ts +4 -44
- package/src/runtime/routes/debug-routes.ts +12 -9
- package/src/runtime/routes/diagnostics-routes.ts +1 -477
- package/src/runtime/routes/guardian-approval-interception.ts +168 -11
- package/src/runtime/routes/guardian-approval-prompt.ts +6 -1
- package/src/runtime/routes/guardian-approval-reply-helpers.ts +103 -21
- package/src/runtime/routes/identity-routes.ts +19 -30
- package/src/runtime/routes/inbound-message-handler.ts +31 -1
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +64 -5
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +52 -40
- package/src/runtime/routes/inbound-stages/secret-ingress-check.ts +4 -33
- package/src/runtime/routes/inbound-stages/transcribe-audio.test.ts +1 -1
- package/src/runtime/routes/integrations/twilio.ts +52 -10
- package/src/runtime/routes/integrations/vercel.ts +89 -0
- package/src/runtime/routes/log-export-routes.ts +5 -0
- package/src/runtime/routes/memory-item-routes.test.ts +3 -3
- package/src/runtime/routes/memory-item-routes.ts +46 -14
- package/src/runtime/routes/migration-rollback-routes.ts +209 -0
- package/src/runtime/routes/migration-routes.ts +17 -1
- package/src/runtime/routes/notification-routes.ts +58 -0
- package/src/runtime/routes/schedule-routes.ts +65 -0
- package/src/runtime/routes/secret-routes.ts +141 -10
- package/src/runtime/routes/settings-routes.ts +41 -1
- package/src/runtime/routes/tts-routes.ts +96 -0
- package/src/runtime/routes/upgrade-broadcast-routes.ts +26 -2
- package/src/runtime/routes/workspace-commit-routes.ts +62 -0
- package/src/runtime/routes/workspace-routes.test.ts +22 -1
- package/src/runtime/routes/workspace-routes.ts +1 -1
- package/src/runtime/routes/workspace-utils.ts +86 -2
- package/src/security/ces-credential-client.ts +75 -29
- package/src/security/ces-rpc-credential-backend.ts +86 -0
- package/src/security/credential-backend.ts +22 -92
- package/src/security/keychain-broker-client.ts +10 -2
- package/src/security/secure-keys.ts +113 -115
- package/src/skills/catalog-install.ts +6 -32
- package/src/skills/skill-memory.ts +1 -0
- package/src/subagent/manager.ts +2 -5
- package/src/telemetry/usage-telemetry-reporter.ts +4 -2
- package/src/tools/acp/spawn.ts +78 -1
- package/src/tools/calls/call-start.ts +1 -0
- package/src/tools/credentials/vault.ts +5 -3
- package/src/tools/executor.ts +0 -4
- package/src/tools/memory/definitions.ts +3 -2
- package/src/tools/memory/handlers.ts +10 -7
- package/src/tools/network/script-proxy/session-manager.ts +19 -4
- package/src/tools/network/web-fetch.ts +3 -1
- package/src/tools/skills/execute.ts +1 -1
- package/src/tools/terminal/safe-env.ts +1 -0
- package/src/tools/types.ts +0 -8
- package/src/util/browser.ts +15 -0
- package/src/util/errors.ts +0 -12
- package/src/util/platform.ts +4 -51
- package/src/workspace/git-service.ts +5 -2
- package/src/workspace/migrations/001-avatar-rename.ts +15 -0
- package/src/workspace/migrations/003-seed-device-id.ts +17 -1
- package/src/workspace/migrations/004-extract-collect-usage-data.ts +33 -0
- package/src/workspace/migrations/005-add-send-diagnostics.ts +3 -0
- package/src/workspace/migrations/006-services-config.ts +49 -0
- package/src/workspace/migrations/007-web-search-provider-rename.ts +27 -0
- package/src/workspace/migrations/008-voice-timeout-and-max-steps.ts +3 -0
- package/src/workspace/migrations/009-backfill-conversation-disk-view.ts +4 -0
- package/src/workspace/migrations/010-app-dir-rename.ts +78 -0
- package/src/workspace/migrations/011-backfill-installation-id.ts +11 -0
- package/src/workspace/migrations/012-rename-conversation-disk-view-dirs.ts +44 -0
- package/src/workspace/migrations/013-repair-conversation-disk-view.ts +5 -0
- package/src/workspace/migrations/015-migrate-credentials-to-keychain.ts +153 -0
- package/src/workspace/migrations/016-extract-feature-flags-to-protected.ts +156 -0
- package/src/workspace/migrations/016-migrate-credentials-from-keychain.ts +150 -0
- package/src/workspace/migrations/017-seed-persona-dirs.ts +96 -0
- package/src/workspace/migrations/018-rekey-compound-credential-keys.ts +184 -0
- package/src/workspace/migrations/019-scope-journal-to-guardian.ts +103 -0
- package/src/workspace/migrations/migrate-to-workspace-volume.ts +27 -5
- package/src/workspace/migrations/registry.ts +12 -0
- package/src/workspace/migrations/runner.ts +106 -2
- package/src/workspace/migrations/types.ts +4 -0
- package/src/workspace/provider-commit-message-generator.ts +12 -21
- package/src/__tests__/claude-code-skill-regression.test.ts +0 -206
- package/src/__tests__/claude-code-tool-profiles.test.ts +0 -99
- package/src/__tests__/diagnostics-export.test.ts +0 -288
- package/src/__tests__/local-gateway-health.test.ts +0 -209
- package/src/__tests__/provider-fail-open-selection.test.ts +0 -271
- package/src/__tests__/provider-failover-actual-provider.test.ts +0 -66
- package/src/__tests__/secret-ingress-handler.test.ts +0 -120
- package/src/__tests__/swarm-conversation-integration.test.ts +0 -358
- package/src/__tests__/swarm-dag-pathological.test.ts +0 -547
- package/src/__tests__/swarm-orchestrator.test.ts +0 -463
- package/src/__tests__/swarm-plan-validator.test.ts +0 -384
- package/src/__tests__/swarm-recursion.test.ts +0 -197
- package/src/__tests__/swarm-router-planner.test.ts +0 -234
- package/src/__tests__/swarm-tool.test.ts +0 -185
- package/src/__tests__/swarm-worker-backend.test.ts +0 -144
- package/src/__tests__/swarm-worker-runner.test.ts +0 -288
- package/src/commands/__tests__/cc-command-registry.test.ts +0 -396
- package/src/commands/cc-command-registry.ts +0 -248
- package/src/config/bundled-skills/claude-code/SKILL.md +0 -53
- package/src/config/bundled-skills/claude-code/TOOLS.json +0 -47
- package/src/config/bundled-skills/claude-code/tools/claude-code.ts +0 -12
- package/src/config/bundled-skills/orchestration/SKILL.md +0 -33
- package/src/config/bundled-skills/orchestration/TOOLS.json +0 -35
- package/src/config/bundled-skills/orchestration/tools/swarm-delegate.ts +0 -12
- package/src/config/schemas/swarm.ts +0 -82
- package/src/logfire.ts +0 -135
- package/src/memory/search/lexical.ts +0 -48
- package/src/providers/failover.ts +0 -186
- package/src/runtime/local-gateway-health.ts +0 -275
- package/src/security/secret-ingress.ts +0 -68
- package/src/swarm/backend-claude-code.ts +0 -225
- package/src/swarm/checkpoint.ts +0 -137
- package/src/swarm/graph-utils.ts +0 -53
- package/src/swarm/index.ts +0 -55
- package/src/swarm/limits.ts +0 -66
- package/src/swarm/orchestrator.ts +0 -424
- package/src/swarm/plan-validator.ts +0 -117
- package/src/swarm/router-planner.ts +0 -162
- package/src/swarm/router-prompts.ts +0 -39
- package/src/swarm/synthesizer.ts +0 -81
- package/src/swarm/types.ts +0 -72
- package/src/swarm/worker-backend.ts +0 -131
- package/src/swarm/worker-prompts.ts +0 -80
- package/src/swarm/worker-runner.ts +0 -170
- package/src/tools/claude-code/claude-code.ts +0 -610
- package/src/tools/swarm/delegate.ts +0 -205
|
@@ -281,3 +281,293 @@ function rebuildScopedApprovalGrants(raw: RawDb): void {
|
|
|
281
281
|
raw.exec("PRAGMA foreign_keys = ON");
|
|
282
282
|
}
|
|
283
283
|
}
|
|
284
|
+
|
|
285
|
+
// ---------------------------------------------------------------------------
|
|
286
|
+
// Down functions
|
|
287
|
+
// ---------------------------------------------------------------------------
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* Reverse v29: convert epoch ms timestamps back to ISO 8601 text in guardian
|
|
291
|
+
* tables.
|
|
292
|
+
*
|
|
293
|
+
* Uses SQLite's datetime() to reconstruct ISO 8601 strings from the integer
|
|
294
|
+
* values. The millisecond component is appended manually since datetime()
|
|
295
|
+
* only returns second precision.
|
|
296
|
+
*/
|
|
297
|
+
export function migrateGuardianTimestampsEpochMsDown(
|
|
298
|
+
database: DrizzleDb,
|
|
299
|
+
): void {
|
|
300
|
+
const raw = getSqliteFrom(database);
|
|
301
|
+
|
|
302
|
+
// Convert canonical_guardian_requests timestamp columns back to ISO 8601
|
|
303
|
+
raw.exec(/*sql*/ `
|
|
304
|
+
UPDATE canonical_guardian_requests
|
|
305
|
+
SET created_at = strftime('%Y-%m-%dT%H:%M:%S', created_at / 1000, 'unixepoch') || '.' || printf('%03d', created_at % 1000) || 'Z',
|
|
306
|
+
updated_at = strftime('%Y-%m-%dT%H:%M:%S', updated_at / 1000, 'unixepoch') || '.' || printf('%03d', updated_at % 1000) || 'Z',
|
|
307
|
+
expires_at = CASE
|
|
308
|
+
WHEN expires_at IS NOT NULL
|
|
309
|
+
THEN strftime('%Y-%m-%dT%H:%M:%S', expires_at / 1000, 'unixepoch') || '.' || printf('%03d', expires_at % 1000) || 'Z'
|
|
310
|
+
ELSE NULL
|
|
311
|
+
END
|
|
312
|
+
WHERE typeof(created_at) = 'integer'
|
|
313
|
+
`);
|
|
314
|
+
|
|
315
|
+
// Convert canonical_guardian_deliveries timestamp columns back to ISO 8601
|
|
316
|
+
raw.exec(/*sql*/ `
|
|
317
|
+
UPDATE canonical_guardian_deliveries
|
|
318
|
+
SET created_at = strftime('%Y-%m-%dT%H:%M:%S', created_at / 1000, 'unixepoch') || '.' || printf('%03d', created_at % 1000) || 'Z',
|
|
319
|
+
updated_at = strftime('%Y-%m-%dT%H:%M:%S', updated_at / 1000, 'unixepoch') || '.' || printf('%03d', updated_at % 1000) || 'Z'
|
|
320
|
+
WHERE typeof(created_at) = 'integer'
|
|
321
|
+
`);
|
|
322
|
+
|
|
323
|
+
// Convert scoped_approval_grants timestamp columns back to ISO 8601
|
|
324
|
+
raw.exec(/*sql*/ `
|
|
325
|
+
UPDATE scoped_approval_grants
|
|
326
|
+
SET expires_at = strftime('%Y-%m-%dT%H:%M:%S', expires_at / 1000, 'unixepoch') || '.' || printf('%03d', expires_at % 1000) || 'Z',
|
|
327
|
+
created_at = strftime('%Y-%m-%dT%H:%M:%S', created_at / 1000, 'unixepoch') || '.' || printf('%03d', created_at % 1000) || 'Z',
|
|
328
|
+
updated_at = strftime('%Y-%m-%dT%H:%M:%S', updated_at / 1000, 'unixepoch') || '.' || printf('%03d', updated_at % 1000) || 'Z',
|
|
329
|
+
consumed_at = CASE
|
|
330
|
+
WHEN consumed_at IS NOT NULL
|
|
331
|
+
THEN strftime('%Y-%m-%dT%H:%M:%S', consumed_at / 1000, 'unixepoch') || '.' || printf('%03d', consumed_at % 1000) || 'Z'
|
|
332
|
+
ELSE NULL
|
|
333
|
+
END
|
|
334
|
+
WHERE typeof(created_at) = 'integer'
|
|
335
|
+
`);
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
/**
|
|
339
|
+
* Reverse v30: rebuild guardian tables with TEXT affinity on timestamp columns.
|
|
340
|
+
*
|
|
341
|
+
* Restores the original TEXT column declarations so that timestamp columns
|
|
342
|
+
* have TEXT affinity (the state before the INTEGER rebuild).
|
|
343
|
+
*/
|
|
344
|
+
export function migrateGuardianTimestampsRebuildDown(
|
|
345
|
+
database: DrizzleDb,
|
|
346
|
+
): void {
|
|
347
|
+
const raw = getSqliteFrom(database);
|
|
348
|
+
|
|
349
|
+
rebuildCanonicalGuardianRequestsToText(raw);
|
|
350
|
+
rebuildCanonicalGuardianDeliveriesToText(raw);
|
|
351
|
+
rebuildScopedApprovalGrantsToText(raw);
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
function hasTextAffinity(raw: RawDb, table: string, column: string): boolean {
|
|
355
|
+
const row = raw
|
|
356
|
+
.query(
|
|
357
|
+
`SELECT type FROM pragma_table_info('${table}') WHERE name = '${column}'`,
|
|
358
|
+
)
|
|
359
|
+
.get() as { type: string } | null;
|
|
360
|
+
if (!row) return true; // column doesn't exist — nothing to fix
|
|
361
|
+
return row.type.toUpperCase() === "TEXT";
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
function rebuildCanonicalGuardianRequestsToText(raw: RawDb): void {
|
|
365
|
+
if (hasTextAffinity(raw, "canonical_guardian_requests", "created_at")) return;
|
|
366
|
+
|
|
367
|
+
raw.exec("PRAGMA foreign_keys = OFF");
|
|
368
|
+
try {
|
|
369
|
+
raw.exec("BEGIN");
|
|
370
|
+
|
|
371
|
+
raw.exec(/*sql*/ `
|
|
372
|
+
CREATE TABLE canonical_guardian_requests_rb (
|
|
373
|
+
id TEXT PRIMARY KEY,
|
|
374
|
+
kind TEXT NOT NULL,
|
|
375
|
+
source_type TEXT NOT NULL,
|
|
376
|
+
source_channel TEXT,
|
|
377
|
+
conversation_id TEXT,
|
|
378
|
+
requester_external_user_id TEXT,
|
|
379
|
+
requester_chat_id TEXT,
|
|
380
|
+
guardian_external_user_id TEXT,
|
|
381
|
+
guardian_principal_id TEXT,
|
|
382
|
+
call_session_id TEXT,
|
|
383
|
+
pending_question_id TEXT,
|
|
384
|
+
question_text TEXT,
|
|
385
|
+
request_code TEXT,
|
|
386
|
+
tool_name TEXT,
|
|
387
|
+
input_digest TEXT,
|
|
388
|
+
status TEXT NOT NULL DEFAULT 'pending',
|
|
389
|
+
answer_text TEXT,
|
|
390
|
+
decided_by_external_user_id TEXT,
|
|
391
|
+
decided_by_principal_id TEXT,
|
|
392
|
+
followup_state TEXT,
|
|
393
|
+
expires_at TEXT,
|
|
394
|
+
created_at TEXT NOT NULL,
|
|
395
|
+
updated_at TEXT NOT NULL
|
|
396
|
+
)
|
|
397
|
+
`);
|
|
398
|
+
|
|
399
|
+
raw.exec(/*sql*/ `
|
|
400
|
+
INSERT INTO canonical_guardian_requests_rb
|
|
401
|
+
SELECT id, kind, source_type, source_channel, conversation_id,
|
|
402
|
+
requester_external_user_id, requester_chat_id,
|
|
403
|
+
guardian_external_user_id, guardian_principal_id,
|
|
404
|
+
call_session_id, pending_question_id, question_text,
|
|
405
|
+
request_code, tool_name, input_digest, status, answer_text,
|
|
406
|
+
decided_by_external_user_id, decided_by_principal_id,
|
|
407
|
+
followup_state, expires_at, created_at, updated_at
|
|
408
|
+
FROM canonical_guardian_requests
|
|
409
|
+
`);
|
|
410
|
+
|
|
411
|
+
raw.exec(/*sql*/ `DROP TABLE canonical_guardian_requests`);
|
|
412
|
+
raw.exec(
|
|
413
|
+
/*sql*/ `ALTER TABLE canonical_guardian_requests_rb RENAME TO canonical_guardian_requests`,
|
|
414
|
+
);
|
|
415
|
+
|
|
416
|
+
raw.exec(
|
|
417
|
+
/*sql*/ `CREATE INDEX IF NOT EXISTS idx_canonical_guardian_requests_status ON canonical_guardian_requests(status)`,
|
|
418
|
+
);
|
|
419
|
+
raw.exec(
|
|
420
|
+
/*sql*/ `CREATE INDEX IF NOT EXISTS idx_canonical_guardian_requests_guardian ON canonical_guardian_requests(guardian_external_user_id, status)`,
|
|
421
|
+
);
|
|
422
|
+
raw.exec(
|
|
423
|
+
/*sql*/ `CREATE INDEX IF NOT EXISTS idx_canonical_guardian_requests_conversation ON canonical_guardian_requests(conversation_id, status)`,
|
|
424
|
+
);
|
|
425
|
+
raw.exec(
|
|
426
|
+
/*sql*/ `CREATE INDEX IF NOT EXISTS idx_canonical_guardian_requests_source ON canonical_guardian_requests(source_type, status)`,
|
|
427
|
+
);
|
|
428
|
+
raw.exec(
|
|
429
|
+
/*sql*/ `CREATE INDEX IF NOT EXISTS idx_canonical_guardian_requests_kind ON canonical_guardian_requests(kind, status)`,
|
|
430
|
+
);
|
|
431
|
+
raw.exec(
|
|
432
|
+
/*sql*/ `CREATE INDEX IF NOT EXISTS idx_canonical_guardian_requests_request_code ON canonical_guardian_requests(request_code)`,
|
|
433
|
+
);
|
|
434
|
+
|
|
435
|
+
raw.exec("COMMIT");
|
|
436
|
+
} catch (e) {
|
|
437
|
+
try {
|
|
438
|
+
raw.exec("ROLLBACK");
|
|
439
|
+
} catch {
|
|
440
|
+
/* no active transaction */
|
|
441
|
+
}
|
|
442
|
+
throw e;
|
|
443
|
+
} finally {
|
|
444
|
+
raw.exec("PRAGMA foreign_keys = ON");
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
function rebuildCanonicalGuardianDeliveriesToText(raw: RawDb): void {
|
|
449
|
+
if (hasTextAffinity(raw, "canonical_guardian_deliveries", "created_at"))
|
|
450
|
+
return;
|
|
451
|
+
|
|
452
|
+
raw.exec("PRAGMA foreign_keys = OFF");
|
|
453
|
+
try {
|
|
454
|
+
raw.exec("BEGIN");
|
|
455
|
+
|
|
456
|
+
raw.exec(/*sql*/ `
|
|
457
|
+
CREATE TABLE canonical_guardian_deliveries_rb (
|
|
458
|
+
id TEXT PRIMARY KEY,
|
|
459
|
+
request_id TEXT NOT NULL REFERENCES canonical_guardian_requests(id) ON DELETE CASCADE,
|
|
460
|
+
destination_channel TEXT NOT NULL,
|
|
461
|
+
destination_conversation_id TEXT,
|
|
462
|
+
destination_chat_id TEXT,
|
|
463
|
+
destination_message_id TEXT,
|
|
464
|
+
status TEXT NOT NULL DEFAULT 'pending',
|
|
465
|
+
created_at TEXT NOT NULL,
|
|
466
|
+
updated_at TEXT NOT NULL
|
|
467
|
+
)
|
|
468
|
+
`);
|
|
469
|
+
|
|
470
|
+
raw.exec(/*sql*/ `
|
|
471
|
+
INSERT INTO canonical_guardian_deliveries_rb
|
|
472
|
+
SELECT id, request_id, destination_channel, destination_conversation_id,
|
|
473
|
+
destination_chat_id, destination_message_id, status,
|
|
474
|
+
created_at, updated_at
|
|
475
|
+
FROM canonical_guardian_deliveries
|
|
476
|
+
`);
|
|
477
|
+
|
|
478
|
+
raw.exec(/*sql*/ `DROP TABLE canonical_guardian_deliveries`);
|
|
479
|
+
raw.exec(
|
|
480
|
+
/*sql*/ `ALTER TABLE canonical_guardian_deliveries_rb RENAME TO canonical_guardian_deliveries`,
|
|
481
|
+
);
|
|
482
|
+
|
|
483
|
+
raw.exec(
|
|
484
|
+
/*sql*/ `CREATE INDEX IF NOT EXISTS idx_canonical_guardian_deliveries_request_id ON canonical_guardian_deliveries(request_id)`,
|
|
485
|
+
);
|
|
486
|
+
raw.exec(
|
|
487
|
+
/*sql*/ `CREATE INDEX IF NOT EXISTS idx_canonical_guardian_deliveries_status ON canonical_guardian_deliveries(status)`,
|
|
488
|
+
);
|
|
489
|
+
raw.exec(
|
|
490
|
+
/*sql*/ `CREATE INDEX IF NOT EXISTS idx_canonical_guardian_deliveries_destination ON canonical_guardian_deliveries(destination_channel, destination_chat_id)`,
|
|
491
|
+
);
|
|
492
|
+
|
|
493
|
+
raw.exec("COMMIT");
|
|
494
|
+
} catch (e) {
|
|
495
|
+
try {
|
|
496
|
+
raw.exec("ROLLBACK");
|
|
497
|
+
} catch {
|
|
498
|
+
/* no active transaction */
|
|
499
|
+
}
|
|
500
|
+
throw e;
|
|
501
|
+
} finally {
|
|
502
|
+
raw.exec("PRAGMA foreign_keys = ON");
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
function rebuildScopedApprovalGrantsToText(raw: RawDb): void {
|
|
507
|
+
if (hasTextAffinity(raw, "scoped_approval_grants", "created_at")) return;
|
|
508
|
+
|
|
509
|
+
raw.exec("PRAGMA foreign_keys = OFF");
|
|
510
|
+
try {
|
|
511
|
+
raw.exec("BEGIN");
|
|
512
|
+
|
|
513
|
+
raw.exec(/*sql*/ `
|
|
514
|
+
CREATE TABLE scoped_approval_grants_rb (
|
|
515
|
+
id TEXT PRIMARY KEY,
|
|
516
|
+
scope_mode TEXT NOT NULL,
|
|
517
|
+
request_id TEXT,
|
|
518
|
+
tool_name TEXT,
|
|
519
|
+
input_digest TEXT,
|
|
520
|
+
request_channel TEXT NOT NULL,
|
|
521
|
+
decision_channel TEXT NOT NULL,
|
|
522
|
+
execution_channel TEXT,
|
|
523
|
+
conversation_id TEXT,
|
|
524
|
+
call_session_id TEXT,
|
|
525
|
+
requester_external_user_id TEXT,
|
|
526
|
+
guardian_external_user_id TEXT,
|
|
527
|
+
status TEXT NOT NULL,
|
|
528
|
+
expires_at TEXT NOT NULL,
|
|
529
|
+
consumed_at TEXT,
|
|
530
|
+
consumed_by_request_id TEXT,
|
|
531
|
+
created_at TEXT NOT NULL,
|
|
532
|
+
updated_at TEXT NOT NULL
|
|
533
|
+
)
|
|
534
|
+
`);
|
|
535
|
+
|
|
536
|
+
raw.exec(/*sql*/ `
|
|
537
|
+
INSERT INTO scoped_approval_grants_rb
|
|
538
|
+
SELECT id, scope_mode, request_id, tool_name, input_digest,
|
|
539
|
+
request_channel, decision_channel, execution_channel,
|
|
540
|
+
conversation_id, call_session_id,
|
|
541
|
+
requester_external_user_id, guardian_external_user_id,
|
|
542
|
+
status, expires_at, consumed_at, consumed_by_request_id,
|
|
543
|
+
created_at, updated_at
|
|
544
|
+
FROM scoped_approval_grants
|
|
545
|
+
`);
|
|
546
|
+
|
|
547
|
+
raw.exec(/*sql*/ `DROP TABLE scoped_approval_grants`);
|
|
548
|
+
raw.exec(
|
|
549
|
+
/*sql*/ `ALTER TABLE scoped_approval_grants_rb RENAME TO scoped_approval_grants`,
|
|
550
|
+
);
|
|
551
|
+
|
|
552
|
+
raw.exec(
|
|
553
|
+
/*sql*/ `CREATE INDEX IF NOT EXISTS idx_scoped_grants_request_id ON scoped_approval_grants(request_id) WHERE request_id IS NOT NULL`,
|
|
554
|
+
);
|
|
555
|
+
raw.exec(
|
|
556
|
+
/*sql*/ `CREATE INDEX IF NOT EXISTS idx_scoped_grants_tool_sig ON scoped_approval_grants(tool_name, input_digest) WHERE tool_name IS NOT NULL`,
|
|
557
|
+
);
|
|
558
|
+
raw.exec(
|
|
559
|
+
/*sql*/ `CREATE INDEX IF NOT EXISTS idx_scoped_grants_status_expires ON scoped_approval_grants(status, expires_at)`,
|
|
560
|
+
);
|
|
561
|
+
|
|
562
|
+
raw.exec("COMMIT");
|
|
563
|
+
} catch (e) {
|
|
564
|
+
try {
|
|
565
|
+
raw.exec("ROLLBACK");
|
|
566
|
+
} catch {
|
|
567
|
+
/* no active transaction */
|
|
568
|
+
}
|
|
569
|
+
throw e;
|
|
570
|
+
} finally {
|
|
571
|
+
raw.exec("PRAGMA foreign_keys = ON");
|
|
572
|
+
}
|
|
573
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { DrizzleDb } from "../db-connection.js";
|
|
2
|
+
import { getSqliteFrom } from "../db-connection.js";
|
|
2
3
|
import { withCrashRecovery } from "./validate-migration-state.js";
|
|
3
4
|
|
|
4
5
|
/**
|
|
@@ -62,3 +63,52 @@ export function migrateRenameGmailProviderKeyToGoogle(
|
|
|
62
63
|
},
|
|
63
64
|
);
|
|
64
65
|
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Reverse: rename "integration:google" back to "integration:gmail" across
|
|
69
|
+
* OAuth tables.
|
|
70
|
+
*
|
|
71
|
+
* Mirrors the forward migration logic but in the opposite direction. If
|
|
72
|
+
* `integration:gmail` already exists (shouldn't normally happen on rollback),
|
|
73
|
+
* deletes the google rows to avoid duplicates.
|
|
74
|
+
*/
|
|
75
|
+
export function migrateRenameGmailProviderKeyToGoogleDown(
|
|
76
|
+
database: DrizzleDb,
|
|
77
|
+
): void {
|
|
78
|
+
const raw = getSqliteFrom(database);
|
|
79
|
+
|
|
80
|
+
raw.exec("PRAGMA foreign_keys = OFF");
|
|
81
|
+
try {
|
|
82
|
+
const gmailExists = raw
|
|
83
|
+
.prepare(
|
|
84
|
+
/*sql*/ `SELECT 1 FROM oauth_providers WHERE provider_key = 'integration:gmail'`,
|
|
85
|
+
)
|
|
86
|
+
.get();
|
|
87
|
+
|
|
88
|
+
if (gmailExists) {
|
|
89
|
+
// Old gmail rows already exist — delete the google ones to avoid duplication.
|
|
90
|
+
raw.exec(
|
|
91
|
+
/*sql*/ `DELETE FROM oauth_connections WHERE provider_key = 'integration:google'`,
|
|
92
|
+
);
|
|
93
|
+
raw.exec(
|
|
94
|
+
/*sql*/ `DELETE FROM oauth_apps WHERE provider_key = 'integration:google'`,
|
|
95
|
+
);
|
|
96
|
+
raw.exec(
|
|
97
|
+
/*sql*/ `DELETE FROM oauth_providers WHERE provider_key = 'integration:google'`,
|
|
98
|
+
);
|
|
99
|
+
} else {
|
|
100
|
+
// Rename google back to gmail — children first, then parent.
|
|
101
|
+
raw.exec(
|
|
102
|
+
/*sql*/ `UPDATE oauth_connections SET provider_key = 'integration:gmail' WHERE provider_key = 'integration:google'`,
|
|
103
|
+
);
|
|
104
|
+
raw.exec(
|
|
105
|
+
/*sql*/ `UPDATE oauth_apps SET provider_key = 'integration:gmail' WHERE provider_key = 'integration:google'`,
|
|
106
|
+
);
|
|
107
|
+
raw.exec(
|
|
108
|
+
/*sql*/ `UPDATE oauth_providers SET provider_key = 'integration:gmail' WHERE provider_key = 'integration:google'`,
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
} finally {
|
|
112
|
+
raw.exec("PRAGMA foreign_keys = ON");
|
|
113
|
+
}
|
|
114
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { DrizzleDb } from "../db-connection.js";
|
|
2
|
+
import { getSqliteFrom } from "../db-connection.js";
|
|
2
3
|
import { withCrashRecovery } from "./validate-migration-state.js";
|
|
3
4
|
|
|
4
5
|
/**
|
|
@@ -51,3 +52,48 @@ export function migrateRenameThreadStartersTable(database: DrizzleDb): void {
|
|
|
51
52
|
},
|
|
52
53
|
);
|
|
53
54
|
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Reverse: rename conversation_starters back to thread_starters and recreate
|
|
58
|
+
* old index names.
|
|
59
|
+
*
|
|
60
|
+
* Idempotent — skips if the old table already exists or the new table is
|
|
61
|
+
* absent.
|
|
62
|
+
*/
|
|
63
|
+
export function migrateRenameThreadStartersTableDown(
|
|
64
|
+
database: DrizzleDb,
|
|
65
|
+
): void {
|
|
66
|
+
const raw = getSqliteFrom(database);
|
|
67
|
+
|
|
68
|
+
// Guard: new table must exist
|
|
69
|
+
const newTableExists = raw
|
|
70
|
+
.query(
|
|
71
|
+
`SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = 'conversation_starters'`,
|
|
72
|
+
)
|
|
73
|
+
.get();
|
|
74
|
+
if (!newTableExists) return;
|
|
75
|
+
|
|
76
|
+
// Guard: old table must not already exist
|
|
77
|
+
const oldTableExists = raw
|
|
78
|
+
.query(
|
|
79
|
+
`SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = 'thread_starters'`,
|
|
80
|
+
)
|
|
81
|
+
.get();
|
|
82
|
+
if (oldTableExists) return;
|
|
83
|
+
|
|
84
|
+
// Rename the table back
|
|
85
|
+
raw.exec(
|
|
86
|
+
/*sql*/ `ALTER TABLE conversation_starters RENAME TO thread_starters`,
|
|
87
|
+
);
|
|
88
|
+
|
|
89
|
+
// Drop new indexes and recreate with old names
|
|
90
|
+
raw.exec(/*sql*/ `DROP INDEX IF EXISTS idx_conversation_starters_batch`);
|
|
91
|
+
raw.exec(
|
|
92
|
+
/*sql*/ `CREATE INDEX IF NOT EXISTS idx_thread_starters_batch ON thread_starters(generation_batch, created_at)`,
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
raw.exec(/*sql*/ `DROP INDEX IF EXISTS idx_conversation_starters_card_type`);
|
|
96
|
+
raw.exec(
|
|
97
|
+
/*sql*/ `CREATE INDEX IF NOT EXISTS idx_thread_starters_card_type ON thread_starters(card_type, scope_id)`,
|
|
98
|
+
);
|
|
99
|
+
}
|
|
@@ -34,3 +34,16 @@ export function migrateDropCapabilityCardState(database: DrizzleDb): void {
|
|
|
34
34
|
raw.exec(/*sql*/ `DROP TABLE IF EXISTS capability_card_categories`);
|
|
35
35
|
});
|
|
36
36
|
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Reverse: no-op.
|
|
40
|
+
*
|
|
41
|
+
* The forward migration deleted rows (card-type conversation starters,
|
|
42
|
+
* generate_capability_cards jobs, capability_cards checkpoints) and dropped
|
|
43
|
+
* the capability_card_categories table. The deleted data cannot be restored
|
|
44
|
+
* — it was discarded as dead state after the capability card feature was
|
|
45
|
+
* removed.
|
|
46
|
+
*/
|
|
47
|
+
export function migrateDropCapabilityCardStateDown(_database: DrizzleDb): void {
|
|
48
|
+
// No-op — see comment above.
|
|
49
|
+
}
|
|
@@ -64,3 +64,19 @@ export function migrateBackfillInlineAttachmentsToDisk(
|
|
|
64
64
|
},
|
|
65
65
|
);
|
|
66
66
|
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Reverse: no-op.
|
|
70
|
+
*
|
|
71
|
+
* The forward migration moved attachment data from inline base64 in the
|
|
72
|
+
* database to on-disk files and cleared the dataBase64 column. The original
|
|
73
|
+
* base64 data has been deleted from the DB, and re-reading it from disk
|
|
74
|
+
* back into the database would be unreliable (file paths may have changed,
|
|
75
|
+
* disk files may have been cleaned up). The on-disk files remain intact
|
|
76
|
+
* and functional.
|
|
77
|
+
*/
|
|
78
|
+
export function migrateBackfillInlineAttachmentsToDiskDown(
|
|
79
|
+
_database: DrizzleDb,
|
|
80
|
+
): void {
|
|
81
|
+
// No-op — see comment above.
|
|
82
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { DrizzleDb } from "../db-connection.js";
|
|
2
|
+
import { getSqliteFrom } from "../db-connection.js";
|
|
2
3
|
import { withCrashRecovery } from "./validate-migration-state.js";
|
|
3
4
|
|
|
4
5
|
/**
|
|
@@ -44,3 +45,29 @@ export function migrateRenameThreadStartersCheckpoints(
|
|
|
44
45
|
},
|
|
45
46
|
);
|
|
46
47
|
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Reverse: rename checkpoint keys from "conversation_starters:" back to
|
|
51
|
+
* "thread_starters:" prefix.
|
|
52
|
+
*
|
|
53
|
+
* Mirrors the forward migration but in reverse. Handles collisions the same
|
|
54
|
+
* way — if an old-prefix key already exists, the new-prefix key is dropped.
|
|
55
|
+
*/
|
|
56
|
+
export function migrateRenameThreadStartersCheckpointsDown(
|
|
57
|
+
database: DrizzleDb,
|
|
58
|
+
): void {
|
|
59
|
+
const raw = getSqliteFrom(database);
|
|
60
|
+
|
|
61
|
+
// 1. Delete conversation_starters: keys where a corresponding
|
|
62
|
+
// thread_starters: key already exists.
|
|
63
|
+
raw.exec(/*sql*/ `DELETE FROM memory_checkpoints
|
|
64
|
+
WHERE key LIKE 'conversation_starters:%'
|
|
65
|
+
AND replace(key, 'conversation_starters:', 'thread_starters:') IN (
|
|
66
|
+
SELECT key FROM memory_checkpoints WHERE key LIKE 'thread_starters:%'
|
|
67
|
+
)`);
|
|
68
|
+
|
|
69
|
+
// 2. Rename remaining keys back to the old prefix.
|
|
70
|
+
raw.exec(
|
|
71
|
+
/*sql*/ `UPDATE memory_checkpoints SET key = replace(key, 'conversation_starters:', 'thread_starters:') WHERE key LIKE 'conversation_starters:%'`,
|
|
72
|
+
);
|
|
73
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { DrizzleDb } from "../db-connection.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Add skip_disclosure column to call_sessions so outbound calls can
|
|
5
|
+
* skip the disclosure announcement on a per-call basis.
|
|
6
|
+
*/
|
|
7
|
+
export function migrateCallSessionSkipDisclosure(database: DrizzleDb): void {
|
|
8
|
+
try {
|
|
9
|
+
database.run(
|
|
10
|
+
/*sql*/ `ALTER TABLE call_sessions ADD COLUMN skip_disclosure INTEGER NOT NULL DEFAULT 0`,
|
|
11
|
+
);
|
|
12
|
+
} catch {
|
|
13
|
+
/* already exists */
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import type { DrizzleDb } from "../db-connection.js";
|
|
2
|
+
import { getSqliteFrom } from "../db-connection.js";
|
|
3
|
+
import { withCrashRecovery } from "./validate-migration-state.js";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Backfill MIME types for audio attachments that were stored with
|
|
7
|
+
* "application/octet-stream" because the EXTENSION_MIME_MAP was
|
|
8
|
+
* missing audio format entries.
|
|
9
|
+
*
|
|
10
|
+
* Updates mime_type based on the file extension in original_filename.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
const AUDIO_EXT_MIME: Record<string, string> = {
|
|
14
|
+
mp3: "audio/mpeg",
|
|
15
|
+
wav: "audio/wav",
|
|
16
|
+
ogg: "audio/ogg",
|
|
17
|
+
flac: "audio/flac",
|
|
18
|
+
aac: "audio/aac",
|
|
19
|
+
m4a: "audio/x-m4a",
|
|
20
|
+
opus: "audio/opus",
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export function migrateBackfillAudioAttachmentMimeTypes(
|
|
24
|
+
database: DrizzleDb,
|
|
25
|
+
): void {
|
|
26
|
+
withCrashRecovery(
|
|
27
|
+
database,
|
|
28
|
+
"migration_backfill_audio_attachment_mime_types_v1",
|
|
29
|
+
() => {
|
|
30
|
+
const raw = getSqliteFrom(database);
|
|
31
|
+
|
|
32
|
+
for (const [ext, mime] of Object.entries(AUDIO_EXT_MIME)) {
|
|
33
|
+
const pattern = `%.${ext}`;
|
|
34
|
+
const result = raw
|
|
35
|
+
.query(
|
|
36
|
+
`UPDATE attachments
|
|
37
|
+
SET mime_type = ?, kind = 'document'
|
|
38
|
+
WHERE lower(original_filename) LIKE ?
|
|
39
|
+
AND mime_type = 'application/octet-stream'`,
|
|
40
|
+
)
|
|
41
|
+
.run(mime, pattern);
|
|
42
|
+
|
|
43
|
+
if ((result as { changes?: number }).changes) {
|
|
44
|
+
console.log(
|
|
45
|
+
`Backfilled ${(result as { changes: number }).changes} .${ext} attachments → ${mime}`,
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Reverse: no-op.
|
|
55
|
+
*
|
|
56
|
+
* The forward migration corrected incorrect MIME types (application/octet-stream)
|
|
57
|
+
* to their proper audio/* values. Restoring the wrong MIME types would break
|
|
58
|
+
* audio playback and file handling. The corrected values are the desired state.
|
|
59
|
+
*/
|
|
60
|
+
export function migrateBackfillAudioAttachmentMimeTypesDown(
|
|
61
|
+
_database: DrizzleDb,
|
|
62
|
+
): void {
|
|
63
|
+
// No-op — see comment above.
|
|
64
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { DrizzleDb } from "../db-connection.js";
|
|
2
|
+
import { getSqliteFrom } from "../db-connection.js";
|
|
3
|
+
import { withCrashRecovery } from "./validate-migration-state.js";
|
|
4
|
+
|
|
5
|
+
export function migrateContactsUserFileColumn(database: DrizzleDb): void {
|
|
6
|
+
withCrashRecovery(database, "migration_contacts_user_file_column_v1", () => {
|
|
7
|
+
const raw = getSqliteFrom(database);
|
|
8
|
+
|
|
9
|
+
try {
|
|
10
|
+
raw.exec(/*sql*/ `ALTER TABLE contacts ADD COLUMN user_file TEXT`);
|
|
11
|
+
} catch {
|
|
12
|
+
/* already exists */
|
|
13
|
+
}
|
|
14
|
+
});
|
|
15
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import type { DrizzleDb } from "../db-connection.js";
|
|
2
|
+
import { getSqliteFrom } from "../db-connection.js";
|
|
3
|
+
import { tableHasColumn } from "./schema-introspection.js";
|
|
4
|
+
import { withCrashRecovery } from "./validate-migration-state.js";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Add source_type and source_message_role columns to memory_items.
|
|
8
|
+
*
|
|
9
|
+
* - source_type: "extraction" (default) or "tool" — distinguishes how the
|
|
10
|
+
* memory was created (LLM/pattern extraction vs explicit tool/API save).
|
|
11
|
+
* - source_message_role: the role of the source message (e.g. "user",
|
|
12
|
+
* "assistant") when the item was created via extraction.
|
|
13
|
+
*
|
|
14
|
+
* Backfills:
|
|
15
|
+
* 1. Items with verification_state = "user_confirmed" → source_type = "tool"
|
|
16
|
+
* 2. source_message_role from the earliest source message's role via subquery
|
|
17
|
+
*/
|
|
18
|
+
export function migrateAddSourceTypeColumns(database: DrizzleDb): void {
|
|
19
|
+
withCrashRecovery(database, "migration_add_source_type_columns_v1", () => {
|
|
20
|
+
const raw = getSqliteFrom(database);
|
|
21
|
+
|
|
22
|
+
// Add source_type column if it doesn't exist
|
|
23
|
+
if (!tableHasColumn(database, "memory_items", "source_type")) {
|
|
24
|
+
raw.exec(
|
|
25
|
+
/*sql*/ `ALTER TABLE memory_items ADD COLUMN source_type TEXT NOT NULL DEFAULT 'extraction'`,
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Add source_message_role column if it doesn't exist
|
|
30
|
+
if (!tableHasColumn(database, "memory_items", "source_message_role")) {
|
|
31
|
+
raw.exec(
|
|
32
|
+
/*sql*/ `ALTER TABLE memory_items ADD COLUMN source_message_role TEXT`,
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Backfill source_type = 'tool' for items that were explicitly saved
|
|
37
|
+
raw.exec(
|
|
38
|
+
/*sql*/ `UPDATE memory_items SET source_type = 'tool' WHERE verification_state = 'user_confirmed'`,
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
// Backfill source_message_role from the earliest source message's role.
|
|
42
|
+
// Only backfill where source_message_role is currently NULL and a source
|
|
43
|
+
// message exists.
|
|
44
|
+
raw.exec(/*sql*/ `
|
|
45
|
+
UPDATE memory_items
|
|
46
|
+
SET source_message_role = (
|
|
47
|
+
SELECT m.role
|
|
48
|
+
FROM memory_item_sources mis
|
|
49
|
+
JOIN messages m ON m.id = mis.message_id
|
|
50
|
+
WHERE mis.memory_item_id = memory_items.id
|
|
51
|
+
ORDER BY mis.created_at ASC
|
|
52
|
+
LIMIT 1
|
|
53
|
+
)
|
|
54
|
+
WHERE source_message_role IS NULL
|
|
55
|
+
AND EXISTS (
|
|
56
|
+
SELECT 1
|
|
57
|
+
FROM memory_item_sources mis
|
|
58
|
+
WHERE mis.memory_item_id = memory_items.id
|
|
59
|
+
)
|
|
60
|
+
`);
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Reverse: drop source_type and source_message_role columns.
|
|
66
|
+
*
|
|
67
|
+
* SQLite doesn't support DROP COLUMN on older versions, but modern SQLite
|
|
68
|
+
* (3.35.0+) does. Since Bun bundles a modern SQLite, this is safe.
|
|
69
|
+
*/
|
|
70
|
+
export function migrateAddSourceTypeColumnsDown(database: DrizzleDb): void {
|
|
71
|
+
const raw = getSqliteFrom(database);
|
|
72
|
+
|
|
73
|
+
if (tableHasColumn(database, "memory_items", "source_type")) {
|
|
74
|
+
raw.exec(/*sql*/ `ALTER TABLE memory_items DROP COLUMN source_type`);
|
|
75
|
+
}
|
|
76
|
+
if (tableHasColumn(database, "memory_items", "source_message_role")) {
|
|
77
|
+
raw.exec(
|
|
78
|
+
/*sql*/ `ALTER TABLE memory_items DROP COLUMN source_message_role`,
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
@@ -128,6 +128,10 @@ export { migrateConversationForkLineage } from "./183-add-conversation-fork-line
|
|
|
128
128
|
export { migrateLlmRequestLogProvider } from "./184-llm-request-log-provider.js";
|
|
129
129
|
export { migrateScheduleQuietFlag } from "./188-schedule-quiet-flag.js";
|
|
130
130
|
export { migrateDropSimplifiedMemory } from "./189-drop-simplified-memory.js";
|
|
131
|
+
export { migrateCallSessionSkipDisclosure } from "./190-call-session-skip-disclosure.js";
|
|
132
|
+
export { migrateBackfillAudioAttachmentMimeTypes } from "./191-backfill-audio-attachment-mime-types.js";
|
|
133
|
+
export { migrateContactsUserFileColumn } from "./192-contacts-user-file-column.js";
|
|
134
|
+
export { migrateAddSourceTypeColumns } from "./193-add-source-type-columns.js";
|
|
131
135
|
export {
|
|
132
136
|
MIGRATION_REGISTRY,
|
|
133
137
|
type MigrationRegistryEntry,
|
|
@@ -135,6 +139,7 @@ export {
|
|
|
135
139
|
} from "./registry.js";
|
|
136
140
|
export {
|
|
137
141
|
recoverCrashedMigrations,
|
|
142
|
+
rollbackMemoryMigration,
|
|
138
143
|
validateMigrationState,
|
|
139
144
|
withCrashRecovery,
|
|
140
145
|
} from "./validate-migration-state.js";
|