@vellumai/assistant 0.4.48 → 0.4.50
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ARCHITECTURE.md +26 -35
- package/README.md +5 -26
- package/docs/architecture/integrations.md +45 -41
- package/docs/architecture/keychain-broker.md +3 -3
- package/docs/architecture/memory.md +180 -119
- package/docs/runbook-trusted-contacts.md +3 -8
- package/hook-templates/debug-prompt-logger/hook.json +1 -1
- package/hook-templates/debug-prompt-logger/run.sh +1 -3
- package/package.json +2 -2
- package/src/__tests__/actor-token-service.test.ts +0 -1
- package/src/__tests__/agent-loop.test.ts +3 -1
- package/src/__tests__/anthropic-provider.test.ts +249 -2
- package/src/__tests__/approval-cascade.test.ts +796 -0
- package/src/__tests__/approval-primitive.test.ts +0 -1
- package/src/__tests__/approval-routes-http.test.ts +4 -0
- package/src/__tests__/assistant-attachments.test.ts +12 -34
- package/src/__tests__/assistant-feature-flag-guard.test.ts +0 -23
- package/src/__tests__/assistant-feature-flag-guardrails.test.ts +76 -0
- package/src/__tests__/assistant-feature-flags-integration.test.ts +0 -1
- package/src/__tests__/browser-skill-baseline-tool-payload.test.ts +2 -2
- package/src/__tests__/canonical-guardian-store.test.ts +95 -0
- package/src/__tests__/channel-guardian.test.ts +0 -2
- package/src/__tests__/channel-readiness-routes.test.ts +15 -6
- package/src/__tests__/channel-readiness-service.test.ts +10 -9
- package/src/__tests__/checker.test.ts +13 -20
- package/src/__tests__/computer-use-skill-manifest-regression.test.ts +1 -1
- package/src/__tests__/computer-use-tools.test.ts +2 -19
- package/src/__tests__/config-schema.test.ts +1 -68
- package/src/__tests__/config-watcher.test.ts +0 -1
- package/src/__tests__/confirmation-request-guardian-bridge.test.ts +0 -1
- package/src/__tests__/context-image-dimensions.test.ts +332 -0
- package/src/__tests__/context-memory-e2e.test.ts +11 -100
- package/src/__tests__/context-token-estimator.test.ts +196 -13
- package/src/__tests__/conversation-attention-store.test.ts +0 -1
- package/src/__tests__/conversation-attention-telegram.test.ts +0 -1
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +152 -0
- package/src/__tests__/conversation-routes-slash-commands.test.ts +2 -0
- package/src/__tests__/credential-metadata-store.test.ts +64 -73
- package/src/__tests__/credential-security-e2e.test.ts +1 -0
- package/src/__tests__/credential-security-invariants.test.ts +13 -7
- package/src/__tests__/credential-vault-unit.test.ts +284 -49
- package/src/__tests__/credential-vault.test.ts +150 -16
- package/src/__tests__/credentials-cli.test.ts +71 -0
- package/src/__tests__/cu-unified-flow.test.ts +532 -0
- package/src/__tests__/date-context.test.ts +93 -77
- package/src/__tests__/deterministic-verification-control-plane.test.ts +64 -0
- package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +0 -1
- package/src/__tests__/ephemeral-permissions.test.ts +3 -3
- package/src/__tests__/gateway-only-guard.test.ts +0 -1
- package/src/__tests__/guardian-action-grant-mint-consume.test.ts +0 -1
- package/src/__tests__/guardian-decision-primitive-canonical.test.ts +0 -1
- package/src/__tests__/guardian-routing-invariants.test.ts +93 -1
- package/src/__tests__/guardian-verification-voice-binding.test.ts +0 -1
- package/src/__tests__/handlers-user-message-approval-consumption.test.ts +0 -39
- package/src/__tests__/heartbeat-service.test.ts +0 -1
- package/src/__tests__/history-repair.test.ts +245 -0
- package/src/__tests__/host-cu-proxy.test.ts +791 -0
- package/src/__tests__/host-shell-tool.test.ts +27 -15
- package/src/__tests__/http-user-message-parity.test.ts +2 -0
- package/src/__tests__/ingress-url-consistency.test.ts +14 -21
- package/src/__tests__/integration-status.test.ts +32 -51
- package/src/__tests__/intent-routing.test.ts +0 -1
- package/src/__tests__/invite-redemption-service.test.ts +65 -1
- package/src/__tests__/invite-routes-http.test.ts +10 -9
- package/src/__tests__/keychain-broker-client.test.ts +14 -46
- package/src/__tests__/memory-context-benchmark.benchmark.test.ts +56 -18
- package/src/__tests__/memory-lifecycle-e2e.test.ts +244 -387
- package/src/__tests__/memory-recall-quality.test.ts +244 -407
- package/src/__tests__/memory-regressions.experimental.test.ts +126 -101
- package/src/__tests__/memory-regressions.test.ts +477 -2841
- package/src/__tests__/memory-retrieval.benchmark.test.ts +33 -150
- package/src/__tests__/memory-upsert-concurrency.test.ts +5 -244
- package/src/__tests__/mime-builder.test.ts +28 -0
- package/src/__tests__/native-web-search.test.ts +1 -0
- package/src/__tests__/notification-routing-intent.test.ts +0 -1
- package/src/__tests__/oauth-cli.test.ts +941 -15
- package/src/__tests__/oauth-provider-profiles.test.ts +9 -9
- package/src/__tests__/oauth-scope-policy.test.ts +4 -6
- package/src/__tests__/oauth-store.test.ts +870 -0
- package/src/__tests__/onboarding-starter-tasks.test.ts +0 -1
- package/src/__tests__/provider-error-scenarios.test.ts +0 -1
- package/src/__tests__/provider-streaming.benchmark.test.ts +0 -1
- package/src/__tests__/public-ingress-urls.test.ts +15 -21
- package/src/__tests__/qdrant-collection-migration.test.ts +53 -8
- package/src/__tests__/recording-handler.test.ts +3 -4
- package/src/__tests__/registry.test.ts +2 -3
- package/src/__tests__/relay-server.test.ts +46 -1
- package/src/__tests__/runtime-events-sse.test.ts +55 -7
- package/src/__tests__/schedule-store.test.ts +0 -1
- package/src/__tests__/schedule-tools.test.ts +32 -0
- package/src/__tests__/scheduler-recurrence.test.ts +0 -1
- package/src/__tests__/scoped-approval-grants.test.ts +0 -1
- package/src/__tests__/scoped-grant-security-matrix.test.ts +0 -1
- package/src/__tests__/script-proxy-certs.test.ts +1 -1
- package/src/__tests__/secret-ingress-handler.test.ts +0 -1
- package/src/__tests__/secret-onetime-send.test.ts +1 -0
- package/src/__tests__/secure-keys.test.ts +7 -2
- package/src/__tests__/send-endpoint-busy.test.ts +24 -6
- package/src/__tests__/sequence-store.test.ts +0 -1
- package/src/__tests__/session-abort-tool-results.test.ts +1 -14
- package/src/__tests__/session-agent-loop-overflow.test.ts +1583 -0
- package/src/__tests__/session-agent-loop.test.ts +19 -15
- package/src/__tests__/session-confirmation-signals.test.ts +1 -15
- package/src/__tests__/session-error.test.ts +124 -2
- package/src/__tests__/session-history-web-search.test.ts +918 -0
- package/src/__tests__/session-init.benchmark.test.ts +4 -5
- package/src/__tests__/session-pre-run-repair.test.ts +1 -14
- package/src/__tests__/session-provider-retry-repair.test.ts +25 -28
- package/src/__tests__/session-queue.test.ts +37 -27
- package/src/__tests__/session-runtime-assembly.test.ts +54 -0
- package/src/__tests__/session-slash-known.test.ts +1 -15
- package/src/__tests__/session-slash-queue.test.ts +1 -15
- package/src/__tests__/session-slash-unknown.test.ts +1 -15
- package/src/__tests__/session-workspace-cache-state.test.ts +3 -33
- package/src/__tests__/session-workspace-injection.test.ts +3 -37
- package/src/__tests__/session-workspace-tool-tracking.test.ts +3 -37
- package/src/__tests__/skill-include-graph.test.ts +66 -0
- package/src/__tests__/skill-load-feature-flag.test.ts +0 -1
- package/src/__tests__/skill-load-tool.test.ts +149 -1
- package/src/__tests__/skill-projection-feature-flag.test.ts +0 -1
- package/src/__tests__/skills-install-extract.test.ts +93 -0
- package/src/__tests__/skills-uninstall.test.ts +1 -1
- package/src/__tests__/skills.test.ts +3 -3
- package/src/__tests__/skillssh-registry.test.ts +451 -0
- package/src/__tests__/slack-channel-config.test.ts +67 -3
- package/src/__tests__/slack-share-routes.test.ts +17 -19
- package/src/__tests__/system-prompt.test.ts +0 -1
- package/src/__tests__/telegram-invite-adapter.test.ts +18 -22
- package/src/__tests__/terminal-tools.test.ts +4 -3
- package/src/__tests__/test-support/computer-use-skill-harness.ts +3 -2
- package/src/__tests__/tool-approval-handler.test.ts +0 -1
- package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +0 -1
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +0 -1
- package/src/__tests__/tool-executor-shell-integration.test.ts +0 -1
- package/src/__tests__/tool-executor.test.ts +0 -1
- package/src/__tests__/tool-grant-request-escalation.test.ts +0 -1
- package/src/__tests__/trust-store-pattern-matches.test.ts +29 -0
- package/src/__tests__/trust-store.test.ts +7 -13
- package/src/__tests__/trusted-contact-approval-notifier.test.ts +0 -1
- package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +0 -1
- package/src/__tests__/twilio-routes.test.ts +0 -16
- package/src/__tests__/verification-control-plane-policy.test.ts +0 -1
- package/src/__tests__/voice-invite-redemption.test.ts +32 -1
- package/src/__tests__/voice-scoped-grant-consumer.test.ts +0 -1
- package/src/agent/ax-tree-compaction.test.ts +286 -0
- package/src/agent/loop.ts +104 -131
- package/src/approvals/AGENTS.md +1 -1
- package/src/approvals/guardian-request-resolvers.ts +14 -2
- package/src/bundler/compiler-tools.ts +66 -2
- package/src/calls/call-domain.ts +133 -6
- package/src/calls/call-store.ts +6 -0
- package/src/calls/relay-server.ts +52 -18
- package/src/calls/relay-setup-router.ts +17 -1
- package/src/calls/twilio-config.ts +3 -8
- package/src/calls/twilio-routes.ts +1 -2
- package/src/calls/types.ts +3 -1
- package/src/calls/voice-ingress-preflight.ts +1 -1
- package/src/cli/commands/browser-relay.ts +18 -12
- package/src/cli/commands/completions.ts +0 -3
- package/src/cli/commands/credentials.ts +101 -15
- package/src/cli/commands/doctor.ts +4 -3
- package/src/cli/commands/mcp.ts +46 -59
- package/src/cli/commands/memory.ts +16 -165
- package/src/cli/commands/oauth/apps.ts +284 -0
- package/src/cli/commands/oauth/connections.ts +633 -0
- package/src/cli/commands/oauth/index.ts +52 -0
- package/src/cli/commands/oauth/providers.ts +256 -0
- package/src/cli/commands/sessions.ts +5 -2
- package/src/cli/commands/skills.ts +177 -339
- package/src/cli/http-client.ts +0 -20
- package/src/cli/main-screen.tsx +2 -2
- package/src/cli/program.ts +6 -11
- package/src/cli/reference.ts +1 -3
- package/src/cli.ts +4 -10
- package/src/config/assistant-feature-flags.ts +0 -3
- package/src/config/bundled-skills/_shared/CLI_RETRIEVAL_PATTERN.md +1 -1
- package/src/config/bundled-skills/computer-use/SKILL.md +3 -6
- package/src/config/bundled-skills/computer-use/TOOLS.json +23 -5
- package/src/config/bundled-skills/computer-use/tools/{computer-use-request-control.ts → computer-use-observe.ts} +1 -5
- package/src/config/bundled-skills/google-calendar/calendar-client.ts +21 -16
- package/src/config/bundled-skills/messaging/tools/shared.ts +1 -4
- package/src/config/bundled-skills/settings/SKILL.md +1 -1
- package/src/config/bundled-skills/settings/TOOLS.json +2 -8
- package/src/config/bundled-skills/settings/tools/voice-config-update.ts +5 -33
- package/src/config/bundled-tool-registry.ts +2 -5
- package/src/config/env-registry.ts +14 -83
- package/src/config/env.ts +11 -50
- package/src/config/feature-flag-registry.json +16 -16
- package/src/config/loader.ts +0 -6
- package/src/config/schema.ts +4 -13
- package/src/config/schemas/memory-lifecycle.ts +0 -9
- package/src/config/schemas/memory-processing.ts +0 -180
- package/src/config/schemas/memory-retrieval.ts +32 -104
- package/src/config/schemas/memory.ts +0 -10
- package/src/config/skills.ts +21 -2
- package/src/config/types.ts +0 -4
- package/src/context/image-dimensions.ts +229 -0
- package/src/context/token-estimator.ts +75 -12
- package/src/context/window-manager.ts +53 -11
- package/src/daemon/assistant-attachments.ts +1 -13
- package/src/daemon/config-watcher.ts +61 -3
- package/src/daemon/daemon-control.ts +1 -1
- package/src/daemon/date-context.ts +114 -31
- package/src/daemon/handlers/config-ingress.ts +8 -33
- package/src/daemon/handlers/config-slack-channel.ts +49 -46
- package/src/daemon/handlers/config-telegram.ts +32 -16
- package/src/daemon/handlers/sessions.ts +27 -36
- package/src/daemon/handlers/shared.ts +0 -130
- package/src/daemon/handlers/skills.ts +20 -1
- package/src/daemon/history-repair.ts +72 -8
- package/src/daemon/host-cu-proxy.ts +430 -0
- package/src/daemon/lifecycle.ts +67 -71
- package/src/daemon/mcp-reload-service.ts +2 -2
- package/src/daemon/message-protocol.ts +3 -0
- package/src/daemon/message-types/computer-use.ts +1 -129
- package/src/daemon/message-types/host-cu.ts +19 -0
- package/src/daemon/message-types/memory.ts +4 -16
- package/src/daemon/message-types/messages.ts +4 -0
- package/src/daemon/message-types/sessions.ts +4 -0
- package/src/daemon/server.ts +25 -21
- package/src/daemon/session-agent-loop-handlers.ts +40 -0
- package/src/daemon/session-agent-loop.ts +334 -48
- package/src/daemon/session-attachments.ts +1 -2
- package/src/daemon/session-error.ts +89 -6
- package/src/daemon/session-history.ts +17 -7
- package/src/daemon/session-media-retry.ts +6 -2
- package/src/daemon/session-memory.ts +69 -149
- package/src/daemon/session-process.ts +10 -1
- package/src/daemon/session-runtime-assembly.ts +49 -19
- package/src/daemon/session-slash.ts +1 -1
- package/src/daemon/session-surfaces.ts +43 -28
- package/src/daemon/session-tool-setup.ts +9 -10
- package/src/daemon/session.ts +150 -17
- package/src/daemon/tool-side-effects.ts +2 -8
- package/src/daemon/watch-handler.ts +2 -2
- package/src/events/tool-metrics-listener.ts +2 -2
- package/src/hooks/manager.ts +1 -4
- package/src/inbound/public-ingress-urls.ts +7 -7
- package/src/instrument.ts +61 -1
- package/src/logfire.ts +16 -5
- package/src/memory/admin.ts +2 -191
- package/src/memory/canonical-guardian-store.ts +38 -2
- package/src/memory/conversation-crud.ts +0 -33
- package/src/memory/conversation-key-store.ts +21 -0
- package/src/memory/conversation-queries.ts +22 -3
- package/src/memory/db-init.ts +32 -0
- package/src/memory/embedding-backend.ts +84 -8
- package/src/memory/embedding-types.ts +9 -1
- package/src/memory/indexer.ts +7 -46
- package/src/memory/items-extractor.ts +274 -76
- package/src/memory/job-handlers/backfill.ts +2 -127
- package/src/memory/job-handlers/cleanup.ts +2 -16
- package/src/memory/job-handlers/extraction.ts +2 -138
- package/src/memory/job-handlers/index-maintenance.ts +1 -6
- package/src/memory/job-handlers/summarization.ts +3 -148
- package/src/memory/job-utils.ts +21 -59
- package/src/memory/jobs-store.ts +1 -159
- package/src/memory/jobs-worker.ts +9 -52
- package/src/memory/migrations/104-core-indexes.ts +3 -3
- package/src/memory/migrations/149-oauth-tables.ts +62 -0
- package/src/memory/migrations/150-oauth-apps-client-secret-path.ts +98 -0
- package/src/memory/migrations/151-oauth-providers-ping-url.ts +11 -0
- package/src/memory/migrations/152-memory-item-supersession.ts +44 -0
- package/src/memory/migrations/153-drop-entity-tables.ts +15 -0
- package/src/memory/migrations/154-drop-fts.ts +20 -0
- package/src/memory/migrations/155-drop-conflicts.ts +7 -0
- package/src/memory/migrations/156-call-session-invite-metadata.ts +24 -0
- package/src/memory/migrations/index.ts +8 -0
- package/src/memory/qdrant-client.ts +148 -51
- package/src/memory/raw-query.ts +1 -1
- package/src/memory/retriever.test.ts +294 -273
- package/src/memory/retriever.ts +421 -645
- package/src/memory/schema/calls.ts +2 -0
- package/src/memory/schema/index.ts +1 -0
- package/src/memory/schema/memory-core.ts +3 -48
- package/src/memory/schema/oauth.ts +67 -0
- package/src/memory/search/formatting.ts +263 -176
- package/src/memory/search/lexical.ts +1 -254
- package/src/memory/search/ranking.ts +0 -455
- package/src/memory/search/semantic.ts +100 -14
- package/src/memory/search/staleness.ts +47 -0
- package/src/memory/search/tier-classifier.ts +21 -0
- package/src/memory/search/types.ts +15 -77
- package/src/memory/task-memory-cleanup.ts +4 -6
- package/src/messaging/provider.ts +4 -4
- package/src/messaging/providers/gmail/client.ts +82 -2
- package/src/messaging/providers/gmail/mime-builder.ts +17 -7
- package/src/messaging/providers/gmail/people-client.ts +10 -10
- package/src/messaging/providers/telegram-bot/adapter.ts +17 -17
- package/src/messaging/providers/whatsapp/adapter.ts +11 -8
- package/src/messaging/registry.ts +2 -32
- package/src/notifications/copy-composer.ts +0 -5
- package/src/notifications/signal.ts +4 -5
- package/src/oauth/byo-connection.test.ts +133 -25
- package/src/oauth/byo-connection.ts +22 -6
- package/src/oauth/connect-orchestrator.ts +113 -57
- package/src/oauth/connect-types.ts +17 -23
- package/src/oauth/connection-resolver.ts +35 -11
- package/src/oauth/connection.ts +1 -1
- package/src/oauth/manual-token-connection.ts +104 -0
- package/src/oauth/oauth-store.ts +582 -0
- package/src/oauth/platform-connection.test.ts +29 -0
- package/src/oauth/platform-connection.ts +6 -5
- package/src/oauth/provider-behaviors.ts +124 -0
- package/src/oauth/scope-policy.ts +9 -2
- package/src/oauth/seed-providers.ts +167 -0
- package/src/oauth/token-persistence.ts +81 -77
- package/src/permissions/checker.ts +3 -3
- package/src/permissions/defaults.ts +1 -1
- package/src/permissions/prompter.ts +10 -1
- package/src/permissions/trust-store.ts +36 -1
- package/src/playbooks/playbook-compiler.ts +1 -1
- package/src/prompts/__tests__/build-cli-reference-section.test.ts +3 -1
- package/src/prompts/system-prompt.ts +46 -42
- package/src/providers/anthropic/client.ts +59 -20
- package/src/providers/retry.ts +1 -27
- package/src/providers/types.ts +7 -1
- package/src/runtime/AGENTS.md +9 -0
- package/src/runtime/auth/route-policy.ts +6 -6
- package/src/runtime/channel-reply-delivery.ts +0 -40
- package/src/runtime/gateway-client.ts +0 -7
- package/src/runtime/guardian-reply-router.ts +24 -22
- package/src/runtime/http-server.ts +10 -8
- package/src/runtime/http-types.ts +2 -2
- package/src/runtime/invite-redemption-service.ts +19 -1
- package/src/runtime/invite-service.ts +25 -0
- package/src/runtime/middleware/twilio-validation.ts +1 -11
- package/src/runtime/pending-interactions.ts +14 -12
- package/src/runtime/routes/brain-graph-routes.ts +10 -90
- package/src/runtime/routes/channel-delivery-routes.ts +0 -1
- package/src/runtime/routes/conversation-routes.ts +81 -19
- package/src/runtime/routes/events-routes.ts +21 -11
- package/src/runtime/routes/host-cu-routes.ts +97 -0
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +21 -12
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +12 -111
- package/src/runtime/routes/integrations/slack/share.ts +6 -7
- package/src/runtime/routes/log-export-routes.ts +126 -8
- package/src/runtime/routes/memory-item-routes.test.ts +754 -0
- package/src/runtime/routes/memory-item-routes.ts +503 -0
- package/src/runtime/routes/session-management-routes.ts +3 -3
- package/src/runtime/routes/settings-routes.ts +55 -48
- package/src/runtime/routes/surface-action-routes.ts +1 -1
- package/src/runtime/routes/trust-rules-routes.ts +14 -0
- package/src/runtime/routes/watch-routes.ts +128 -0
- package/src/runtime/routes/workspace-routes.ts +2 -1
- package/src/schedule/integration-status.ts +10 -9
- package/src/security/credential-key.ts +0 -156
- package/src/security/keychain-broker-client.ts +22 -10
- package/src/security/oauth2.ts +1 -1
- package/src/security/secure-keys.ts +25 -3
- package/src/security/token-manager.ts +137 -64
- package/src/skills/catalog-install.ts +414 -0
- package/src/skills/include-graph.ts +32 -0
- package/src/skills/skillssh-registry.ts +503 -0
- package/src/telegram/bot-username.ts +2 -3
- package/src/tools/assets/search.ts +5 -1
- package/src/tools/browser/network-recorder.ts +1 -1
- package/src/tools/browser/network-recording-types.ts +1 -1
- package/src/tools/computer-use/definitions.ts +36 -11
- package/src/tools/computer-use/registry.ts +5 -6
- package/src/tools/credentials/broker.ts +1 -2
- package/src/tools/credentials/metadata-store.ts +17 -121
- package/src/tools/credentials/vault.ts +92 -167
- package/src/tools/memory/definitions.ts +4 -13
- package/src/tools/memory/handlers.test.ts +83 -103
- package/src/tools/memory/handlers.ts +50 -85
- package/src/tools/registry.ts +2 -7
- package/src/tools/schedule/create.ts +8 -1
- package/src/tools/schedule/update.ts +8 -1
- package/src/tools/skills/load.ts +85 -3
- package/src/tools/watch/watch-state.ts +0 -12
- package/src/util/logger.ts +7 -41
- package/src/util/platform.ts +9 -28
- package/src/watcher/providers/google-calendar.ts +2 -1
- package/src/__tests__/clarification-resolver.test.ts +0 -193
- package/src/__tests__/computer-use-session-compaction.test.ts +0 -143
- package/src/__tests__/computer-use-session-lifecycle.test.ts +0 -322
- package/src/__tests__/computer-use-session-working-dir.test.ts +0 -166
- package/src/__tests__/computer-use-skill-baseline.test.ts +0 -78
- package/src/__tests__/computer-use-skill-endstate.test.ts +0 -105
- package/src/__tests__/computer-use-skill-lifecycle-cleanup.test.ts +0 -249
- package/src/__tests__/conflict-intent-tokenization.test.ts +0 -160
- package/src/__tests__/conflict-policy.test.ts +0 -269
- package/src/__tests__/conflict-store.test.ts +0 -372
- package/src/__tests__/contradiction-checker.test.ts +0 -361
- package/src/__tests__/entity-extractor.test.ts +0 -211
- package/src/__tests__/entity-search.test.ts +0 -1117
- package/src/__tests__/profile-compiler.test.ts +0 -392
- package/src/__tests__/ride-shotgun-handler.test.ts +0 -452
- package/src/__tests__/session-conflict-gate.test.ts +0 -1228
- package/src/__tests__/session-profile-injection.test.ts +0 -557
- package/src/cli/commands/dev.ts +0 -129
- package/src/cli/commands/map.ts +0 -391
- package/src/cli/commands/oauth.ts +0 -77
- package/src/config/bundled-skills/knowledge-graph/SKILL.md +0 -25
- package/src/config/bundled-skills/knowledge-graph/TOOLS.json +0 -66
- package/src/config/bundled-skills/knowledge-graph/tools/graph-query.ts +0 -211
- package/src/daemon/computer-use-session.ts +0 -1026
- package/src/daemon/ride-shotgun-handler.ts +0 -569
- package/src/daemon/session-conflict-gate.ts +0 -167
- package/src/daemon/session-dynamic-profile.ts +0 -77
- package/src/memory/clarification-resolver.ts +0 -417
- package/src/memory/conflict-intent.ts +0 -205
- package/src/memory/conflict-policy.ts +0 -127
- package/src/memory/conflict-store.ts +0 -410
- package/src/memory/contradiction-checker.ts +0 -508
- package/src/memory/entity-extractor.ts +0 -535
- package/src/memory/format-recall.ts +0 -47
- package/src/memory/fts-reconciler.ts +0 -165
- package/src/memory/job-handlers/conflict.ts +0 -200
- package/src/memory/profile-compiler.ts +0 -195
- package/src/memory/recall-cache.ts +0 -117
- package/src/memory/search/entity.ts +0 -535
- package/src/memory/search/query-expansion.test.ts +0 -70
- package/src/memory/search/query-expansion.ts +0 -118
- package/src/oauth/provider-base-urls.ts +0 -21
- package/src/oauth/provider-profiles.ts +0 -192
- package/src/prompts/computer-use-prompt.ts +0 -98
- package/src/runtime/routes/computer-use-routes.ts +0 -641
- package/src/runtime/routes/mcp-routes.ts +0 -20
- package/src/runtime/telegram-streaming-delivery.test.ts +0 -729
- package/src/runtime/telegram-streaming-delivery.ts +0 -393
- package/src/tools/computer-use/request-computer-control.ts +0 -56
|
@@ -48,6 +48,13 @@ export async function handleAddTrustRuleManage(
|
|
|
48
48
|
if (!toolName || typeof toolName !== "string") {
|
|
49
49
|
return httpError("BAD_REQUEST", "toolName is required", 400);
|
|
50
50
|
}
|
|
51
|
+
if (toolName.startsWith("__internal:")) {
|
|
52
|
+
return httpError(
|
|
53
|
+
"BAD_REQUEST",
|
|
54
|
+
"toolName must not start with __internal:",
|
|
55
|
+
400,
|
|
56
|
+
);
|
|
57
|
+
}
|
|
51
58
|
if (!pattern || typeof pattern !== "string") {
|
|
52
59
|
return httpError("BAD_REQUEST", "pattern is required", 400);
|
|
53
60
|
}
|
|
@@ -124,6 +131,13 @@ export async function handleUpdateTrustRuleManage(
|
|
|
124
131
|
priority?: number;
|
|
125
132
|
};
|
|
126
133
|
|
|
134
|
+
if (typeof body.tool === "string" && body.tool.startsWith("__internal:")) {
|
|
135
|
+
return httpError(
|
|
136
|
+
"BAD_REQUEST",
|
|
137
|
+
"tool must not start with __internal:",
|
|
138
|
+
400,
|
|
139
|
+
);
|
|
140
|
+
}
|
|
127
141
|
if (body.decision !== undefined) {
|
|
128
142
|
const validDecisions = ["allow", "deny", "ask"] as const;
|
|
129
143
|
if (
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HTTP route handler for watch (ambient observation) functionality.
|
|
3
|
+
*
|
|
4
|
+
* Decoupled from computer-use routes so that the watch endpoint has
|
|
5
|
+
* zero dependency on CU session state.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { getLogger } from "../../util/logger.js";
|
|
9
|
+
import { httpError } from "../http-errors.js";
|
|
10
|
+
import type { RouteDefinition } from "../http-router.js";
|
|
11
|
+
|
|
12
|
+
const log = getLogger("watch-routes");
|
|
13
|
+
|
|
14
|
+
// ---------------------------------------------------------------------------
|
|
15
|
+
// Dependency injection interface
|
|
16
|
+
// ---------------------------------------------------------------------------
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Minimal interface for watch observation handling.
|
|
20
|
+
* The daemon wires a concrete implementation at startup.
|
|
21
|
+
*/
|
|
22
|
+
export interface WatchDeps {
|
|
23
|
+
/** Handle a watch observation. */
|
|
24
|
+
handleWatchObservation: (params: {
|
|
25
|
+
watchId: string;
|
|
26
|
+
sessionId: string;
|
|
27
|
+
ocrText: string;
|
|
28
|
+
appName?: string;
|
|
29
|
+
windowTitle?: string;
|
|
30
|
+
bundleIdentifier?: string;
|
|
31
|
+
timestamp: number;
|
|
32
|
+
captureIndex: number;
|
|
33
|
+
totalExpected: number;
|
|
34
|
+
}) => Promise<void>;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// ---------------------------------------------------------------------------
|
|
38
|
+
// Route handler
|
|
39
|
+
// ---------------------------------------------------------------------------
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* POST /v1/computer-use/watch — send a watch observation.
|
|
43
|
+
*
|
|
44
|
+
* Body: { watchId, sessionId, ocrText, appName?, windowTitle?,
|
|
45
|
+
* bundleIdentifier?, timestamp, captureIndex, totalExpected }
|
|
46
|
+
*/
|
|
47
|
+
async function handleWatchObservationRoute(
|
|
48
|
+
req: Request,
|
|
49
|
+
deps: WatchDeps,
|
|
50
|
+
): Promise<Response> {
|
|
51
|
+
const body = (await req.json()) as {
|
|
52
|
+
watchId?: string;
|
|
53
|
+
sessionId?: string;
|
|
54
|
+
ocrText?: string;
|
|
55
|
+
appName?: string;
|
|
56
|
+
windowTitle?: string;
|
|
57
|
+
bundleIdentifier?: string;
|
|
58
|
+
timestamp?: number;
|
|
59
|
+
captureIndex?: number;
|
|
60
|
+
totalExpected?: number;
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
if (!body.watchId || typeof body.watchId !== "string") {
|
|
64
|
+
return httpError("BAD_REQUEST", "watchId is required", 400);
|
|
65
|
+
}
|
|
66
|
+
if (!body.sessionId || typeof body.sessionId !== "string") {
|
|
67
|
+
return httpError("BAD_REQUEST", "sessionId is required", 400);
|
|
68
|
+
}
|
|
69
|
+
if (!body.ocrText || typeof body.ocrText !== "string") {
|
|
70
|
+
return httpError("BAD_REQUEST", "ocrText is required", 400);
|
|
71
|
+
}
|
|
72
|
+
if (typeof body.timestamp !== "number") {
|
|
73
|
+
return httpError("BAD_REQUEST", "timestamp is required", 400);
|
|
74
|
+
}
|
|
75
|
+
if (typeof body.captureIndex !== "number") {
|
|
76
|
+
return httpError("BAD_REQUEST", "captureIndex is required", 400);
|
|
77
|
+
}
|
|
78
|
+
if (typeof body.totalExpected !== "number") {
|
|
79
|
+
return httpError("BAD_REQUEST", "totalExpected is required", 400);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
try {
|
|
83
|
+
await deps.handleWatchObservation({
|
|
84
|
+
watchId: body.watchId,
|
|
85
|
+
sessionId: body.sessionId,
|
|
86
|
+
ocrText: body.ocrText,
|
|
87
|
+
appName: body.appName,
|
|
88
|
+
windowTitle: body.windowTitle,
|
|
89
|
+
bundleIdentifier: body.bundleIdentifier,
|
|
90
|
+
timestamp: body.timestamp,
|
|
91
|
+
captureIndex: body.captureIndex,
|
|
92
|
+
totalExpected: body.totalExpected,
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
return Response.json({ ok: true });
|
|
96
|
+
} catch (err) {
|
|
97
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
98
|
+
log.error(
|
|
99
|
+
{ err, watchId: body.watchId },
|
|
100
|
+
"Failed to handle watch observation via HTTP",
|
|
101
|
+
);
|
|
102
|
+
return httpError("INTERNAL_ERROR", message, 500);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// ---------------------------------------------------------------------------
|
|
107
|
+
// Route definitions
|
|
108
|
+
// ---------------------------------------------------------------------------
|
|
109
|
+
|
|
110
|
+
export function watchRouteDefinitions(deps: {
|
|
111
|
+
getWatchDeps?: () => WatchDeps;
|
|
112
|
+
}): RouteDefinition[] {
|
|
113
|
+
const getDeps = (): WatchDeps => {
|
|
114
|
+
if (!deps.getWatchDeps) {
|
|
115
|
+
throw new Error("Watch deps not available");
|
|
116
|
+
}
|
|
117
|
+
return deps.getWatchDeps();
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
return [
|
|
121
|
+
{
|
|
122
|
+
endpoint: "computer-use/watch",
|
|
123
|
+
method: "POST",
|
|
124
|
+
policyKey: "computer-use/watch",
|
|
125
|
+
handler: async ({ req }) => handleWatchObservationRoute(req, getDeps()),
|
|
126
|
+
},
|
|
127
|
+
];
|
|
128
|
+
}
|
|
@@ -33,6 +33,7 @@ interface TreeEntry {
|
|
|
33
33
|
|
|
34
34
|
function handleWorkspaceTree(ctx: RouteContext): Response {
|
|
35
35
|
const requestedPath = ctx.url.searchParams.get("path") ?? "";
|
|
36
|
+
const showHidden = ctx.url.searchParams.get("showHidden") === "true";
|
|
36
37
|
const resolved = resolveWorkspacePath(requestedPath);
|
|
37
38
|
if (resolved === undefined) {
|
|
38
39
|
return httpError("BAD_REQUEST", "Invalid path", 400);
|
|
@@ -45,7 +46,7 @@ function handleWorkspaceTree(ctx: RouteContext): Response {
|
|
|
45
46
|
const entries: TreeEntry[] = [];
|
|
46
47
|
for (const entry of dirents) {
|
|
47
48
|
// Filter out dotfiles/directories (.env, .git, .private, etc.)
|
|
48
|
-
if (entry.name.startsWith(".")) continue;
|
|
49
|
+
if (!showHidden && entry.name.startsWith(".")) continue;
|
|
49
50
|
|
|
50
51
|
const fullPath = join(resolved, entry.name);
|
|
51
52
|
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { hasTwilioCredentials } from "../calls/twilio-rest.js";
|
|
2
|
-
import {
|
|
3
|
-
|
|
2
|
+
import {
|
|
3
|
+
getConnectionByProvider,
|
|
4
|
+
isProviderConnected,
|
|
5
|
+
} from "../oauth/oauth-store.js";
|
|
4
6
|
|
|
5
7
|
interface IntegrationProbe {
|
|
6
8
|
name: string;
|
|
@@ -13,14 +15,12 @@ const INTEGRATION_PROBES: IntegrationProbe[] = [
|
|
|
13
15
|
{
|
|
14
16
|
name: "Gmail",
|
|
15
17
|
category: "email",
|
|
16
|
-
isConnected: () =>
|
|
17
|
-
!!getSecureKey(credentialKey("integration:gmail", "access_token")),
|
|
18
|
+
isConnected: () => isProviderConnected("integration:gmail"),
|
|
18
19
|
},
|
|
19
20
|
{
|
|
20
21
|
name: "Slack",
|
|
21
22
|
category: "messaging",
|
|
22
|
-
isConnected: () =>
|
|
23
|
-
!!getSecureKey(credentialKey("integration:slack", "access_token")),
|
|
23
|
+
isConnected: () => isProviderConnected("integration:slack"),
|
|
24
24
|
},
|
|
25
25
|
{
|
|
26
26
|
name: "Twilio",
|
|
@@ -30,9 +30,10 @@ const INTEGRATION_PROBES: IntegrationProbe[] = [
|
|
|
30
30
|
{
|
|
31
31
|
name: "Telegram",
|
|
32
32
|
category: "messaging",
|
|
33
|
-
isConnected: () =>
|
|
34
|
-
|
|
35
|
-
!!
|
|
33
|
+
isConnected: () => {
|
|
34
|
+
const conn = getConnectionByProvider("telegram");
|
|
35
|
+
return !!(conn && conn.status === "active");
|
|
36
|
+
},
|
|
36
37
|
},
|
|
37
38
|
];
|
|
38
39
|
|
|
@@ -2,23 +2,8 @@
|
|
|
2
2
|
* Single source of truth for credential key format in the secure store.
|
|
3
3
|
*
|
|
4
4
|
* Keys follow the pattern: credential/{service}/{field}
|
|
5
|
-
*
|
|
6
|
-
* Previously, keys used colons as delimiters (credential:service:field),
|
|
7
|
-
* which was ambiguous when service names contained colons (e.g.
|
|
8
|
-
* "integration:gmail"). The slash-delimited format avoids this.
|
|
9
5
|
*/
|
|
10
6
|
|
|
11
|
-
import { listCredentialMetadata } from "../tools/credentials/metadata-store.js";
|
|
12
|
-
import { getLogger } from "../util/logger.js";
|
|
13
|
-
import {
|
|
14
|
-
deleteSecureKey,
|
|
15
|
-
getSecureKey,
|
|
16
|
-
listSecureKeys,
|
|
17
|
-
setSecureKey,
|
|
18
|
-
} from "./secure-keys.js";
|
|
19
|
-
|
|
20
|
-
const log = getLogger("credential-key");
|
|
21
|
-
|
|
22
7
|
/**
|
|
23
8
|
* Build a credential key for the secure store.
|
|
24
9
|
*
|
|
@@ -27,144 +12,3 @@ const log = getLogger("credential-key");
|
|
|
27
12
|
export function credentialKey(service: string, field: string): string {
|
|
28
13
|
return `credential/${service}/${field}`;
|
|
29
14
|
}
|
|
30
|
-
|
|
31
|
-
// ---------------------------------------------------------------------------
|
|
32
|
-
// Migration from colon-delimited keys
|
|
33
|
-
// ---------------------------------------------------------------------------
|
|
34
|
-
|
|
35
|
-
let migrated = false;
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* Migrate any legacy colon-delimited credential keys to the new
|
|
39
|
-
* slash-delimited format. Idempotent: skips keys that already exist
|
|
40
|
-
* under the new format, and only runs once per process (guarded by a
|
|
41
|
-
* module-level flag).
|
|
42
|
-
*
|
|
43
|
-
* Legacy key format: `credential:<service>:<field>`
|
|
44
|
-
* New key format: `credential/<service>/<field>`
|
|
45
|
-
*
|
|
46
|
-
* The old colon-delimited format is ambiguous when either the service
|
|
47
|
-
* or field name contains colons — for `credential:A:B:C:D`, you can't
|
|
48
|
-
* tell where the service ends and the field begins without external
|
|
49
|
-
* context.
|
|
50
|
-
*
|
|
51
|
-
* To resolve this, the function first consults the credential metadata
|
|
52
|
-
* store to find which (service, field) pair matches a valid split.
|
|
53
|
-
* If no metadata match is found, it falls back to splitting on the
|
|
54
|
-
* **first** colon after the prefix — this handles the common case
|
|
55
|
-
* where service names are simple (e.g. "doordash.com") and field
|
|
56
|
-
* names may contain colons (e.g. "session:cookies").
|
|
57
|
-
*/
|
|
58
|
-
export function migrateKeys(): void {
|
|
59
|
-
if (migrated) return;
|
|
60
|
-
migrated = true;
|
|
61
|
-
|
|
62
|
-
let allKeys: string[];
|
|
63
|
-
try {
|
|
64
|
-
allKeys = listSecureKeys();
|
|
65
|
-
} catch (err) {
|
|
66
|
-
log.warn({ err }, "Failed to list secure keys during migration");
|
|
67
|
-
return;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
const colonKeys = allKeys.filter(
|
|
71
|
-
(k) => k.startsWith("credential:") && !k.startsWith("credential/"),
|
|
72
|
-
);
|
|
73
|
-
if (colonKeys.length === 0) return;
|
|
74
|
-
|
|
75
|
-
log.info(
|
|
76
|
-
{ count: colonKeys.length },
|
|
77
|
-
"Migrating colon-delimited credential keys to slash-delimited format",
|
|
78
|
-
);
|
|
79
|
-
|
|
80
|
-
// Build a set of known (service, field) pairs from credential metadata
|
|
81
|
-
// to disambiguate colon-delimited keys.
|
|
82
|
-
const knownPairs = new Set<string>();
|
|
83
|
-
try {
|
|
84
|
-
for (const meta of listCredentialMetadata()) {
|
|
85
|
-
knownPairs.add(`${meta.service}\0${meta.field}`);
|
|
86
|
-
}
|
|
87
|
-
} catch {
|
|
88
|
-
// If metadata is unavailable, we'll rely on the first-colon fallback.
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
for (const oldKey of colonKeys) {
|
|
92
|
-
// Strip the "credential:" prefix — `rest` is "service:field" with
|
|
93
|
-
// potential colons in either part.
|
|
94
|
-
const rest = oldKey.slice("credential:".length);
|
|
95
|
-
|
|
96
|
-
const parsed = parseServiceField(rest, knownPairs);
|
|
97
|
-
if (parsed === undefined) {
|
|
98
|
-
log.warn({ key: oldKey }, "Skipping malformed credential key");
|
|
99
|
-
continue;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
const { service, field } = parsed;
|
|
103
|
-
const newKey = credentialKey(service, field);
|
|
104
|
-
|
|
105
|
-
// Skip if the new key already exists (idempotent)
|
|
106
|
-
if (getSecureKey(newKey) !== undefined) {
|
|
107
|
-
// Clean up old key
|
|
108
|
-
deleteSecureKey(oldKey);
|
|
109
|
-
continue;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
const value = getSecureKey(oldKey);
|
|
113
|
-
if (value === undefined) {
|
|
114
|
-
continue;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
const ok = setSecureKey(newKey, value);
|
|
118
|
-
if (ok) {
|
|
119
|
-
deleteSecureKey(oldKey);
|
|
120
|
-
} else {
|
|
121
|
-
log.warn(
|
|
122
|
-
{ oldKey, newKey },
|
|
123
|
-
"Failed to write migrated key; keeping old key",
|
|
124
|
-
);
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
/**
|
|
130
|
-
* Parse a "service:field" string, using known metadata pairs to
|
|
131
|
-
* disambiguate when colons appear in either part.
|
|
132
|
-
*
|
|
133
|
-
* Strategy:
|
|
134
|
-
* 1. Try every possible split position and check against metadata.
|
|
135
|
-
* 2. If no metadata match, fall back to splitting on the first colon
|
|
136
|
-
* (field names with colons are more common than service names with colons).
|
|
137
|
-
*
|
|
138
|
-
* Returns undefined for malformed keys that have no colon.
|
|
139
|
-
*/
|
|
140
|
-
function parseServiceField(
|
|
141
|
-
rest: string,
|
|
142
|
-
knownPairs: Set<string>,
|
|
143
|
-
): { service: string; field: string } | undefined {
|
|
144
|
-
const firstColon = rest.indexOf(":");
|
|
145
|
-
if (firstColon <= 0) return undefined;
|
|
146
|
-
|
|
147
|
-
// Try each possible split position against metadata
|
|
148
|
-
if (knownPairs.size > 0) {
|
|
149
|
-
for (let i = firstColon; i < rest.length; i++) {
|
|
150
|
-
if (rest[i] !== ":") continue;
|
|
151
|
-
const service = rest.slice(0, i);
|
|
152
|
-
const field = rest.slice(i + 1);
|
|
153
|
-
if (field.length > 0 && knownPairs.has(`${service}\0${field}`)) {
|
|
154
|
-
return { service, field };
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
// Fallback: split on first colon — handles simple services with
|
|
160
|
-
// compound field names (e.g. "doordash.com:session:cookies").
|
|
161
|
-
return {
|
|
162
|
-
service: rest.slice(0, firstColon),
|
|
163
|
-
field: rest.slice(firstColon + 1),
|
|
164
|
-
};
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
/** @internal Test-only: reset the migration guard so migrateKeys() runs again. */
|
|
168
|
-
export function _resetMigrationFlag(): void {
|
|
169
|
-
migrated = false;
|
|
170
|
-
}
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* provides a graceful-fallback interface: every public method returns a
|
|
7
7
|
* safe default on failure and never throws.
|
|
8
8
|
*
|
|
9
|
-
* Socket path:
|
|
9
|
+
* Socket path: derived from getRootDir() as `~/.vellum/keychain-broker.sock`.
|
|
10
10
|
* Auth token: read from ~/.vellum/protected/keychain-broker.token on first
|
|
11
11
|
* connection, cached for process lifetime.
|
|
12
12
|
*/
|
|
@@ -33,11 +33,18 @@ const REQUEST_TIMEOUT_MS = 5_000;
|
|
|
33
33
|
* back); `{ found: false }` means the key doesn't exist in the keychain. */
|
|
34
34
|
export type BrokerGetResult = { found: boolean; value?: string } | null;
|
|
35
35
|
|
|
36
|
+
/** Result of a `set()` call — distinguishes broker-unreachable from an active
|
|
37
|
+
* rejection so callers can log meaningful diagnostics. */
|
|
38
|
+
export type BrokerSetResult =
|
|
39
|
+
| { status: "ok" }
|
|
40
|
+
| { status: "unreachable" }
|
|
41
|
+
| { status: "rejected"; code: string; message: string };
|
|
42
|
+
|
|
36
43
|
export interface KeychainBrokerClient {
|
|
37
44
|
isAvailable(): boolean;
|
|
38
45
|
ping(): Promise<{ pong: boolean } | null>;
|
|
39
46
|
get(account: string): Promise<BrokerGetResult>;
|
|
40
|
-
set(account: string, value: string): Promise<
|
|
47
|
+
set(account: string, value: string): Promise<BrokerSetResult>;
|
|
41
48
|
del(account: string): Promise<boolean>;
|
|
42
49
|
list(): Promise<string[]>;
|
|
43
50
|
}
|
|
@@ -70,8 +77,8 @@ function getTokenPath(): string {
|
|
|
70
77
|
return join(getRootDir(), "protected", "keychain-broker.token");
|
|
71
78
|
}
|
|
72
79
|
|
|
73
|
-
function getSocketPath(): string
|
|
74
|
-
return
|
|
80
|
+
function getSocketPath(): string {
|
|
81
|
+
return join(getRootDir(), "keychain-broker.sock");
|
|
75
82
|
}
|
|
76
83
|
|
|
77
84
|
// ---------------------------------------------------------------------------
|
|
@@ -172,7 +179,7 @@ export function createBrokerClient(): KeychainBrokerClient {
|
|
|
172
179
|
function connect(): Promise<Socket> {
|
|
173
180
|
return new Promise((resolve, reject) => {
|
|
174
181
|
const socketPath = getSocketPath();
|
|
175
|
-
if (!socketPath) {
|
|
182
|
+
if (!pathExists(socketPath)) {
|
|
176
183
|
reject(new Error("No socket path"));
|
|
177
184
|
return;
|
|
178
185
|
}
|
|
@@ -328,8 +335,7 @@ export function createBrokerClient(): KeychainBrokerClient {
|
|
|
328
335
|
return {
|
|
329
336
|
isAvailable(): boolean {
|
|
330
337
|
if (permanentlyUnavailable) return false;
|
|
331
|
-
|
|
332
|
-
if (!socketPath) return false;
|
|
338
|
+
if (!pathExists(getSocketPath())) return false;
|
|
333
339
|
return pathExists(getTokenPath());
|
|
334
340
|
},
|
|
335
341
|
|
|
@@ -361,12 +367,18 @@ export function createBrokerClient(): KeychainBrokerClient {
|
|
|
361
367
|
}
|
|
362
368
|
},
|
|
363
369
|
|
|
364
|
-
async set(account: string, value: string): Promise<
|
|
370
|
+
async set(account: string, value: string): Promise<BrokerSetResult> {
|
|
365
371
|
try {
|
|
366
372
|
const response = await doRequest("key.set", { account, value });
|
|
367
|
-
|
|
373
|
+
if (!response) return { status: "unreachable" };
|
|
374
|
+
if (response.ok) return { status: "ok" };
|
|
375
|
+
return {
|
|
376
|
+
status: "rejected",
|
|
377
|
+
code: response.error?.code ?? "UNKNOWN",
|
|
378
|
+
message: response.error?.message ?? "unknown error",
|
|
379
|
+
};
|
|
368
380
|
} catch {
|
|
369
|
-
return
|
|
381
|
+
return { status: "unreachable" };
|
|
370
382
|
}
|
|
371
383
|
},
|
|
372
384
|
|
package/src/security/oauth2.ts
CHANGED
|
@@ -691,7 +691,7 @@ export async function startOAuth2Flow(
|
|
|
691
691
|
if (transport === "gateway") {
|
|
692
692
|
if (!hasPublicUrl) {
|
|
693
693
|
throw new Error(
|
|
694
|
-
"Gateway transport requires a public ingress URL. Set ingress.publicBaseUrl
|
|
694
|
+
"Gateway transport requires a public ingress URL. Set ingress.publicBaseUrl, or use loopback transport.",
|
|
695
695
|
);
|
|
696
696
|
}
|
|
697
697
|
log.debug({ transport: "gateway" }, "OAuth2 flow starting");
|
|
@@ -7,10 +7,13 @@
|
|
|
7
7
|
* encrypted store (startup code paths cannot do async I/O).
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
+
import { getLogger } from "../util/logger.js";
|
|
10
11
|
import * as encryptedStore from "./encrypted-store.js";
|
|
11
12
|
import type { KeychainBrokerClient } from "./keychain-broker-client.js";
|
|
12
13
|
import { createBrokerClient } from "./keychain-broker-client.js";
|
|
13
14
|
|
|
15
|
+
const log = getLogger("secure-keys");
|
|
16
|
+
|
|
14
17
|
let _broker: KeychainBrokerClient | undefined;
|
|
15
18
|
|
|
16
19
|
function getBroker(): KeychainBrokerClient {
|
|
@@ -120,13 +123,32 @@ export async function setSecureKeyAsync(
|
|
|
120
123
|
): Promise<boolean> {
|
|
121
124
|
const broker = getBroker();
|
|
122
125
|
if (broker.isAvailable()) {
|
|
123
|
-
const
|
|
124
|
-
if (
|
|
126
|
+
const result = await broker.set(account, value);
|
|
127
|
+
if (result.status !== "ok") {
|
|
128
|
+
log.warn(
|
|
129
|
+
{
|
|
130
|
+
account,
|
|
131
|
+
brokerStatus: result.status,
|
|
132
|
+
...(result.status === "rejected"
|
|
133
|
+
? { brokerCode: result.code, brokerMessage: result.message }
|
|
134
|
+
: {}),
|
|
135
|
+
},
|
|
136
|
+
"Broker set failed for secure key",
|
|
137
|
+
);
|
|
138
|
+
return false;
|
|
139
|
+
}
|
|
125
140
|
// Broker succeeded — also persist to encrypted store for sync callers.
|
|
126
141
|
const encOk = encryptedStore.setKey(account, value);
|
|
142
|
+
if (!encOk) {
|
|
143
|
+
log.warn({ account }, "Encrypted store set failed after broker success");
|
|
144
|
+
}
|
|
127
145
|
return encOk;
|
|
128
146
|
}
|
|
129
|
-
|
|
147
|
+
const encOk = encryptedStore.setKey(account, value);
|
|
148
|
+
if (!encOk) {
|
|
149
|
+
log.warn({ account }, "Encrypted store set failed (broker unavailable)");
|
|
150
|
+
}
|
|
151
|
+
return encOk;
|
|
130
152
|
}
|
|
131
153
|
|
|
132
154
|
/**
|