@vellumai/assistant 0.5.10 → 0.5.12
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/AGENTS.md +8 -0
- package/ARCHITECTURE.md +43 -43
- package/Dockerfile +3 -0
- package/docs/architecture/integrations.md +37 -42
- package/docs/architecture/memory.md +7 -12
- package/docs/credential-execution-service.md +9 -9
- package/docs/skills.md +1 -1
- package/node_modules/@vellumai/ces-contracts/src/__tests__/grants.test.ts +7 -7
- package/node_modules/@vellumai/ces-contracts/src/handles.ts +5 -4
- package/node_modules/@vellumai/credential-storage/src/index.ts +3 -3
- package/node_modules/@vellumai/credential-storage/src/static-credentials.ts +1 -1
- package/openapi.yaml +7208 -0
- package/package.json +2 -1
- package/scripts/generate-openapi.ts +562 -0
- package/src/__tests__/acp-session.test.ts +239 -44
- package/src/__tests__/assistant-feature-flag-guard.test.ts +8 -8
- package/src/__tests__/assistant-feature-flag-guardrails.test.ts +5 -86
- package/src/__tests__/assistant-feature-flags-integration.test.ts +7 -14
- package/src/__tests__/browser-skill-endstate.test.ts +1 -1
- package/src/__tests__/btw-routes.test.ts +8 -0
- package/src/__tests__/bundled-skill-retrieval-guard.test.ts +10 -10
- package/src/__tests__/catalog-cache.test.ts +164 -0
- package/src/__tests__/catalog-search.test.ts +61 -0
- package/src/__tests__/channel-approvals.test.ts +7 -7
- package/src/__tests__/channel-readiness-service.test.ts +41 -0
- package/src/__tests__/cli-command-risk-guard.test.ts +181 -6
- package/src/__tests__/config-schema.test.ts +10 -2
- package/src/__tests__/context-memory-e2e.test.ts +2 -6
- package/src/__tests__/conversation-delete-schedule-cleanup.test.ts +396 -0
- package/src/__tests__/conversation-error.test.ts +3 -2
- package/src/__tests__/conversation-skill-tools.test.ts +1 -3
- package/src/__tests__/conversation-title-service.test.ts +2 -15
- package/src/__tests__/credential-execution-feature-gates.test.ts +4 -8
- package/src/__tests__/credential-execution-managed-contract.test.ts +8 -8
- package/src/__tests__/credential-security-e2e.test.ts +4 -4
- package/src/__tests__/credential-security-invariants.test.ts +12 -18
- package/src/__tests__/credential-vault-unit.test.ts +32 -34
- package/src/__tests__/credential-vault.test.ts +25 -33
- package/src/__tests__/credentials-cli.test.ts +3 -3
- package/src/__tests__/daemon-credential-client.test.ts +2 -2
- package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +1 -1
- package/src/__tests__/gateway-only-guard.test.ts +3 -0
- package/src/__tests__/heartbeat-service.test.ts +35 -0
- package/src/__tests__/host-bash-proxy.test.ts +79 -0
- package/src/__tests__/host-cu-proxy.test.ts +90 -0
- package/src/__tests__/host-file-proxy.test.ts +89 -0
- package/src/__tests__/host-shell-tool.test.ts +1 -1
- package/src/__tests__/inline-skill-load-permissions.test.ts +3 -3
- package/src/__tests__/integration-status.test.ts +5 -5
- package/src/__tests__/list-messages-attachments.test.ts +171 -0
- package/src/__tests__/llm-request-log-turn-query.test.ts +64 -0
- package/src/__tests__/log-export-workspace.test.ts +1 -1
- package/src/__tests__/mcp-abort-signal.test.ts +205 -0
- package/src/__tests__/mcp-client-auth.test.ts +1 -1
- package/src/__tests__/memory-lifecycle-e2e.test.ts +2 -2
- package/src/__tests__/memory-recall-log-store.test.ts +182 -0
- package/src/__tests__/memory-recall-quality.test.ts +6 -8
- package/src/__tests__/memory-regressions.test.ts +53 -42
- package/src/__tests__/memory-retrieval.benchmark.test.ts +5 -9
- package/src/__tests__/messaging-send-tool.test.ts +5 -5
- package/src/__tests__/messaging-skill-split.test.ts +2 -17
- package/src/__tests__/notification-telegram-adapter.test.ts +125 -0
- package/src/__tests__/oauth-cli.test.ts +203 -649
- package/src/__tests__/oauth-provider-profiles.test.ts +55 -20
- package/src/__tests__/oauth-scope-policy.test.ts +4 -6
- package/src/__tests__/onboarding-template-contract.test.ts +2 -2
- package/src/__tests__/platform-callback-registration.test.ts +119 -0
- package/src/__tests__/secret-ingress-channel.test.ts +261 -0
- package/src/__tests__/secret-ingress-cli.test.ts +201 -0
- package/src/__tests__/secret-ingress-http.test.ts +312 -0
- package/src/__tests__/secret-ingress.test.ts +283 -0
- package/src/__tests__/secret-onetime-send.test.ts +4 -4
- package/src/__tests__/secret-routes-managed-proxy.test.ts +78 -0
- package/src/__tests__/secure-keys-managed-failover.test.ts +73 -0
- package/src/__tests__/skill-feature-flags-integration.test.ts +4 -4
- package/src/__tests__/skill-feature-flags.test.ts +11 -19
- package/src/__tests__/skill-load-feature-flag.test.ts +1 -1
- package/src/__tests__/skill-load-inline-command.test.ts +3 -3
- package/src/__tests__/skill-load-inline-includes.test.ts +2 -2
- package/src/__tests__/skill-memory.test.ts +2 -4
- package/src/__tests__/skill-projection-feature-flag.test.ts +2 -4
- package/src/__tests__/skill-projection.benchmark.test.ts +1 -3
- package/src/__tests__/skills-uninstall.test.ts +2 -2
- package/src/__tests__/skills.test.ts +16 -2
- package/src/__tests__/slack-channel-config.test.ts +1 -1
- package/src/__tests__/slack-messaging-token-resolution.test.ts +22 -24
- package/src/__tests__/slack-share-routes.test.ts +5 -5
- package/src/__tests__/slack-skill.test.ts +5 -69
- package/src/__tests__/system-prompt.test.ts +39 -0
- package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +1 -1
- package/src/__tests__/workspace-migration-018-rekey-compound-credential-keys.test.ts +181 -0
- package/src/__tests__/workspace-migration-backfill-installation-id.test.ts +5 -4
- package/src/acp/client-handler.ts +113 -31
- package/src/acp/session-manager.ts +29 -27
- package/src/approvals/guardian-request-resolvers.ts +1 -1
- package/src/cli/AGENTS.md +113 -0
- package/src/cli/commands/autonomy.ts +3 -5
- package/src/cli/commands/browser-relay.ts +2 -17
- package/src/cli/commands/contacts.ts +6 -4
- package/src/cli/commands/conversations.ts +13 -1
- package/src/cli/commands/credential-execution.ts +17 -3
- package/src/cli/commands/credentials.ts +2 -8
- package/src/cli/commands/memory.ts +2 -3
- package/src/cli/commands/oauth/__tests__/connect.test.ts +706 -0
- package/src/cli/commands/oauth/__tests__/disconnect.test.ts +686 -0
- package/src/cli/commands/oauth/__tests__/mode.test.ts +625 -0
- package/src/cli/commands/oauth/__tests__/ping.test.ts +631 -0
- package/src/cli/commands/oauth/__tests__/providers-delete.test.ts +574 -0
- package/src/cli/commands/oauth/__tests__/providers-update.test.ts +416 -0
- package/src/cli/commands/oauth/__tests__/status.test.ts +551 -0
- package/src/cli/commands/oauth/__tests__/token.test.ts +420 -0
- package/src/cli/commands/oauth/apps.ts +87 -50
- package/src/cli/commands/oauth/connect.ts +405 -0
- package/src/cli/commands/oauth/disconnect.ts +285 -0
- package/src/cli/commands/oauth/index.ts +62 -20
- package/src/cli/commands/oauth/mode.ts +251 -0
- package/src/cli/commands/oauth/ping.ts +196 -0
- package/src/cli/commands/oauth/providers.ts +589 -55
- package/src/cli/commands/oauth/request.ts +564 -0
- package/src/cli/commands/oauth/shared.ts +114 -0
- package/src/cli/commands/oauth/status.ts +191 -0
- package/src/cli/commands/oauth/token.ts +150 -0
- package/src/cli/commands/platform/connect.ts +104 -0
- package/src/cli/commands/platform/disconnect.ts +118 -0
- package/src/cli/commands/platform/index.ts +252 -0
- package/src/cli/commands/sequence.ts +5 -4
- package/src/cli/commands/shotgun.ts +16 -0
- package/src/cli/commands/skills.ts +173 -41
- package/src/cli/commands/usage.ts +5 -11
- package/src/cli/lib/daemon-credential-client.ts +22 -38
- package/src/cli/program.ts +1 -1
- package/src/cli.ts +82 -17
- package/src/config/assistant-feature-flags.ts +77 -18
- package/src/config/bundled-skills/_shared/CLI_RETRIEVAL_PATTERN.md +1 -1
- package/src/config/bundled-skills/app-builder/tools/app-create.ts +1 -1
- package/src/config/bundled-skills/contacts/tools/google-contacts.ts +1 -1
- package/src/config/bundled-skills/conversations/SKILL.md +20 -0
- package/src/config/bundled-skills/conversations/TOOLS.json +23 -0
- package/src/config/bundled-skills/conversations/tools/rename-conversation.ts +66 -0
- package/src/config/bundled-skills/gmail/SKILL.md +13 -13
- package/src/config/bundled-skills/gmail/tools/gmail-archive.ts +3 -3
- package/src/config/bundled-skills/gmail/tools/gmail-attachments.ts +2 -2
- package/src/config/bundled-skills/gmail/tools/gmail-draft.ts +1 -1
- package/src/config/bundled-skills/gmail/tools/gmail-filters.ts +1 -1
- package/src/config/bundled-skills/gmail/tools/gmail-follow-up.ts +1 -1
- package/src/config/bundled-skills/gmail/tools/gmail-forward.ts +1 -1
- package/src/config/bundled-skills/gmail/tools/gmail-label.ts +2 -2
- package/src/config/bundled-skills/gmail/tools/gmail-outreach-scan.ts +1 -1
- package/src/config/bundled-skills/gmail/tools/gmail-send-draft.ts +1 -1
- package/src/config/bundled-skills/gmail/tools/gmail-sender-digest.ts +1 -1
- package/src/config/bundled-skills/gmail/tools/gmail-trash.ts +1 -1
- package/src/config/bundled-skills/gmail/tools/gmail-unsubscribe.ts +1 -1
- package/src/config/bundled-skills/gmail/tools/gmail-vacation.ts +1 -1
- package/src/config/bundled-skills/google-calendar/SKILL.md +10 -4
- package/src/config/bundled-skills/google-calendar/tools/shared.ts +1 -1
- package/src/config/bundled-skills/messaging/SKILL.md +19 -42
- package/src/config/bundled-skills/messaging/TOOLS.json +9 -9
- package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +1 -1
- package/src/config/bundled-skills/messaging/tools/messaging-send.ts +5 -2
- package/src/config/bundled-skills/messaging/tools/shared.ts +5 -6
- package/src/config/bundled-skills/notifications/SKILL.md +1 -1
- package/src/config/bundled-skills/schedule/SKILL.md +2 -2
- package/src/config/bundled-skills/settings/SKILL.md +5 -3
- package/src/config/bundled-skills/settings/TOOLS.json +17 -0
- package/src/config/bundled-skills/settings/tools/avatar-get.ts +50 -0
- package/src/config/bundled-skills/settings/tools/avatar-remove.ts +7 -0
- package/src/config/bundled-skills/settings/tools/avatar-update.ts +6 -1
- package/src/config/bundled-skills/settings/tools/identity-avatar.ts +55 -0
- package/src/config/bundled-skills/skills-catalog/SKILL.md +3 -3
- package/src/config/bundled-skills/slack/SKILL.md +58 -44
- package/src/config/bundled-tool-registry.ts +7 -19
- package/src/config/env.ts +5 -1
- package/src/config/feature-flag-registry.json +58 -42
- package/src/config/loader.ts +4 -0
- package/src/config/schemas/platform.ts +0 -8
- package/src/config/schemas/security.ts +9 -1
- package/src/config/schemas/services.ts +1 -1
- package/src/config/skill-state.ts +1 -3
- package/src/config/skills.ts +2 -4
- package/src/credential-execution/client.ts +1 -1
- package/src/credential-execution/feature-gates.ts +9 -16
- package/src/credential-execution/process-manager.ts +12 -0
- package/src/daemon/config-watcher.ts +4 -0
- package/src/daemon/conversation-agent-loop-handlers.ts +10 -0
- package/src/daemon/conversation-agent-loop.ts +51 -2
- package/src/daemon/conversation-error.ts +36 -6
- package/src/daemon/conversation-memory.ts +0 -1
- package/src/daemon/conversation-messaging.ts +9 -0
- package/src/daemon/conversation-runtime-assembly.ts +33 -0
- package/src/daemon/conversation-surfaces.ts +120 -14
- package/src/daemon/conversation.ts +5 -0
- package/src/daemon/handlers/config-slack-channel.ts +43 -1
- package/src/daemon/handlers/conversations.ts +41 -33
- package/src/daemon/handlers/skills.ts +148 -3
- package/src/daemon/host-bash-proxy.ts +16 -0
- package/src/daemon/host-cu-proxy.ts +16 -0
- package/src/daemon/host-file-proxy.ts +16 -0
- package/src/daemon/lifecycle.ts +73 -3
- package/src/daemon/message-types/acp.ts +0 -15
- package/src/daemon/message-types/conversations.ts +1 -0
- package/src/daemon/message-types/guardian-actions.ts +2 -0
- package/src/daemon/message-types/host-bash.ts +6 -1
- package/src/daemon/message-types/host-cu.ts +6 -1
- package/src/daemon/message-types/host-file.ts +6 -1
- package/src/daemon/message-types/integrations.ts +0 -1
- package/src/daemon/message-types/memory.ts +0 -1
- package/src/daemon/message-types/messages.ts +9 -1
- package/src/daemon/message-types/schedules.ts +9 -0
- package/src/daemon/server.ts +48 -9
- package/src/email/feature-gate.ts +3 -3
- package/src/heartbeat/heartbeat-service.ts +48 -0
- package/src/hooks/cli.ts +74 -0
- package/src/inbound/platform-callback-registration.ts +68 -19
- package/src/mcp/client.ts +6 -1
- package/src/mcp/manager.ts +2 -1
- package/src/mcp/mcp-oauth-provider.ts +3 -3
- package/src/memory/app-store.ts +3 -3
- package/src/memory/conversation-crud.ts +213 -0
- package/src/memory/conversation-key-store.ts +26 -0
- package/src/memory/conversation-title-service.ts +7 -17
- package/src/memory/db-init.ts +24 -0
- package/src/memory/embedding-local.ts +47 -2
- package/src/memory/indexer.ts +13 -10
- package/src/memory/items-extractor.ts +12 -4
- package/src/memory/job-utils.ts +5 -0
- package/src/memory/jobs-store.ts +10 -2
- package/src/memory/journal-memory.ts +6 -2
- package/src/memory/llm-request-log-store.ts +88 -21
- package/src/memory/memory-recall-log-store.ts +128 -0
- package/src/memory/migrations/194-memory-recall-logs.ts +50 -0
- package/src/memory/migrations/195-oauth-providers-ping-config.ts +23 -0
- package/src/memory/migrations/196-messages-conversation-created-at-index.ts +9 -0
- package/src/memory/migrations/196-strip-integration-prefix-from-provider-keys.ts +186 -0
- package/src/memory/migrations/197-oauth-providers-behavior-columns.ts +29 -0
- package/src/memory/migrations/198-drop-setup-skill-id-column.ts +11 -0
- package/src/memory/migrations/index.ts +6 -0
- package/src/memory/migrations/registry.ts +8 -0
- package/src/memory/retriever.test.ts +4 -5
- package/src/memory/schema/infrastructure.ts +31 -0
- package/src/memory/schema/oauth.ts +14 -0
- package/src/messaging/provider.ts +13 -12
- package/src/messaging/providers/gmail/adapter.ts +44 -35
- package/src/messaging/providers/slack/adapter.ts +63 -33
- package/src/messaging/providers/telegram-bot/adapter.ts +7 -9
- package/src/messaging/providers/whatsapp/adapter.ts +6 -8
- package/src/notifications/adapters/telegram.ts +78 -2
- package/src/oauth/__tests__/identity-verifier.test.ts +464 -0
- package/src/oauth/byo-connection.test.ts +22 -24
- package/src/oauth/connect-orchestrator.ts +79 -64
- package/src/oauth/connect-types.ts +7 -65
- package/src/oauth/connection-resolver.test.ts +13 -13
- package/src/oauth/connection-resolver.ts +3 -4
- package/src/oauth/identity-verifier.ts +177 -0
- package/src/oauth/manual-token-connection.ts +5 -5
- package/src/oauth/oauth-store.ts +251 -5
- package/src/oauth/platform-connection.test.ts +56 -6
- package/src/oauth/platform-connection.ts +8 -1
- package/src/oauth/seed-providers.ts +256 -34
- package/src/permissions/checker.ts +129 -3
- package/src/permissions/trust-client.ts +2 -2
- package/src/platform/client.ts +2 -2
- package/src/prompts/journal-context.ts +6 -1
- package/src/prompts/system-prompt.ts +43 -9
- package/src/prompts/templates/BOOTSTRAP.md +16 -5
- package/src/providers/anthropic/client.ts +139 -28
- package/src/runtime/auth/__tests__/middleware.test.ts +19 -0
- package/src/runtime/auth/route-policy.ts +0 -1
- package/src/runtime/btw-sidechain.ts +7 -1
- package/src/runtime/channel-approvals.ts +2 -2
- package/src/runtime/channel-readiness-service.ts +30 -7
- package/src/runtime/guardian-action-service.ts +7 -2
- package/src/runtime/http-router.ts +31 -0
- package/src/runtime/http-server.ts +26 -7
- package/src/runtime/http-types.ts +9 -0
- package/src/runtime/pending-interactions.ts +21 -3
- package/src/runtime/routes/acp-routes.ts +46 -28
- package/src/runtime/routes/app-management-routes.ts +123 -0
- package/src/runtime/routes/app-routes.ts +31 -0
- package/src/runtime/routes/approval-routes.ts +108 -3
- package/src/runtime/routes/attachment-routes.ts +45 -0
- package/src/runtime/routes/avatar-routes.ts +16 -0
- package/src/runtime/routes/brain-graph-routes.ts +18 -0
- package/src/runtime/routes/btw-routes.ts +20 -0
- package/src/runtime/routes/call-routes.ts +81 -0
- package/src/runtime/routes/channel-readiness-routes.ts +48 -7
- package/src/runtime/routes/channel-routes.ts +18 -0
- package/src/runtime/routes/channel-verification-routes.ts +49 -1
- package/src/runtime/routes/contact-routes.ts +77 -0
- package/src/runtime/routes/conversation-attention-routes.ts +37 -0
- package/src/runtime/routes/conversation-management-routes.ts +125 -0
- package/src/runtime/routes/conversation-query-routes.ts +78 -0
- package/src/runtime/routes/conversation-routes.ts +191 -39
- package/src/runtime/routes/conversation-starter-routes.ts +29 -0
- package/src/runtime/routes/debug-routes.ts +23 -0
- package/src/runtime/routes/diagnostics-routes.ts +30 -0
- package/src/runtime/routes/documents-routes.ts +42 -0
- package/src/runtime/routes/events-routes.ts +10 -0
- package/src/runtime/routes/global-search-routes.ts +35 -0
- package/src/runtime/routes/guardian-action-routes.ts +61 -3
- package/src/runtime/routes/guardian-approval-prompt.ts +77 -2
- package/src/runtime/routes/heartbeat-routes.ts +278 -0
- package/src/runtime/routes/host-bash-routes.ts +16 -1
- package/src/runtime/routes/host-cu-routes.ts +23 -1
- package/src/runtime/routes/host-file-routes.ts +18 -1
- package/src/runtime/routes/identity-routes.ts +35 -0
- package/src/runtime/routes/inbound-message-handler.ts +46 -25
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +21 -8
- package/src/runtime/routes/inbound-stages/secret-ingress-check.ts +30 -2
- package/src/runtime/routes/inbound-stages/transcribe-audio.ts +1 -2
- package/src/runtime/routes/integrations/slack/share.ts +1 -1
- package/src/runtime/routes/integrations/twilio.ts +32 -22
- package/src/runtime/routes/invite-routes.ts +83 -0
- package/src/runtime/routes/log-export-routes.ts +14 -0
- package/src/runtime/routes/memory-item-routes.ts +99 -1
- package/src/runtime/routes/migration-rollback-routes.ts +25 -0
- package/src/runtime/routes/migration-routes.ts +40 -0
- package/src/runtime/routes/notification-routes.ts +20 -0
- package/src/runtime/routes/oauth-apps.ts +13 -4
- package/src/runtime/routes/pairing-routes.ts +15 -0
- package/src/runtime/routes/recording-routes.ts +72 -0
- package/src/runtime/routes/schedule-routes.ts +77 -5
- package/src/runtime/routes/secret-routes.ts +99 -14
- package/src/runtime/routes/settings-routes.ts +102 -19
- package/src/runtime/routes/skills-routes.ts +141 -18
- package/src/runtime/routes/subagents-routes.ts +38 -3
- package/src/runtime/routes/surface-action-routes.ts +66 -24
- package/src/runtime/routes/surface-content-routes.ts +20 -0
- package/src/runtime/routes/telemetry-routes.ts +12 -0
- package/src/runtime/routes/trace-event-routes.ts +25 -0
- package/src/runtime/routes/trust-rules-routes.ts +46 -0
- package/src/runtime/routes/tts-routes.ts +15 -4
- package/src/runtime/routes/upgrade-broadcast-routes.ts +38 -0
- package/src/runtime/routes/usage-routes.ts +59 -0
- package/src/runtime/routes/watch-routes.ts +28 -0
- package/src/runtime/routes/work-items-routes.ts +59 -0
- package/src/runtime/routes/workspace-commit-routes.ts +12 -0
- package/src/runtime/routes/workspace-routes.ts +102 -0
- package/src/schedule/integration-status.ts +2 -2
- package/src/schedule/scheduler.ts +7 -1
- package/src/security/AGENTS.md +7 -0
- package/src/security/ces-rpc-credential-backend.ts +19 -16
- package/src/security/credential-backend.ts +1 -1
- package/src/security/encrypted-store.ts +3 -3
- package/src/security/oauth-completion-page.ts +153 -0
- package/src/security/oauth2.ts +58 -17
- package/src/security/secret-ingress.ts +174 -0
- package/src/security/secret-patterns.ts +133 -0
- package/src/security/secret-scanner.ts +28 -117
- package/src/security/secure-keys.ts +207 -7
- package/src/security/token-manager.ts +3 -6
- package/src/signals/bash.ts +6 -1
- package/src/signals/confirm.ts +12 -8
- package/src/signals/user-message.ts +18 -3
- package/src/skills/catalog-cache.ts +44 -0
- package/src/skills/catalog-search.ts +18 -0
- package/src/skills/skill-memory.ts +1 -2
- package/src/tasks/task-runner.ts +7 -1
- package/src/tools/credentials/broker.ts +1 -1
- package/src/tools/credentials/metadata-store.ts +1 -1
- package/src/tools/credentials/post-connect-hooks.ts +1 -1
- package/src/tools/credentials/vault.ts +36 -48
- package/src/tools/host-terminal/host-shell.ts +16 -3
- package/src/tools/mcp/mcp-tool-factory.ts +2 -1
- package/src/tools/memory/definitions.ts +1 -1
- package/src/tools/memory/handlers.test.ts +2 -4
- package/src/tools/skills/load.ts +1 -1
- package/src/tools/skills/sandbox-runner.ts +16 -3
- package/src/tools/terminal/safe-env.ts +7 -0
- package/src/tools/terminal/shell.ts +16 -3
- package/src/tools/tool-manifest.ts +1 -1
- package/src/util/log-redact.ts +9 -34
- package/src/util/logger.ts +11 -1
- package/src/util/sentry-log-stream.ts +51 -0
- package/src/watcher/providers/github.ts +2 -2
- package/src/watcher/providers/gmail.ts +1 -1
- package/src/watcher/providers/google-calendar.ts +1 -1
- package/src/watcher/providers/linear.ts +2 -2
- package/src/workspace/migrations/011-backfill-installation-id.ts +5 -3
- package/src/workspace/migrations/020-rename-oauth-skill-dirs.ts +119 -0
- package/src/workspace/migrations/registry.ts +2 -0
- package/docs/architecture/keychain-broker.md +0 -68
- package/src/cli/commands/oauth/connections.ts +0 -734
- package/src/cli/commands/oauth/platform.ts +0 -525
- package/src/cli/commands/platform.ts +0 -176
- package/src/config/bundled-skills/slack/TOOLS.json +0 -272
- package/src/config/bundled-skills/slack/tools/shared.ts +0 -34
- package/src/config/bundled-skills/slack/tools/slack-add-reaction.ts +0 -27
- package/src/config/bundled-skills/slack/tools/slack-channel-details.ts +0 -38
- package/src/config/bundled-skills/slack/tools/slack-channel-permissions.ts +0 -146
- package/src/config/bundled-skills/slack/tools/slack-configure-channels.ts +0 -105
- package/src/config/bundled-skills/slack/tools/slack-delete-message.ts +0 -26
- package/src/config/bundled-skills/slack/tools/slack-edit-message.ts +0 -27
- package/src/config/bundled-skills/slack/tools/slack-leave-channel.ts +0 -25
- package/src/config/bundled-skills/slack/tools/slack-scan-digest.ts +0 -372
- package/src/oauth/provider-behaviors.ts +0 -634
|
@@ -3,11 +3,18 @@ import { type Command } from "commander";
|
|
|
3
3
|
import { loadConfig } from "../../../config/loader.js";
|
|
4
4
|
import { getOAuthCallbackUrl } from "../../../inbound/public-ingress-urls.js";
|
|
5
5
|
import {
|
|
6
|
+
deleteApp,
|
|
7
|
+
deleteConnection,
|
|
8
|
+
deleteProvider,
|
|
9
|
+
disconnectOAuthProvider,
|
|
6
10
|
getProvider,
|
|
11
|
+
listApps,
|
|
12
|
+
listConnections,
|
|
7
13
|
listProviders,
|
|
8
14
|
registerProvider,
|
|
15
|
+
updateProvider,
|
|
9
16
|
} from "../../../oauth/oauth-store.js";
|
|
10
|
-
import {
|
|
17
|
+
import { SEEDED_PROVIDER_KEYS } from "../../../oauth/seed-providers.js";
|
|
11
18
|
import { getCliLogger } from "../../logger.js";
|
|
12
19
|
import { shouldOutputJson, writeOutput } from "../../output.js";
|
|
13
20
|
|
|
@@ -17,21 +24,19 @@ const LOOPBACK_CALLBACK_PATH = "/oauth/callback";
|
|
|
17
24
|
|
|
18
25
|
/** Resolve the redirect URI for a provider based on its callback transport. */
|
|
19
26
|
function resolveRedirectUri(
|
|
20
|
-
providerKey: string,
|
|
21
27
|
callbackTransport: string | null,
|
|
28
|
+
loopbackPort: number | null,
|
|
22
29
|
): string | null {
|
|
23
30
|
const transport = callbackTransport ?? "loopback";
|
|
24
31
|
if (transport === "loopback") {
|
|
25
|
-
|
|
26
|
-
const port = behavior?.loopbackPort;
|
|
27
|
-
if (!port) {
|
|
32
|
+
if (!loopbackPort) {
|
|
28
33
|
// No fixed port — loopback still works at runtime with an OS-assigned
|
|
29
34
|
// port, but we can't predict the redirect URI ahead of time. Return
|
|
30
35
|
// a sentinel so callers know the transport is loopback-dynamic rather
|
|
31
36
|
// than unsupported.
|
|
32
37
|
return "http://localhost:<dynamic>/oauth/callback";
|
|
33
38
|
}
|
|
34
|
-
return `http://localhost:${
|
|
39
|
+
return `http://localhost:${loopbackPort}${LOOPBACK_CALLBACK_PATH}`;
|
|
35
40
|
}
|
|
36
41
|
// Gateway transport — resolve from public ingress config.
|
|
37
42
|
// Try the explicit publicBaseUrl first, then fall back to platform
|
|
@@ -55,11 +60,31 @@ function parseProviderRow(row: ReturnType<typeof getProvider>) {
|
|
|
55
60
|
description: row.description ?? null,
|
|
56
61
|
dashboardUrl: row.dashboardUrl ?? null,
|
|
57
62
|
clientIdPlaceholder: row.clientIdPlaceholder ?? null,
|
|
58
|
-
requiresClientSecret: row.requiresClientSecret ?? 1,
|
|
63
|
+
requiresClientSecret: !!(row.requiresClientSecret ?? 1),
|
|
64
|
+
supportsManagedMode: !!row.managedServiceConfigKey,
|
|
59
65
|
defaultScopes: row.defaultScopes ? JSON.parse(row.defaultScopes) : [],
|
|
60
66
|
scopePolicy: row.scopePolicy ? JSON.parse(row.scopePolicy) : {},
|
|
61
67
|
extraParams: row.extraParams ? JSON.parse(row.extraParams) : null,
|
|
62
|
-
|
|
68
|
+
pingHeaders: row.pingHeaders ? JSON.parse(row.pingHeaders) : null,
|
|
69
|
+
pingBody: row.pingBody ? JSON.parse(row.pingBody) : null,
|
|
70
|
+
loopbackPort: row.loopbackPort ?? null,
|
|
71
|
+
injectionTemplates: row.injectionTemplates
|
|
72
|
+
? JSON.parse(row.injectionTemplates)
|
|
73
|
+
: null,
|
|
74
|
+
appType: row.appType ?? null,
|
|
75
|
+
setupNotes: row.setupNotes ? JSON.parse(row.setupNotes) : null,
|
|
76
|
+
identityUrl: row.identityUrl ?? null,
|
|
77
|
+
identityMethod: row.identityMethod ?? null,
|
|
78
|
+
identityHeaders: row.identityHeaders
|
|
79
|
+
? JSON.parse(row.identityHeaders)
|
|
80
|
+
: null,
|
|
81
|
+
identityBody: row.identityBody ? JSON.parse(row.identityBody) : null,
|
|
82
|
+
identityResponsePaths: row.identityResponsePaths
|
|
83
|
+
? JSON.parse(row.identityResponsePaths)
|
|
84
|
+
: null,
|
|
85
|
+
identityFormat: row.identityFormat ?? null,
|
|
86
|
+
identityOkField: row.identityOkField ?? null,
|
|
87
|
+
redirectUri: resolveRedirectUri(row.callbackTransport, row.loopbackPort),
|
|
63
88
|
createdAt: new Date(row.createdAt).toISOString(),
|
|
64
89
|
updatedAt: new Date(row.updatedAt).toISOString(),
|
|
65
90
|
};
|
|
@@ -69,7 +94,7 @@ export function registerProviderCommands(oauth: Command): void {
|
|
|
69
94
|
const providers = oauth
|
|
70
95
|
.command("providers")
|
|
71
96
|
.description(
|
|
72
|
-
"
|
|
97
|
+
"Fetch configured OAuth providers and register custom providers of your own",
|
|
73
98
|
);
|
|
74
99
|
|
|
75
100
|
providers.addHelpText(
|
|
@@ -81,7 +106,7 @@ authorization URL, token URL, default scopes, and other endpoint details.
|
|
|
81
106
|
They are seeded on startup for built-in integrations (e.g. Google, Slack,
|
|
82
107
|
GitHub) but can also be registered dynamically via the "register" subcommand.
|
|
83
108
|
|
|
84
|
-
Each provider is identified by a provider key (e.g. "
|
|
109
|
+
Each provider is identified by a provider key (e.g. "google").`,
|
|
85
110
|
);
|
|
86
111
|
|
|
87
112
|
// ---------------------------------------------------------------------------
|
|
@@ -157,7 +182,7 @@ Examples:
|
|
|
157
182
|
"after",
|
|
158
183
|
`
|
|
159
184
|
Arguments:
|
|
160
|
-
provider-key
|
|
185
|
+
provider-key Provider key (e.g. "google").
|
|
161
186
|
Must match the key used during registration or seeding.
|
|
162
187
|
|
|
163
188
|
Returns the full provider configuration including auth URL, token URL,
|
|
@@ -165,8 +190,8 @@ default scopes, scope policy, and extra parameters. Exits with code 1
|
|
|
165
190
|
if the provider key is not found.
|
|
166
191
|
|
|
167
192
|
Examples:
|
|
168
|
-
$ assistant oauth providers get
|
|
169
|
-
$ assistant oauth providers get
|
|
193
|
+
$ assistant oauth providers get google
|
|
194
|
+
$ assistant oauth providers get twitter --json`,
|
|
170
195
|
)
|
|
171
196
|
.action((providerKey: string, _opts: unknown, cmd: Command) => {
|
|
172
197
|
try {
|
|
@@ -175,7 +200,7 @@ Examples:
|
|
|
175
200
|
if (!row) {
|
|
176
201
|
writeOutput(cmd, {
|
|
177
202
|
ok: false,
|
|
178
|
-
error: `Provider not found: ${providerKey}
|
|
203
|
+
error: `Provider not found: "${providerKey}". Run 'assistant oauth providers list' to see all registered providers. To register a custom provider, run 'assistant oauth providers register --help'.`,
|
|
179
204
|
});
|
|
180
205
|
process.exitCode = 1;
|
|
181
206
|
return;
|
|
@@ -196,69 +221,150 @@ Examples:
|
|
|
196
221
|
providers
|
|
197
222
|
.command("register")
|
|
198
223
|
.description("Register a new OAuth provider configuration")
|
|
199
|
-
.requiredOption(
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
.
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
224
|
+
.requiredOption(
|
|
225
|
+
"--provider-key <key>",
|
|
226
|
+
"Unique provider key (e.g. \"custom-service\"). Must not collide with an existing key from 'assistant oauth providers list'.",
|
|
227
|
+
)
|
|
228
|
+
.requiredOption(
|
|
229
|
+
"--auth-url <url>",
|
|
230
|
+
"OAuth authorization endpoint URL (e.g. https://accounts.example.com/o/oauth2/auth)",
|
|
231
|
+
)
|
|
232
|
+
.requiredOption(
|
|
233
|
+
"--token-url <url>",
|
|
234
|
+
"OAuth token endpoint URL (e.g. https://oauth2.example.com/token)",
|
|
235
|
+
)
|
|
236
|
+
.option("--base-url <url>", "API base URL for the service")
|
|
237
|
+
.option("--userinfo-url <url>", "OpenID Connect userinfo endpoint URL")
|
|
238
|
+
.option(
|
|
239
|
+
"--scopes <scopes>",
|
|
240
|
+
'Comma-separated default scopes (e.g. "read,write,profile")',
|
|
241
|
+
)
|
|
242
|
+
.option(
|
|
243
|
+
"--token-auth-method <method>",
|
|
244
|
+
'How the client authenticates at the token endpoint: "client_secret_post" or "client_secret_basic"',
|
|
245
|
+
)
|
|
246
|
+
.option(
|
|
247
|
+
"--callback-transport <transport>",
|
|
248
|
+
'OAuth callback transport: "loopback" (local HTTP server, default) or "gateway" (public ingress)',
|
|
249
|
+
)
|
|
207
250
|
.option(
|
|
208
251
|
"--ping-url <url>",
|
|
209
|
-
|
|
252
|
+
'Health-check endpoint URL for token validation (e.g. "https://api.example.com/user"). Used by "assistant oauth ping" to verify a stored token.',
|
|
253
|
+
)
|
|
254
|
+
.option(
|
|
255
|
+
"--ping-method <method>",
|
|
256
|
+
"HTTP method for the ping endpoint: GET (default) or POST",
|
|
257
|
+
)
|
|
258
|
+
.option(
|
|
259
|
+
"--ping-headers <json>",
|
|
260
|
+
'JSON object of extra headers for the ping request (e.g. \'{"Notion-Version":"2022-06-28"}\')',
|
|
261
|
+
)
|
|
262
|
+
.option(
|
|
263
|
+
"--ping-body <json>",
|
|
264
|
+
'JSON body to send with the ping request (e.g. \'{"query":"{ viewer { id } }"}\')',
|
|
265
|
+
)
|
|
266
|
+
.option(
|
|
267
|
+
"--display-name <name>",
|
|
268
|
+
"Human-readable display name for the provider",
|
|
269
|
+
)
|
|
270
|
+
.option("--description <text>", "Short description of the provider")
|
|
271
|
+
.option(
|
|
272
|
+
"--dashboard-url <url>",
|
|
273
|
+
"URL to the provider's developer console / dashboard",
|
|
274
|
+
)
|
|
275
|
+
.option(
|
|
276
|
+
"--client-id-placeholder <text>",
|
|
277
|
+
"Placeholder text shown in the client ID input field",
|
|
210
278
|
)
|
|
211
|
-
.option("--display-name <name>", "Display name for the provider")
|
|
212
|
-
.option("--description <text>", "Short description")
|
|
213
|
-
.option("--dashboard-url <url>", "Developer console URL")
|
|
214
|
-
.option("--client-id-placeholder <text>", "Placeholder for client ID field")
|
|
215
279
|
.option(
|
|
216
280
|
"--no-client-secret",
|
|
217
|
-
"
|
|
281
|
+
"Mark this provider as not requiring a client secret (default: required)",
|
|
282
|
+
)
|
|
283
|
+
.option(
|
|
284
|
+
"--loopback-port <port>",
|
|
285
|
+
"Fixed port for the local OAuth callback server (e.g. 17322). When set, the redirect URI is http://localhost:<port>/oauth/callback",
|
|
286
|
+
)
|
|
287
|
+
.option(
|
|
288
|
+
"--injection-templates <json>",
|
|
289
|
+
'JSON array of token injection templates — each with hostPattern, injectionType, headerName, valuePrefix (e.g. \'[{"hostPattern":"api.example.com","injectionType":"header","headerName":"Authorization","valuePrefix":"Bearer "}]\')',
|
|
290
|
+
)
|
|
291
|
+
.option(
|
|
292
|
+
"--app-type <type>",
|
|
293
|
+
'What the provider calls its OAuth apps (e.g. "OAuth App", "Desktop app", "Public integration")',
|
|
294
|
+
)
|
|
295
|
+
.option(
|
|
296
|
+
"--identity-url <url>",
|
|
297
|
+
"Identity verification endpoint URL — called after OAuth to identify the connected account",
|
|
298
|
+
)
|
|
299
|
+
.option(
|
|
300
|
+
"--identity-method <method>",
|
|
301
|
+
"HTTP method for the identity endpoint: GET (default) or POST",
|
|
302
|
+
)
|
|
303
|
+
.option(
|
|
304
|
+
"--identity-headers <json>",
|
|
305
|
+
'JSON object of extra headers for the identity request (e.g. \'{"Notion-Version":"2022-06-28"}\')',
|
|
306
|
+
)
|
|
307
|
+
.option(
|
|
308
|
+
"--identity-body <body>",
|
|
309
|
+
'JSON body to send with the identity request (e.g. \'{"query":"{ viewer { email } }"}\')',
|
|
310
|
+
)
|
|
311
|
+
.option(
|
|
312
|
+
"--identity-response-paths <paths>",
|
|
313
|
+
'Comma-separated dot-notation paths to extract identity from the response (e.g. "email,name,person.email")',
|
|
314
|
+
)
|
|
315
|
+
.option(
|
|
316
|
+
"--identity-format <template>",
|
|
317
|
+
'Format template for the extracted identity using ${pathName} tokens from --identity-response-paths (e.g. "@${login}" or "@${user} (${team})")',
|
|
318
|
+
)
|
|
319
|
+
.option(
|
|
320
|
+
"--identity-ok-field <field>",
|
|
321
|
+
'Dot-notation path to a boolean field that must be truthy for the response to be considered valid (e.g. "ok")',
|
|
322
|
+
)
|
|
323
|
+
.option(
|
|
324
|
+
"--setup-notes <json>",
|
|
325
|
+
'JSON array of setup instruction notes shown during guided setup (e.g. \'["Enable the Gmail API","Add test users"]\')',
|
|
218
326
|
)
|
|
219
327
|
.addHelpText(
|
|
220
328
|
"after",
|
|
221
329
|
`
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
--base-url Optional API base URL for the service.
|
|
228
|
-
--userinfo-url Optional OpenID Connect userinfo endpoint.
|
|
229
|
-
--scopes Comma-separated list of default scopes (e.g. "read,write,profile").
|
|
230
|
-
--token-auth-method How the client authenticates at the token endpoint
|
|
231
|
-
(e.g. "client_secret_post", "client_secret_basic").
|
|
232
|
-
--callback-transport Transport method for the OAuth callback.
|
|
233
|
-
--ping-url Optional URL for a lightweight health-check endpoint.
|
|
234
|
-
Used by "connections ping" to validate that a stored token
|
|
235
|
-
is still functional (e.g. "https://api.example.com/user").
|
|
236
|
-
--display-name Optional human-readable display name for the provider.
|
|
237
|
-
--description Optional short description of the provider.
|
|
238
|
-
--dashboard-url Optional URL to the provider's developer console / dashboard.
|
|
239
|
-
--client-id-placeholder Optional placeholder text for the client ID input field.
|
|
240
|
-
--no-client-secret If set, marks the provider as not requiring a client secret
|
|
241
|
-
(sets requires_client_secret to 0). Default is true (1).
|
|
242
|
-
|
|
243
|
-
Registers a new OAuth provider configuration in the local store. This is
|
|
244
|
-
used for custom integrations not covered by the built-in provider seeds.
|
|
330
|
+
Registers a new OAuth provider configuration in the local store for custom
|
|
331
|
+
integrations not covered by the built-in provider seeds. The provider key
|
|
332
|
+
must be unique — if it collides with an existing key, the command fails.
|
|
333
|
+
Run 'assistant oauth providers list' to see existing keys.
|
|
334
|
+
|
|
245
335
|
On success, returns the full provider row including generated timestamps.
|
|
336
|
+
After registering, create an OAuth app with 'assistant oauth apps create'
|
|
337
|
+
and then connect with 'assistant oauth connect <provider-key>'.
|
|
338
|
+
|
|
339
|
+
Token injection templates control how the OAuth access token is injected
|
|
340
|
+
into outgoing HTTP requests matched by host pattern. Identity config
|
|
341
|
+
defines how the assistant verifies the connected account after OAuth.
|
|
246
342
|
|
|
247
343
|
Examples:
|
|
248
344
|
$ assistant oauth providers register \\
|
|
249
|
-
--provider-key
|
|
345
|
+
--provider-key custom-api \\
|
|
250
346
|
--auth-url https://custom-api.example.com/oauth/authorize \\
|
|
251
347
|
--token-url https://custom-api.example.com/oauth/token
|
|
252
348
|
$ assistant oauth providers register \\
|
|
253
|
-
--provider-key
|
|
349
|
+
--provider-key my-service \\
|
|
254
350
|
--auth-url https://my-service.com/auth \\
|
|
255
351
|
--token-url https://my-service.com/token \\
|
|
256
352
|
--scopes read,write --json
|
|
257
353
|
$ assistant oauth providers register \\
|
|
258
|
-
--provider-key
|
|
354
|
+
--provider-key my-graphql-api \\
|
|
259
355
|
--auth-url https://example.com/auth \\
|
|
260
356
|
--token-url https://example.com/token \\
|
|
261
|
-
--ping-url https://example.com/
|
|
357
|
+
--ping-url https://example.com/graphql \\
|
|
358
|
+
--ping-method POST \\
|
|
359
|
+
--ping-body '{"query":"{ viewer { id } }"}'
|
|
360
|
+
$ assistant oauth providers register \\
|
|
361
|
+
--provider-key my-api \\
|
|
362
|
+
--auth-url https://example.com/auth \\
|
|
363
|
+
--token-url https://example.com/token \\
|
|
364
|
+
--loopback-port 17400 \\
|
|
365
|
+
--injection-templates '[{"hostPattern":"api.example.com","injectionType":"header","headerName":"Authorization","valuePrefix":"Bearer "}]' \\
|
|
366
|
+
--identity-url https://api.example.com/me \\
|
|
367
|
+
--identity-response-paths email,name`,
|
|
262
368
|
)
|
|
263
369
|
.action(
|
|
264
370
|
(
|
|
@@ -272,11 +378,25 @@ Examples:
|
|
|
272
378
|
tokenAuthMethod?: string;
|
|
273
379
|
callbackTransport?: string;
|
|
274
380
|
pingUrl?: string;
|
|
381
|
+
pingMethod?: string;
|
|
382
|
+
pingHeaders?: string;
|
|
383
|
+
pingBody?: string;
|
|
275
384
|
displayName?: string;
|
|
276
385
|
description?: string;
|
|
277
386
|
dashboardUrl?: string;
|
|
278
387
|
clientIdPlaceholder?: string;
|
|
279
388
|
clientSecret: boolean;
|
|
389
|
+
loopbackPort?: string;
|
|
390
|
+
injectionTemplates?: string;
|
|
391
|
+
appType?: string;
|
|
392
|
+
identityUrl?: string;
|
|
393
|
+
identityMethod?: string;
|
|
394
|
+
identityHeaders?: string;
|
|
395
|
+
identityBody?: string;
|
|
396
|
+
identityResponsePaths?: string;
|
|
397
|
+
identityFormat?: string;
|
|
398
|
+
identityOkField?: string;
|
|
399
|
+
setupNotes?: string;
|
|
280
400
|
},
|
|
281
401
|
cmd: Command,
|
|
282
402
|
) => {
|
|
@@ -292,14 +412,428 @@ Examples:
|
|
|
292
412
|
tokenEndpointAuthMethod: opts.tokenAuthMethod,
|
|
293
413
|
callbackTransport: opts.callbackTransport,
|
|
294
414
|
pingUrl: opts.pingUrl,
|
|
415
|
+
pingMethod: opts.pingMethod,
|
|
416
|
+
pingHeaders: opts.pingHeaders
|
|
417
|
+
? JSON.parse(opts.pingHeaders)
|
|
418
|
+
: undefined,
|
|
419
|
+
pingBody: opts.pingBody ? JSON.parse(opts.pingBody) : undefined,
|
|
295
420
|
displayName: opts.displayName,
|
|
296
421
|
description: opts.description,
|
|
297
422
|
dashboardUrl: opts.dashboardUrl,
|
|
298
423
|
clientIdPlaceholder: opts.clientIdPlaceholder,
|
|
299
424
|
requiresClientSecret: opts.clientSecret ? 1 : 0,
|
|
425
|
+
loopbackPort: opts.loopbackPort
|
|
426
|
+
? parseInt(opts.loopbackPort, 10)
|
|
427
|
+
: undefined,
|
|
428
|
+
injectionTemplates: opts.injectionTemplates
|
|
429
|
+
? JSON.parse(opts.injectionTemplates)
|
|
430
|
+
: undefined,
|
|
431
|
+
appType: opts.appType,
|
|
432
|
+
identityUrl: opts.identityUrl,
|
|
433
|
+
identityMethod: opts.identityMethod,
|
|
434
|
+
identityHeaders: opts.identityHeaders
|
|
435
|
+
? JSON.parse(opts.identityHeaders)
|
|
436
|
+
: undefined,
|
|
437
|
+
identityBody: opts.identityBody
|
|
438
|
+
? JSON.parse(opts.identityBody)
|
|
439
|
+
: undefined,
|
|
440
|
+
identityResponsePaths: opts.identityResponsePaths
|
|
441
|
+
? opts.identityResponsePaths.split(",")
|
|
442
|
+
: undefined,
|
|
443
|
+
identityFormat: opts.identityFormat,
|
|
444
|
+
identityOkField: opts.identityOkField,
|
|
445
|
+
setupNotes: opts.setupNotes
|
|
446
|
+
? JSON.parse(opts.setupNotes)
|
|
447
|
+
: undefined,
|
|
300
448
|
});
|
|
301
449
|
|
|
302
450
|
writeOutput(cmd, parseProviderRow(row));
|
|
451
|
+
} catch (err) {
|
|
452
|
+
let message = err instanceof Error ? err.message : String(err);
|
|
453
|
+
if (message.includes("already exists")) {
|
|
454
|
+
message += ` Run 'assistant oauth providers list' to see existing providers, or choose a different --provider-key.`;
|
|
455
|
+
}
|
|
456
|
+
writeOutput(cmd, { ok: false, error: message });
|
|
457
|
+
process.exitCode = 1;
|
|
458
|
+
}
|
|
459
|
+
},
|
|
460
|
+
);
|
|
461
|
+
|
|
462
|
+
// ---------------------------------------------------------------------------
|
|
463
|
+
// providers update <provider-key>
|
|
464
|
+
// ---------------------------------------------------------------------------
|
|
465
|
+
|
|
466
|
+
providers
|
|
467
|
+
.command("update <provider-key>")
|
|
468
|
+
.description("Update an existing custom OAuth provider configuration")
|
|
469
|
+
.option(
|
|
470
|
+
"--auth-url <url>",
|
|
471
|
+
"OAuth authorization endpoint URL (e.g. https://accounts.example.com/o/oauth2/auth)",
|
|
472
|
+
)
|
|
473
|
+
.option(
|
|
474
|
+
"--token-url <url>",
|
|
475
|
+
"OAuth token endpoint URL (e.g. https://oauth2.example.com/token)",
|
|
476
|
+
)
|
|
477
|
+
.option("--base-url <url>", "API base URL for the service")
|
|
478
|
+
.option("--userinfo-url <url>", "OpenID Connect userinfo endpoint URL")
|
|
479
|
+
.option(
|
|
480
|
+
"--scopes <scopes>",
|
|
481
|
+
'Comma-separated default scopes (e.g. "read,write,profile")',
|
|
482
|
+
)
|
|
483
|
+
.option(
|
|
484
|
+
"--token-auth-method <method>",
|
|
485
|
+
'How the client authenticates at the token endpoint: "client_secret_post" or "client_secret_basic"',
|
|
486
|
+
)
|
|
487
|
+
.option(
|
|
488
|
+
"--callback-transport <transport>",
|
|
489
|
+
'OAuth callback transport: "loopback" (local HTTP server, default) or "gateway" (public ingress)',
|
|
490
|
+
)
|
|
491
|
+
.option(
|
|
492
|
+
"--ping-url <url>",
|
|
493
|
+
'Health-check endpoint URL for token validation (e.g. "https://api.example.com/user"). Used by "assistant oauth ping" to verify a stored token.',
|
|
494
|
+
)
|
|
495
|
+
.option(
|
|
496
|
+
"--ping-method <method>",
|
|
497
|
+
"HTTP method for the ping endpoint: GET (default) or POST",
|
|
498
|
+
)
|
|
499
|
+
.option(
|
|
500
|
+
"--ping-headers <json>",
|
|
501
|
+
'JSON object of extra headers for the ping request (e.g. \'{"Notion-Version":"2022-06-28"}\')',
|
|
502
|
+
)
|
|
503
|
+
.option(
|
|
504
|
+
"--ping-body <json>",
|
|
505
|
+
'JSON body to send with the ping request (e.g. \'{"query":"{ viewer { id } }"}\')',
|
|
506
|
+
)
|
|
507
|
+
.option(
|
|
508
|
+
"--display-name <name>",
|
|
509
|
+
"Human-readable display name for the provider",
|
|
510
|
+
)
|
|
511
|
+
.option("--description <text>", "Short description of the provider")
|
|
512
|
+
.option(
|
|
513
|
+
"--dashboard-url <url>",
|
|
514
|
+
"URL to the provider's developer console / dashboard",
|
|
515
|
+
)
|
|
516
|
+
.option(
|
|
517
|
+
"--client-id-placeholder <text>",
|
|
518
|
+
"Placeholder text shown in the client ID input field",
|
|
519
|
+
)
|
|
520
|
+
.option(
|
|
521
|
+
"--no-client-secret",
|
|
522
|
+
"Mark this provider as not requiring a client secret (default: required)",
|
|
523
|
+
)
|
|
524
|
+
.option(
|
|
525
|
+
"--loopback-port <port>",
|
|
526
|
+
"Fixed port for the local OAuth callback server (e.g. 17322). When set, the redirect URI is http://localhost:<port>/oauth/callback",
|
|
527
|
+
)
|
|
528
|
+
.option(
|
|
529
|
+
"--injection-templates <json>",
|
|
530
|
+
'JSON array of token injection templates — each with hostPattern, injectionType, headerName, valuePrefix (e.g. \'[{"hostPattern":"api.example.com","injectionType":"header","headerName":"Authorization","valuePrefix":"Bearer "}]\')',
|
|
531
|
+
)
|
|
532
|
+
.option(
|
|
533
|
+
"--app-type <type>",
|
|
534
|
+
'What the provider calls its OAuth apps (e.g. "OAuth App", "Desktop app", "Public integration")',
|
|
535
|
+
)
|
|
536
|
+
.option(
|
|
537
|
+
"--identity-url <url>",
|
|
538
|
+
"Identity verification endpoint URL — called after OAuth to identify the connected account",
|
|
539
|
+
)
|
|
540
|
+
.option(
|
|
541
|
+
"--identity-method <method>",
|
|
542
|
+
"HTTP method for the identity endpoint: GET (default) or POST",
|
|
543
|
+
)
|
|
544
|
+
.option(
|
|
545
|
+
"--identity-headers <json>",
|
|
546
|
+
'JSON object of extra headers for the identity request (e.g. \'{"Notion-Version":"2022-06-28"}\')',
|
|
547
|
+
)
|
|
548
|
+
.option(
|
|
549
|
+
"--identity-body <body>",
|
|
550
|
+
'JSON body to send with the identity request (e.g. \'{"query":"{ viewer { email } }"}\')',
|
|
551
|
+
)
|
|
552
|
+
.option(
|
|
553
|
+
"--identity-response-paths <paths>",
|
|
554
|
+
'Comma-separated dot-notation paths to extract identity from the response (e.g. "email,name,person.email")',
|
|
555
|
+
)
|
|
556
|
+
.option(
|
|
557
|
+
"--identity-format <template>",
|
|
558
|
+
'Format template for the extracted identity using ${pathName} tokens from --identity-response-paths (e.g. "@${login}" or "@${user} (${team})")',
|
|
559
|
+
)
|
|
560
|
+
.option(
|
|
561
|
+
"--identity-ok-field <field>",
|
|
562
|
+
'Dot-notation path to a boolean field that must be truthy for the response to be considered valid (e.g. "ok")',
|
|
563
|
+
)
|
|
564
|
+
.option(
|
|
565
|
+
"--setup-notes <json>",
|
|
566
|
+
'JSON array of setup instruction notes shown during guided setup (e.g. \'["Enable the Gmail API","Add test users"]\')',
|
|
567
|
+
)
|
|
568
|
+
.addHelpText(
|
|
569
|
+
"after",
|
|
570
|
+
`
|
|
571
|
+
Arguments:
|
|
572
|
+
provider-key Provider key to update (e.g. "custom-api").
|
|
573
|
+
Run 'assistant oauth providers list' to see all registered providers.
|
|
574
|
+
|
|
575
|
+
Only the fields you specify are updated — all other fields remain unchanged.
|
|
576
|
+
Built-in providers (e.g. "google", "slack") cannot be updated; they are
|
|
577
|
+
managed by the system and reset on startup. To create a custom provider with
|
|
578
|
+
different settings, use 'assistant oauth providers register'.
|
|
579
|
+
|
|
580
|
+
Token injection templates control how the OAuth access token is injected
|
|
581
|
+
into outgoing HTTP requests matched by host pattern. Identity config
|
|
582
|
+
defines how the assistant verifies the connected account after OAuth.
|
|
583
|
+
|
|
584
|
+
Examples:
|
|
585
|
+
$ assistant oauth providers update custom-api --display-name "My Custom API"
|
|
586
|
+
$ assistant oauth providers update custom-api --scopes read,write --auth-url https://new.example.com/auth
|
|
587
|
+
$ assistant oauth providers update custom-api --ping-url https://api.example.com/me --json
|
|
588
|
+
$ assistant oauth providers update custom-api \\
|
|
589
|
+
--identity-url https://api.example.com/me \\
|
|
590
|
+
--identity-response-paths email,name
|
|
591
|
+
$ assistant oauth providers update custom-api \\
|
|
592
|
+
--injection-templates '[{"hostPattern":"api.example.com","injectionType":"header","headerName":"Authorization","valuePrefix":"Bearer "}]'`,
|
|
593
|
+
)
|
|
594
|
+
.action(
|
|
595
|
+
(
|
|
596
|
+
providerKey: string,
|
|
597
|
+
opts: {
|
|
598
|
+
authUrl?: string;
|
|
599
|
+
tokenUrl?: string;
|
|
600
|
+
baseUrl?: string;
|
|
601
|
+
userinfoUrl?: string;
|
|
602
|
+
scopes?: string;
|
|
603
|
+
tokenAuthMethod?: string;
|
|
604
|
+
callbackTransport?: string;
|
|
605
|
+
pingUrl?: string;
|
|
606
|
+
pingMethod?: string;
|
|
607
|
+
pingHeaders?: string;
|
|
608
|
+
pingBody?: string;
|
|
609
|
+
displayName?: string;
|
|
610
|
+
description?: string;
|
|
611
|
+
dashboardUrl?: string;
|
|
612
|
+
clientIdPlaceholder?: string;
|
|
613
|
+
clientSecret: boolean;
|
|
614
|
+
loopbackPort?: string;
|
|
615
|
+
injectionTemplates?: string;
|
|
616
|
+
appType?: string;
|
|
617
|
+
identityUrl?: string;
|
|
618
|
+
identityMethod?: string;
|
|
619
|
+
identityHeaders?: string;
|
|
620
|
+
identityBody?: string;
|
|
621
|
+
identityResponsePaths?: string;
|
|
622
|
+
identityFormat?: string;
|
|
623
|
+
identityOkField?: string;
|
|
624
|
+
setupNotes?: string;
|
|
625
|
+
},
|
|
626
|
+
cmd: Command,
|
|
627
|
+
) => {
|
|
628
|
+
try {
|
|
629
|
+
// Verify provider exists
|
|
630
|
+
const existing = getProvider(providerKey);
|
|
631
|
+
if (!existing) {
|
|
632
|
+
writeOutput(cmd, {
|
|
633
|
+
ok: false,
|
|
634
|
+
error: `Provider "${providerKey}" not found. Run 'assistant oauth providers list' to see all registered providers.`,
|
|
635
|
+
});
|
|
636
|
+
process.exitCode = 1;
|
|
637
|
+
return;
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
// Block updates to built-in providers
|
|
641
|
+
if (SEEDED_PROVIDER_KEYS.has(providerKey)) {
|
|
642
|
+
writeOutput(cmd, {
|
|
643
|
+
ok: false,
|
|
644
|
+
error: `Cannot update built-in provider "${providerKey}". Built-in providers are managed by the system and reset on startup. To create a custom provider with different settings, use 'assistant oauth providers register --provider-key <your-custom-key> ...'`,
|
|
645
|
+
});
|
|
646
|
+
process.exitCode = 1;
|
|
647
|
+
return;
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
// Build params object from provided options, omitting undefined values
|
|
651
|
+
const params: Record<string, unknown> = {};
|
|
652
|
+
|
|
653
|
+
if (opts.authUrl !== undefined) params.authUrl = opts.authUrl;
|
|
654
|
+
if (opts.tokenUrl !== undefined) params.tokenUrl = opts.tokenUrl;
|
|
655
|
+
if (opts.baseUrl !== undefined) params.baseUrl = opts.baseUrl;
|
|
656
|
+
if (opts.userinfoUrl !== undefined)
|
|
657
|
+
params.userinfoUrl = opts.userinfoUrl;
|
|
658
|
+
if (opts.scopes !== undefined)
|
|
659
|
+
params.defaultScopes = opts.scopes.split(",");
|
|
660
|
+
if (opts.tokenAuthMethod !== undefined)
|
|
661
|
+
params.tokenEndpointAuthMethod = opts.tokenAuthMethod;
|
|
662
|
+
if (opts.callbackTransport !== undefined)
|
|
663
|
+
params.callbackTransport = opts.callbackTransport;
|
|
664
|
+
if (opts.pingUrl !== undefined) params.pingUrl = opts.pingUrl;
|
|
665
|
+
if (opts.pingMethod !== undefined)
|
|
666
|
+
params.pingMethod = opts.pingMethod;
|
|
667
|
+
if (opts.pingHeaders !== undefined)
|
|
668
|
+
params.pingHeaders = JSON.parse(opts.pingHeaders);
|
|
669
|
+
if (opts.pingBody !== undefined)
|
|
670
|
+
params.pingBody = JSON.parse(opts.pingBody);
|
|
671
|
+
if (opts.displayName !== undefined)
|
|
672
|
+
params.displayName = opts.displayName;
|
|
673
|
+
if (opts.description !== undefined)
|
|
674
|
+
params.description = opts.description;
|
|
675
|
+
if (opts.dashboardUrl !== undefined)
|
|
676
|
+
params.dashboardUrl = opts.dashboardUrl;
|
|
677
|
+
if (opts.clientIdPlaceholder !== undefined)
|
|
678
|
+
params.clientIdPlaceholder = opts.clientIdPlaceholder;
|
|
679
|
+
|
|
680
|
+
// Handle the negated --no-client-* flag: Commander defaults
|
|
681
|
+
// opts.clientSecret to true; the negated form sets it to false.
|
|
682
|
+
// Use getOptionValueSource to detect explicit user intent.
|
|
683
|
+
if (cmd.getOptionValueSource("clientSecret") === "cli") {
|
|
684
|
+
params.requiresClientSecret = opts.clientSecret ? 1 : 0;
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
if (opts.loopbackPort !== undefined)
|
|
688
|
+
params.loopbackPort = parseInt(opts.loopbackPort, 10);
|
|
689
|
+
if (opts.injectionTemplates !== undefined)
|
|
690
|
+
params.injectionTemplates = JSON.parse(opts.injectionTemplates);
|
|
691
|
+
if (opts.appType !== undefined) params.appType = opts.appType;
|
|
692
|
+
if (opts.identityUrl !== undefined)
|
|
693
|
+
params.identityUrl = opts.identityUrl;
|
|
694
|
+
if (opts.identityMethod !== undefined)
|
|
695
|
+
params.identityMethod = opts.identityMethod;
|
|
696
|
+
if (opts.identityHeaders !== undefined)
|
|
697
|
+
params.identityHeaders = JSON.parse(opts.identityHeaders);
|
|
698
|
+
if (opts.identityBody !== undefined)
|
|
699
|
+
params.identityBody = JSON.parse(opts.identityBody);
|
|
700
|
+
if (opts.identityResponsePaths !== undefined)
|
|
701
|
+
params.identityResponsePaths =
|
|
702
|
+
opts.identityResponsePaths.split(",");
|
|
703
|
+
if (opts.identityFormat !== undefined)
|
|
704
|
+
params.identityFormat = opts.identityFormat;
|
|
705
|
+
if (opts.identityOkField !== undefined)
|
|
706
|
+
params.identityOkField = opts.identityOkField;
|
|
707
|
+
if (opts.setupNotes !== undefined)
|
|
708
|
+
params.setupNotes = JSON.parse(opts.setupNotes);
|
|
709
|
+
|
|
710
|
+
// Check if any fields were actually provided
|
|
711
|
+
if (Object.keys(params).length === 0) {
|
|
712
|
+
writeOutput(cmd, {
|
|
713
|
+
ok: false,
|
|
714
|
+
error:
|
|
715
|
+
"Nothing to update. Provide at least one option to change (e.g. --auth-url, --scopes, --display-name). Run 'assistant oauth providers update --help' for all options.",
|
|
716
|
+
});
|
|
717
|
+
process.exitCode = 1;
|
|
718
|
+
return;
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
const row = updateProvider(providerKey, params);
|
|
722
|
+
|
|
723
|
+
writeOutput(cmd, parseProviderRow(row));
|
|
724
|
+
} catch (err) {
|
|
725
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
726
|
+
writeOutput(cmd, { ok: false, error: message });
|
|
727
|
+
process.exitCode = 1;
|
|
728
|
+
}
|
|
729
|
+
},
|
|
730
|
+
);
|
|
731
|
+
|
|
732
|
+
// ---------------------------------------------------------------------------
|
|
733
|
+
// providers delete <provider-key>
|
|
734
|
+
// ---------------------------------------------------------------------------
|
|
735
|
+
|
|
736
|
+
providers
|
|
737
|
+
.command("delete <provider-key>")
|
|
738
|
+
.description(
|
|
739
|
+
"Delete a custom OAuth provider and optionally its associated apps and connections",
|
|
740
|
+
)
|
|
741
|
+
.option(
|
|
742
|
+
"--force",
|
|
743
|
+
"Cascade-delete all associated apps and connections before removing the provider",
|
|
744
|
+
)
|
|
745
|
+
.addHelpText(
|
|
746
|
+
"after",
|
|
747
|
+
`
|
|
748
|
+
Arguments:
|
|
749
|
+
provider-key Provider key to delete (e.g. "custom-api").
|
|
750
|
+
Run 'assistant oauth providers list' to see registered providers.
|
|
751
|
+
|
|
752
|
+
When --force is specified, all OAuth connections and apps that depend on
|
|
753
|
+
this provider are deleted before the provider itself is removed. Without
|
|
754
|
+
--force, the command refuses to delete a provider that has dependents and
|
|
755
|
+
exits with an error listing the counts.
|
|
756
|
+
|
|
757
|
+
Built-in providers (e.g. "google", "slack") can be deleted, but a warning
|
|
758
|
+
is emitted because they will be re-created automatically on the next
|
|
759
|
+
assistant startup.
|
|
760
|
+
|
|
761
|
+
Examples:
|
|
762
|
+
$ assistant oauth providers delete custom-api
|
|
763
|
+
$ assistant oauth providers delete custom-api --force
|
|
764
|
+
$ assistant oauth providers delete custom-api --force --json`,
|
|
765
|
+
)
|
|
766
|
+
.action(
|
|
767
|
+
async (providerKey: string, opts: { force?: boolean }, cmd: Command) => {
|
|
768
|
+
try {
|
|
769
|
+
const provider = getProvider(providerKey);
|
|
770
|
+
if (!provider) {
|
|
771
|
+
writeOutput(cmd, {
|
|
772
|
+
ok: false,
|
|
773
|
+
error: `Provider not found: "${providerKey}". Run 'assistant oauth providers list' to see all registered providers.`,
|
|
774
|
+
});
|
|
775
|
+
process.exitCode = 1;
|
|
776
|
+
return;
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
if (SEEDED_PROVIDER_KEYS.has(providerKey) && !opts.force) {
|
|
780
|
+
log.info(
|
|
781
|
+
`Note: "${providerKey}" is a built-in provider and will be re-created on next startup.`,
|
|
782
|
+
);
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
const dependentApps = listApps().filter(
|
|
786
|
+
(a) => a.providerKey === providerKey,
|
|
787
|
+
);
|
|
788
|
+
const dependentConnections = listConnections(providerKey);
|
|
789
|
+
const appCount = dependentApps.length;
|
|
790
|
+
const connCount = dependentConnections.length;
|
|
791
|
+
|
|
792
|
+
if ((appCount > 0 || connCount > 0) && !opts.force) {
|
|
793
|
+
writeOutput(cmd, {
|
|
794
|
+
ok: false,
|
|
795
|
+
error: `Cannot delete provider "${providerKey}": ${appCount} app(s) and ${connCount} connection(s) depend on it. Use --force to cascade-delete all dependent apps and connections, or remove them manually first with 'assistant oauth apps delete' and 'assistant oauth disconnect'.`,
|
|
796
|
+
});
|
|
797
|
+
process.exitCode = 1;
|
|
798
|
+
return;
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
// Warn about built-in providers when --force is used
|
|
802
|
+
if (SEEDED_PROVIDER_KEYS.has(providerKey) && opts.force) {
|
|
803
|
+
log.info(
|
|
804
|
+
`Note: "${providerKey}" is a built-in provider and will be re-created on next startup.`,
|
|
805
|
+
);
|
|
806
|
+
}
|
|
807
|
+
|
|
808
|
+
// Cascade-delete connections first, then apps, then the provider.
|
|
809
|
+
// Use disconnectOAuthProvider to clean up OAuth tokens from secure
|
|
810
|
+
// storage in addition to deleting the connection DB row.
|
|
811
|
+
for (const conn of dependentConnections) {
|
|
812
|
+
const result = await disconnectOAuthProvider(
|
|
813
|
+
providerKey,
|
|
814
|
+
undefined,
|
|
815
|
+
conn.id as string,
|
|
816
|
+
);
|
|
817
|
+
if (result === "error") {
|
|
818
|
+
log.info(
|
|
819
|
+
`Warning: failed to clean up tokens for connection ${conn.id} — deleting connection row to continue cascade.`,
|
|
820
|
+
);
|
|
821
|
+
deleteConnection(conn.id);
|
|
822
|
+
}
|
|
823
|
+
}
|
|
824
|
+
for (const app of dependentApps) {
|
|
825
|
+
await deleteApp(app.id);
|
|
826
|
+
}
|
|
827
|
+
deleteProvider(providerKey);
|
|
828
|
+
|
|
829
|
+
if (!shouldOutputJson(cmd)) {
|
|
830
|
+
log.info(`Deleted provider: ${providerKey}`);
|
|
831
|
+
}
|
|
832
|
+
|
|
833
|
+
writeOutput(cmd, {
|
|
834
|
+
ok: true,
|
|
835
|
+
deleted: { provider: 1, apps: appCount, connections: connCount },
|
|
836
|
+
});
|
|
303
837
|
} catch (err) {
|
|
304
838
|
const message = err instanceof Error ? err.message : String(err);
|
|
305
839
|
writeOutput(cmd, { ok: false, error: message });
|