@vellumai/assistant 0.4.46 → 0.4.49
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ARCHITECTURE.md +7 -7
- package/README.md +2 -23
- package/docs/architecture/integrations.md +45 -41
- package/docs/architecture/keychain-broker.md +3 -3
- package/docs/architecture/security.md +5 -5
- package/docs/runbook-trusted-contacts.md +3 -8
- package/hook-templates/debug-prompt-logger/hook.json +1 -1
- package/hook-templates/debug-prompt-logger/run.sh +1 -3
- package/package.json +1 -1
- package/src/__tests__/actor-token-service.test.ts +0 -1
- package/src/__tests__/anthropic-provider.test.ts +156 -0
- package/src/__tests__/approval-cascade.test.ts +810 -0
- package/src/__tests__/approval-primitive.test.ts +0 -1
- package/src/__tests__/approval-routes-http.test.ts +2 -0
- package/src/__tests__/assistant-attachments.test.ts +12 -34
- package/src/__tests__/assistant-feature-flag-guardrails.test.ts +76 -0
- package/src/__tests__/assistant-feature-flags-integration.test.ts +0 -1
- package/src/__tests__/browser-fill-credential.test.ts +5 -2
- package/src/__tests__/browser-skill-baseline-tool-payload.test.ts +2 -2
- package/src/__tests__/bundled-skill-retrieval-guard.test.ts +2 -1
- package/src/__tests__/channel-guardian.test.ts +0 -2
- package/src/__tests__/channel-readiness-routes.test.ts +35 -25
- package/src/__tests__/channel-readiness-service.test.ts +10 -9
- package/src/__tests__/checker.test.ts +9 -29
- package/src/__tests__/cli.test.ts +23 -0
- package/src/__tests__/computer-use-skill-manifest-regression.test.ts +1 -1
- package/src/__tests__/computer-use-tools.test.ts +2 -19
- package/src/__tests__/config-watcher.test.ts +0 -1
- package/src/__tests__/confirmation-request-guardian-bridge.test.ts +0 -1
- package/src/__tests__/context-image-dimensions.test.ts +332 -0
- package/src/__tests__/context-token-estimator.test.ts +196 -13
- package/src/__tests__/conversation-attention-store.test.ts +0 -1
- package/src/__tests__/conversation-attention-telegram.test.ts +0 -1
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +144 -0
- package/src/__tests__/conversation-routes-slash-commands.test.ts +1 -0
- package/src/__tests__/credential-broker-browser-fill.test.ts +23 -22
- package/src/__tests__/credential-broker-server-use.test.ts +22 -21
- package/src/__tests__/credential-broker.test.ts +2 -1
- package/src/__tests__/credential-metadata-store.test.ts +239 -26
- package/src/__tests__/credential-resolve.test.ts +5 -4
- package/src/__tests__/credential-security-e2e.test.ts +8 -8
- package/src/__tests__/credential-security-invariants.test.ts +111 -7
- package/src/__tests__/credential-vault-unit.test.ts +287 -54
- package/src/__tests__/credential-vault.test.ts +406 -12
- package/src/__tests__/credentials-cli.test.ts +82 -6
- package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +0 -1
- package/src/__tests__/ephemeral-permissions.test.ts +3 -3
- package/src/__tests__/gateway-only-enforcement.test.ts +4 -2
- package/src/__tests__/gateway-only-guard.test.ts +0 -1
- package/src/__tests__/gemini-image-service.test.ts +75 -45
- package/src/__tests__/gemini-provider.test.ts +9 -6
- package/src/__tests__/guardian-action-conversation-turn.test.ts +1 -33
- package/src/__tests__/guardian-action-copy-generator.test.ts +0 -20
- package/src/__tests__/guardian-action-followup-executor.test.ts +1 -28
- package/src/__tests__/guardian-action-followup-store.test.ts +1 -1
- package/src/__tests__/guardian-action-grant-mint-consume.test.ts +0 -1
- package/src/__tests__/guardian-decision-primitive-canonical.test.ts +0 -1
- package/src/__tests__/guardian-grant-minting.test.ts +35 -0
- package/src/__tests__/guardian-routing-invariants.test.ts +0 -1
- package/src/__tests__/guardian-verification-voice-binding.test.ts +0 -1
- package/src/__tests__/handlers-user-message-approval-consumption.test.ts +0 -39
- package/src/__tests__/heartbeat-service.test.ts +0 -1
- package/src/__tests__/host-cu-proxy.test.ts +629 -0
- package/src/__tests__/host-shell-tool.test.ts +27 -15
- package/src/__tests__/http-user-message-parity.test.ts +1 -0
- package/src/__tests__/ingress-url-consistency.test.ts +14 -21
- package/src/__tests__/integration-status.test.ts +38 -25
- package/src/__tests__/intent-routing.test.ts +0 -1
- package/src/__tests__/invite-routes-http.test.ts +10 -9
- package/src/__tests__/keychain-broker-client.test.ts +11 -43
- package/src/__tests__/managed-proxy-context.test.ts +5 -3
- package/src/__tests__/media-generate-image.test.ts +63 -2
- package/src/__tests__/media-reuse-story.e2e.test.ts +7 -3
- package/src/__tests__/messaging-send-tool.test.ts +4 -6
- package/src/__tests__/notification-routing-intent.test.ts +0 -1
- package/src/__tests__/oauth-cli.test.ts +373 -14
- package/src/__tests__/oauth-provider-profiles.test.ts +9 -9
- package/src/__tests__/oauth-scope-policy.test.ts +4 -6
- package/src/__tests__/oauth-store.test.ts +756 -0
- package/src/__tests__/onboarding-starter-tasks.test.ts +0 -1
- package/src/__tests__/provider-error-scenarios.test.ts +0 -1
- package/src/__tests__/provider-fail-open-selection.test.ts +3 -1
- package/src/__tests__/provider-managed-proxy-integration.test.ts +70 -6
- package/src/__tests__/provider-streaming.benchmark.test.ts +0 -1
- package/src/__tests__/public-ingress-urls.test.ts +15 -21
- package/src/__tests__/recording-handler.test.ts +3 -4
- package/src/__tests__/registry.test.ts +2 -2
- package/src/__tests__/runtime-events-sse.test.ts +55 -7
- package/src/__tests__/schedule-store.test.ts +0 -1
- package/src/__tests__/scheduler-recurrence.test.ts +0 -1
- package/src/__tests__/schema-transforms.test.ts +226 -0
- package/src/__tests__/scoped-approval-grants.test.ts +0 -1
- package/src/__tests__/scoped-grant-security-matrix.test.ts +0 -1
- package/src/__tests__/script-proxy-injection-runtime.test.ts +23 -13
- package/src/__tests__/script-proxy-policy-runtime.test.ts +1 -1
- package/src/__tests__/script-proxy-session-manager.test.ts +1 -1
- package/src/__tests__/secret-ingress-handler.test.ts +0 -1
- package/src/__tests__/secret-onetime-send.test.ts +5 -3
- package/src/__tests__/send-endpoint-busy.test.ts +21 -6
- package/src/__tests__/sequence-store.test.ts +0 -1
- package/src/__tests__/session-init.benchmark.test.ts +4 -5
- package/src/__tests__/session-messaging-secret-redirect.test.ts +5 -4
- package/src/__tests__/skill-include-graph.test.ts +66 -0
- package/src/__tests__/skill-load-feature-flag.test.ts +0 -1
- package/src/__tests__/skill-load-tool.test.ts +149 -1
- package/src/__tests__/skill-projection-feature-flag.test.ts +0 -1
- package/src/__tests__/skills-uninstall.test.ts +3 -3
- package/src/__tests__/skills.test.ts +3 -12
- package/src/__tests__/slack-channel-config.test.ts +76 -11
- package/src/__tests__/slack-share-routes.test.ts +17 -14
- package/src/__tests__/system-prompt.test.ts +0 -1
- package/src/__tests__/telegram-bot-username-resolution.test.ts +3 -0
- package/src/__tests__/telegram-invite-adapter.test.ts +18 -22
- package/src/__tests__/terminal-tools.test.ts +4 -3
- package/src/__tests__/test-support/computer-use-skill-harness.ts +3 -2
- package/src/__tests__/tool-approval-handler.test.ts +0 -1
- package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +0 -1
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +0 -1
- package/src/__tests__/tool-executor-shell-integration.test.ts +0 -1
- package/src/__tests__/tool-executor.test.ts +0 -1
- package/src/__tests__/tool-grant-request-escalation.test.ts +0 -1
- package/src/__tests__/trust-store-pattern-matches.test.ts +29 -0
- package/src/__tests__/trust-store.test.ts +1 -22
- package/src/__tests__/trusted-contact-approval-notifier.test.ts +0 -1
- package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +0 -1
- package/src/__tests__/twilio-config.test.ts +2 -1
- package/src/__tests__/twilio-provider.test.ts +4 -2
- package/src/__tests__/twilio-routes.test.ts +5 -20
- package/src/__tests__/verification-control-plane-policy.test.ts +0 -1
- package/src/__tests__/voice-scoped-grant-consumer.test.ts +0 -1
- package/src/agent/ax-tree-compaction.test.ts +235 -0
- package/src/agent/loop.ts +76 -130
- package/src/calls/call-domain.ts +8 -10
- package/src/calls/relay-server.ts +9 -13
- package/src/calls/twilio-config.ts +4 -8
- package/src/calls/twilio-provider.ts +2 -1
- package/src/calls/twilio-rest.ts +2 -1
- package/src/calls/twilio-routes.ts +1 -2
- package/src/calls/voice-ingress-preflight.ts +1 -1
- package/src/cli/commands/browser-relay.ts +46 -15
- package/src/cli/commands/completions.ts +0 -3
- package/src/cli/commands/credentials.ts +110 -23
- package/src/cli/commands/oauth/apps.ts +255 -0
- package/src/cli/commands/oauth/connections.ts +299 -0
- package/src/cli/commands/oauth/index.ts +52 -0
- package/src/cli/commands/oauth/providers.ts +242 -0
- package/src/cli/commands/skills.ts +4 -338
- package/src/cli/program.ts +1 -5
- package/src/cli/reference.ts +1 -3
- package/src/cli.ts +3 -2
- package/src/config/assistant-feature-flags.ts +0 -3
- package/src/config/bundled-skills/_shared/CLI_RETRIEVAL_PATTERN.md +1 -1
- package/src/config/bundled-skills/claude-code/TOOLS.json +0 -4
- package/src/config/bundled-skills/computer-use/SKILL.md +3 -6
- package/src/config/bundled-skills/computer-use/TOOLS.json +22 -4
- package/src/config/bundled-skills/contacts/tools/google-contacts.ts +29 -32
- package/src/config/bundled-skills/gmail/SKILL.md +4 -4
- package/src/config/bundled-skills/gmail/tools/gmail-archive.ts +54 -61
- package/src/config/bundled-skills/gmail/tools/gmail-attachments.ts +25 -28
- package/src/config/bundled-skills/gmail/tools/gmail-draft.ts +14 -17
- package/src/config/bundled-skills/gmail/tools/gmail-filters.ts +39 -44
- package/src/config/bundled-skills/gmail/tools/gmail-follow-up.ts +61 -58
- package/src/config/bundled-skills/gmail/tools/gmail-forward.ts +50 -49
- package/src/config/bundled-skills/gmail/tools/gmail-label.ts +11 -13
- package/src/config/bundled-skills/gmail/tools/gmail-outreach-scan.ts +148 -146
- package/src/config/bundled-skills/gmail/tools/gmail-send-draft.ts +4 -7
- package/src/config/bundled-skills/gmail/tools/gmail-sender-digest.ts +175 -173
- package/src/config/bundled-skills/gmail/tools/gmail-trash.ts +4 -7
- package/src/config/bundled-skills/gmail/tools/gmail-unsubscribe.ts +71 -76
- package/src/config/bundled-skills/gmail/tools/gmail-vacation.ts +32 -38
- package/src/config/bundled-skills/google-calendar/SKILL.md +2 -2
- package/src/config/bundled-skills/google-calendar/calendar-client.ts +90 -44
- package/src/config/bundled-skills/google-calendar/tools/calendar-check-availability.ts +9 -10
- package/src/config/bundled-skills/google-calendar/tools/calendar-create-event.ts +5 -6
- package/src/config/bundled-skills/google-calendar/tools/calendar-get-event.ts +4 -5
- package/src/config/bundled-skills/google-calendar/tools/calendar-list-events.ts +14 -15
- package/src/config/bundled-skills/google-calendar/tools/calendar-rsvp.ts +37 -37
- package/src/config/bundled-skills/google-calendar/tools/shared.ts +4 -9
- package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +24 -3
- package/src/config/bundled-skills/messaging/SKILL.md +6 -6
- package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +62 -63
- package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +15 -16
- package/src/config/bundled-skills/messaging/tools/messaging-auth-test.ts +4 -5
- package/src/config/bundled-skills/messaging/tools/messaging-list-conversations.ts +6 -7
- package/src/config/bundled-skills/messaging/tools/messaging-mark-read.ts +4 -5
- package/src/config/bundled-skills/messaging/tools/messaging-read.ts +14 -15
- package/src/config/bundled-skills/messaging/tools/messaging-search.ts +4 -5
- package/src/config/bundled-skills/messaging/tools/messaging-send.ts +128 -128
- package/src/config/bundled-skills/messaging/tools/messaging-sender-digest.ts +33 -34
- package/src/config/bundled-skills/messaging/tools/shared.ts +12 -15
- package/src/config/bundled-skills/settings/SKILL.md +1 -1
- package/src/config/bundled-skills/settings/TOOLS.json +2 -8
- package/src/config/bundled-skills/settings/tools/voice-config-update.ts +5 -33
- package/src/config/bundled-skills/slack/tools/shared.ts +4 -10
- package/src/config/bundled-skills/slack/tools/slack-add-reaction.ts +4 -5
- package/src/config/bundled-skills/slack/tools/slack-channel-details.ts +15 -16
- package/src/config/bundled-skills/slack/tools/slack-delete-message.ts +4 -5
- package/src/config/bundled-skills/slack/tools/slack-edit-message.ts +4 -5
- package/src/config/bundled-skills/slack/tools/slack-leave-channel.ts +4 -5
- package/src/config/bundled-skills/slack/tools/slack-scan-digest.ts +95 -92
- package/src/config/env-registry.ts +14 -83
- package/src/config/env.ts +11 -50
- package/src/config/feature-flag-registry.json +16 -16
- package/src/config/schema.ts +3 -1
- package/src/config/skills.ts +21 -2
- package/src/context/image-dimensions.ts +229 -0
- package/src/context/token-estimator.ts +75 -12
- package/src/context/window-manager.ts +49 -10
- package/src/daemon/assistant-attachments.ts +1 -13
- package/src/daemon/guardian-action-generators.ts +4 -5
- package/src/daemon/handlers/config-ingress.ts +8 -33
- package/src/daemon/handlers/config-slack-channel.ts +76 -56
- package/src/daemon/handlers/config-telegram.ts +53 -24
- package/src/daemon/handlers/sessions.ts +10 -24
- package/src/daemon/handlers/shared.ts +0 -130
- package/src/daemon/host-cu-proxy.ts +401 -0
- package/src/daemon/lifecycle.ts +39 -63
- package/src/daemon/message-protocol.ts +3 -0
- package/src/daemon/message-types/computer-use.ts +2 -119
- package/src/daemon/message-types/host-cu.ts +19 -0
- package/src/daemon/message-types/integrations.ts +1 -0
- package/src/daemon/message-types/messages.ts +3 -0
- package/src/daemon/server.ts +14 -21
- package/src/daemon/session-agent-loop-handlers.ts +2 -0
- package/src/daemon/session-attachments.ts +1 -2
- package/src/daemon/session-messaging.ts +3 -1
- package/src/daemon/session-slash.ts +1 -1
- package/src/daemon/session-surfaces.ts +40 -28
- package/src/daemon/session-tool-setup.ts +20 -11
- package/src/daemon/session.ts +139 -16
- package/src/daemon/tool-side-effects.ts +2 -8
- package/src/daemon/watch-handler.ts +2 -2
- package/src/email/providers/index.ts +2 -1
- package/src/events/tool-metrics-listener.ts +2 -2
- package/src/hooks/manager.ts +1 -4
- package/src/inbound/public-ingress-urls.ts +7 -7
- package/src/instrument.ts +15 -1
- package/src/logfire.ts +16 -5
- package/src/media/app-icon-generator.ts +30 -4
- package/src/media/avatar-router.ts +26 -3
- package/src/media/gemini-image-service.ts +28 -2
- package/src/memory/conversation-key-store.ts +21 -0
- package/src/memory/db-init.ts +4 -0
- package/src/memory/guardian-action-store.ts +1 -1
- package/src/memory/migrations/149-oauth-tables.ts +60 -0
- package/src/memory/migrations/index.ts +1 -0
- package/src/memory/schema/guardian.ts +1 -1
- package/src/memory/schema/index.ts +1 -0
- package/src/memory/schema/oauth.ts +65 -0
- package/src/messaging/provider.ts +19 -13
- package/src/messaging/providers/gmail/adapter.ts +40 -23
- package/src/messaging/providers/gmail/client.ts +283 -122
- package/src/messaging/providers/gmail/people-client.ts +32 -24
- package/src/messaging/providers/slack/adapter.ts +29 -19
- package/src/messaging/providers/slack/client.ts +265 -78
- package/src/messaging/providers/telegram-bot/adapter.ts +19 -18
- package/src/messaging/providers/whatsapp/adapter.ts +17 -11
- package/src/messaging/registry.ts +2 -31
- package/src/notifications/copy-composer.ts +0 -5
- package/src/notifications/signal.ts +4 -5
- package/src/oauth/byo-connection.test.ts +537 -0
- package/src/oauth/byo-connection.ts +128 -0
- package/src/oauth/connect-orchestrator.ts +139 -56
- package/src/oauth/connect-types.ts +17 -23
- package/src/oauth/connection-resolver.ts +58 -0
- package/src/oauth/connection.ts +38 -0
- package/src/oauth/manual-token-connection.ts +104 -0
- package/src/oauth/oauth-store.ts +496 -0
- package/src/oauth/platform-connection.test.ts +192 -0
- package/src/oauth/platform-connection.ts +111 -0
- package/src/oauth/provider-behaviors.ts +124 -0
- package/src/oauth/scope-policy.ts +9 -2
- package/src/oauth/seed-providers.ts +161 -0
- package/src/oauth/token-persistence.ts +74 -78
- package/src/permissions/checker.ts +8 -4
- package/src/permissions/defaults.ts +0 -1
- package/src/permissions/prompter.ts +10 -1
- package/src/permissions/trust-store.ts +13 -0
- package/src/prompts/__tests__/build-cli-reference-section.test.ts +3 -1
- package/src/prompts/system-prompt.ts +70 -45
- package/src/providers/anthropic/client.ts +133 -24
- package/src/providers/gemini/client.ts +15 -6
- package/src/providers/managed-proxy/constants.ts +2 -2
- package/src/providers/managed-proxy/context.ts +5 -1
- package/src/providers/ratelimit.ts +17 -0
- package/src/providers/registry.ts +2 -2
- package/src/providers/retry.ts +1 -27
- package/src/runtime/AGENTS.md +17 -0
- package/src/runtime/auth/route-policy.ts +0 -3
- package/src/runtime/channel-invite-transports/telegram.ts +2 -1
- package/src/runtime/channel-readiness-service.ts +168 -195
- package/src/runtime/channel-readiness-types.ts +4 -0
- package/src/runtime/channel-reply-delivery.ts +0 -40
- package/src/runtime/gateway-client.ts +0 -7
- package/src/runtime/guardian-action-conversation-turn.ts +1 -3
- package/src/runtime/guardian-action-followup-executor.ts +1 -1
- package/src/runtime/guardian-action-message-composer.ts +3 -23
- package/src/runtime/http-server.ts +17 -10
- package/src/runtime/http-types.ts +2 -3
- package/src/runtime/middleware/rate-limiter.ts +74 -20
- package/src/runtime/middleware/twilio-validation.ts +1 -11
- package/src/runtime/pending-interactions.ts +14 -12
- package/src/runtime/routes/channel-delivery-routes.ts +0 -1
- package/src/runtime/routes/channel-readiness-routes.ts +2 -0
- package/src/runtime/routes/conversation-routes.ts +73 -19
- package/src/runtime/routes/diagnostics-routes.ts +11 -9
- package/src/runtime/routes/events-routes.ts +21 -11
- package/src/runtime/routes/guardian-approval-interception.ts +20 -5
- package/src/runtime/routes/host-cu-routes.ts +97 -0
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +12 -111
- package/src/runtime/routes/integrations/slack/share.ts +6 -6
- package/src/runtime/routes/integrations/twilio.ts +6 -5
- package/src/runtime/routes/log-export-routes.ts +126 -8
- package/src/runtime/routes/secret-routes.ts +3 -2
- package/src/runtime/routes/settings-routes.ts +113 -48
- package/src/runtime/routes/surface-action-routes.ts +1 -1
- package/src/runtime/routes/watch-routes.ts +128 -0
- package/src/schedule/integration-status.ts +10 -8
- package/src/security/credential-key.ts +14 -0
- package/src/security/keychain-broker-client.ts +5 -6
- package/src/security/oauth2.ts +1 -1
- package/src/security/token-manager.ts +145 -43
- package/src/skills/catalog-install.ts +358 -0
- package/src/skills/include-graph.ts +32 -0
- package/src/telegram/bot-username.ts +2 -3
- package/src/tools/apps/definitions.ts +0 -5
- package/src/tools/assets/materialize.ts +0 -5
- package/src/tools/assets/search.ts +0 -5
- package/src/tools/browser/headless-browser.ts +1 -67
- package/src/tools/browser/network-recorder.ts +1 -1
- package/src/tools/browser/network-recording-types.ts +1 -1
- package/src/tools/claude-code/claude-code.ts +0 -5
- package/src/tools/computer-use/definitions.ts +46 -11
- package/src/tools/computer-use/registry.ts +4 -5
- package/src/tools/credentials/broker.ts +5 -4
- package/src/tools/credentials/metadata-store.ts +22 -74
- package/src/tools/credentials/resolve.ts +2 -1
- package/src/tools/credentials/vault.ts +139 -151
- package/src/tools/filesystem/edit.ts +1 -6
- package/src/tools/filesystem/read.ts +0 -5
- package/src/tools/filesystem/write.ts +1 -6
- package/src/tools/host-filesystem/edit.ts +1 -6
- package/src/tools/host-filesystem/read.ts +1 -6
- package/src/tools/host-filesystem/write.ts +1 -6
- package/src/tools/mcp/mcp-tool-factory.ts +18 -1
- package/src/tools/memory/definitions.ts +0 -5
- package/src/tools/network/web-fetch.ts +0 -5
- package/src/tools/network/web-search.ts +0 -5
- package/src/tools/registry.ts +2 -7
- package/src/tools/schema-transforms.ts +99 -0
- package/src/tools/skills/load.ts +62 -8
- package/src/tools/swarm/delegate.ts +0 -5
- package/src/tools/system/avatar-generator.ts +0 -5
- package/src/tools/ui-surface/definitions.ts +0 -15
- package/src/tools/watch/screen-watch.ts +0 -5
- package/src/tools/watch/watch-state.ts +0 -12
- package/src/util/logger.ts +7 -41
- package/src/util/platform.ts +9 -28
- package/src/version.ts +10 -0
- package/src/watcher/providers/github.ts +51 -52
- package/src/watcher/providers/gmail.ts +88 -80
- package/src/watcher/providers/google-calendar.ts +94 -86
- package/src/watcher/providers/linear.ts +87 -93
- package/src/__tests__/computer-use-session-compaction.test.ts +0 -143
- package/src/__tests__/computer-use-session-lifecycle.test.ts +0 -322
- package/src/__tests__/computer-use-session-working-dir.test.ts +0 -166
- package/src/__tests__/computer-use-skill-baseline.test.ts +0 -78
- package/src/__tests__/computer-use-skill-endstate.test.ts +0 -105
- package/src/__tests__/computer-use-skill-lifecycle-cleanup.test.ts +0 -249
- package/src/__tests__/ride-shotgun-handler.test.ts +0 -452
- package/src/cli/commands/dev.ts +0 -129
- package/src/cli/commands/map.ts +0 -391
- package/src/cli/commands/oauth.ts +0 -77
- package/src/config/bundled-skills/computer-use/tools/computer-use-request-control.ts +0 -16
- package/src/daemon/computer-use-session.ts +0 -1020
- package/src/daemon/ride-shotgun-handler.ts +0 -567
- package/src/oauth/provider-profiles.ts +0 -192
- package/src/prompts/computer-use-prompt.ts +0 -98
- package/src/runtime/routes/computer-use-routes.ts +0 -641
- package/src/runtime/telegram-streaming-delivery.test.ts +0 -597
- package/src/runtime/telegram-streaming-delivery.ts +0 -383
- package/src/tools/computer-use/request-computer-control.ts +0 -61
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
import { type Command, InvalidArgumentError } from "commander";
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
getProvider,
|
|
5
|
+
listProviders,
|
|
6
|
+
registerProvider,
|
|
7
|
+
} from "../../../oauth/oauth-store.js";
|
|
8
|
+
import { getCliLogger } from "../../logger.js";
|
|
9
|
+
import { shouldOutputJson, writeOutput } from "../../output.js";
|
|
10
|
+
|
|
11
|
+
const log = getCliLogger("cli");
|
|
12
|
+
|
|
13
|
+
/** Parse stored JSON string fields into their native types. */
|
|
14
|
+
function parseProviderRow(row: ReturnType<typeof getProvider>) {
|
|
15
|
+
if (!row) return row;
|
|
16
|
+
return {
|
|
17
|
+
...row,
|
|
18
|
+
defaultScopes: row.defaultScopes ? JSON.parse(row.defaultScopes) : [],
|
|
19
|
+
scopePolicy: row.scopePolicy ? JSON.parse(row.scopePolicy) : {},
|
|
20
|
+
extraParams: row.extraParams ? JSON.parse(row.extraParams) : null,
|
|
21
|
+
createdAt: new Date(row.createdAt).toISOString(),
|
|
22
|
+
updatedAt: new Date(row.updatedAt).toISOString(),
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function registerProviderCommands(oauth: Command): void {
|
|
27
|
+
const providers = oauth
|
|
28
|
+
.command("providers")
|
|
29
|
+
.description(
|
|
30
|
+
"Manage OAuth provider configurations (auth URLs, scopes, endpoints)",
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
providers.addHelpText(
|
|
34
|
+
"after",
|
|
35
|
+
`
|
|
36
|
+
Providers define the protocol-level configuration for an OAuth integration:
|
|
37
|
+
authorization URL, token URL, default scopes, and other endpoint details.
|
|
38
|
+
|
|
39
|
+
They are seeded on startup for built-in integrations (e.g. Gmail, Twitter,
|
|
40
|
+
Slack) but can also be registered dynamically via the "register" subcommand.
|
|
41
|
+
|
|
42
|
+
Each provider is identified by a provider key (e.g. "integration:gmail").`,
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
// ---------------------------------------------------------------------------
|
|
46
|
+
// providers list
|
|
47
|
+
// ---------------------------------------------------------------------------
|
|
48
|
+
|
|
49
|
+
providers
|
|
50
|
+
.command("list")
|
|
51
|
+
.description("List all registered OAuth providers")
|
|
52
|
+
.option(
|
|
53
|
+
"--provider-key <key>",
|
|
54
|
+
'Filter by provider key substring (case-insensitive). Comma-separated values are OR\'d (e.g. "gmail,google")',
|
|
55
|
+
)
|
|
56
|
+
.addHelpText(
|
|
57
|
+
"after",
|
|
58
|
+
`
|
|
59
|
+
Returns registered OAuth providers, including both built-in providers
|
|
60
|
+
seeded at startup and any dynamically registered via "providers register".
|
|
61
|
+
|
|
62
|
+
When --provider-key is specified, only providers whose key contains the
|
|
63
|
+
given substring (case-insensitive) are returned. Multiple substrings can
|
|
64
|
+
be OR'd together using commas (e.g. "gmail,google" matches any provider
|
|
65
|
+
whose key contains "gmail" OR "google"). Without the flag, all providers
|
|
66
|
+
are listed.
|
|
67
|
+
|
|
68
|
+
Each provider row includes its key, auth URL, token URL, default scopes,
|
|
69
|
+
and configuration timestamps.
|
|
70
|
+
|
|
71
|
+
Examples:
|
|
72
|
+
$ assistant oauth providers list
|
|
73
|
+
$ assistant oauth providers list --provider-key gmail
|
|
74
|
+
$ assistant oauth providers list --provider-key "gmail,google"
|
|
75
|
+
$ assistant oauth providers list --provider-key slack --json`,
|
|
76
|
+
)
|
|
77
|
+
.action((opts: { providerKey?: string }, cmd: Command) => {
|
|
78
|
+
try {
|
|
79
|
+
let rows = listProviders().map(parseProviderRow);
|
|
80
|
+
|
|
81
|
+
if (opts.providerKey) {
|
|
82
|
+
const needles = opts.providerKey
|
|
83
|
+
.split(",")
|
|
84
|
+
.map((n) => n.trim().toLowerCase())
|
|
85
|
+
.filter(Boolean);
|
|
86
|
+
rows = rows.filter(
|
|
87
|
+
(r) =>
|
|
88
|
+
r &&
|
|
89
|
+
needles.some((needle) =>
|
|
90
|
+
r.providerKey.toLowerCase().includes(needle),
|
|
91
|
+
),
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (!shouldOutputJson(cmd)) {
|
|
96
|
+
log.info(`Found ${rows.length} provider(s)`);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
writeOutput(cmd, rows);
|
|
100
|
+
} catch (err) {
|
|
101
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
102
|
+
writeOutput(cmd, { ok: false, error: message });
|
|
103
|
+
process.exitCode = 1;
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
// ---------------------------------------------------------------------------
|
|
108
|
+
// providers get <provider-key>
|
|
109
|
+
// ---------------------------------------------------------------------------
|
|
110
|
+
|
|
111
|
+
providers
|
|
112
|
+
.command("get <provider-key>")
|
|
113
|
+
.description("Show details of a specific OAuth provider")
|
|
114
|
+
.addHelpText(
|
|
115
|
+
"after",
|
|
116
|
+
`
|
|
117
|
+
Arguments:
|
|
118
|
+
provider-key The full provider key (e.g. "integration:gmail").
|
|
119
|
+
Must match the key used during registration or seeding.
|
|
120
|
+
|
|
121
|
+
Returns the full provider configuration including auth URL, token URL,
|
|
122
|
+
default scopes, scope policy, and extra parameters. Exits with code 1
|
|
123
|
+
if the provider key is not found.
|
|
124
|
+
|
|
125
|
+
Examples:
|
|
126
|
+
$ assistant oauth providers get integration:gmail
|
|
127
|
+
$ assistant oauth providers get integration:twitter --json`,
|
|
128
|
+
)
|
|
129
|
+
.action((providerKey: string, _opts: unknown, cmd: Command) => {
|
|
130
|
+
try {
|
|
131
|
+
const row = getProvider(providerKey);
|
|
132
|
+
|
|
133
|
+
if (!row) {
|
|
134
|
+
writeOutput(cmd, {
|
|
135
|
+
ok: false,
|
|
136
|
+
error: `Provider not found: ${providerKey}`,
|
|
137
|
+
});
|
|
138
|
+
process.exitCode = 1;
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
writeOutput(cmd, parseProviderRow(row));
|
|
143
|
+
} catch (err) {
|
|
144
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
145
|
+
writeOutput(cmd, { ok: false, error: message });
|
|
146
|
+
process.exitCode = 1;
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
// ---------------------------------------------------------------------------
|
|
151
|
+
// providers register
|
|
152
|
+
// ---------------------------------------------------------------------------
|
|
153
|
+
|
|
154
|
+
providers
|
|
155
|
+
.command("register")
|
|
156
|
+
.description("Register a new OAuth provider configuration")
|
|
157
|
+
.requiredOption("--provider-key <key>", "Provider key")
|
|
158
|
+
.requiredOption("--auth-url <url>", "Authorization endpoint URL")
|
|
159
|
+
.requiredOption("--token-url <url>", "Token endpoint URL")
|
|
160
|
+
.option("--base-url <url>", "API base URL")
|
|
161
|
+
.option("--userinfo-url <url>", "Userinfo endpoint URL")
|
|
162
|
+
.option("--scopes <scopes>", "Comma-separated default scopes")
|
|
163
|
+
.option("--token-auth-method <method>", "Token endpoint auth method")
|
|
164
|
+
.option("--callback-transport <transport>", "Callback transport")
|
|
165
|
+
.option("--loopback-port <port>", "Loopback port", (value: string) => {
|
|
166
|
+
const port = parseInt(value, 10);
|
|
167
|
+
if (isNaN(port) || port <= 0 || port > 65535) {
|
|
168
|
+
throw new InvalidArgumentError(
|
|
169
|
+
"Port must be a number between 1 and 65535",
|
|
170
|
+
);
|
|
171
|
+
}
|
|
172
|
+
return port;
|
|
173
|
+
})
|
|
174
|
+
.addHelpText(
|
|
175
|
+
"after",
|
|
176
|
+
`
|
|
177
|
+
Arguments (via options):
|
|
178
|
+
--provider-key Unique identifier for this provider (e.g. "integration:custom-service").
|
|
179
|
+
Must not collide with an existing provider key.
|
|
180
|
+
--auth-url The OAuth authorization endpoint URL.
|
|
181
|
+
--token-url The OAuth token endpoint URL.
|
|
182
|
+
--base-url Optional API base URL for the service.
|
|
183
|
+
--userinfo-url Optional OpenID Connect userinfo endpoint.
|
|
184
|
+
--scopes Comma-separated list of default scopes (e.g. "read,write,profile").
|
|
185
|
+
--token-auth-method How the client authenticates at the token endpoint
|
|
186
|
+
(e.g. "client_secret_post", "client_secret_basic").
|
|
187
|
+
--callback-transport Transport method for the OAuth callback.
|
|
188
|
+
--loopback-port Port number for the local loopback callback server (1-65535).
|
|
189
|
+
|
|
190
|
+
Registers a new OAuth provider configuration in the local store. This is
|
|
191
|
+
used for custom integrations not covered by the built-in provider seeds.
|
|
192
|
+
On success, returns the full provider row including generated timestamps.
|
|
193
|
+
|
|
194
|
+
Examples:
|
|
195
|
+
$ assistant oauth providers register \\
|
|
196
|
+
--provider-key integration:custom-api \\
|
|
197
|
+
--auth-url https://custom-api.example.com/oauth/authorize \\
|
|
198
|
+
--token-url https://custom-api.example.com/oauth/token
|
|
199
|
+
$ assistant oauth providers register \\
|
|
200
|
+
--provider-key integration:my-service \\
|
|
201
|
+
--auth-url https://my-service.com/auth \\
|
|
202
|
+
--token-url https://my-service.com/token \\
|
|
203
|
+
--scopes read,write --json`,
|
|
204
|
+
)
|
|
205
|
+
.action(
|
|
206
|
+
(
|
|
207
|
+
opts: {
|
|
208
|
+
providerKey: string;
|
|
209
|
+
authUrl: string;
|
|
210
|
+
tokenUrl: string;
|
|
211
|
+
baseUrl?: string;
|
|
212
|
+
userinfoUrl?: string;
|
|
213
|
+
scopes?: string;
|
|
214
|
+
tokenAuthMethod?: string;
|
|
215
|
+
callbackTransport?: string;
|
|
216
|
+
loopbackPort?: number;
|
|
217
|
+
},
|
|
218
|
+
cmd: Command,
|
|
219
|
+
) => {
|
|
220
|
+
try {
|
|
221
|
+
const row = registerProvider({
|
|
222
|
+
providerKey: opts.providerKey,
|
|
223
|
+
authUrl: opts.authUrl,
|
|
224
|
+
tokenUrl: opts.tokenUrl,
|
|
225
|
+
baseUrl: opts.baseUrl,
|
|
226
|
+
userinfoUrl: opts.userinfoUrl,
|
|
227
|
+
defaultScopes: opts.scopes ? opts.scopes.split(",") : [],
|
|
228
|
+
scopePolicy: {},
|
|
229
|
+
tokenEndpointAuthMethod: opts.tokenAuthMethod,
|
|
230
|
+
callbackTransport: opts.callbackTransport,
|
|
231
|
+
loopbackPort: opts.loopbackPort,
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
writeOutput(cmd, parseProviderRow(row));
|
|
235
|
+
} catch (err) {
|
|
236
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
237
|
+
writeOutput(cmd, { ok: false, error: message });
|
|
238
|
+
process.exitCode = 1;
|
|
239
|
+
}
|
|
240
|
+
},
|
|
241
|
+
);
|
|
242
|
+
}
|
|
@@ -1,348 +1,14 @@
|
|
|
1
|
-
import { execSync } from "node:child_process";
|
|
2
|
-
import { randomUUID } from "node:crypto";
|
|
3
|
-
import {
|
|
4
|
-
cpSync,
|
|
5
|
-
existsSync,
|
|
6
|
-
mkdirSync,
|
|
7
|
-
readFileSync,
|
|
8
|
-
renameSync,
|
|
9
|
-
rmSync,
|
|
10
|
-
writeFileSync,
|
|
11
|
-
} from "node:fs";
|
|
12
|
-
import { homedir } from "node:os";
|
|
13
|
-
import { dirname, join } from "node:path";
|
|
14
|
-
import { gunzipSync } from "node:zlib";
|
|
15
|
-
|
|
16
1
|
import type { Command } from "commander";
|
|
17
2
|
|
|
3
|
+
import type { CatalogSkill } from "../../skills/catalog-install.js";
|
|
18
4
|
import {
|
|
19
|
-
getWorkspaceConfigPath,
|
|
20
|
-
getWorkspaceSkillsDir,
|
|
21
|
-
readPlatformToken,
|
|
22
|
-
} from "../../util/platform.js";
|
|
23
|
-
import { log } from "../logger.js";
|
|
24
|
-
|
|
25
|
-
// ---------------------------------------------------------------------------
|
|
26
|
-
// Path helpers
|
|
27
|
-
// ---------------------------------------------------------------------------
|
|
28
|
-
|
|
29
|
-
function getSkillsIndexPath(): string {
|
|
30
|
-
return join(getWorkspaceSkillsDir(), "SKILLS.md");
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* Resolve the repo-level skills/ directory when running in dev mode.
|
|
35
|
-
* Returns the path if VELLUM_DEV is set and the directory exists, or undefined.
|
|
36
|
-
*/
|
|
37
|
-
function getRepoSkillsDir(): string | undefined {
|
|
38
|
-
if (!process.env.VELLUM_DEV) return undefined;
|
|
39
|
-
|
|
40
|
-
// assistant/src/cli/commands/skills.ts -> ../../../../skills/
|
|
41
|
-
const candidate = join(import.meta.dir, "..", "..", "..", "..", "skills");
|
|
42
|
-
if (existsSync(join(candidate, "catalog.json"))) {
|
|
43
|
-
return candidate;
|
|
44
|
-
}
|
|
45
|
-
return undefined;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* Read skills from the repo-local catalog.json.
|
|
50
|
-
*/
|
|
51
|
-
function readLocalCatalog(repoSkillsDir: string): CatalogSkill[] {
|
|
52
|
-
try {
|
|
53
|
-
const raw = readFileSync(join(repoSkillsDir, "catalog.json"), "utf-8");
|
|
54
|
-
const manifest = JSON.parse(raw) as CatalogManifest;
|
|
55
|
-
if (!Array.isArray(manifest.skills)) return [];
|
|
56
|
-
return manifest.skills;
|
|
57
|
-
} catch {
|
|
58
|
-
return [];
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
// ---------------------------------------------------------------------------
|
|
63
|
-
// Platform API client
|
|
64
|
-
// ---------------------------------------------------------------------------
|
|
65
|
-
|
|
66
|
-
function getConfigPlatformUrl(): string | undefined {
|
|
67
|
-
try {
|
|
68
|
-
const configPath = getWorkspaceConfigPath();
|
|
69
|
-
if (!existsSync(configPath)) return undefined;
|
|
70
|
-
const raw = JSON.parse(readFileSync(configPath, "utf-8")) as Record<
|
|
71
|
-
string,
|
|
72
|
-
unknown
|
|
73
|
-
>;
|
|
74
|
-
const platform = raw.platform as Record<string, unknown> | undefined;
|
|
75
|
-
const baseUrl = platform?.baseUrl;
|
|
76
|
-
if (typeof baseUrl === "string" && baseUrl.trim()) return baseUrl.trim();
|
|
77
|
-
} catch {
|
|
78
|
-
// ignore
|
|
79
|
-
}
|
|
80
|
-
return undefined;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
function getPlatformUrl(): string {
|
|
84
|
-
return (
|
|
85
|
-
process.env.VELLUM_ASSISTANT_PLATFORM_URL ??
|
|
86
|
-
getConfigPlatformUrl() ??
|
|
87
|
-
"https://platform.vellum.ai"
|
|
88
|
-
);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
function buildHeaders(): Record<string, string> {
|
|
92
|
-
const headers: Record<string, string> = {};
|
|
93
|
-
const token = readPlatformToken();
|
|
94
|
-
if (token) {
|
|
95
|
-
headers["X-Session-Token"] = token;
|
|
96
|
-
}
|
|
97
|
-
return headers;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
// ---------------------------------------------------------------------------
|
|
101
|
-
// Types
|
|
102
|
-
// ---------------------------------------------------------------------------
|
|
103
|
-
|
|
104
|
-
interface CatalogSkill {
|
|
105
|
-
id: string;
|
|
106
|
-
name: string;
|
|
107
|
-
description: string;
|
|
108
|
-
emoji?: string;
|
|
109
|
-
includes?: string[];
|
|
110
|
-
version?: string;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
interface CatalogManifest {
|
|
114
|
-
version: number;
|
|
115
|
-
skills: CatalogSkill[];
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
// ---------------------------------------------------------------------------
|
|
119
|
-
// Catalog operations
|
|
120
|
-
// ---------------------------------------------------------------------------
|
|
121
|
-
|
|
122
|
-
async function fetchCatalog(): Promise<CatalogSkill[]> {
|
|
123
|
-
const url = `${getPlatformUrl()}/v1/skills/`;
|
|
124
|
-
const response = await fetch(url, {
|
|
125
|
-
headers: buildHeaders(),
|
|
126
|
-
signal: AbortSignal.timeout(10000),
|
|
127
|
-
});
|
|
128
|
-
|
|
129
|
-
if (!response.ok) {
|
|
130
|
-
throw new Error(
|
|
131
|
-
`Platform API error ${response.status}: ${response.statusText}`,
|
|
132
|
-
);
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
const manifest = (await response.json()) as CatalogManifest;
|
|
136
|
-
if (!Array.isArray(manifest.skills)) {
|
|
137
|
-
throw new Error("Platform catalog has invalid skills array");
|
|
138
|
-
}
|
|
139
|
-
return manifest.skills;
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
/**
|
|
143
|
-
* Extract all files from a tar archive (uncompressed) into a directory.
|
|
144
|
-
* Returns true if a SKILL.md was found in the archive.
|
|
145
|
-
*/
|
|
146
|
-
function extractTarToDir(tarBuffer: Buffer, destDir: string): boolean {
|
|
147
|
-
let foundSkillMd = false;
|
|
148
|
-
let offset = 0;
|
|
149
|
-
while (offset + 512 <= tarBuffer.length) {
|
|
150
|
-
const header = tarBuffer.subarray(offset, offset + 512);
|
|
151
|
-
|
|
152
|
-
// End-of-archive (two consecutive zero blocks)
|
|
153
|
-
if (header.every((b) => b === 0)) break;
|
|
154
|
-
|
|
155
|
-
// Filename (bytes 0-99, null-terminated)
|
|
156
|
-
const nameEnd = header.indexOf(0, 0);
|
|
157
|
-
const name = header
|
|
158
|
-
.subarray(0, Math.min(nameEnd >= 0 ? nameEnd : 100, 100))
|
|
159
|
-
.toString("utf-8");
|
|
160
|
-
|
|
161
|
-
// File type (byte 156): '5' = directory, '0' or '\0' = regular file
|
|
162
|
-
const typeFlag = header[156];
|
|
163
|
-
|
|
164
|
-
// File size (bytes 124-135, octal)
|
|
165
|
-
const sizeStr = header.subarray(124, 136).toString("utf-8").trim();
|
|
166
|
-
const size = parseInt(sizeStr, 8) || 0;
|
|
167
|
-
|
|
168
|
-
offset += 512; // past header
|
|
169
|
-
|
|
170
|
-
// Skip directories and empty names
|
|
171
|
-
if (name && typeFlag !== 53 /* '5' */) {
|
|
172
|
-
// Prevent path traversal
|
|
173
|
-
const normalizedName = name.replace(/^\.\//, "");
|
|
174
|
-
if (!normalizedName.startsWith("..") && !normalizedName.includes("/..")) {
|
|
175
|
-
const destPath = join(destDir, normalizedName);
|
|
176
|
-
mkdirSync(dirname(destPath), { recursive: true });
|
|
177
|
-
writeFileSync(destPath, tarBuffer.subarray(offset, offset + size));
|
|
178
|
-
|
|
179
|
-
if (
|
|
180
|
-
normalizedName === "SKILL.md" ||
|
|
181
|
-
normalizedName.endsWith("/SKILL.md")
|
|
182
|
-
) {
|
|
183
|
-
foundSkillMd = true;
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
// Skip to next header (data padded to 512 bytes)
|
|
189
|
-
offset += Math.ceil(size / 512) * 512;
|
|
190
|
-
}
|
|
191
|
-
return foundSkillMd;
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
async function fetchAndExtractSkill(
|
|
195
|
-
skillId: string,
|
|
196
|
-
destDir: string,
|
|
197
|
-
): Promise<void> {
|
|
198
|
-
const url = `${getPlatformUrl()}/v1/skills/${encodeURIComponent(skillId)}/`;
|
|
199
|
-
const response = await fetch(url, {
|
|
200
|
-
headers: buildHeaders(),
|
|
201
|
-
signal: AbortSignal.timeout(15000),
|
|
202
|
-
});
|
|
203
|
-
|
|
204
|
-
if (!response.ok) {
|
|
205
|
-
throw new Error(
|
|
206
|
-
`Failed to fetch skill "${skillId}": HTTP ${response.status}`,
|
|
207
|
-
);
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
const gzipBuffer = Buffer.from(await response.arrayBuffer());
|
|
211
|
-
const tarBuffer = gunzipSync(gzipBuffer);
|
|
212
|
-
const foundSkillMd = extractTarToDir(tarBuffer, destDir);
|
|
213
|
-
|
|
214
|
-
if (!foundSkillMd) {
|
|
215
|
-
throw new Error(`SKILL.md not found in archive for "${skillId}"`);
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
// ---------------------------------------------------------------------------
|
|
220
|
-
// Managed skill installation
|
|
221
|
-
// ---------------------------------------------------------------------------
|
|
222
|
-
|
|
223
|
-
function atomicWriteFile(filePath: string, content: string): void {
|
|
224
|
-
const dir = dirname(filePath);
|
|
225
|
-
mkdirSync(dir, { recursive: true });
|
|
226
|
-
const tmpPath = join(dir, `.tmp-${randomUUID()}`);
|
|
227
|
-
writeFileSync(tmpPath, content, "utf-8");
|
|
228
|
-
renameSync(tmpPath, filePath);
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
function upsertSkillsIndex(id: string): void {
|
|
232
|
-
const indexPath = getSkillsIndexPath();
|
|
233
|
-
let lines: string[] = [];
|
|
234
|
-
if (existsSync(indexPath)) {
|
|
235
|
-
lines = readFileSync(indexPath, "utf-8").split("\n");
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
const escaped = id.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
239
|
-
const pattern = new RegExp(`^[-*]\\s+(?:\`)?${escaped}(?:\`)?\\s*$`);
|
|
240
|
-
if (lines.some((line) => pattern.test(line))) return;
|
|
241
|
-
|
|
242
|
-
const nonEmpty = lines.filter((l) => l.trim());
|
|
243
|
-
nonEmpty.push(`- ${id}`);
|
|
244
|
-
const content = nonEmpty.join("\n");
|
|
245
|
-
atomicWriteFile(indexPath, content.endsWith("\n") ? content : content + "\n");
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
function removeSkillsIndexEntry(id: string): void {
|
|
249
|
-
const indexPath = getSkillsIndexPath();
|
|
250
|
-
if (!existsSync(indexPath)) return;
|
|
251
|
-
|
|
252
|
-
const lines = readFileSync(indexPath, "utf-8").split("\n");
|
|
253
|
-
const escaped = id.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
254
|
-
const pattern = new RegExp(`^[-*]\\s+(?:\`)?${escaped}(?:\`)?\\s*$`);
|
|
255
|
-
const filtered = lines.filter((line) => !pattern.test(line));
|
|
256
|
-
|
|
257
|
-
// If nothing changed, skip the write
|
|
258
|
-
if (filtered.length === lines.length) return;
|
|
259
|
-
|
|
260
|
-
const content = filtered.join("\n");
|
|
261
|
-
atomicWriteFile(indexPath, content.endsWith("\n") ? content : content + "\n");
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
function uninstallSkillLocally(skillId: string): void {
|
|
265
|
-
const skillDir = join(getWorkspaceSkillsDir(), skillId);
|
|
266
|
-
|
|
267
|
-
if (!existsSync(skillDir)) {
|
|
268
|
-
throw new Error(`Skill "${skillId}" is not installed.`);
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
rmSync(skillDir, { recursive: true, force: true });
|
|
272
|
-
removeSkillsIndexEntry(skillId);
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
async function installSkillLocally(
|
|
276
|
-
skillId: string,
|
|
277
|
-
catalogEntry: CatalogSkill,
|
|
278
|
-
overwrite: boolean,
|
|
279
|
-
): Promise<void> {
|
|
280
|
-
const skillDir = join(getWorkspaceSkillsDir(), skillId);
|
|
281
|
-
const skillFilePath = join(skillDir, "SKILL.md");
|
|
282
|
-
|
|
283
|
-
if (existsSync(skillFilePath) && !overwrite) {
|
|
284
|
-
throw new Error(
|
|
285
|
-
`Skill "${skillId}" is already installed. Use --overwrite to replace it.`,
|
|
286
|
-
);
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
mkdirSync(skillDir, { recursive: true });
|
|
290
|
-
|
|
291
|
-
// In dev mode, install from the local repo skills directory if available
|
|
292
|
-
const repoSkillsDir = getRepoSkillsDir();
|
|
293
|
-
const repoSkillSource = repoSkillsDir
|
|
294
|
-
? join(repoSkillsDir, skillId)
|
|
295
|
-
: undefined;
|
|
296
|
-
|
|
297
|
-
if (repoSkillSource && existsSync(join(repoSkillSource, "SKILL.md"))) {
|
|
298
|
-
cpSync(repoSkillSource, skillDir, { recursive: true });
|
|
299
|
-
} else {
|
|
300
|
-
await fetchAndExtractSkill(skillId, skillDir);
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
// Write version metadata
|
|
304
|
-
if (catalogEntry.version) {
|
|
305
|
-
const meta = {
|
|
306
|
-
version: catalogEntry.version,
|
|
307
|
-
installedAt: new Date().toISOString(),
|
|
308
|
-
};
|
|
309
|
-
atomicWriteFile(
|
|
310
|
-
join(skillDir, "version.json"),
|
|
311
|
-
JSON.stringify(meta, null, 2) + "\n",
|
|
312
|
-
);
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
// Install npm dependencies if the skill has a package.json
|
|
316
|
-
if (existsSync(join(skillDir, "package.json"))) {
|
|
317
|
-
const bunPath = `${homedir()}/.bun/bin`;
|
|
318
|
-
execSync("bun install", {
|
|
319
|
-
cwd: skillDir,
|
|
320
|
-
stdio: "inherit",
|
|
321
|
-
env: { ...process.env, PATH: `${bunPath}:${process.env.PATH}` },
|
|
322
|
-
});
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
// Register in SKILLS.md only after all steps succeed
|
|
326
|
-
upsertSkillsIndex(skillId);
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
// ---------------------------------------------------------------------------
|
|
330
|
-
// Exported types and functions for testing
|
|
331
|
-
// ---------------------------------------------------------------------------
|
|
332
|
-
|
|
333
|
-
export type { CatalogManifest, CatalogSkill };
|
|
334
|
-
|
|
335
|
-
export {
|
|
336
|
-
extractTarToDir,
|
|
337
|
-
fetchAndExtractSkill,
|
|
338
5
|
fetchCatalog,
|
|
339
|
-
|
|
6
|
+
getRepoSkillsDir,
|
|
340
7
|
installSkillLocally,
|
|
341
8
|
readLocalCatalog,
|
|
342
|
-
removeSkillsIndexEntry,
|
|
343
9
|
uninstallSkillLocally,
|
|
344
|
-
|
|
345
|
-
};
|
|
10
|
+
} from "../../skills/catalog-install.js";
|
|
11
|
+
import { log } from "../logger.js";
|
|
346
12
|
|
|
347
13
|
// ---------------------------------------------------------------------------
|
|
348
14
|
// Command registration
|
package/src/cli/program.ts
CHANGED
|
@@ -12,15 +12,13 @@ import { registerConfigCommand } from "./commands/config.js";
|
|
|
12
12
|
import { registerContactsCommand } from "./commands/contacts.js";
|
|
13
13
|
import { registerCredentialsCommand } from "./commands/credentials.js";
|
|
14
14
|
import { registerDefaultAction } from "./commands/default-action.js";
|
|
15
|
-
import { registerDevCommand } from "./commands/dev.js";
|
|
16
15
|
import { registerDoctorCommand } from "./commands/doctor.js";
|
|
17
16
|
import { registerEmailCommand } from "./commands/email.js";
|
|
18
17
|
import { registerKeysCommand } from "./commands/keys.js";
|
|
19
|
-
import { registerMapCommand } from "./commands/map.js";
|
|
20
18
|
import { registerMcpCommand } from "./commands/mcp.js";
|
|
21
19
|
import { registerMemoryCommand } from "./commands/memory.js";
|
|
22
20
|
import { registerNotificationsCommand } from "./commands/notifications.js";
|
|
23
|
-
import { registerOAuthCommand } from "./commands/oauth.js";
|
|
21
|
+
import { registerOAuthCommand } from "./commands/oauth/index.js";
|
|
24
22
|
import { registerPlatformCommand } from "./commands/platform.js";
|
|
25
23
|
import { registerSequenceCommand } from "./commands/sequence.js";
|
|
26
24
|
import { registerSessionsCommand } from "./commands/sessions.js";
|
|
@@ -36,7 +34,6 @@ export function buildCliProgram(): Command {
|
|
|
36
34
|
program.name("assistant").description("Local AI assistant").version(version);
|
|
37
35
|
|
|
38
36
|
registerDefaultAction(program);
|
|
39
|
-
registerDevCommand(program);
|
|
40
37
|
registerSessionsCommand(program);
|
|
41
38
|
registerConfigCommand(program);
|
|
42
39
|
registerKeysCommand(program);
|
|
@@ -58,7 +55,6 @@ export function buildCliProgram(): Command {
|
|
|
58
55
|
registerSkillsCommand(program);
|
|
59
56
|
registerBrowserRelayCommand(program);
|
|
60
57
|
|
|
61
|
-
registerMapCommand(program);
|
|
62
58
|
registerSequenceCommand(program);
|
|
63
59
|
|
|
64
60
|
return program;
|
package/src/cli/reference.ts
CHANGED
|
@@ -10,7 +10,6 @@ Options:
|
|
|
10
10
|
-h, --help display help for command
|
|
11
11
|
|
|
12
12
|
Commands:
|
|
13
|
-
dev [options] Run the assistant in dev mode
|
|
14
13
|
sessions Manage sessions
|
|
15
14
|
config Manage configuration
|
|
16
15
|
keys Manage API keys in secure storage
|
|
@@ -28,9 +27,8 @@ Commands:
|
|
|
28
27
|
completions <shell> Generate shell completion script (e.g. assistant completions bash >> ~/.bashrc)
|
|
29
28
|
notifications [options] Send and inspect notifications through the unified notification router
|
|
30
29
|
platform [options] Manage platform integration for containerized deployments
|
|
31
|
-
oauth [options] Manage OAuth
|
|
30
|
+
oauth [options] Manage OAuth providers, apps, connections, and tokens
|
|
32
31
|
skills Browse and install skills from the Vellum catalog
|
|
33
32
|
browser Browser automation, extension relay, and Chrome CDP management
|
|
34
|
-
map [options] <domain> Auto-navigate a domain and produce a deduplicated API map. Launches Chrome with CDP, starts a Ride Shotgun learn session, then analyzes captured network traffic.
|
|
35
33
|
sequence [options] Manage email sequences
|
|
36
34
|
`;
|
package/src/cli.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
1
2
|
import { appendFileSync, mkdirSync, readFileSync } from "node:fs";
|
|
2
3
|
import { dirname } from "node:path";
|
|
3
4
|
import * as readline from "node:readline";
|
|
@@ -503,7 +504,7 @@ export async function startCli(): Promise<void> {
|
|
|
503
504
|
const trimmed = answer.trim().toLowerCase();
|
|
504
505
|
if (trimmed === "n") {
|
|
505
506
|
// Create a new conversation by using a unique key
|
|
506
|
-
conversationKey = `builtin-cli:${
|
|
507
|
+
conversationKey = `builtin-cli:${randomUUID()}`;
|
|
507
508
|
sessionId = "";
|
|
508
509
|
pendingSessionPick = false;
|
|
509
510
|
// Reconnect SSE with new conversation key
|
|
@@ -1147,7 +1148,7 @@ export async function startCli(): Promise<void> {
|
|
|
1147
1148
|
|
|
1148
1149
|
if (content === "/new") {
|
|
1149
1150
|
// Create a new conversation by using a unique key
|
|
1150
|
-
conversationKey = `builtin-cli:${
|
|
1151
|
+
conversationKey = `builtin-cli:${randomUUID()}`;
|
|
1151
1152
|
sessionId = "";
|
|
1152
1153
|
reconnectSse().then(() => {
|
|
1153
1154
|
process.stdout.write(
|
|
@@ -42,10 +42,7 @@ function loadDefaultsRegistry(): FeatureFlagDefaultsRegistry {
|
|
|
42
42
|
if (cachedDefaults) return cachedDefaults;
|
|
43
43
|
|
|
44
44
|
const thisDir = import.meta.dirname ?? __dirname;
|
|
45
|
-
const envPath = process.env.FEATURE_FLAG_DEFAULTS_PATH?.trim();
|
|
46
45
|
const candidates = [
|
|
47
|
-
// Explicit override (primarily for tests / controlled environments)
|
|
48
|
-
...(envPath ? [envPath] : []),
|
|
49
46
|
// Bundled: co-located copy in the same directory as this source file.
|
|
50
47
|
// Works in Docker / packaged builds where the repo-root `meta/` dir
|
|
51
48
|
// is not available.
|
|
@@ -6,7 +6,7 @@ For account and auth workflows, prefer documented `assistant` CLI commands over
|
|
|
6
6
|
any generic account registry:
|
|
7
7
|
|
|
8
8
|
- `assistant credentials ...` for stored secrets and credential metadata
|
|
9
|
-
- `assistant oauth token <
|
|
9
|
+
- `assistant oauth connections token <provider-key>` for OAuth-backed integrations
|
|
10
10
|
- `assistant mcp auth <name>` when an MCP server needs browser login
|
|
11
11
|
- `assistant platform status` for platform-linked deployment/auth context
|
|
12
12
|
|