@vellumai/assistant 0.5.13 → 0.5.14
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 +1 -6
- package/AGENTS.md +4 -0
- package/ARCHITECTURE.md +0 -1
- package/bunfig.toml +1 -0
- package/docs/architecture/memory.md +3 -3
- package/openapi.yaml +127 -22
- package/package.json +1 -1
- package/src/__tests__/access-request-decision.test.ts +2 -32
- package/src/__tests__/actor-token-service.test.ts +1 -31
- package/src/__tests__/anthropic-provider.test.ts +53 -40
- package/src/__tests__/app-git-history.test.ts +9 -17
- package/src/__tests__/app-git-service.test.ts +14 -20
- package/src/__tests__/app-store-dir-names.test.ts +10 -20
- package/src/__tests__/approval-cascade.test.ts +2 -19
- package/src/__tests__/approval-primitive.test.ts +2 -27
- package/src/__tests__/approval-routes-http.test.ts +2 -30
- package/src/__tests__/assistant-events-sse-hardening.test.ts +2 -28
- package/src/__tests__/assistant-feature-flags-integration.test.ts +2 -45
- package/src/__tests__/attachments-store.test.ts +5 -32
- package/src/__tests__/audit-log-rotation.test.ts +5 -36
- package/src/__tests__/avatar-e2e.test.ts +1 -9
- package/src/__tests__/avatar-generator.test.ts +1 -7
- package/src/__tests__/browser-fill-credential.test.ts +0 -4
- package/src/__tests__/browser-manager.test.ts +0 -6
- package/src/__tests__/call-controller.test.ts +1 -22
- package/src/__tests__/call-conversation-messages.test.ts +0 -21
- package/src/__tests__/call-domain.test.ts +0 -25
- package/src/__tests__/call-pointer-messages.test.ts +0 -21
- package/src/__tests__/call-recovery.test.ts +0 -22
- package/src/__tests__/call-routes-http.test.ts +0 -24
- package/src/__tests__/call-store.test.ts +0 -21
- package/src/__tests__/cancel-resolves-conversation-key.test.ts +0 -24
- package/src/__tests__/canonical-guardian-store.test.ts +48 -21
- package/src/__tests__/channel-approval-routes.test.ts +6 -26
- package/src/__tests__/channel-approvals.test.ts +1 -38
- package/src/__tests__/channel-delivery-store.test.ts +0 -21
- package/src/__tests__/channel-guardian.test.ts +0 -26
- package/src/__tests__/channel-reply-delivery.test.ts +5 -0
- package/src/__tests__/channel-retry-sweep.test.ts +0 -21
- package/src/__tests__/checker.test.ts +26 -61
- package/src/__tests__/clawhub.test.ts +9 -25
- package/src/__tests__/cli-command-risk-guard.test.ts +0 -18
- package/src/__tests__/config-loader-backfill.test.ts +9 -28
- package/src/__tests__/config-schema-cmd.test.ts +5 -25
- package/src/__tests__/config-schema.test.ts +21 -40
- package/src/__tests__/config-watcher.test.ts +4 -91
- package/src/__tests__/confirmation-request-guardian-bridge.test.ts +0 -21
- package/src/__tests__/contacts-tools.test.ts +0 -21
- package/src/__tests__/context-memory-e2e.test.ts +0 -21
- package/src/__tests__/context-window-manager.test.ts +130 -3
- package/src/__tests__/conversation-abort-tool-results.test.ts +0 -4
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +0 -4
- package/src/__tests__/conversation-agent-loop.test.ts +0 -4
- package/src/__tests__/conversation-attachments.test.ts +1 -24
- package/src/__tests__/conversation-attention-store.test.ts +0 -21
- package/src/__tests__/conversation-attention-telegram.test.ts +0 -22
- package/src/__tests__/conversation-clear-safety.test.ts +0 -22
- package/src/__tests__/conversation-confirmation-signals.test.ts +2 -21
- package/src/__tests__/conversation-delete-schedule-cleanup.test.ts +0 -24
- package/src/__tests__/conversation-disk-view-integration.test.ts +1 -23
- package/src/__tests__/conversation-disk-view.test.ts +5 -27
- package/src/__tests__/conversation-error.test.ts +1 -1
- package/src/__tests__/conversation-fork-crud.test.ts +1 -33
- package/src/__tests__/conversation-fork-route.test.ts +0 -27
- package/src/__tests__/conversation-history-web-search.test.ts +23 -16
- package/src/__tests__/conversation-init.benchmark.test.ts +22 -43
- package/src/__tests__/conversation-key-store-disk-view.test.ts +8 -34
- package/src/__tests__/conversation-load-history-repair.test.ts +0 -4
- package/src/__tests__/conversation-pre-run-repair.test.ts +0 -4
- package/src/__tests__/conversation-provider-retry-repair.test.ts +0 -4
- package/src/__tests__/conversation-queue.test.ts +8 -8
- package/src/__tests__/conversation-routes-disk-view.test.ts +13 -51
- package/src/__tests__/conversation-runtime-assembly.test.ts +64 -38
- package/src/__tests__/conversation-slash-commands.test.ts +5 -0
- package/src/__tests__/conversation-slash-queue.test.ts +0 -4
- package/src/__tests__/conversation-slash-unknown.test.ts +0 -4
- package/src/__tests__/conversation-speed-override.test.ts +326 -0
- package/src/__tests__/conversation-starter-routes.test.ts +0 -23
- package/src/__tests__/conversation-store.test.ts +0 -21
- package/src/__tests__/conversation-unread-route.test.ts +0 -24
- package/src/__tests__/conversation-usage.test.ts +56 -21
- package/src/__tests__/conversation-wipe.test.ts +0 -21
- package/src/__tests__/conversation-workspace-cache-state.test.ts +0 -4
- package/src/__tests__/conversation-workspace-injection.test.ts +0 -4
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +0 -4
- package/src/__tests__/credential-execution-shell-lockdown.test.ts +8 -5
- package/src/__tests__/credential-vault-unit.test.ts +9 -428
- package/src/__tests__/credentials-cli.test.ts +10 -10
- package/src/__tests__/daemon-assistant-events.test.ts +0 -19
- package/src/__tests__/date-context.test.ts +77 -97
- package/src/__tests__/db-conversation-fork-lineage-migration.test.ts +7 -24
- package/src/__tests__/db-llm-request-log-provider-migration.test.ts +29 -42
- package/src/__tests__/delete-managed-skill-tool.test.ts +2 -10
- package/src/__tests__/deterministic-verification-control-plane.test.ts +1 -26
- package/src/__tests__/docker-signing-key-bootstrap.test.ts +61 -15
- package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +2 -36
- package/src/__tests__/email-cli.test.ts +6 -6
- package/src/__tests__/ephemeral-permissions.test.ts +5 -17
- package/src/__tests__/first-greeting.test.ts +4 -32
- package/src/__tests__/followup-tools.test.ts +0 -21
- package/src/__tests__/gateway-only-enforcement.test.ts +0 -20
- package/src/__tests__/guardian-action-conversation-turn.test.ts +0 -23
- package/src/__tests__/guardian-action-followup-executor.test.ts +0 -23
- package/src/__tests__/guardian-action-followup-store.test.ts +0 -21
- package/src/__tests__/guardian-action-grant-mint-consume.test.ts +0 -21
- package/src/__tests__/guardian-action-late-reply.test.ts +0 -21
- package/src/__tests__/guardian-action-store.test.ts +0 -21
- package/src/__tests__/guardian-action-sweep.test.ts +0 -21
- package/src/__tests__/guardian-binding-drift-heal.test.ts +0 -23
- package/src/__tests__/guardian-decision-primitive-canonical.test.ts +172 -22
- package/src/__tests__/guardian-dispatch.test.ts +0 -21
- package/src/__tests__/guardian-grant-minting.test.ts +0 -22
- package/src/__tests__/guardian-outbound-http.test.ts +0 -22
- package/src/__tests__/guardian-principal-id-roundtrip.test.ts +0 -23
- package/src/__tests__/guardian-routing-invariants.test.ts +0 -22
- package/src/__tests__/guardian-routing-state.test.ts +0 -22
- package/src/__tests__/guardian-verification-voice-binding.test.ts +0 -24
- package/src/__tests__/headless-browser-interactions.test.ts +0 -4
- package/src/__tests__/headless-browser-navigate.test.ts +0 -4
- package/src/__tests__/headless-browser-read-tools.test.ts +0 -4
- package/src/__tests__/headless-browser-snapshot.test.ts +0 -4
- package/src/__tests__/heartbeat-service.test.ts +99 -26
- package/src/__tests__/hooks-blocking.test.ts +3 -3
- package/src/__tests__/hooks-config.test.ts +7 -7
- package/src/__tests__/hooks-discovery.test.ts +3 -3
- package/src/__tests__/hooks-integration.test.ts +5 -5
- package/src/__tests__/hooks-manager.test.ts +3 -3
- package/src/__tests__/hooks-runner.test.ts +5 -23
- package/src/__tests__/hooks-settings.test.ts +3 -3
- package/src/__tests__/hooks-templates.test.ts +3 -3
- package/src/__tests__/http-conversation-lineage.test.ts +0 -27
- package/src/__tests__/identity-intro-cache.test.ts +0 -4
- package/src/__tests__/inbound-invite-redemption.test.ts +0 -22
- package/src/__tests__/inline-skill-load-permissions.test.ts +5 -16
- package/src/__tests__/intent-routing.test.ts +2 -55
- package/src/__tests__/invite-redemption-service.test.ts +0 -21
- package/src/__tests__/invite-routes-http.test.ts +0 -21
- package/src/__tests__/jobs-store-qdrant-breaker.test.ts +0 -17
- package/src/__tests__/journal-context.test.ts +8 -75
- package/src/__tests__/list-messages-attachments.test.ts +0 -22
- package/src/__tests__/llm-context-route-provider.test.ts +0 -21
- package/src/__tests__/llm-request-log-turn-query.test.ts +46 -28
- package/src/__tests__/llm-usage-store.test.ts +0 -21
- package/src/__tests__/log-export-workspace.test.ts +1 -1
- package/src/__tests__/managed-skill-lifecycle.test.ts +1 -1
- package/src/__tests__/managed-store.test.ts +1 -1
- package/src/__tests__/mcp-cli.test.ts +7 -10
- package/src/__tests__/memory-context-benchmark.benchmark.test.ts +0 -21
- package/src/__tests__/memory-jobs-worker-backoff.test.ts +0 -11
- package/src/__tests__/memory-lifecycle-e2e.test.ts +0 -21
- package/src/__tests__/memory-recall-log-store.test.ts +0 -27
- package/src/__tests__/memory-recall-quality.test.ts +0 -21
- package/src/__tests__/memory-regressions.experimental.test.ts +31 -30
- package/src/__tests__/memory-regressions.test.ts +282 -70
- package/src/__tests__/memory-retrieval.benchmark.test.ts +0 -21
- package/src/__tests__/memory-upsert-concurrency.test.ts +0 -21
- package/src/__tests__/messaging-send-tool.test.ts +201 -0
- package/src/__tests__/migration-cross-version-compatibility.test.ts +18 -13
- package/src/__tests__/migration-export-http.test.ts +7 -1
- package/src/__tests__/migration-import-commit-http.test.ts +16 -14
- package/src/__tests__/migration-import-preflight-http.test.ts +27 -44
- package/src/__tests__/migration-validate-http.test.ts +1 -28
- package/src/__tests__/native-web-search.test.ts +25 -22
- package/src/__tests__/non-member-access-request.test.ts +0 -22
- package/src/__tests__/notification-guardian-path.test.ts +0 -21
- package/src/__tests__/notification-schedule-dedup.test.ts +1 -25
- package/src/__tests__/oauth-apps-routes.test.ts +103 -2
- package/src/__tests__/oauth-cli.test.ts +52 -0
- package/src/__tests__/oauth-provider-profiles.test.ts +0 -16
- package/src/__tests__/oauth-provider-serializer.test.ts +232 -0
- package/src/__tests__/oauth-providers-routes.test.ts +257 -0
- package/src/__tests__/oauth-store.test.ts +0 -21
- package/src/__tests__/onboarding-template-contract.test.ts +2 -2
- package/src/__tests__/openai-provider.test.ts +261 -0
- package/src/__tests__/pairing-concurrent.test.ts +6 -6
- package/src/__tests__/pairing-routes.test.ts +7 -1
- package/src/__tests__/path-policy.test.ts +1 -1
- package/src/__tests__/platform.test.ts +64 -88
- package/src/__tests__/playbook-execution.test.ts +0 -21
- package/src/__tests__/playbook-tools.test.ts +0 -21
- package/src/__tests__/pricing.test.ts +100 -0
- package/src/__tests__/relay-server.test.ts +1 -25
- package/src/__tests__/runtime-attachment-metadata.test.ts +0 -24
- package/src/__tests__/runtime-events-sse-parity.test.ts +2 -24
- package/src/__tests__/runtime-events-sse.test.ts +0 -24
- package/src/__tests__/sandbox-diagnostics.test.ts +2 -1
- package/src/__tests__/scaffold-managed-skill-tool.test.ts +1 -1
- package/src/__tests__/schedule-store.test.ts +0 -21
- package/src/__tests__/schedule-tools.test.ts +0 -21
- package/src/__tests__/scheduler-recurrence.test.ts +0 -21
- package/src/__tests__/scoped-approval-grants.test.ts +0 -21
- package/src/__tests__/scoped-grant-security-matrix.test.ts +0 -21
- package/src/__tests__/secret-allowlist.test.ts +1 -1
- package/src/__tests__/secret-ingress-channel.test.ts +0 -5
- package/src/__tests__/secret-ingress-cli.test.ts +0 -6
- package/src/__tests__/secret-ingress-http.test.ts +0 -5
- package/src/__tests__/secret-ingress.test.ts +0 -5
- package/src/__tests__/send-endpoint-busy.test.ts +0 -24
- package/src/__tests__/sequence-store.test.ts +0 -21
- package/src/__tests__/server-history-render.test.ts +0 -24
- package/src/__tests__/shell-tool-proxy-mode.test.ts +0 -4
- package/src/__tests__/skill-load-inline-command.test.ts +9 -0
- package/src/__tests__/skill-load-inline-includes.test.ts +9 -0
- package/src/__tests__/skill-load-tool.test.ts +11 -0
- package/src/__tests__/skills-uninstall.test.ts +10 -8
- package/src/__tests__/skills.test.ts +1 -1
- package/src/__tests__/slack-channel-config.test.ts +1 -1
- package/src/__tests__/slack-inbound-verification.test.ts +0 -22
- package/src/__tests__/starter-bundle.test.ts +4 -1
- package/src/__tests__/suggestion-routes.test.ts +2 -0
- package/src/__tests__/system-prompt.test.ts +1 -1
- package/src/__tests__/terminal-tools.test.ts +1 -1
- package/src/__tests__/test-preload.ts +31 -0
- package/src/__tests__/tool-execution-abort-cleanup.test.ts +1 -1
- package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +1 -1
- package/src/__tests__/tool-executor.test.ts +0 -20
- package/src/__tests__/tool-input-summary.test.ts +124 -0
- package/src/__tests__/tool-preview-lifecycle.test.ts +2 -1
- package/src/__tests__/trust-store.test.ts +7 -1
- package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +1 -1
- package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +1 -1
- package/src/__tests__/trusted-contact-multichannel.test.ts +1 -1
- package/src/__tests__/trusted-contact-verification.test.ts +1 -1
- package/src/__tests__/turn-boundary-resolution.test.ts +1 -1
- package/src/__tests__/twilio-routes.test.ts +1 -1
- package/src/__tests__/update-bulletin.test.ts +1 -1
- package/src/__tests__/vbundle-pax-and-symlink.test.ts +1 -1
- package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +1 -0
- package/src/__tests__/voice-scoped-grant-consumer.test.ts +1 -1
- package/src/__tests__/voice-session-bridge.test.ts +1 -1
- package/src/__tests__/workspace-migration-009-backfill-conversation-disk-view.test.ts +4 -4
- package/src/__tests__/workspace-migration-013-repair-conversation-disk-view.test.ts +1 -1
- package/src/__tests__/workspace-migration-down-functions.test.ts +15 -3
- package/src/__tests__/workspace-migration-seed-device-id.test.ts +40 -4
- package/src/agent/loop.ts +6 -9
- package/src/approvals/guardian-decision-primitive.ts +46 -18
- package/src/approvals/guardian-request-resolvers.ts +19 -2
- package/src/calls/active-call-lease.ts +2 -2
- package/src/cli/AGENTS.md +1 -1
- package/src/cli/commands/doctor.ts +9 -9
- package/src/cli/commands/memory.ts +142 -0
- package/src/cli/commands/oauth/__tests__/connect.test.ts +13 -11
- package/src/cli/commands/oauth/__tests__/ping.test.ts +1 -1
- package/src/cli/commands/oauth/connect.ts +13 -12
- package/src/cli/commands/oauth/index.ts +1 -1
- package/src/cli/commands/oauth/providers.ts +47 -62
- package/src/cli/commands/platform/__tests__/connect.test.ts +72 -46
- package/src/cli/commands/platform/__tests__/disconnect.test.ts +54 -1
- package/src/cli/commands/platform/__tests__/status.test.ts +36 -0
- package/src/cli/commands/platform/connect.ts +17 -7
- package/src/cli/commands/platform/disconnect.ts +28 -3
- package/src/cli/commands/platform/index.ts +3 -3
- package/src/cli.ts +1 -299
- package/src/config/assistant-feature-flags.ts +23 -15
- package/src/config/bundled-skills/app-builder/TOOLS.json +16 -0
- package/src/config/bundled-skills/app-builder/tools/app-create.ts +4 -0
- package/src/config/bundled-skills/app-builder/tools/app-delete.ts +5 -1
- package/src/config/bundled-skills/app-builder/tools/app-generate-icon.ts +9 -1
- package/src/config/bundled-skills/app-builder/tools/app-refresh.ts +5 -1
- package/src/config/bundled-skills/contacts/TOOLS.json +8 -0
- package/src/config/bundled-skills/contacts/tools/contact-search.ts +10 -1
- package/src/config/bundled-skills/contacts/tools/contact-upsert.ts +16 -2
- package/src/config/bundled-skills/media-processing/tools/ingest-media.ts +1 -0
- package/src/config/bundled-skills/messaging/SKILL.md +7 -7
- package/src/config/bundled-skills/messaging/tools/messaging-send.ts +37 -0
- package/src/config/bundled-skills/slack/SKILL.md +18 -0
- package/src/config/env-registry.ts +15 -11
- package/src/config/env.ts +1 -11
- package/src/config/feature-flag-registry.json +16 -0
- package/src/config/schema.ts +4 -0
- package/src/config/schemas/heartbeat.ts +6 -1
- package/src/config/schemas/inference.ts +14 -3
- package/src/config/schemas/memory-processing.ts +16 -8
- package/src/config/schemas/memory-retrieval.ts +3 -3
- package/src/config/skills.ts +1 -1
- package/src/context/window-manager.ts +174 -51
- package/src/credential-execution/executable-discovery.ts +2 -2
- package/src/daemon/approved-devices-store.ts +2 -2
- package/src/daemon/assistant-attachments.ts +2 -0
- package/src/daemon/config-watcher.ts +4 -50
- package/src/daemon/conversation-agent-loop-handlers.ts +9 -1
- package/src/daemon/conversation-agent-loop.ts +12 -0
- package/src/daemon/conversation-error.ts +3 -5
- package/src/daemon/conversation-history.ts +7 -3
- package/src/daemon/conversation-lifecycle.ts +16 -0
- package/src/daemon/conversation-messaging.ts +1 -0
- package/src/daemon/conversation-notifiers.ts +67 -30
- package/src/daemon/conversation-process.ts +161 -2
- package/src/daemon/conversation-queue-manager.ts +2 -0
- package/src/daemon/conversation-runtime-assembly.ts +33 -11
- package/src/daemon/conversation-slash.ts +14 -3
- package/src/daemon/conversation-tool-setup.ts +2 -0
- package/src/daemon/conversation-usage.ts +32 -4
- package/src/daemon/conversation.ts +33 -1
- package/src/daemon/daemon-control.ts +32 -16
- package/src/daemon/date-context.ts +47 -45
- package/src/daemon/dictation-profile-store.ts +2 -2
- package/src/daemon/handlers/conversations.ts +19 -0
- package/src/daemon/handlers/shared.ts +14 -21
- package/src/daemon/lifecycle.ts +5 -7
- package/src/daemon/message-types/conversations.ts +2 -0
- package/src/daemon/message-types/guardian-actions.ts +3 -17
- package/src/daemon/message-types/integrations.ts +11 -1
- package/src/daemon/message-types/messages.ts +1 -0
- package/src/daemon/pairing-store.ts +2 -79
- package/src/daemon/server.ts +154 -8
- package/src/daemon/watch-handler.ts +65 -21
- package/src/email/guardrails.ts +3 -3
- package/src/heartbeat/heartbeat-service.ts +14 -7
- package/src/hooks/cli.ts +2 -2
- package/src/hooks/config.ts +2 -2
- package/src/hooks/discovery.ts +2 -2
- package/src/hooks/manager.ts +2 -2
- package/src/hooks/runner.ts +5 -2
- package/src/hooks/templates.ts +2 -2
- package/src/memory/admin.ts +181 -2
- package/src/memory/app-git-service.ts +61 -4
- package/src/memory/attachments-store.ts +2 -0
- package/src/memory/canonical-guardian-store.ts +16 -0
- package/src/memory/db-init.ts +8 -0
- package/src/memory/embedding-local.ts +5 -2
- package/src/memory/indexer.ts +44 -26
- package/src/memory/items-extractor.ts +34 -82
- package/src/memory/job-handlers/batch-extraction.ts +741 -0
- package/src/memory/job-handlers/journal-carry-forward.test.ts +383 -0
- package/src/memory/job-handlers/journal-carry-forward.ts +255 -0
- package/src/memory/jobs-store.ts +28 -0
- package/src/memory/jobs-worker.ts +56 -9
- package/src/memory/lifecycle-events-store.ts +4 -2
- package/src/memory/llm-request-log-store.ts +40 -2
- package/src/memory/llm-usage-store.ts +4 -3
- package/src/memory/migrations/199-guardian-request-enrichment-columns.ts +71 -0
- package/src/memory/migrations/200-usage-llm-call-count.ts +20 -0
- package/src/memory/migrations/index.ts +2 -0
- package/src/memory/query-expansion.ts +83 -0
- package/src/memory/retriever.test.ts +119 -0
- package/src/memory/retriever.ts +513 -105
- package/src/memory/schema/guardian.ts +4 -0
- package/src/memory/schema/infrastructure.ts +1 -0
- package/src/memory/search/formatting.test.ts +140 -0
- package/src/memory/search/formatting.ts +143 -198
- package/src/memory/search/mmr.ts +136 -0
- package/src/memory/search/staleness.ts +0 -15
- package/src/memory/search/tier-classifier.ts +10 -21
- package/src/memory/search/types.ts +17 -0
- package/src/messaging/providers/slack/adapter.ts +51 -5
- package/src/notifications/broadcaster.ts +13 -0
- package/src/notifications/copy-composer.ts +8 -0
- package/src/oauth/connect-orchestrator.ts +1 -1
- package/src/oauth/connection-resolver.ts +2 -2
- package/src/oauth/provider-serializer.ts +116 -0
- package/src/permissions/trust-store.ts +24 -7
- package/src/prompts/__tests__/build-cli-reference-section.test.ts +5 -0
- package/src/prompts/journal-context.ts +50 -35
- package/src/prompts/persona-resolver.ts +1 -1
- package/src/prompts/system-prompt.ts +27 -28
- package/src/prompts/templates/BOOTSTRAP.md +14 -1
- package/src/prompts/templates/HEARTBEAT.md +10 -0
- package/src/prompts/templates/NOW.md +19 -25
- package/src/prompts/templates/SOUL.md +13 -1
- package/src/prompts/templates/UPDATES.md +12 -0
- package/src/prompts/update-bulletin.ts +1 -1
- package/src/providers/anthropic/client.ts +89 -18
- package/src/providers/model-catalog.ts +22 -2
- package/src/providers/model-intents.ts +2 -2
- package/src/providers/openai/client.ts +40 -1
- package/src/providers/retry.ts +23 -4
- package/src/providers/types.ts +2 -0
- package/src/runtime/assistant-scope.ts +1 -1
- package/src/runtime/auth/__tests__/credential-service.test.ts +1 -0
- package/src/runtime/auth/route-policy.ts +1 -0
- package/src/runtime/auth/token-service.ts +51 -29
- package/src/runtime/confirmation-request-guardian-bridge.ts +3 -1
- package/src/runtime/guardian-decision-types.ts +16 -10
- package/src/runtime/http-server.ts +3 -14
- package/src/runtime/http-types.ts +1 -0
- package/src/runtime/migrations/vbundle-builder.ts +7 -4
- package/src/runtime/migrations/vbundle-import-analyzer.ts +0 -4
- package/src/runtime/migrations/vbundle-importer.ts +1 -1
- package/src/runtime/routes/conversation-query-routes.ts +40 -8
- package/src/runtime/routes/conversation-routes.ts +125 -3
- package/src/runtime/routes/guardian-action-routes.ts +9 -3
- package/src/runtime/routes/identity-routes.ts +25 -4
- package/src/runtime/routes/llm-context-normalization.ts +1 -0
- package/src/runtime/routes/log-export-routes.ts +34 -12
- package/src/runtime/routes/migration-routes.ts +6 -10
- package/src/runtime/routes/oauth-apps.ts +2 -9
- package/src/runtime/routes/oauth-providers.ts +60 -0
- package/src/runtime/routes/pairing-routes.ts +0 -8
- package/src/runtime/routes/settings-routes.ts +0 -1
- package/src/runtime/routes/telemetry-routes.ts +16 -4
- package/src/security/encrypted-store.ts +2 -2
- package/src/security/secret-allowlist.ts +3 -3
- package/src/signals/emit-event.ts +42 -0
- package/src/signals/user-message.ts +37 -0
- package/src/telemetry/usage-telemetry-reporter.test.ts +83 -19
- package/src/telemetry/usage-telemetry-reporter.ts +23 -17
- package/src/tools/browser/runtime-check.ts +2 -2
- package/src/tools/credentials/vault.ts +2 -249
- package/src/tools/memory/definitions.ts +1 -1
- package/src/tools/memory/handlers.test.ts +50 -8
- package/src/tools/memory/handlers.ts +3 -1
- package/src/tools/side-effects.ts +1 -6
- package/src/tools/terminal/safe-env.ts +3 -2
- package/src/tools/terminal/shell.ts +11 -14
- package/src/tools/tool-approval-handler.ts +20 -1
- package/src/tools/tool-input-summary.ts +66 -0
- package/src/tools/types.ts +4 -0
- package/src/usage/types.ts +4 -0
- package/src/util/device-id.ts +10 -10
- package/src/util/platform.ts +71 -33
- package/src/util/pricing.ts +19 -6
- package/src/util/strip-comment-lines.ts +28 -0
- package/src/workspace/git-service.ts +8 -18
- package/src/workspace/migrations/003-seed-device-id.ts +6 -4
- package/src/workspace/migrations/016-extract-feature-flags-to-protected.ts +7 -1
- package/src/workspace/migrations/017-seed-persona-dirs.ts +2 -4
- package/src/workspace/migrations/021-move-signals-to-workspace.ts +84 -0
- package/src/workspace/migrations/022-move-hooks-to-workspace.ts +94 -0
- package/src/workspace/migrations/023-move-config-files-to-workspace.ts +86 -0
- package/src/workspace/migrations/024-move-runtime-files-to-workspace.ts +126 -0
- package/src/workspace/migrations/migrate-to-workspace-volume.ts +3 -6
- package/src/workspace/migrations/registry.ts +8 -0
- package/src/signals/confirm.ts +0 -82
- package/src/signals/trust-rule.ts +0 -174
|
@@ -48,27 +48,10 @@ mock.module("../tools/registry.js", () => ({
|
|
|
48
48
|
// Mock oauth-store to avoid SQLite dependency in unit tests
|
|
49
49
|
// ---------------------------------------------------------------------------
|
|
50
50
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
typeof mock<(key: string, clientId: string) => unknown>
|
|
56
|
-
>;
|
|
57
|
-
let mockGetProvider: ReturnType<typeof mock<(key: string) => unknown>>;
|
|
58
|
-
|
|
59
|
-
mock.module("../oauth/oauth-store.js", () => {
|
|
60
|
-
mockGetMostRecentAppByProvider = mock(() => undefined);
|
|
61
|
-
mockGetAppByProviderAndClientId = mock(() => undefined);
|
|
62
|
-
mockGetProvider = mock(() => undefined);
|
|
63
|
-
return {
|
|
64
|
-
getMostRecentAppByProvider: mockGetMostRecentAppByProvider,
|
|
65
|
-
getAppByProviderAndClientId: mockGetAppByProviderAndClientId,
|
|
66
|
-
getProvider: mockGetProvider,
|
|
67
|
-
listConnections: mock(() => []),
|
|
68
|
-
seedProviders: mock(() => {}),
|
|
69
|
-
disconnectOAuthProvider: mock(async () => "not-found" as const),
|
|
70
|
-
};
|
|
71
|
-
});
|
|
51
|
+
mock.module("../oauth/oauth-store.js", () => ({
|
|
52
|
+
disconnectOAuthProvider: mock(async () => "not-found" as const),
|
|
53
|
+
getActiveConnection: mock(() => undefined),
|
|
54
|
+
}));
|
|
72
55
|
|
|
73
56
|
let manualConnectionStore: Record<string, string> = {};
|
|
74
57
|
let slackChannelConfigCalls: Array<{
|
|
@@ -181,36 +164,6 @@ mock.module("../daemon/handlers/config-slack-channel.js", () => ({
|
|
|
181
164
|
},
|
|
182
165
|
}));
|
|
183
166
|
|
|
184
|
-
// ---------------------------------------------------------------------------
|
|
185
|
-
// Mock public ingress URL — not available in unit tests. The connect
|
|
186
|
-
// orchestrator dynamically imports this for non-interactive flows.
|
|
187
|
-
// ---------------------------------------------------------------------------
|
|
188
|
-
|
|
189
|
-
mock.module("../inbound/public-ingress-urls.js", () => ({
|
|
190
|
-
getPublicBaseUrl: () => {
|
|
191
|
-
throw new Error("No public ingress URL configured");
|
|
192
|
-
},
|
|
193
|
-
}));
|
|
194
|
-
|
|
195
|
-
// ---------------------------------------------------------------------------
|
|
196
|
-
// Mock prepareOAuth2Flow — unit tests should not start real loopback HTTP
|
|
197
|
-
// servers. The connect orchestrator still runs its own validation logic
|
|
198
|
-
// (scope policy, non-interactive ingress checks, etc.) but the actual
|
|
199
|
-
// OAuth flow setup is stubbed.
|
|
200
|
-
// ---------------------------------------------------------------------------
|
|
201
|
-
|
|
202
|
-
mock.module("../security/oauth2.js", () => ({
|
|
203
|
-
prepareOAuth2Flow: mock(async () => ({
|
|
204
|
-
authUrl: "https://mock-auth-url.example.com/authorize",
|
|
205
|
-
state: "mock-state",
|
|
206
|
-
completion: new Promise(() => {}),
|
|
207
|
-
})),
|
|
208
|
-
startOAuth2Flow: mock(async () => ({
|
|
209
|
-
grantedScopes: [],
|
|
210
|
-
tokens: { access_token: "mock-token" },
|
|
211
|
-
})),
|
|
212
|
-
}));
|
|
213
|
-
|
|
214
167
|
// ---------------------------------------------------------------------------
|
|
215
168
|
// Imports under test
|
|
216
169
|
// ---------------------------------------------------------------------------
|
|
@@ -749,372 +702,7 @@ describe("credential_store tool — prompt action", () => {
|
|
|
749
702
|
});
|
|
750
703
|
|
|
751
704
|
// ---------------------------------------------------------------------------
|
|
752
|
-
// 4. Vault —
|
|
753
|
-
// ---------------------------------------------------------------------------
|
|
754
|
-
|
|
755
|
-
describe("credential_store tool — oauth2_connect error paths", () => {
|
|
756
|
-
/** Well-known provider rows returned by the mocked getProvider */
|
|
757
|
-
const wellKnownProviders: Record<string, object> = {
|
|
758
|
-
google: {
|
|
759
|
-
key: "google",
|
|
760
|
-
authUrl: "https://accounts.google.com/o/oauth2/v2/auth",
|
|
761
|
-
tokenUrl: "https://oauth2.googleapis.com/token",
|
|
762
|
-
defaultScopes: JSON.stringify(["https://mail.google.com/"]),
|
|
763
|
-
scopePolicy: JSON.stringify({}),
|
|
764
|
-
callbackTransport: "loopback",
|
|
765
|
-
loopbackPort: 8756,
|
|
766
|
-
},
|
|
767
|
-
slack: {
|
|
768
|
-
key: "slack",
|
|
769
|
-
authUrl: "https://slack.com/oauth/v2/authorize",
|
|
770
|
-
tokenUrl: "https://slack.com/api/oauth.v2.access",
|
|
771
|
-
defaultScopes: JSON.stringify(["channels:read"]),
|
|
772
|
-
scopePolicy: JSON.stringify({}),
|
|
773
|
-
},
|
|
774
|
-
};
|
|
775
|
-
|
|
776
|
-
beforeEach(() => {
|
|
777
|
-
if (existsSync(TEST_DIR)) rmSync(TEST_DIR, { recursive: true });
|
|
778
|
-
mkdirSync(TEST_DIR, { recursive: true });
|
|
779
|
-
_setStorePath(STORE_PATH);
|
|
780
|
-
_resetBackend();
|
|
781
|
-
_setMetadataPath(join(TEST_DIR, "metadata.json"));
|
|
782
|
-
// Return well-known provider rows so vault.ts knows google/slack are
|
|
783
|
-
// registered, and custom providers return undefined.
|
|
784
|
-
mockGetProvider.mockImplementation(
|
|
785
|
-
(key: string) => wellKnownProviders[key] ?? undefined,
|
|
786
|
-
);
|
|
787
|
-
mockGetMostRecentAppByProvider.mockClear();
|
|
788
|
-
mockGetMostRecentAppByProvider.mockImplementation(() => undefined);
|
|
789
|
-
mockGetAppByProviderAndClientId.mockClear();
|
|
790
|
-
mockGetAppByProviderAndClientId.mockImplementation(() => undefined);
|
|
791
|
-
});
|
|
792
|
-
|
|
793
|
-
afterEach(() => {
|
|
794
|
-
_setMetadataPath(null);
|
|
795
|
-
_setStorePath(null);
|
|
796
|
-
_resetBackend();
|
|
797
|
-
mockGetProvider.mockImplementation(() => undefined);
|
|
798
|
-
mockGetMostRecentAppByProvider.mockImplementation(() => undefined);
|
|
799
|
-
mockGetAppByProviderAndClientId.mockImplementation(() => undefined);
|
|
800
|
-
});
|
|
801
|
-
|
|
802
|
-
test("requires service parameter", async () => {
|
|
803
|
-
const result = await credentialStoreTool.execute(
|
|
804
|
-
{ action: "oauth2_connect" },
|
|
805
|
-
_ctx,
|
|
806
|
-
);
|
|
807
|
-
expect(result.isError).toBe(true);
|
|
808
|
-
expect(result.content).toContain("service is required");
|
|
809
|
-
});
|
|
810
|
-
|
|
811
|
-
test("rejects unknown service without registered provider", async () => {
|
|
812
|
-
const result = await credentialStoreTool.execute(
|
|
813
|
-
{
|
|
814
|
-
action: "oauth2_connect",
|
|
815
|
-
service: "custom-svc",
|
|
816
|
-
auth_url: "https://a",
|
|
817
|
-
token_url: "https://t",
|
|
818
|
-
scopes: ["read"],
|
|
819
|
-
},
|
|
820
|
-
_ctx,
|
|
821
|
-
);
|
|
822
|
-
expect(result.isError).toBe(true);
|
|
823
|
-
expect(result.content).toContain("no OAuth provider registered");
|
|
824
|
-
});
|
|
825
|
-
|
|
826
|
-
test("requires client_id", async () => {
|
|
827
|
-
mockGetProvider.mockImplementation((key: string) => {
|
|
828
|
-
if (key === "custom-svc") {
|
|
829
|
-
return {
|
|
830
|
-
key: "custom-svc",
|
|
831
|
-
authUrl: "https://auth.example.com",
|
|
832
|
-
tokenUrl: "https://token.example.com",
|
|
833
|
-
defaultScopes: JSON.stringify(["read"]),
|
|
834
|
-
scopePolicy: JSON.stringify({}),
|
|
835
|
-
};
|
|
836
|
-
}
|
|
837
|
-
return wellKnownProviders[key] ?? undefined;
|
|
838
|
-
});
|
|
839
|
-
const result = await credentialStoreTool.execute(
|
|
840
|
-
{
|
|
841
|
-
action: "oauth2_connect",
|
|
842
|
-
service: "custom-svc",
|
|
843
|
-
scopes: ["read"],
|
|
844
|
-
},
|
|
845
|
-
_ctx,
|
|
846
|
-
);
|
|
847
|
-
expect(result.isError).toBe(true);
|
|
848
|
-
expect(result.content).toContain("client_id is required");
|
|
849
|
-
});
|
|
850
|
-
|
|
851
|
-
test("non-interactive loopback oauth2_connect returns deferred auth URL", async () => {
|
|
852
|
-
// After the blanket non-interactive guard was removed (#16337),
|
|
853
|
-
// loopback-transport flows succeed with a deferred auth URL so the
|
|
854
|
-
// agent can present it to the user.
|
|
855
|
-
mockGetProvider.mockImplementation((key: string) => {
|
|
856
|
-
if (key === "custom-svc") {
|
|
857
|
-
return {
|
|
858
|
-
key: "custom-svc",
|
|
859
|
-
authUrl: "https://auth.example.com",
|
|
860
|
-
tokenUrl: "https://token.example.com",
|
|
861
|
-
defaultScopes: JSON.stringify(["read"]),
|
|
862
|
-
scopePolicy: JSON.stringify({}),
|
|
863
|
-
};
|
|
864
|
-
}
|
|
865
|
-
return wellKnownProviders[key] ?? undefined;
|
|
866
|
-
});
|
|
867
|
-
|
|
868
|
-
const result = await credentialStoreTool.execute(
|
|
869
|
-
{
|
|
870
|
-
action: "oauth2_connect",
|
|
871
|
-
service: "custom-svc",
|
|
872
|
-
auth_url: "https://auth.example.com",
|
|
873
|
-
token_url: "https://token.example.com",
|
|
874
|
-
scopes: ["read"],
|
|
875
|
-
client_id: "test-client-id",
|
|
876
|
-
},
|
|
877
|
-
{ ..._ctx, isInteractive: false },
|
|
878
|
-
);
|
|
879
|
-
expect(result.isError).toBe(false);
|
|
880
|
-
expect(result.content).toContain("mock-auth-url.example.com");
|
|
881
|
-
});
|
|
882
|
-
|
|
883
|
-
test("rejects missing client_id for google", async () => {
|
|
884
|
-
// Missing client_id should fail
|
|
885
|
-
const result = await credentialStoreTool.execute(
|
|
886
|
-
{
|
|
887
|
-
action: "oauth2_connect",
|
|
888
|
-
service: "google",
|
|
889
|
-
},
|
|
890
|
-
_ctx,
|
|
891
|
-
);
|
|
892
|
-
expect(result.isError).toBe(true);
|
|
893
|
-
// Should fail on client_id since none is stored
|
|
894
|
-
expect(result.content).toContain("client_id is required");
|
|
895
|
-
});
|
|
896
|
-
|
|
897
|
-
test("resolves slack to its canonical name", async () => {
|
|
898
|
-
const result = await credentialStoreTool.execute(
|
|
899
|
-
{
|
|
900
|
-
action: "oauth2_connect",
|
|
901
|
-
service: "slack",
|
|
902
|
-
},
|
|
903
|
-
_ctx,
|
|
904
|
-
);
|
|
905
|
-
expect(result.isError).toBe(true);
|
|
906
|
-
expect(result.content).toContain("client_id is required");
|
|
907
|
-
});
|
|
908
|
-
|
|
909
|
-
test("uses stored client_id from oauth-store DB", async () => {
|
|
910
|
-
// Mock getMostRecentAppByProvider to return an app with a client_id
|
|
911
|
-
// and store client_secret in the secure store.
|
|
912
|
-
mockGetMostRecentAppByProvider.mockImplementation(() => ({
|
|
913
|
-
id: "test-app-id",
|
|
914
|
-
providerKey: "google",
|
|
915
|
-
clientId: "stored-client-id-123",
|
|
916
|
-
clientSecretCredentialPath: "oauth_app/test-app-id/client_secret",
|
|
917
|
-
createdAt: Date.now(),
|
|
918
|
-
}));
|
|
919
|
-
mockGetProvider.mockImplementation(() => ({
|
|
920
|
-
key: "google",
|
|
921
|
-
authUrl: "https://accounts.google.com/o/oauth2/v2/auth",
|
|
922
|
-
tokenUrl: "https://oauth2.googleapis.com/token",
|
|
923
|
-
defaultScopes: JSON.stringify(["https://mail.google.com/"]),
|
|
924
|
-
scopePolicy: JSON.stringify({}),
|
|
925
|
-
callbackTransport: "loopback",
|
|
926
|
-
loopbackPort: 8756,
|
|
927
|
-
}));
|
|
928
|
-
await setSecureKeyAsync(
|
|
929
|
-
"oauth_app/test-app-id/client_secret",
|
|
930
|
-
"test-secret",
|
|
931
|
-
);
|
|
932
|
-
|
|
933
|
-
const result = await credentialStoreTool.execute(
|
|
934
|
-
{
|
|
935
|
-
action: "oauth2_connect",
|
|
936
|
-
service: "google",
|
|
937
|
-
},
|
|
938
|
-
{ ..._ctx, isInteractive: false },
|
|
939
|
-
);
|
|
940
|
-
|
|
941
|
-
// Should pass client_id and client_secret checks — the flow proceeds
|
|
942
|
-
// through the channel path (google uses loopback transport so no
|
|
943
|
-
// public ingress URL is needed) and returns the authorization URL.
|
|
944
|
-
expect(result.isError).toBe(false);
|
|
945
|
-
expect(result.content).toContain("To connect google, open this link");
|
|
946
|
-
expect(result.content).not.toContain("client_id is required");
|
|
947
|
-
expect(result.content).not.toContain("client_secret is required");
|
|
948
|
-
|
|
949
|
-
// Reset mocks
|
|
950
|
-
mockGetMostRecentAppByProvider.mockImplementation(() => undefined);
|
|
951
|
-
mockGetProvider.mockImplementation(() => undefined);
|
|
952
|
-
});
|
|
953
|
-
|
|
954
|
-
test("uses getAppByProviderAndClientId when client_id is provided without client_secret", async () => {
|
|
955
|
-
// When client_id is supplied but client_secret is not, the vault should
|
|
956
|
-
// look up the matching app via getAppByProviderAndClientId (not the
|
|
957
|
-
// most-recent-app heuristic) so the secret comes from the correct app.
|
|
958
|
-
mockGetAppByProviderAndClientId.mockImplementation(
|
|
959
|
-
(providerKey: string, cId: string) => {
|
|
960
|
-
if (providerKey === "google" && cId === "caller-supplied-client-id") {
|
|
961
|
-
return {
|
|
962
|
-
id: "matched-app-id",
|
|
963
|
-
providerKey: "google",
|
|
964
|
-
clientId: "caller-supplied-client-id",
|
|
965
|
-
clientSecretCredentialPath:
|
|
966
|
-
"oauth_app/matched-app-id/client_secret",
|
|
967
|
-
createdAt: Date.now(),
|
|
968
|
-
};
|
|
969
|
-
}
|
|
970
|
-
return undefined;
|
|
971
|
-
},
|
|
972
|
-
);
|
|
973
|
-
mockGetProvider.mockImplementation(() => ({
|
|
974
|
-
key: "google",
|
|
975
|
-
authUrl: "https://accounts.google.com/o/oauth2/v2/auth",
|
|
976
|
-
tokenUrl: "https://oauth2.googleapis.com/token",
|
|
977
|
-
defaultScopes: JSON.stringify(["https://mail.google.com/"]),
|
|
978
|
-
scopePolicy: JSON.stringify({}),
|
|
979
|
-
callbackTransport: "loopback",
|
|
980
|
-
loopbackPort: 8756,
|
|
981
|
-
}));
|
|
982
|
-
await setSecureKeyAsync(
|
|
983
|
-
"oauth_app/matched-app-id/client_secret",
|
|
984
|
-
"matched-secret",
|
|
985
|
-
);
|
|
986
|
-
|
|
987
|
-
const result = await credentialStoreTool.execute(
|
|
988
|
-
{
|
|
989
|
-
action: "oauth2_connect",
|
|
990
|
-
service: "google",
|
|
991
|
-
client_id: "caller-supplied-client-id",
|
|
992
|
-
},
|
|
993
|
-
{ ..._ctx, isInteractive: false },
|
|
994
|
-
);
|
|
995
|
-
|
|
996
|
-
// Should succeed — client_secret resolved from the matched app
|
|
997
|
-
expect(result.isError).toBe(false);
|
|
998
|
-
expect(result.content).toContain("To connect google, open this link");
|
|
999
|
-
// getMostRecentAppByProvider should NOT have been called since client_id was known
|
|
1000
|
-
expect(mockGetMostRecentAppByProvider).not.toHaveBeenCalled();
|
|
1001
|
-
|
|
1002
|
-
// Reset mocks
|
|
1003
|
-
mockGetAppByProviderAndClientId.mockImplementation(() => undefined);
|
|
1004
|
-
mockGetProvider.mockImplementation(() => undefined);
|
|
1005
|
-
});
|
|
1006
|
-
|
|
1007
|
-
test("falls back to getMostRecentAppByProvider when client_id is not provided", async () => {
|
|
1008
|
-
// When neither client_id nor client_secret is provided, the vault should
|
|
1009
|
-
// use getMostRecentAppByProvider (the fallback heuristic).
|
|
1010
|
-
mockGetMostRecentAppByProvider.mockImplementation(() => ({
|
|
1011
|
-
id: "recent-app-id",
|
|
1012
|
-
providerKey: "google",
|
|
1013
|
-
clientId: "recent-client-id",
|
|
1014
|
-
clientSecretCredentialPath: "oauth_app/recent-app-id/client_secret",
|
|
1015
|
-
createdAt: Date.now(),
|
|
1016
|
-
}));
|
|
1017
|
-
mockGetProvider.mockImplementation(() => ({
|
|
1018
|
-
key: "google",
|
|
1019
|
-
authUrl: "https://accounts.google.com/o/oauth2/v2/auth",
|
|
1020
|
-
tokenUrl: "https://oauth2.googleapis.com/token",
|
|
1021
|
-
defaultScopes: JSON.stringify(["https://mail.google.com/"]),
|
|
1022
|
-
scopePolicy: JSON.stringify({}),
|
|
1023
|
-
callbackTransport: "loopback",
|
|
1024
|
-
loopbackPort: 8756,
|
|
1025
|
-
}));
|
|
1026
|
-
await setSecureKeyAsync(
|
|
1027
|
-
"oauth_app/recent-app-id/client_secret",
|
|
1028
|
-
"recent-secret",
|
|
1029
|
-
);
|
|
1030
|
-
|
|
1031
|
-
const result = await credentialStoreTool.execute(
|
|
1032
|
-
{
|
|
1033
|
-
action: "oauth2_connect",
|
|
1034
|
-
service: "google",
|
|
1035
|
-
},
|
|
1036
|
-
{ ..._ctx, isInteractive: false },
|
|
1037
|
-
);
|
|
1038
|
-
|
|
1039
|
-
expect(result.isError).toBe(false);
|
|
1040
|
-
expect(result.content).toContain("To connect google, open this link");
|
|
1041
|
-
// getAppByProviderAndClientId should NOT have been called since client_id was unknown
|
|
1042
|
-
expect(mockGetAppByProviderAndClientId).not.toHaveBeenCalled();
|
|
1043
|
-
|
|
1044
|
-
// Reset mocks
|
|
1045
|
-
mockGetMostRecentAppByProvider.mockImplementation(() => undefined);
|
|
1046
|
-
mockGetProvider.mockImplementation(() => undefined);
|
|
1047
|
-
});
|
|
1048
|
-
|
|
1049
|
-
test("getAppByProviderAndClientId returning undefined leaves client_secret unresolved", async () => {
|
|
1050
|
-
// When client_id is provided but getAppByProviderAndClientId returns no
|
|
1051
|
-
// matching app, client_secret remains unresolved and the vault should
|
|
1052
|
-
// report the missing secret error.
|
|
1053
|
-
mockGetAppByProviderAndClientId.mockImplementation(() => undefined);
|
|
1054
|
-
mockGetProvider.mockImplementation(() => ({
|
|
1055
|
-
key: "google",
|
|
1056
|
-
authUrl: "https://accounts.google.com/o/oauth2/v2/auth",
|
|
1057
|
-
tokenUrl: "https://oauth2.googleapis.com/token",
|
|
1058
|
-
defaultScopes: JSON.stringify(["https://mail.google.com/"]),
|
|
1059
|
-
requiresClientSecret: 1,
|
|
1060
|
-
}));
|
|
1061
|
-
|
|
1062
|
-
const result = await credentialStoreTool.execute(
|
|
1063
|
-
{
|
|
1064
|
-
action: "oauth2_connect",
|
|
1065
|
-
service: "google",
|
|
1066
|
-
client_id: "unknown-client-id",
|
|
1067
|
-
},
|
|
1068
|
-
_ctx,
|
|
1069
|
-
);
|
|
1070
|
-
|
|
1071
|
-
expect(result.isError).toBe(true);
|
|
1072
|
-
expect(result.content).toContain("client_secret is required for google");
|
|
1073
|
-
// getMostRecentAppByProvider should NOT have been called
|
|
1074
|
-
expect(mockGetMostRecentAppByProvider).not.toHaveBeenCalled();
|
|
1075
|
-
|
|
1076
|
-
// Reset mocks
|
|
1077
|
-
mockGetAppByProviderAndClientId.mockImplementation(() => undefined);
|
|
1078
|
-
mockGetProvider.mockImplementation(() => undefined);
|
|
1079
|
-
});
|
|
1080
|
-
|
|
1081
|
-
test("rejects when client_secret is missing for service that requires it", async () => {
|
|
1082
|
-
// Mock getMostRecentAppByProvider to return an app with client_id but
|
|
1083
|
-
// no client_secret in secure storage — validates the requiresClientSecret
|
|
1084
|
-
// guardrail.
|
|
1085
|
-
mockGetMostRecentAppByProvider.mockImplementation(() => ({
|
|
1086
|
-
id: "test-app-id-no-secret",
|
|
1087
|
-
providerKey: "google",
|
|
1088
|
-
clientId: "stored-client-id-456",
|
|
1089
|
-
createdAt: Date.now(),
|
|
1090
|
-
}));
|
|
1091
|
-
mockGetProvider.mockImplementation(() => ({
|
|
1092
|
-
key: "google",
|
|
1093
|
-
authUrl: "https://accounts.google.com/o/oauth2/v2/auth",
|
|
1094
|
-
tokenUrl: "https://oauth2.googleapis.com/token",
|
|
1095
|
-
defaultScopes: JSON.stringify(["https://mail.google.com/"]),
|
|
1096
|
-
requiresClientSecret: 1,
|
|
1097
|
-
}));
|
|
1098
|
-
|
|
1099
|
-
const result = await credentialStoreTool.execute(
|
|
1100
|
-
{
|
|
1101
|
-
action: "oauth2_connect",
|
|
1102
|
-
service: "google",
|
|
1103
|
-
},
|
|
1104
|
-
_ctx,
|
|
1105
|
-
);
|
|
1106
|
-
|
|
1107
|
-
expect(result.isError).toBe(true);
|
|
1108
|
-
expect(result.content).toContain("client_secret is required for google");
|
|
1109
|
-
|
|
1110
|
-
// Reset mocks
|
|
1111
|
-
mockGetMostRecentAppByProvider.mockImplementation(() => undefined);
|
|
1112
|
-
mockGetProvider.mockImplementation(() => undefined);
|
|
1113
|
-
});
|
|
1114
|
-
});
|
|
1115
|
-
|
|
1116
|
-
// ---------------------------------------------------------------------------
|
|
1117
|
-
// 5. Vault — store action validation edge cases
|
|
705
|
+
// 4. Vault — store action validation edge cases
|
|
1118
706
|
// ---------------------------------------------------------------------------
|
|
1119
707
|
|
|
1120
708
|
describe("credential_store tool — store validation edge cases", () => {
|
|
@@ -1282,7 +870,7 @@ describe("credential_store tool — store validation edge cases", () => {
|
|
|
1282
870
|
});
|
|
1283
871
|
|
|
1284
872
|
// ---------------------------------------------------------------------------
|
|
1285
|
-
//
|
|
873
|
+
// 5. Vault — tool definition schema
|
|
1286
874
|
// ---------------------------------------------------------------------------
|
|
1287
875
|
|
|
1288
876
|
describe("credential_store tool — tool definition", () => {
|
|
@@ -1298,14 +886,7 @@ describe("credential_store tool — tool definition", () => {
|
|
|
1298
886
|
expect(schema.type).toBe("object");
|
|
1299
887
|
expect(schema.required).toContain("action");
|
|
1300
888
|
const props = schema.properties as Record<string, Record<string, unknown>>;
|
|
1301
|
-
expect(props.action.enum).toEqual([
|
|
1302
|
-
"store",
|
|
1303
|
-
"list",
|
|
1304
|
-
"delete",
|
|
1305
|
-
"prompt",
|
|
1306
|
-
"oauth2_connect",
|
|
1307
|
-
"describe",
|
|
1308
|
-
]);
|
|
889
|
+
expect(props.action.enum).toEqual(["store", "list", "delete", "prompt"]);
|
|
1309
890
|
});
|
|
1310
891
|
|
|
1311
892
|
test("getDefinition includes injection_templates schema", () => {
|
|
@@ -1326,7 +907,7 @@ describe("credential_store tool — tool definition", () => {
|
|
|
1326
907
|
});
|
|
1327
908
|
|
|
1328
909
|
// ---------------------------------------------------------------------------
|
|
1329
|
-
//
|
|
910
|
+
// 6. Broker — serverUseById with transient not supported
|
|
1330
911
|
// (transient is scoped to authorize+consume and browserFill/serverUse)
|
|
1331
912
|
// ---------------------------------------------------------------------------
|
|
1332
913
|
|
|
@@ -1399,7 +980,7 @@ describe("CredentialBroker — serverUseById edge cases", () => {
|
|
|
1399
980
|
});
|
|
1400
981
|
|
|
1401
982
|
// ---------------------------------------------------------------------------
|
|
1402
|
-
//
|
|
983
|
+
// 7. Broker — revokeAll clears transient values indirectly via token cleanup
|
|
1403
984
|
// ---------------------------------------------------------------------------
|
|
1404
985
|
|
|
1405
986
|
describe("CredentialBroker — revokeAll", () => {
|
|
@@ -1087,32 +1087,32 @@ describe("assistant credentials CLI", () => {
|
|
|
1087
1087
|
});
|
|
1088
1088
|
|
|
1089
1089
|
// =========================================================================
|
|
1090
|
-
// instance-scoped
|
|
1090
|
+
// instance-scoped workspace
|
|
1091
1091
|
// =========================================================================
|
|
1092
1092
|
|
|
1093
|
-
describe("instance-scoped
|
|
1094
|
-
let
|
|
1093
|
+
describe("instance-scoped workspace", () => {
|
|
1094
|
+
let savedWorkspaceDir: string | undefined;
|
|
1095
1095
|
|
|
1096
1096
|
beforeEach(() => {
|
|
1097
|
-
|
|
1097
|
+
savedWorkspaceDir = process.env.VELLUM_WORKSPACE_DIR;
|
|
1098
1098
|
});
|
|
1099
1099
|
|
|
1100
1100
|
afterEach(() => {
|
|
1101
|
-
if (
|
|
1102
|
-
delete process.env.
|
|
1101
|
+
if (savedWorkspaceDir === undefined) {
|
|
1102
|
+
delete process.env.VELLUM_WORKSPACE_DIR;
|
|
1103
1103
|
} else {
|
|
1104
|
-
process.env.
|
|
1104
|
+
process.env.VELLUM_WORKSPACE_DIR = savedWorkspaceDir;
|
|
1105
1105
|
}
|
|
1106
1106
|
});
|
|
1107
1107
|
|
|
1108
|
-
test("credential reveal reads from instance-scoped store when
|
|
1109
|
-
// Point
|
|
1108
|
+
test("credential reveal reads from instance-scoped store when VELLUM_WORKSPACE_DIR is set", async () => {
|
|
1109
|
+
// Point VELLUM_WORKSPACE_DIR to a temp directory (simulating instance-scoped dir)
|
|
1110
1110
|
const tmpDir = (await import("node:os")).tmpdir();
|
|
1111
1111
|
const instanceDir = (await import("node:path")).join(
|
|
1112
1112
|
tmpDir,
|
|
1113
1113
|
`vellum-test-instance-${Date.now()}`,
|
|
1114
1114
|
);
|
|
1115
|
-
process.env.
|
|
1115
|
+
process.env.VELLUM_WORKSPACE_DIR = instanceDir;
|
|
1116
1116
|
|
|
1117
1117
|
// Seed a credential in the mock store
|
|
1118
1118
|
seedCredential("twilio", "auth_token", "instance_secret_abc123");
|
|
@@ -9,25 +9,6 @@
|
|
|
9
9
|
import { describe, expect, mock, test } from "bun:test";
|
|
10
10
|
|
|
11
11
|
// ── Platform mock (must happen before imports that read it) ─────────────────
|
|
12
|
-
mock.module("../util/platform.js", () => ({
|
|
13
|
-
getSessionTokenPath: () => "/tmp/test-token",
|
|
14
|
-
getRootDir: () => "/tmp/test",
|
|
15
|
-
getDataDir: () => "/tmp/test",
|
|
16
|
-
getWorkspaceDir: () => "/tmp/test/workspace",
|
|
17
|
-
getWorkspaceSkillsDir: () => "/tmp/test/skills",
|
|
18
|
-
getSandboxWorkingDir: () => "/tmp/test/sandbox",
|
|
19
|
-
getTCPPort: () => undefined,
|
|
20
|
-
getTCPHost: () => "127.0.0.1",
|
|
21
|
-
isTCPEnabled: () => false,
|
|
22
|
-
isMacOS: () => false,
|
|
23
|
-
isLinux: () => true,
|
|
24
|
-
isWindows: () => false,
|
|
25
|
-
getPidPath: () => "/tmp/test.pid",
|
|
26
|
-
getLogPath: () => "/tmp/test.log",
|
|
27
|
-
getDbPath: () => "/tmp/test.db",
|
|
28
|
-
ensureDataDir: () => {},
|
|
29
|
-
}));
|
|
30
|
-
|
|
31
12
|
mock.module("../util/logger.js", () => ({
|
|
32
13
|
getLogger: () =>
|
|
33
14
|
new Proxy({} as Record<string, unknown>, {
|