@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
|
@@ -28,7 +28,6 @@ import {
|
|
|
28
28
|
memoryItems,
|
|
29
29
|
} from "../../memory/schema.js";
|
|
30
30
|
import { getLogger } from "../../util/logger.js";
|
|
31
|
-
import { truncate } from "../../util/truncate.js";
|
|
32
31
|
import { httpError } from "../http-errors.js";
|
|
33
32
|
import type { RouteContext, RouteDefinition } from "../http-router.js";
|
|
34
33
|
|
|
@@ -45,6 +44,8 @@ const VALID_KINDS = [
|
|
|
45
44
|
"decision",
|
|
46
45
|
"constraint",
|
|
47
46
|
"event",
|
|
47
|
+
"capability",
|
|
48
|
+
"journal",
|
|
48
49
|
] as const;
|
|
49
50
|
|
|
50
51
|
type MemoryItemKind = (typeof VALID_KINDS)[number];
|
|
@@ -154,7 +155,7 @@ async function searchItemsSemantic(
|
|
|
154
155
|
const sparse = generateSparseEmbedding(query);
|
|
155
156
|
const sparseVector = { indices: sparse.indices, values: sparse.values };
|
|
156
157
|
|
|
157
|
-
// Build Qdrant filter — items only, exclude
|
|
158
|
+
// Build Qdrant filter — items only, exclude sentinel
|
|
158
159
|
const mustConditions: Array<Record<string, unknown>> = [
|
|
159
160
|
{ key: "target_type", match: { value: "item" } },
|
|
160
161
|
];
|
|
@@ -167,10 +168,7 @@ async function searchItemsSemantic(
|
|
|
167
168
|
|
|
168
169
|
const filter = {
|
|
169
170
|
must: mustConditions,
|
|
170
|
-
must_not: [
|
|
171
|
-
{ key: "kind", match: { value: "capability" } },
|
|
172
|
-
{ key: "_meta", match: { value: true } },
|
|
173
|
-
],
|
|
171
|
+
must_not: [{ key: "_meta", match: { value: true } }],
|
|
174
172
|
};
|
|
175
173
|
|
|
176
174
|
const qdrant = getQdrantClient();
|
|
@@ -185,6 +183,11 @@ async function searchItemsSemantic(
|
|
|
185
183
|
);
|
|
186
184
|
|
|
187
185
|
const ids = results.map((r) => r.payload.target_id);
|
|
186
|
+
|
|
187
|
+
// Use the vector search result count as the pagination total.
|
|
188
|
+
// A DB-wide COUNT would include items with no embedding yet (lagging) and
|
|
189
|
+
// items irrelevant to the search query, inflating the total and causing
|
|
190
|
+
// clients to paginate into empty pages.
|
|
188
191
|
return { ids, total: ids.length };
|
|
189
192
|
} catch (err) {
|
|
190
193
|
log.warn({ err }, "Semantic memory search failed, falling back to SQL");
|
|
@@ -249,11 +252,24 @@ export async function handleListMemoryItems(url: URL): Promise<Response> {
|
|
|
249
252
|
offsetParam + limitParam,
|
|
250
253
|
);
|
|
251
254
|
|
|
252
|
-
|
|
255
|
+
if (pageIds.length === 0) {
|
|
256
|
+
return Response.json({ items: [], total: semanticResult.total });
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
// Re-apply the same DB-side filters used in the SQL path as defense-
|
|
260
|
+
// in-depth against stale Qdrant payloads leaking deleted/mismatched rows.
|
|
261
|
+
const hydrationConditions = [inArray(memoryItems.id, pageIds)];
|
|
262
|
+
if (statusParam && statusParam !== "all") {
|
|
263
|
+
hydrationConditions.push(eq(memoryItems.status, statusParam));
|
|
264
|
+
}
|
|
265
|
+
if (kindParam) {
|
|
266
|
+
hydrationConditions.push(eq(memoryItems.kind, kindParam));
|
|
267
|
+
}
|
|
268
|
+
|
|
253
269
|
const rows = db
|
|
254
270
|
.select()
|
|
255
271
|
.from(memoryItems)
|
|
256
|
-
.where(
|
|
272
|
+
.where(and(...hydrationConditions))
|
|
257
273
|
.all();
|
|
258
274
|
|
|
259
275
|
// Preserve Qdrant relevance ordering
|
|
@@ -279,8 +295,6 @@ export async function handleListMemoryItems(url: URL): Promise<Response> {
|
|
|
279
295
|
|
|
280
296
|
// ── SQL path (default or fallback) ──────────────────────────────────
|
|
281
297
|
const conditions = [];
|
|
282
|
-
// Hide system-managed capability memories (skill announcements) from the UI
|
|
283
|
-
conditions.push(ne(memoryItems.kind, "capability"));
|
|
284
298
|
if (statusParam && statusParam !== "all") {
|
|
285
299
|
conditions.push(eq(memoryItems.status, statusParam));
|
|
286
300
|
}
|
|
@@ -428,8 +442,8 @@ export async function handleCreateMemoryItem(
|
|
|
428
442
|
);
|
|
429
443
|
}
|
|
430
444
|
|
|
431
|
-
const trimmedSubject =
|
|
432
|
-
const trimmedStatement =
|
|
445
|
+
const trimmedSubject = subject.trim();
|
|
446
|
+
const trimmedStatement = statement.trim();
|
|
433
447
|
|
|
434
448
|
const scopeId = "default";
|
|
435
449
|
const fingerprint = computeMemoryFingerprint(
|
|
@@ -474,6 +488,7 @@ export async function handleCreateMemoryItem(
|
|
|
474
488
|
confidence: 0.95,
|
|
475
489
|
importance: importance ?? 0.8,
|
|
476
490
|
fingerprint,
|
|
491
|
+
sourceType: "tool",
|
|
477
492
|
verificationState: "user_confirmed",
|
|
478
493
|
scopeId,
|
|
479
494
|
firstSeenAt: now,
|
|
@@ -516,6 +531,7 @@ export async function handleUpdateMemoryItem(
|
|
|
516
531
|
kind?: string;
|
|
517
532
|
status?: string;
|
|
518
533
|
importance?: number;
|
|
534
|
+
sourceType?: string;
|
|
519
535
|
verificationState?: string;
|
|
520
536
|
};
|
|
521
537
|
|
|
@@ -540,13 +556,13 @@ export async function handleUpdateMemoryItem(
|
|
|
540
556
|
if (typeof body.subject !== "string") {
|
|
541
557
|
return httpError("BAD_REQUEST", "subject must be a string", 400);
|
|
542
558
|
}
|
|
543
|
-
set.subject =
|
|
559
|
+
set.subject = body.subject.trim();
|
|
544
560
|
}
|
|
545
561
|
if (body.statement !== undefined) {
|
|
546
562
|
if (typeof body.statement !== "string") {
|
|
547
563
|
return httpError("BAD_REQUEST", "statement must be a string", 400);
|
|
548
564
|
}
|
|
549
|
-
set.statement =
|
|
565
|
+
set.statement = body.statement.trim();
|
|
550
566
|
}
|
|
551
567
|
if (body.kind !== undefined) {
|
|
552
568
|
if (!isValidKind(body.kind)) {
|
|
@@ -564,8 +580,24 @@ export async function handleUpdateMemoryItem(
|
|
|
564
580
|
if (body.importance !== undefined) {
|
|
565
581
|
set.importance = body.importance;
|
|
566
582
|
}
|
|
583
|
+
if (body.sourceType !== undefined) {
|
|
584
|
+
set.sourceType = body.sourceType;
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
// Accept verificationState from clients that haven't migrated to sourceType yet.
|
|
588
|
+
// Map verificationState → sourceType for forward compat, and write both fields.
|
|
567
589
|
if (body.verificationState !== undefined) {
|
|
568
590
|
set.verificationState = body.verificationState;
|
|
591
|
+
// Map verificationState to sourceType if sourceType wasn't explicitly provided
|
|
592
|
+
if (body.sourceType === undefined) {
|
|
593
|
+
set.sourceType =
|
|
594
|
+
body.verificationState === "user_confirmed" ? "tool" : "extraction";
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
// If sourceType was set (either directly or via mapping), also write verificationState
|
|
598
|
+
if (body.sourceType !== undefined && body.verificationState === undefined) {
|
|
599
|
+
set.verificationState =
|
|
600
|
+
body.sourceType === "tool" ? "user_confirmed" : "assistant_inferred";
|
|
569
601
|
}
|
|
570
602
|
|
|
571
603
|
// If subject, statement, or kind changed, recompute fingerprint
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Migration rollback endpoint — rolls back DB and/or workspace migrations
|
|
3
|
+
* to a specified target version/migration ID.
|
|
4
|
+
*
|
|
5
|
+
* Protected by a route policy restricting access to gateway service
|
|
6
|
+
* principals only (`svc_gateway` with `internal.write` scope), following
|
|
7
|
+
* the same pattern as other gateway-forwarded control-plane endpoints.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { getDb } from "../../memory/db-connection.js";
|
|
11
|
+
import { getMaxMigrationVersion } from "../../memory/migrations/registry.js";
|
|
12
|
+
import { rollbackMemoryMigration } from "../../memory/migrations/validate-migration-state.js";
|
|
13
|
+
import { getWorkspaceDir } from "../../util/platform.js";
|
|
14
|
+
import { WORKSPACE_MIGRATIONS } from "../../workspace/migrations/registry.js";
|
|
15
|
+
import {
|
|
16
|
+
getLastWorkspaceMigrationId,
|
|
17
|
+
loadCheckpoints,
|
|
18
|
+
rollbackWorkspaceMigrations,
|
|
19
|
+
} from "../../workspace/migrations/runner.js";
|
|
20
|
+
import { httpError } from "../http-errors.js";
|
|
21
|
+
import type { RouteDefinition } from "../http-router.js";
|
|
22
|
+
|
|
23
|
+
export function migrationRollbackRouteDefinitions(): RouteDefinition[] {
|
|
24
|
+
return [
|
|
25
|
+
{
|
|
26
|
+
endpoint: "admin/rollback-migrations",
|
|
27
|
+
method: "POST",
|
|
28
|
+
handler: async ({ req }) => {
|
|
29
|
+
let body: unknown;
|
|
30
|
+
try {
|
|
31
|
+
body = await req.json();
|
|
32
|
+
} catch {
|
|
33
|
+
return httpError("BAD_REQUEST", "Invalid JSON body", 400);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (!body || typeof body !== "object") {
|
|
37
|
+
return httpError(
|
|
38
|
+
"BAD_REQUEST",
|
|
39
|
+
"Request body must be a JSON object",
|
|
40
|
+
400,
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const {
|
|
45
|
+
targetDbVersion,
|
|
46
|
+
targetWorkspaceMigrationId,
|
|
47
|
+
rollbackToRegistryCeiling,
|
|
48
|
+
} = body as {
|
|
49
|
+
targetDbVersion?: unknown;
|
|
50
|
+
targetWorkspaceMigrationId?: unknown;
|
|
51
|
+
rollbackToRegistryCeiling?: unknown;
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
// When rollbackToRegistryCeiling is true, auto-determine targets
|
|
55
|
+
// from this daemon's own migration registry ceilings.
|
|
56
|
+
let effectiveDbVersion = targetDbVersion as number | undefined;
|
|
57
|
+
let effectiveWorkspaceMigrationId = targetWorkspaceMigrationId as
|
|
58
|
+
| string
|
|
59
|
+
| undefined;
|
|
60
|
+
|
|
61
|
+
if (rollbackToRegistryCeiling === true) {
|
|
62
|
+
if (effectiveDbVersion === undefined)
|
|
63
|
+
effectiveDbVersion = getMaxMigrationVersion();
|
|
64
|
+
if (effectiveWorkspaceMigrationId === undefined)
|
|
65
|
+
effectiveWorkspaceMigrationId =
|
|
66
|
+
getLastWorkspaceMigrationId(WORKSPACE_MIGRATIONS) ?? undefined;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// At least one rollback target must be specified.
|
|
70
|
+
if (
|
|
71
|
+
effectiveDbVersion === undefined &&
|
|
72
|
+
effectiveWorkspaceMigrationId === undefined
|
|
73
|
+
) {
|
|
74
|
+
return httpError(
|
|
75
|
+
"BAD_REQUEST",
|
|
76
|
+
"At least one of targetDbVersion or targetWorkspaceMigrationId must be provided",
|
|
77
|
+
400,
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Validate effectiveDbVersion when provided.
|
|
82
|
+
if (effectiveDbVersion !== undefined) {
|
|
83
|
+
if (
|
|
84
|
+
typeof effectiveDbVersion !== "number" ||
|
|
85
|
+
!Number.isInteger(effectiveDbVersion) ||
|
|
86
|
+
effectiveDbVersion < 0
|
|
87
|
+
) {
|
|
88
|
+
return httpError(
|
|
89
|
+
"BAD_REQUEST",
|
|
90
|
+
"targetDbVersion must be a non-negative integer",
|
|
91
|
+
400,
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Validate effectiveWorkspaceMigrationId when provided.
|
|
97
|
+
if (effectiveWorkspaceMigrationId !== undefined) {
|
|
98
|
+
if (
|
|
99
|
+
typeof effectiveWorkspaceMigrationId !== "string" ||
|
|
100
|
+
effectiveWorkspaceMigrationId.length === 0
|
|
101
|
+
) {
|
|
102
|
+
return httpError(
|
|
103
|
+
"BAD_REQUEST",
|
|
104
|
+
"targetWorkspaceMigrationId must be a non-empty string",
|
|
105
|
+
400,
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Preflight: validate that the workspace migration ID exists in the
|
|
111
|
+
// registry BEFORE executing any mutations. This prevents the DB
|
|
112
|
+
// rollback from committing when the workspace target is invalid.
|
|
113
|
+
let resolvedTargetIndex = -1;
|
|
114
|
+
if (effectiveWorkspaceMigrationId !== undefined) {
|
|
115
|
+
const targetId = effectiveWorkspaceMigrationId as string;
|
|
116
|
+
resolvedTargetIndex = WORKSPACE_MIGRATIONS.findIndex(
|
|
117
|
+
(m) => m.id === targetId,
|
|
118
|
+
);
|
|
119
|
+
if (resolvedTargetIndex === -1) {
|
|
120
|
+
return httpError(
|
|
121
|
+
"BAD_REQUEST",
|
|
122
|
+
`Target workspace migration "${targetId}" not found in the registry`,
|
|
123
|
+
400,
|
|
124
|
+
);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const rolledBack: { db: string[]; workspace: string[] } = {
|
|
129
|
+
db: [],
|
|
130
|
+
workspace: [],
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
// Roll back DB migrations if requested.
|
|
134
|
+
if (effectiveDbVersion !== undefined) {
|
|
135
|
+
try {
|
|
136
|
+
rolledBack.db = rollbackMemoryMigration(
|
|
137
|
+
getDb(),
|
|
138
|
+
effectiveDbVersion,
|
|
139
|
+
);
|
|
140
|
+
} catch (err) {
|
|
141
|
+
const detail = err instanceof Error ? err.message : "Unknown error";
|
|
142
|
+
return httpError(
|
|
143
|
+
"INTERNAL_ERROR",
|
|
144
|
+
`DB migration rollback failed: ${detail}`,
|
|
145
|
+
500,
|
|
146
|
+
);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// Roll back workspace migrations if requested.
|
|
151
|
+
if (effectiveWorkspaceMigrationId !== undefined) {
|
|
152
|
+
const workspaceDir = getWorkspaceDir();
|
|
153
|
+
|
|
154
|
+
// Compute which migrations are candidates for rollback before
|
|
155
|
+
// executing, since rollbackWorkspaceMigrations returns void.
|
|
156
|
+
const targetId = effectiveWorkspaceMigrationId;
|
|
157
|
+
|
|
158
|
+
const checkpointsBefore = loadCheckpoints(workspaceDir);
|
|
159
|
+
const candidateIds = WORKSPACE_MIGRATIONS.slice(
|
|
160
|
+
resolvedTargetIndex + 1,
|
|
161
|
+
)
|
|
162
|
+
.filter((m) => {
|
|
163
|
+
const entry = checkpointsBefore.applied[m.id];
|
|
164
|
+
return (
|
|
165
|
+
entry &&
|
|
166
|
+
entry.status !== "started" &&
|
|
167
|
+
entry.status !== "rolling_back"
|
|
168
|
+
);
|
|
169
|
+
})
|
|
170
|
+
.map((m) => m.id);
|
|
171
|
+
|
|
172
|
+
try {
|
|
173
|
+
await rollbackWorkspaceMigrations(
|
|
174
|
+
workspaceDir,
|
|
175
|
+
WORKSPACE_MIGRATIONS,
|
|
176
|
+
targetId,
|
|
177
|
+
);
|
|
178
|
+
|
|
179
|
+
rolledBack.workspace = candidateIds;
|
|
180
|
+
} catch (err) {
|
|
181
|
+
// Re-read checkpoints to determine which migrations were actually
|
|
182
|
+
// rolled back before the error occurred. A candidate whose entry
|
|
183
|
+
// is no longer present in the checkpoint file was successfully
|
|
184
|
+
// reverted.
|
|
185
|
+
const checkpointsAfter = loadCheckpoints(workspaceDir);
|
|
186
|
+
const actuallyRolledBack = candidateIds.filter(
|
|
187
|
+
(id) => !checkpointsAfter.applied[id],
|
|
188
|
+
);
|
|
189
|
+
|
|
190
|
+
const detail = err instanceof Error ? err.message : "Unknown error";
|
|
191
|
+
return httpError(
|
|
192
|
+
"INTERNAL_ERROR",
|
|
193
|
+
`Workspace migration rollback failed: ${detail}`,
|
|
194
|
+
500,
|
|
195
|
+
{
|
|
196
|
+
partialRolledBack: {
|
|
197
|
+
db: rolledBack.db,
|
|
198
|
+
workspace: actuallyRolledBack,
|
|
199
|
+
},
|
|
200
|
+
},
|
|
201
|
+
);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
return Response.json({ ok: true, rolledBack });
|
|
206
|
+
},
|
|
207
|
+
},
|
|
208
|
+
];
|
|
209
|
+
}
|
|
@@ -15,7 +15,8 @@ import { join } from "node:path";
|
|
|
15
15
|
import { Database } from "bun:sqlite";
|
|
16
16
|
|
|
17
17
|
import { invalidateConfigCache } from "../../config/loader.js";
|
|
18
|
-
import { resetDb } from "../../memory/db-connection.js";
|
|
18
|
+
import { getDb, resetDb } from "../../memory/db-connection.js";
|
|
19
|
+
import { validateMigrationState } from "../../memory/migrations/validate-migration-state.js";
|
|
19
20
|
import { clearCache as clearTrustCache } from "../../permissions/trust-store.js";
|
|
20
21
|
import { getLogger } from "../../util/logger.js";
|
|
21
22
|
import {
|
|
@@ -438,6 +439,21 @@ export async function handleMigrationImport(req: Request): Promise<Response> {
|
|
|
438
439
|
invalidateConfigCache();
|
|
439
440
|
clearTrustCache();
|
|
440
441
|
|
|
442
|
+
// Check whether the imported database contains migration checkpoints from
|
|
443
|
+
// a newer version. This is non-blocking — the import has already
|
|
444
|
+
// succeeded — but we surface a warning so the caller knows some data may
|
|
445
|
+
// not be fully compatible with this daemon's schema.
|
|
446
|
+
try {
|
|
447
|
+
const migrationValidation = validateMigrationState(getDb());
|
|
448
|
+
if (migrationValidation.unknownCheckpoints.length > 0) {
|
|
449
|
+
result.report.warnings.push(
|
|
450
|
+
`Imported data contains ${migrationValidation.unknownCheckpoints.length} migration(s) from a newer version. Some data may not be fully compatible.`,
|
|
451
|
+
);
|
|
452
|
+
}
|
|
453
|
+
} catch {
|
|
454
|
+
// Don't fail the import if validation itself errors
|
|
455
|
+
}
|
|
456
|
+
|
|
441
457
|
return Response.json(result.report);
|
|
442
458
|
} catch (err) {
|
|
443
459
|
log.error({ err }, "Unexpected error during import commit");
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Route handlers for notification delivery acknowledgments.
|
|
3
|
+
*
|
|
4
|
+
* Provides a REST endpoint for clients to report the outcome of
|
|
5
|
+
* local notification delivery (UNUserNotificationCenter.add).
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { eq } from "drizzle-orm";
|
|
9
|
+
|
|
10
|
+
import { getDb } from "../../memory/db.js";
|
|
11
|
+
import { notificationDeliveries } from "../../memory/schema.js";
|
|
12
|
+
import { httpError } from "../http-errors.js";
|
|
13
|
+
import type { RouteDefinition } from "../http-router.js";
|
|
14
|
+
|
|
15
|
+
export function notificationRouteDefinitions(): RouteDefinition[] {
|
|
16
|
+
return [
|
|
17
|
+
// POST /v1/notification-intent-result — client ack for notification delivery
|
|
18
|
+
{
|
|
19
|
+
endpoint: "notification-intent-result",
|
|
20
|
+
method: "POST",
|
|
21
|
+
policyKey: "notification-intent-result",
|
|
22
|
+
handler: async ({ req }) => {
|
|
23
|
+
const body = (await req.json()) as {
|
|
24
|
+
deliveryId?: string;
|
|
25
|
+
success?: boolean;
|
|
26
|
+
errorMessage?: string;
|
|
27
|
+
errorCode?: string;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
if (!body.deliveryId || typeof body.deliveryId !== "string") {
|
|
31
|
+
return httpError("BAD_REQUEST", "deliveryId is required", 400);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const db = getDb();
|
|
35
|
+
const now = Date.now();
|
|
36
|
+
|
|
37
|
+
const updates: Record<string, unknown> = {
|
|
38
|
+
clientDeliveryStatus: body.success ? "delivered" : "client_failed",
|
|
39
|
+
clientDeliveryAt: now,
|
|
40
|
+
updatedAt: now,
|
|
41
|
+
};
|
|
42
|
+
if (body.errorMessage) {
|
|
43
|
+
updates.clientDeliveryError = body.errorMessage;
|
|
44
|
+
}
|
|
45
|
+
if (body.errorCode) {
|
|
46
|
+
updates.errorCode = body.errorCode;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
db.update(notificationDeliveries)
|
|
50
|
+
.set(updates)
|
|
51
|
+
.where(eq(notificationDeliveries.id, body.deliveryId))
|
|
52
|
+
.run();
|
|
53
|
+
|
|
54
|
+
return Response.json({ ok: true });
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
];
|
|
58
|
+
}
|
|
@@ -99,6 +99,59 @@ function handleCancelSchedule(id: string): Response {
|
|
|
99
99
|
return handleListSchedules();
|
|
100
100
|
}
|
|
101
101
|
|
|
102
|
+
const VALID_MODES = ["notify", "execute"] as const;
|
|
103
|
+
const VALID_ROUTING_INTENTS = [
|
|
104
|
+
"single_channel",
|
|
105
|
+
"multi_channel",
|
|
106
|
+
"all_channels",
|
|
107
|
+
] as const;
|
|
108
|
+
|
|
109
|
+
function handleUpdateSchedule(
|
|
110
|
+
id: string,
|
|
111
|
+
body: Record<string, unknown>,
|
|
112
|
+
): Response {
|
|
113
|
+
const updates: Record<string, unknown> = {};
|
|
114
|
+
|
|
115
|
+
if ("mode" in body && !VALID_MODES.includes(body.mode as (typeof VALID_MODES)[number])) {
|
|
116
|
+
return httpError("BAD_REQUEST", `Invalid mode: must be one of ${VALID_MODES.join(", ")}`, 400);
|
|
117
|
+
}
|
|
118
|
+
if ("routingIntent" in body && !VALID_ROUTING_INTENTS.includes(body.routingIntent as (typeof VALID_ROUTING_INTENTS)[number])) {
|
|
119
|
+
return httpError("BAD_REQUEST", `Invalid routingIntent: must be one of ${VALID_ROUTING_INTENTS.join(", ")}`, 400);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
for (const key of [
|
|
123
|
+
"name",
|
|
124
|
+
"expression",
|
|
125
|
+
"timezone",
|
|
126
|
+
"message",
|
|
127
|
+
"mode",
|
|
128
|
+
"routingIntent",
|
|
129
|
+
"quiet",
|
|
130
|
+
] as const) {
|
|
131
|
+
if (key in body) {
|
|
132
|
+
updates[key] = body[key];
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
try {
|
|
137
|
+
const updated = updateSchedule(id, updates);
|
|
138
|
+
if (!updated) {
|
|
139
|
+
return httpError("NOT_FOUND", "Schedule not found", 404);
|
|
140
|
+
}
|
|
141
|
+
log.info({ id, updates }, "Schedule updated via HTTP");
|
|
142
|
+
} catch (err) {
|
|
143
|
+
if (
|
|
144
|
+
err instanceof Error &&
|
|
145
|
+
(err.message.includes("Invalid") || err.message.includes("invalid"))
|
|
146
|
+
) {
|
|
147
|
+
return httpError("BAD_REQUEST", err.message, 400);
|
|
148
|
+
}
|
|
149
|
+
log.error({ err }, "Failed to update schedule");
|
|
150
|
+
return httpError("INTERNAL_ERROR", "Failed to update schedule", 500);
|
|
151
|
+
}
|
|
152
|
+
return handleListSchedules();
|
|
153
|
+
}
|
|
154
|
+
|
|
102
155
|
async function handleRunScheduleNow(
|
|
103
156
|
id: string,
|
|
104
157
|
sendMessageDeps?: SendMessageDeps,
|
|
@@ -243,6 +296,18 @@ export function scheduleRouteDefinitions(deps: {
|
|
|
243
296
|
policyKey: "schedules",
|
|
244
297
|
handler: ({ params }) => handleDeleteSchedule(params.id),
|
|
245
298
|
},
|
|
299
|
+
{
|
|
300
|
+
endpoint: "schedules/:id",
|
|
301
|
+
method: "PATCH",
|
|
302
|
+
policyKey: "schedules",
|
|
303
|
+
handler: async ({ req, params }) => {
|
|
304
|
+
const body: unknown = await req.json();
|
|
305
|
+
if (typeof body !== "object" || !body || Array.isArray(body)) {
|
|
306
|
+
return httpError("BAD_REQUEST", "Request body must be a JSON object", 400);
|
|
307
|
+
}
|
|
308
|
+
return handleUpdateSchedule(params.id, body as Record<string, unknown>);
|
|
309
|
+
},
|
|
310
|
+
},
|
|
246
311
|
{
|
|
247
312
|
endpoint: "schedules/:id/run",
|
|
248
313
|
method: "POST",
|