@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,22 +28,6 @@ import type { ScopeProfile, TokenAudience, TokenClaims } from "./types.js";
|
|
|
28
28
|
|
|
29
29
|
const log = getLogger("token-service");
|
|
30
30
|
|
|
31
|
-
// ---------------------------------------------------------------------------
|
|
32
|
-
// Bootstrap sentinel error
|
|
33
|
-
// ---------------------------------------------------------------------------
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* Thrown when the gateway's signing-key bootstrap endpoint returns 403,
|
|
37
|
-
* indicating that bootstrap has already completed (daemon restart case).
|
|
38
|
-
* The caller should fall back to loading the key from disk.
|
|
39
|
-
*/
|
|
40
|
-
export class BootstrapAlreadyCompleted extends Error {
|
|
41
|
-
constructor() {
|
|
42
|
-
super("Gateway signing key bootstrap already completed");
|
|
43
|
-
this.name = "BootstrapAlreadyCompleted";
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
|
|
47
31
|
// ---------------------------------------------------------------------------
|
|
48
32
|
// Signing key management
|
|
49
33
|
// ---------------------------------------------------------------------------
|
|
@@ -58,28 +42,44 @@ function getSigningKeyPath(): string {
|
|
|
58
42
|
return join(getRootDir(), "protected", "actor-token-signing-key");
|
|
59
43
|
}
|
|
60
44
|
|
|
45
|
+
/**
|
|
46
|
+
* Load a signing key from disk. Returns the key buffer if found and valid,
|
|
47
|
+
* or undefined if the file does not exist or is invalid.
|
|
48
|
+
*
|
|
49
|
+
* Used in the Docker 403-fallback path where generating a new key would
|
|
50
|
+
* create a mismatch with the gateway's already-bootstrapped key.
|
|
51
|
+
*/
|
|
52
|
+
export function loadSigningKey(): Buffer | undefined {
|
|
53
|
+
const keyPath = getSigningKeyPath();
|
|
54
|
+
if (!existsSync(keyPath)) {
|
|
55
|
+
return undefined;
|
|
56
|
+
}
|
|
57
|
+
try {
|
|
58
|
+
const raw = readFileSync(keyPath);
|
|
59
|
+
if (raw.length === 32) {
|
|
60
|
+
log.info("Auth signing key loaded from disk");
|
|
61
|
+
return raw;
|
|
62
|
+
}
|
|
63
|
+
log.warn("Signing key file has unexpected length");
|
|
64
|
+
return undefined;
|
|
65
|
+
} catch (err) {
|
|
66
|
+
log.warn({ err }, "Failed to read signing key file");
|
|
67
|
+
return undefined;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
61
71
|
/**
|
|
62
72
|
* Load a signing key from disk or generate and persist a new one.
|
|
63
73
|
* Uses atomic-write + chmod 0o600 for safe persistence.
|
|
64
74
|
*/
|
|
65
75
|
export function loadOrCreateSigningKey(): Buffer {
|
|
66
|
-
const
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
if (existsSync(keyPath)) {
|
|
70
|
-
try {
|
|
71
|
-
const raw = readFileSync(keyPath);
|
|
72
|
-
if (raw.length === 32) {
|
|
73
|
-
log.info("Auth signing key loaded from disk");
|
|
74
|
-
return raw;
|
|
75
|
-
}
|
|
76
|
-
log.warn("Signing key file has unexpected length, regenerating");
|
|
77
|
-
} catch (err) {
|
|
78
|
-
log.warn({ err }, "Failed to read signing key file, regenerating");
|
|
79
|
-
}
|
|
76
|
+
const existing = loadSigningKey();
|
|
77
|
+
if (existing) {
|
|
78
|
+
return existing;
|
|
80
79
|
}
|
|
81
80
|
|
|
82
81
|
// Generate and persist a new key
|
|
82
|
+
const keyPath = getSigningKeyPath();
|
|
83
83
|
const newKey = randomBytes(32);
|
|
84
84
|
const dir = dirname(keyPath);
|
|
85
85
|
if (!existsSync(dir)) {
|
|
@@ -94,120 +94,25 @@ export function loadOrCreateSigningKey(): Buffer {
|
|
|
94
94
|
return newKey;
|
|
95
95
|
}
|
|
96
96
|
|
|
97
|
-
/**
|
|
98
|
-
* Fetch the shared signing key from the gateway's bootstrap endpoint.
|
|
99
|
-
*
|
|
100
|
-
* Used in Docker mode where the gateway owns the signing key and the daemon
|
|
101
|
-
* must fetch it at startup. Retries up to 30 times with 1s intervals to
|
|
102
|
-
* tolerate gateway startup delays.
|
|
103
|
-
*
|
|
104
|
-
* @returns A 32-byte Buffer containing the signing key.
|
|
105
|
-
* @throws {BootstrapAlreadyCompleted} If the gateway returns 403 (bootstrap
|
|
106
|
-
* already completed — daemon restart case). Caller should fall back to
|
|
107
|
-
* loading the key from disk.
|
|
108
|
-
* @throws {Error} If the gateway is unreachable after all retry attempts.
|
|
109
|
-
*/
|
|
110
|
-
export async function fetchSigningKeyFromGateway(): Promise<Buffer> {
|
|
111
|
-
const gatewayUrl = process.env.GATEWAY_INTERNAL_URL;
|
|
112
|
-
if (!gatewayUrl) {
|
|
113
|
-
throw new Error("GATEWAY_INTERNAL_URL not set — cannot fetch signing key");
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
const maxAttempts = 30;
|
|
117
|
-
const intervalMs = 1000;
|
|
118
|
-
|
|
119
|
-
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
120
|
-
let resp: Response | undefined;
|
|
121
|
-
try {
|
|
122
|
-
resp = await fetch(`${gatewayUrl}/internal/signing-key-bootstrap`, {
|
|
123
|
-
signal: AbortSignal.timeout(5000),
|
|
124
|
-
});
|
|
125
|
-
} catch (err) {
|
|
126
|
-
log.warn(
|
|
127
|
-
{ err, attempt },
|
|
128
|
-
"Signing key bootstrap: connection failed, retrying",
|
|
129
|
-
);
|
|
130
|
-
await Bun.sleep(intervalMs);
|
|
131
|
-
continue;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
if (resp.ok) {
|
|
135
|
-
const body = (await resp.json()) as { key: string };
|
|
136
|
-
const keyBuf = Buffer.from(body.key, "hex");
|
|
137
|
-
if (keyBuf.length !== 32) {
|
|
138
|
-
throw new Error(`Invalid signing key length: ${keyBuf.length}`);
|
|
139
|
-
}
|
|
140
|
-
log.info("Signing key fetched from gateway bootstrap endpoint");
|
|
141
|
-
return keyBuf;
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
if (resp.status === 403) {
|
|
145
|
-
// Bootstrap already completed — fall through to file-based load.
|
|
146
|
-
// This happens on daemon restart when the gateway lockfile persists.
|
|
147
|
-
log.info(
|
|
148
|
-
"Gateway signing key bootstrap already completed — loading from disk",
|
|
149
|
-
);
|
|
150
|
-
throw new BootstrapAlreadyCompleted();
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
log.warn(
|
|
154
|
-
{ status: resp.status, attempt },
|
|
155
|
-
"Signing key bootstrap: gateway not ready, retrying",
|
|
156
|
-
);
|
|
157
|
-
|
|
158
|
-
await Bun.sleep(intervalMs);
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
throw new Error("Signing key bootstrap: timed out waiting for gateway");
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
/**
|
|
165
|
-
* Persist a signing key to disk using an atomic-write pattern.
|
|
166
|
-
* Used after fetching the key from the gateway so daemon restarts can
|
|
167
|
-
* load it from disk when the gateway returns 403.
|
|
168
|
-
*/
|
|
169
|
-
function persistSigningKey(key: Buffer): void {
|
|
170
|
-
const keyPath = getSigningKeyPath();
|
|
171
|
-
const dir = dirname(keyPath);
|
|
172
|
-
if (!existsSync(dir)) {
|
|
173
|
-
mkdirSync(dir, { recursive: true });
|
|
174
|
-
}
|
|
175
|
-
const tmpPath = keyPath + ".tmp." + process.pid;
|
|
176
|
-
writeFileSync(tmpPath, key, { mode: 0o600 });
|
|
177
|
-
renameSync(tmpPath, keyPath);
|
|
178
|
-
chmodSync(keyPath, 0o600);
|
|
179
|
-
}
|
|
180
|
-
|
|
181
97
|
/**
|
|
182
98
|
* Resolve the signing key for the current environment.
|
|
183
99
|
*
|
|
184
|
-
*
|
|
185
|
-
*
|
|
186
|
-
*
|
|
187
|
-
* loading the key from disk.
|
|
188
|
-
*
|
|
189
|
-
* In local mode, delegates to the existing file-based loadOrCreateSigningKey().
|
|
100
|
+
* Resolution order:
|
|
101
|
+
* 1. ACTOR_TOKEN_SIGNING_KEY env var (hex-encoded, set by CLI for Docker)
|
|
102
|
+
* 2. File-based load/create (~/.vellum/protected/actor-token-signing-key)
|
|
190
103
|
*/
|
|
191
|
-
export
|
|
192
|
-
const
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
// Persist locally so daemon restarts (where gateway returns 403) load from disk.
|
|
199
|
-
persistSigningKey(key);
|
|
200
|
-
return key;
|
|
201
|
-
} catch (err) {
|
|
202
|
-
if (err instanceof BootstrapAlreadyCompleted) {
|
|
203
|
-
// Gateway already bootstrapped (daemon restart) — load from disk.
|
|
204
|
-
return loadOrCreateSigningKey();
|
|
205
|
-
}
|
|
206
|
-
throw err;
|
|
104
|
+
export function resolveSigningKey(): Buffer {
|
|
105
|
+
const envKey = process.env.ACTOR_TOKEN_SIGNING_KEY;
|
|
106
|
+
if (envKey) {
|
|
107
|
+
if (!/^[0-9a-f]{64}$/i.test(envKey)) {
|
|
108
|
+
throw new Error(
|
|
109
|
+
`Invalid ACTOR_TOKEN_SIGNING_KEY: expected 64 hex characters, got ${envKey.length} chars`,
|
|
110
|
+
);
|
|
207
111
|
}
|
|
112
|
+
log.info("Signing key loaded from ACTOR_TOKEN_SIGNING_KEY env var");
|
|
113
|
+
return Buffer.from(envKey, "hex");
|
|
208
114
|
}
|
|
209
115
|
|
|
210
|
-
// Local mode: use file-based load/create (unchanged behavior).
|
|
211
116
|
return loadOrCreateSigningKey();
|
|
212
117
|
}
|
|
213
118
|
|
|
@@ -246,7 +151,7 @@ export function isSigningKeyInitialized(): boolean {
|
|
|
246
151
|
|
|
247
152
|
/**
|
|
248
153
|
* Returns a short hex fingerprint of the current signing key.
|
|
249
|
-
* Used by
|
|
154
|
+
* Used by assistant_status to let clients detect instance switches.
|
|
250
155
|
*/
|
|
251
156
|
export function getSigningKeyFingerprint(): string {
|
|
252
157
|
return createHash("sha256")
|
|
@@ -15,7 +15,6 @@ import type {
|
|
|
15
15
|
ReadinessCheckResult,
|
|
16
16
|
SetupStatus,
|
|
17
17
|
} from "./channel-readiness-types.js";
|
|
18
|
-
import { probeLocalGatewayHealth } from "./local-gateway-health.js";
|
|
19
18
|
|
|
20
19
|
/** Remote check results are cached for 5 minutes before being considered stale. */
|
|
21
20
|
export const REMOTE_TTL_MS = 5 * 60 * 1000;
|
|
@@ -82,7 +81,7 @@ const voiceProbe: ChannelProbe = {
|
|
|
82
81
|
const hasPhone = !!resolveTwilioPhoneNumber();
|
|
83
82
|
const ingress = checkIngress();
|
|
84
83
|
|
|
85
|
-
|
|
84
|
+
return [
|
|
86
85
|
check(
|
|
87
86
|
"twilio_credentials",
|
|
88
87
|
hasCreds,
|
|
@@ -97,20 +96,6 @@ const voiceProbe: ChannelProbe = {
|
|
|
97
96
|
),
|
|
98
97
|
ingress,
|
|
99
98
|
];
|
|
100
|
-
|
|
101
|
-
if (ingress.passed) {
|
|
102
|
-
const gw = await probeLocalGatewayHealth();
|
|
103
|
-
checks.push(
|
|
104
|
-
check(
|
|
105
|
-
"gateway_health",
|
|
106
|
-
gw.healthy,
|
|
107
|
-
`Local gateway is serving requests at ${gw.target}`,
|
|
108
|
-
`Local gateway is not serving requests at ${gw.target}${gw.error ? `: ${gw.error}` : ""}`,
|
|
109
|
-
),
|
|
110
|
-
);
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
return checks;
|
|
114
99
|
},
|
|
115
100
|
};
|
|
116
101
|
|
|
@@ -6,6 +6,24 @@ import type { RuntimeAttachmentMetadata } from "./http-types.js";
|
|
|
6
6
|
|
|
7
7
|
const log = getLogger("gateway-client");
|
|
8
8
|
|
|
9
|
+
/**
|
|
10
|
+
* Error thrown when the gateway returns a non-OK response for channel delivery.
|
|
11
|
+
* Carries the optional `userMessage` field from the gateway so callers can
|
|
12
|
+
* surface actionable error text to end-users.
|
|
13
|
+
*/
|
|
14
|
+
export class ChannelDeliveryError extends Error {
|
|
15
|
+
readonly statusCode: number;
|
|
16
|
+
/** A user-facing error message from the gateway, if available. */
|
|
17
|
+
readonly userMessage?: string;
|
|
18
|
+
|
|
19
|
+
constructor(statusCode: number, body: string, userMessage?: string) {
|
|
20
|
+
super(`Channel reply delivery failed (${statusCode}): ${body}`);
|
|
21
|
+
this.name = "ChannelDeliveryError";
|
|
22
|
+
this.statusCode = statusCode;
|
|
23
|
+
this.userMessage = userMessage;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
9
27
|
const DELIVERY_TIMEOUT_MS = 30_000;
|
|
10
28
|
const MANAGED_OUTBOUND_SEND_PATH =
|
|
11
29
|
"/v1/internal/managed-gateway/outbound-send/";
|
|
@@ -37,6 +55,8 @@ export interface ChannelReplyPayload {
|
|
|
37
55
|
useBlocks?: boolean;
|
|
38
56
|
/** When provided, add or remove an emoji reaction on a message. */
|
|
39
57
|
reaction?: { action: "add" | "remove"; name: string; messageTs: string };
|
|
58
|
+
/** When provided, set or clear the Slack Assistants API thread status. */
|
|
59
|
+
assistantThreadStatus?: { channel: string; threadTs: string; status: string };
|
|
40
60
|
}
|
|
41
61
|
|
|
42
62
|
export interface ChannelDeliveryResult {
|
|
@@ -81,13 +101,36 @@ export async function deliverChannelReply(
|
|
|
81
101
|
|
|
82
102
|
if (!response.ok) {
|
|
83
103
|
const body = await response.text().catch(() => "<unreadable>");
|
|
104
|
+
|
|
105
|
+
// Try to extract userMessage from JSON error responses (e.g. from the
|
|
106
|
+
// Slack delivery endpoint) so callers can surface actionable errors.
|
|
107
|
+
let userMessage: string | undefined;
|
|
108
|
+
try {
|
|
109
|
+
const parsed = JSON.parse(body) as { userMessage?: string };
|
|
110
|
+
if (typeof parsed.userMessage === "string") {
|
|
111
|
+
userMessage = parsed.userMessage;
|
|
112
|
+
}
|
|
113
|
+
} catch {
|
|
114
|
+
// Body wasn't JSON — that's fine, userMessage stays undefined.
|
|
115
|
+
}
|
|
116
|
+
|
|
84
117
|
log.error(
|
|
85
|
-
{
|
|
118
|
+
{
|
|
119
|
+
status: response.status,
|
|
120
|
+
body,
|
|
121
|
+
callbackUrl,
|
|
122
|
+
chatId: payload.chatId,
|
|
123
|
+
...(userMessage && { userMessage }),
|
|
124
|
+
},
|
|
86
125
|
"Channel reply delivery failed",
|
|
87
126
|
);
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
127
|
+
if (userMessage) {
|
|
128
|
+
log.warn(
|
|
129
|
+
{ chatId: payload.chatId, userMessage },
|
|
130
|
+
"Gateway returned actionable error for user",
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
throw new ChannelDeliveryError(response.status, body, userMessage);
|
|
91
134
|
}
|
|
92
135
|
|
|
93
136
|
const result: ChannelDeliveryResult = { ok: true };
|
|
@@ -38,6 +38,8 @@ export interface GuardianDecisionAction {
|
|
|
38
38
|
action: string;
|
|
39
39
|
/** Human-readable label for the action. */
|
|
40
40
|
label: string;
|
|
41
|
+
/** Short explanation shown in rich-UI legends (Telegram, Slack). */
|
|
42
|
+
description?: string;
|
|
41
43
|
}
|
|
42
44
|
|
|
43
45
|
// ---------------------------------------------------------------------------
|
|
@@ -46,14 +48,27 @@ export interface GuardianDecisionAction {
|
|
|
46
48
|
|
|
47
49
|
/** Canonical set of all guardian decision actions with their labels. */
|
|
48
50
|
export const GUARDIAN_DECISION_ACTIONS = {
|
|
49
|
-
approve_once: {
|
|
50
|
-
|
|
51
|
+
approve_once: {
|
|
52
|
+
action: "approve_once",
|
|
53
|
+
label: "Approve once",
|
|
54
|
+
description: "This tool, this call only",
|
|
55
|
+
},
|
|
56
|
+
approve_10m: {
|
|
57
|
+
action: "approve_10m",
|
|
58
|
+
label: "Allow 10 min",
|
|
59
|
+
description: "All tools for 10 minutes",
|
|
60
|
+
},
|
|
51
61
|
approve_conversation: {
|
|
52
62
|
action: "approve_conversation",
|
|
53
63
|
label: "Allow conversation",
|
|
64
|
+
description: "All tools for this conversation",
|
|
65
|
+
},
|
|
66
|
+
approve_always: {
|
|
67
|
+
action: "approve_always",
|
|
68
|
+
label: "Approve always",
|
|
69
|
+
description: "This tool, permanently",
|
|
54
70
|
},
|
|
55
|
-
|
|
56
|
-
reject: { action: "reject", label: "Reject" },
|
|
71
|
+
reject: { action: "reject", label: "Reject", description: "Deny this call" },
|
|
57
72
|
} as const satisfies Record<string, GuardianDecisionAction>;
|
|
58
73
|
|
|
59
74
|
/**
|
|
@@ -89,6 +104,32 @@ export function buildDecisionActions(opts?: {
|
|
|
89
104
|
];
|
|
90
105
|
}
|
|
91
106
|
|
|
107
|
+
/**
|
|
108
|
+
* Build a compact legend string explaining each action, for rich-UI channels
|
|
109
|
+
* (Telegram, Slack) where buttons are shown but their scope isn't obvious.
|
|
110
|
+
*
|
|
111
|
+
* Accepts either `GuardianDecisionAction[]` or action ID strings and looks up
|
|
112
|
+
* descriptions from the canonical constants.
|
|
113
|
+
*/
|
|
114
|
+
export function buildActionLegend(
|
|
115
|
+
actionIds: readonly (string | { action?: string; id?: string })[],
|
|
116
|
+
): string {
|
|
117
|
+
const lookup = GUARDIAN_DECISION_ACTIONS as Record<
|
|
118
|
+
string,
|
|
119
|
+
GuardianDecisionAction | undefined
|
|
120
|
+
>;
|
|
121
|
+
const lines = actionIds
|
|
122
|
+
.map((a) => {
|
|
123
|
+
const id = typeof a === "string" ? a : (a.action ?? a.id ?? "");
|
|
124
|
+
const canonical = lookup[id];
|
|
125
|
+
return canonical?.description
|
|
126
|
+
? `• *${canonical.label}* — ${canonical.description}`
|
|
127
|
+
: null;
|
|
128
|
+
})
|
|
129
|
+
.filter(Boolean);
|
|
130
|
+
return lines.length > 0 ? lines.join("\n") : "";
|
|
131
|
+
}
|
|
132
|
+
|
|
92
133
|
/**
|
|
93
134
|
* Build the plain-text fallback instruction string that matches the given
|
|
94
135
|
* set of decision actions. Ensures the text always includes parser-compatible
|
|
@@ -106,6 +106,7 @@ import { handleServePage } from "./routes/app-routes.js";
|
|
|
106
106
|
import { appRouteDefinitions } from "./routes/app-routes.js";
|
|
107
107
|
import { approvalRouteDefinitions } from "./routes/approval-routes.js";
|
|
108
108
|
import { attachmentRouteDefinitions } from "./routes/attachment-routes.js";
|
|
109
|
+
import { handleGetAudio } from "./routes/audio-routes.js";
|
|
109
110
|
import { avatarRouteDefinitions } from "./routes/avatar-routes.js";
|
|
110
111
|
import { brainGraphRouteDefinitions } from "./routes/brain-graph-routes.js";
|
|
111
112
|
import { btwRouteDefinitions } from "./routes/btw-routes.js";
|
|
@@ -144,16 +145,22 @@ import { handleGuardianRefresh } from "./routes/guardian-refresh-routes.js";
|
|
|
144
145
|
import { hostBashRouteDefinitions } from "./routes/host-bash-routes.js";
|
|
145
146
|
import { hostCuRouteDefinitions } from "./routes/host-cu-routes.js";
|
|
146
147
|
import { hostFileRouteDefinitions } from "./routes/host-file-routes.js";
|
|
147
|
-
import {
|
|
148
|
-
|
|
148
|
+
import {
|
|
149
|
+
handleHealth,
|
|
150
|
+
handleReadyz,
|
|
151
|
+
identityRouteDefinitions,
|
|
152
|
+
} from "./routes/identity-routes.js";
|
|
149
153
|
import { slackChannelRouteDefinitions } from "./routes/integrations/slack/channel.js";
|
|
150
154
|
import { slackShareRouteDefinitions } from "./routes/integrations/slack/share.js";
|
|
151
155
|
import { telegramRouteDefinitions } from "./routes/integrations/telegram.js";
|
|
152
156
|
import { twilioRouteDefinitions } from "./routes/integrations/twilio.js";
|
|
157
|
+
import { vercelRouteDefinitions } from "./routes/integrations/vercel.js";
|
|
153
158
|
import { inviteRouteDefinitions } from "./routes/invite-routes.js";
|
|
154
159
|
import { logExportRouteDefinitions } from "./routes/log-export-routes.js";
|
|
155
160
|
import { memoryItemRouteDefinitions } from "./routes/memory-item-routes.js";
|
|
161
|
+
import { migrationRollbackRouteDefinitions } from "./routes/migration-rollback-routes.js";
|
|
156
162
|
import { migrationRouteDefinitions } from "./routes/migration-routes.js";
|
|
163
|
+
import { notificationRouteDefinitions } from "./routes/notification-routes.js";
|
|
157
164
|
import { oauthAppsRouteDefinitions } from "./routes/oauth-apps.js";
|
|
158
165
|
import type { PairingHandlerContext } from "./routes/pairing-routes.js";
|
|
159
166
|
import {
|
|
@@ -172,10 +179,12 @@ import { surfaceContentRouteDefinitions } from "./routes/surface-content-routes.
|
|
|
172
179
|
import { telemetryRouteDefinitions } from "./routes/telemetry-routes.js";
|
|
173
180
|
import { traceEventRouteDefinitions } from "./routes/trace-event-routes.js";
|
|
174
181
|
import { trustRulesRouteDefinitions } from "./routes/trust-rules-routes.js";
|
|
182
|
+
import { ttsRouteDefinitions } from "./routes/tts-routes.js";
|
|
175
183
|
import { upgradeBroadcastRouteDefinitions } from "./routes/upgrade-broadcast-routes.js";
|
|
176
184
|
import { usageRouteDefinitions } from "./routes/usage-routes.js";
|
|
177
185
|
import { watchRouteDefinitions } from "./routes/watch-routes.js";
|
|
178
186
|
import { workItemRouteDefinitions } from "./routes/work-items-routes.js";
|
|
187
|
+
import { workspaceCommitRouteDefinitions } from "./routes/workspace-commit-routes.js";
|
|
179
188
|
import { workspaceRouteDefinitions } from "./routes/workspace-routes.js";
|
|
180
189
|
|
|
181
190
|
// Re-export for consumers
|
|
@@ -464,7 +473,10 @@ export class RuntimeHttpServer {
|
|
|
464
473
|
server.timeout(req, 1800);
|
|
465
474
|
// Skip request logging for health-check probes to reduce log noise.
|
|
466
475
|
const url = new URL(req.url);
|
|
467
|
-
if (
|
|
476
|
+
if (
|
|
477
|
+
(url.pathname === "/healthz" || url.pathname === "/readyz") &&
|
|
478
|
+
req.method === "GET"
|
|
479
|
+
) {
|
|
468
480
|
return this.routeRequest(req, server);
|
|
469
481
|
}
|
|
470
482
|
return withRequestLogging(req, () => this.routeRequest(req, server));
|
|
@@ -481,6 +493,10 @@ export class RuntimeHttpServer {
|
|
|
481
493
|
return handleHealth();
|
|
482
494
|
}
|
|
483
495
|
|
|
496
|
+
if (path === "/readyz" && req.method === "GET") {
|
|
497
|
+
return handleReadyz();
|
|
498
|
+
}
|
|
499
|
+
|
|
484
500
|
// WebSocket upgrade for the Chrome extension browser relay.
|
|
485
501
|
if (
|
|
486
502
|
path === "/v1/browser-relay" &&
|
|
@@ -503,6 +519,13 @@ export class RuntimeHttpServer {
|
|
|
503
519
|
const twilioResponse = await this.handleTwilioWebhook(req, path);
|
|
504
520
|
if (twilioResponse) return twilioResponse;
|
|
505
521
|
|
|
522
|
+
// Audio serving endpoint — before auth check because Twilio
|
|
523
|
+
// fetches these URLs directly. The audioId is an unguessable UUID.
|
|
524
|
+
const audioMatch = path.match(/^\/v1\/audio\/([^/]+)$/);
|
|
525
|
+
if (audioMatch && req.method === "GET") {
|
|
526
|
+
return handleGetAudio(audioMatch[1]);
|
|
527
|
+
}
|
|
528
|
+
|
|
506
529
|
// Pairing endpoints (unauthenticated, secret-gated)
|
|
507
530
|
if (path === "/v1/pairing/request" && req.method === "POST") {
|
|
508
531
|
return await handlePairingRequest(req, this.pairingContext);
|
|
@@ -920,6 +943,8 @@ export class RuntimeHttpServer {
|
|
|
920
943
|
}),
|
|
921
944
|
...identityRouteDefinitions(),
|
|
922
945
|
...upgradeBroadcastRouteDefinitions(),
|
|
946
|
+
...workspaceCommitRouteDefinitions(),
|
|
947
|
+
...migrationRollbackRouteDefinitions(),
|
|
923
948
|
...debugRouteDefinitions(),
|
|
924
949
|
...usageRouteDefinitions(),
|
|
925
950
|
...telemetryRouteDefinitions(),
|
|
@@ -931,6 +956,7 @@ export class RuntimeHttpServer {
|
|
|
931
956
|
...scheduleRouteDefinitions({
|
|
932
957
|
sendMessageDeps: this.sendMessageDeps,
|
|
933
958
|
}),
|
|
959
|
+
...notificationRouteDefinitions(),
|
|
934
960
|
...diagnosticsRouteDefinitions(),
|
|
935
961
|
...logExportRouteDefinitions(),
|
|
936
962
|
...documentRouteDefinitions(),
|
|
@@ -961,6 +987,7 @@ export class RuntimeHttpServer {
|
|
|
961
987
|
}
|
|
962
988
|
: undefined,
|
|
963
989
|
}),
|
|
990
|
+
...ttsRouteDefinitions(),
|
|
964
991
|
|
|
965
992
|
// Browser relay — not extracted into a domain module because
|
|
966
993
|
// these two routes depend on the in-process extensionRelayServer
|
|
@@ -1165,6 +1192,7 @@ export class RuntimeHttpServer {
|
|
|
1165
1192
|
...slackChannelRouteDefinitions(),
|
|
1166
1193
|
...slackShareRouteDefinitions(),
|
|
1167
1194
|
...twilioRouteDefinitions(),
|
|
1195
|
+
...vercelRouteDefinitions(),
|
|
1168
1196
|
...channelReadinessRouteDefinitions(),
|
|
1169
1197
|
...oauthAppsRouteDefinitions(),
|
|
1170
1198
|
...attachmentRouteDefinitions(),
|
|
@@ -4,7 +4,6 @@
|
|
|
4
4
|
|
|
5
5
|
import {
|
|
6
6
|
ConfigError,
|
|
7
|
-
IngressBlockedError,
|
|
8
7
|
ProviderNotConfiguredError,
|
|
9
8
|
} from "../../util/errors.js";
|
|
10
9
|
import { getLogger } from "../../util/logger.js";
|
|
@@ -14,7 +13,7 @@ const log = getLogger("runtime-http");
|
|
|
14
13
|
|
|
15
14
|
/**
|
|
16
15
|
* Wrap an async endpoint handler with standard error handling.
|
|
17
|
-
* Catches
|
|
16
|
+
* Catches ConfigError (422) and generic errors (500).
|
|
18
17
|
*/
|
|
19
18
|
export async function withErrorHandling(
|
|
20
19
|
endpoint: string,
|
|
@@ -23,13 +22,6 @@ export async function withErrorHandling(
|
|
|
23
22
|
try {
|
|
24
23
|
return await handler();
|
|
25
24
|
} catch (err) {
|
|
26
|
-
if (err instanceof IngressBlockedError) {
|
|
27
|
-
log.warn(
|
|
28
|
-
{ endpoint, detectedTypes: err.detectedTypes },
|
|
29
|
-
"Blocked HTTP request containing secrets",
|
|
30
|
-
);
|
|
31
|
-
return httpError("UNPROCESSABLE_ENTITY", err.message, 422);
|
|
32
|
-
}
|
|
33
25
|
if (err instanceof ProviderNotConfiguredError) {
|
|
34
26
|
log.warn({ err, endpoint }, "No LLM provider configured");
|
|
35
27
|
return httpError(
|
|
@@ -116,7 +116,7 @@ export async function deliverVerificationCodeToGuardian(params: {
|
|
|
116
116
|
}): Promise<DeliveryResult> {
|
|
117
117
|
const text =
|
|
118
118
|
`You approved access for ${params.requesterIdentifier}. ` +
|
|
119
|
-
`Give them this verification code:
|
|
119
|
+
`Give them this verification code: \`${params.verificationCode}\`. ` +
|
|
120
120
|
`The code expires in 10 minutes.`;
|
|
121
121
|
|
|
122
122
|
try {
|
|
@@ -189,7 +189,7 @@ export async function deliverVerificationCodeToRequester(params: {
|
|
|
189
189
|
}): Promise<DeliveryResult> {
|
|
190
190
|
const text =
|
|
191
191
|
`Great news — your access request was approved! ` +
|
|
192
|
-
`Your verification code is:
|
|
192
|
+
`Your verification code is: \`${params.verificationCode}\`. ` +
|
|
193
193
|
`Reply with it here to complete verification. The code expires in 10 minutes.`;
|
|
194
194
|
|
|
195
195
|
const target = resolveRequesterTarget(params);
|
|
@@ -36,6 +36,7 @@ import {
|
|
|
36
36
|
getApp,
|
|
37
37
|
getAppDirPath,
|
|
38
38
|
getAppPreview,
|
|
39
|
+
inlineDistAssets,
|
|
39
40
|
isMultifileApp,
|
|
40
41
|
listApps,
|
|
41
42
|
queryAppRecords,
|
|
@@ -684,7 +685,7 @@ export function appManagementRouteDefinitions(): RouteDefinition[] {
|
|
|
684
685
|
}
|
|
685
686
|
}
|
|
686
687
|
if (existsSync(distIndex)) {
|
|
687
|
-
html = readFileSync(distIndex, "utf-8");
|
|
688
|
+
html = inlineDistAssets(appDir, readFileSync(distIndex, "utf-8"));
|
|
688
689
|
} else {
|
|
689
690
|
html = `<p>App compilation failed. Edit a source file to trigger a rebuild.</p>`;
|
|
690
691
|
}
|