@vellumai/assistant 0.3.5 → 0.3.6
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/README.md +51 -0
- package/eslint.config.mjs +31 -0
- package/package.json +1 -1
- package/scripts/ipc/check-swift-decoder-drift.ts +4 -1
- package/scripts/ipc/generate-swift.ts +18 -2
- package/src/__tests__/__snapshots__/ipc-snapshot.test.ts.snap +338 -1
- package/src/__tests__/approval-conversation-turn.test.ts +214 -0
- package/src/__tests__/browser-manager.test.ts +1 -0
- package/src/__tests__/call-conversation-messages.test.ts +130 -0
- package/src/__tests__/call-orchestrator.test.ts +752 -271
- package/src/__tests__/call-pointer-messages.test.ts +148 -0
- package/src/__tests__/call-recovery.test.ts +3 -0
- package/src/__tests__/call-routes-http.test.ts +5 -0
- package/src/__tests__/call-store.test.ts +3 -0
- package/src/__tests__/channel-approval-routes.test.ts +1260 -85
- package/src/__tests__/channel-approval.test.ts +37 -0
- package/src/__tests__/channel-approvals.test.ts +4 -65
- package/src/__tests__/channel-guardian.test.ts +556 -0
- package/src/__tests__/channel-readiness-service.test.ts +74 -7
- package/src/__tests__/checker.test.ts +14 -7
- package/src/__tests__/clarification-resolver.test.ts +44 -24
- package/src/__tests__/commit-message-enrichment-service.test.ts +9 -4
- package/src/__tests__/computer-use-session-working-dir.test.ts +8 -0
- package/src/__tests__/config-schema.test.ts +12 -7
- package/src/__tests__/context-window-manager.test.ts +30 -2
- package/src/__tests__/contradiction-checker.test.ts +20 -5
- package/src/__tests__/credential-security-invariants.test.ts +6 -2
- package/src/__tests__/db-migration-rollback.test.ts +752 -0
- package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +2 -0
- package/src/__tests__/fuzzy-match-property.test.ts +5 -5
- package/src/__tests__/guardian-action-store.test.ts +123 -0
- package/src/__tests__/guardian-action-sweep.test.ts +277 -0
- package/src/__tests__/guardian-dispatch.test.ts +389 -0
- package/src/__tests__/guardian-question-copy.test.ts +47 -0
- package/src/__tests__/handlers-telegram-config.test.ts +4 -2
- package/src/__tests__/handlers-twilio-config.test.ts +126 -0
- package/src/__tests__/intent-routing.test.ts +2 -0
- package/src/__tests__/ipc-snapshot.test.ts +228 -1
- package/src/__tests__/memory-upsert-concurrency.test.ts +828 -0
- package/src/__tests__/model-intents.test.ts +96 -0
- package/src/__tests__/no-direct-anthropic-sdk-imports.test.ts +42 -0
- package/src/__tests__/oauth2-gateway-transport.test.ts +130 -0
- package/src/__tests__/onboarding-starter-tasks.test.ts +2 -0
- package/src/__tests__/provider-commit-message-generator.test.ts +89 -13
- package/src/__tests__/provider-error-scenarios.test.ts +621 -0
- package/src/__tests__/provider-fail-open-selection.test.ts +119 -0
- package/src/__tests__/qdrant-manager.test.ts +27 -20
- package/src/__tests__/relay-server.test.ts +779 -40
- package/src/__tests__/run-orchestrator-assistant-events.test.ts +2 -0
- package/src/__tests__/run-orchestrator.test.ts +20 -4
- package/src/__tests__/runtime-runs-http.test.ts +17 -1
- package/src/__tests__/runtime-runs.test.ts +16 -0
- package/src/__tests__/schedule-store.test.ts +18 -4
- package/src/__tests__/scheduler-recurrence.test.ts +13 -4
- package/src/__tests__/session-abort-tool-results.test.ts +6 -0
- package/src/__tests__/session-agent-loop.test.ts +857 -0
- package/src/__tests__/session-conflict-gate.test.ts +6 -0
- package/src/__tests__/session-pre-run-repair.test.ts +6 -0
- package/src/__tests__/session-profile-injection.test.ts +6 -0
- package/src/__tests__/session-provider-retry-repair.test.ts +6 -0
- package/src/__tests__/session-queue.test.ts +6 -0
- package/src/__tests__/session-runtime-assembly.test.ts +237 -13
- package/src/__tests__/session-slash-known.test.ts +6 -0
- package/src/__tests__/session-slash-queue.test.ts +6 -0
- package/src/__tests__/session-slash-unknown.test.ts +6 -0
- package/src/__tests__/session-surfaces-task-progress.test.ts +2 -0
- package/src/__tests__/session-tool-setup-app-refresh.test.ts +1 -0
- package/src/__tests__/session-tool-setup-memory-scope.test.ts +1 -0
- package/src/__tests__/session-tool-setup-side-effect-flag.test.ts +1 -0
- package/src/__tests__/session-workspace-injection.test.ts +6 -0
- package/src/__tests__/session-workspace-tool-tracking.test.ts +6 -0
- package/src/__tests__/skills.test.ts +2 -0
- package/src/__tests__/sms-messaging-provider.test.ts +2 -1
- package/src/__tests__/starter-task-flow.test.ts +2 -0
- package/src/__tests__/swarm-dag-pathological.test.ts +535 -0
- package/src/__tests__/system-prompt.test.ts +2 -0
- package/src/__tests__/task-management-tools.test.ts +2 -2
- package/src/__tests__/task-runner.test.ts +14 -4
- package/src/__tests__/terminal-tools.test.ts +25 -19
- package/src/__tests__/tool-execution-abort-cleanup.test.ts +545 -0
- package/src/__tests__/tool-executor-shell-integration.test.ts +11 -11
- package/src/__tests__/tool-executor.test.ts +23 -24
- package/src/__tests__/trust-store.test.ts +3 -3
- package/src/__tests__/twilio-rest.test.ts +29 -0
- package/src/__tests__/twilio-routes-elevenlabs.test.ts +3 -0
- package/src/__tests__/twilio-routes-twiml.test.ts +11 -0
- package/src/__tests__/twilio-routes.test.ts +141 -21
- package/src/__tests__/user-reference.test.ts +2 -0
- package/src/__tests__/voice-quality.test.ts +222 -0
- package/src/__tests__/web-search.test.ts +45 -29
- package/src/agent/loop.ts +1 -1
- package/src/agent-heartbeat/agent-heartbeat-service.ts +2 -10
- package/src/amazon/client.ts +1418 -0
- package/src/amazon/request-extractor.ts +135 -0
- package/src/amazon/session.ts +109 -0
- package/src/autonomy/autonomy-store.ts +5 -5
- package/src/browser-extension-relay/client.ts +124 -0
- package/src/browser-extension-relay/protocol.ts +63 -0
- package/src/browser-extension-relay/server.ts +177 -0
- package/src/bundler/app-bundler.ts +3 -3
- package/src/bundler/bundle-signer.ts +1 -1
- package/src/bundler/signature-verifier.ts +1 -1
- package/src/calls/call-conversation-messages.ts +33 -0
- package/src/calls/call-domain.ts +106 -5
- package/src/calls/call-orchestrator.ts +252 -54
- package/src/calls/call-pointer-messages.ts +53 -0
- package/src/calls/call-recovery.ts +3 -8
- package/src/calls/call-store.ts +69 -87
- package/src/calls/elevenlabs-config.ts +3 -2
- package/src/calls/guardian-action-sweep.ts +105 -0
- package/src/calls/guardian-dispatch.ts +203 -0
- package/src/calls/guardian-question-copy.ts +133 -0
- package/src/calls/relay-server.ts +466 -8
- package/src/calls/speaker-identification.ts +1 -1
- package/src/calls/twilio-config.ts +7 -5
- package/src/calls/twilio-provider.ts +6 -4
- package/src/calls/twilio-rest.ts +40 -15
- package/src/calls/twilio-routes.ts +60 -45
- package/src/calls/types.ts +3 -1
- package/src/channels/types.ts +25 -0
- package/src/cli/amazon.ts +815 -0
- package/src/cli/config-commands.ts +2 -2
- package/src/cli/core-commands.ts +4 -3
- package/src/cli/influencer.ts +244 -0
- package/src/cli/map.ts +89 -6
- package/src/cli.ts +1 -1
- package/src/config/agent-schema.ts +171 -0
- package/src/config/bundled-skills/amazon/SKILL.md +127 -0
- package/src/config/bundled-skills/amazon/icon.svg +13 -0
- package/src/config/bundled-skills/api-mapping/SKILL.md +78 -0
- package/src/config/bundled-skills/browser/SKILL.md +1 -0
- package/src/config/bundled-skills/browser/TOOLS.json +17 -0
- package/src/config/bundled-skills/browser/tools/browser-wait-for-download.ts +25 -0
- package/src/config/bundled-skills/doordash/SKILL.md +51 -51
- package/src/config/bundled-skills/email-setup/SKILL.md +14 -5
- package/src/config/bundled-skills/google-oauth-setup/SKILL.md +183 -0
- package/src/config/bundled-skills/influencer/SKILL.md +144 -0
- package/src/config/bundled-skills/macos-automation/icon.svg +12 -0
- package/src/config/bundled-skills/media-processing/SKILL.md +72 -95
- package/src/config/bundled-skills/media-processing/TOOLS.json +57 -147
- package/src/config/bundled-skills/media-processing/__tests__/concurrency-pool.test.ts +77 -0
- package/src/config/bundled-skills/media-processing/__tests__/cost-tracker.test.ts +69 -0
- package/src/config/bundled-skills/media-processing/__tests__/preprocess.test.ts +303 -0
- package/src/config/bundled-skills/media-processing/services/concurrency-pool.ts +55 -0
- package/src/config/bundled-skills/media-processing/services/cost-tracker.ts +86 -0
- package/src/config/bundled-skills/media-processing/services/gemini-map.ts +339 -0
- package/src/config/bundled-skills/media-processing/services/preprocess.ts +551 -0
- package/src/config/bundled-skills/media-processing/services/processing-pipeline.ts +7 -9
- package/src/config/bundled-skills/media-processing/services/reduce.ts +197 -0
- package/src/config/bundled-skills/media-processing/tools/analyze-keyframes.ts +88 -253
- package/src/config/bundled-skills/media-processing/tools/extract-keyframes.ts +22 -153
- package/src/config/bundled-skills/media-processing/tools/generate-clip.ts +2 -2
- package/src/config/bundled-skills/media-processing/tools/media-diagnostics.ts +28 -51
- package/src/config/bundled-skills/media-processing/tools/query-media-events.ts +35 -270
- package/src/config/bundled-skills/messaging/SKILL.md +12 -2
- package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +4 -7
- package/src/config/bundled-skills/messaging/tools/messaging-reply.ts +2 -1
- package/src/config/bundled-skills/phone-calls/SKILL.md +86 -21
- package/src/config/bundled-skills/twitter/icon.svg +14 -0
- package/src/config/bundled-tool-registry.ts +310 -0
- package/src/config/calls-schema.ts +181 -0
- package/src/config/core-schema.ts +309 -0
- package/src/config/defaults.ts +26 -2
- package/src/config/env-registry.ts +162 -0
- package/src/config/env.ts +175 -0
- package/src/config/loader.ts +6 -6
- package/src/config/memory-schema.ts +528 -0
- package/src/config/sandbox-schema.ts +55 -0
- package/src/config/schema.ts +156 -1137
- package/src/config/skill-state.ts +1 -1
- package/src/config/skills-schema.ts +32 -0
- package/src/config/skills.ts +35 -24
- package/src/config/system-prompt.ts +107 -56
- package/src/config/templates/SOUL.md +1 -1
- package/src/config/types.ts +1 -0
- package/src/config/user-reference.ts +4 -9
- package/src/config/vellum-skills/catalog.json +0 -7
- package/src/config/vellum-skills/chatgpt-import/tools/chatgpt-import.ts +5 -1
- package/src/config/vellum-skills/slack-oauth-setup/SKILL.md +1 -0
- package/src/config/vellum-skills/sms-setup/SKILL.md +112 -14
- package/src/context/window-manager.ts +27 -7
- package/src/daemon/approval-generators.ts +186 -0
- package/src/daemon/approved-devices-store.ts +140 -0
- package/src/daemon/assistant-attachments.ts +1 -1
- package/src/daemon/classifier.ts +35 -32
- package/src/daemon/config-watcher.ts +1 -1
- package/src/daemon/daemon-control.ts +217 -0
- package/src/daemon/handlers/apps.ts +2 -3
- package/src/daemon/handlers/config-channels.ts +158 -0
- package/src/daemon/handlers/config-inbox.ts +540 -0
- package/src/daemon/handlers/config-ingress.ts +231 -0
- package/src/daemon/handlers/config-integrations.ts +258 -0
- package/src/daemon/handlers/config-model.ts +143 -0
- package/src/daemon/handlers/config-parental.ts +163 -0
- package/src/daemon/handlers/config-scheduling.ts +172 -0
- package/src/daemon/handlers/config-slack.ts +92 -0
- package/src/daemon/handlers/config-telegram.ts +301 -0
- package/src/daemon/handlers/config-tools.ts +177 -0
- package/src/daemon/handlers/config-trust.ts +104 -0
- package/src/daemon/handlers/config-twilio.ts +1080 -0
- package/src/daemon/handlers/config.ts +53 -2463
- package/src/daemon/handlers/diagnostics.ts +1 -1
- package/src/daemon/handlers/dictation.ts +4 -6
- package/src/daemon/handlers/documents.ts +18 -32
- package/src/daemon/handlers/index.ts +9 -0
- package/src/daemon/handlers/misc.ts +3 -5
- package/src/daemon/handlers/pairing.ts +98 -0
- package/src/daemon/handlers/sessions.ts +54 -5
- package/src/daemon/handlers/shared.ts +3 -1
- package/src/daemon/handlers/skills.ts +1 -1
- package/src/daemon/handlers/twitter-auth.ts +2 -0
- package/src/daemon/handlers/work-items.ts +2 -2
- package/src/daemon/handlers/workspace-files.ts +4 -3
- package/src/daemon/install-cli-launchers.ts +113 -0
- package/src/daemon/ipc-contract/apps.ts +356 -0
- package/src/daemon/ipc-contract/browser.ts +74 -0
- package/src/daemon/ipc-contract/computer-use.ts +151 -0
- package/src/daemon/ipc-contract/diagnostics.ts +56 -0
- package/src/daemon/ipc-contract/documents.ts +74 -0
- package/src/daemon/ipc-contract/inbox.ts +209 -0
- package/src/daemon/ipc-contract/integrations.ts +284 -0
- package/src/daemon/ipc-contract/memory.ts +48 -0
- package/src/daemon/ipc-contract/messages.ts +211 -0
- package/src/daemon/ipc-contract/pairing.ts +45 -0
- package/src/daemon/ipc-contract/parental-control.ts +95 -0
- package/src/daemon/ipc-contract/schedules.ts +97 -0
- package/src/daemon/ipc-contract/sessions.ts +315 -0
- package/src/daemon/ipc-contract/shared.ts +42 -0
- package/src/daemon/ipc-contract/skills.ts +120 -0
- package/src/daemon/ipc-contract/subagents.ts +58 -0
- package/src/daemon/ipc-contract/surfaces.ts +250 -0
- package/src/daemon/ipc-contract/trust.ts +60 -0
- package/src/daemon/ipc-contract/work-items.ts +225 -0
- package/src/daemon/ipc-contract/workspace.ts +113 -0
- package/src/daemon/ipc-contract-inventory.json +60 -0
- package/src/daemon/ipc-contract-inventory.ts +55 -29
- package/src/daemon/ipc-contract.ts +226 -2527
- package/src/daemon/ipc-protocol.ts +1 -1
- package/src/daemon/ipc-validate.ts +7 -0
- package/src/daemon/lifecycle.ts +97 -379
- package/src/daemon/pairing-store.ts +177 -0
- package/src/daemon/providers-setup.ts +43 -0
- package/src/daemon/ride-shotgun-handler.ts +67 -2
- package/src/daemon/server.ts +60 -44
- package/src/daemon/session-agent-loop-handlers.ts +421 -0
- package/src/daemon/session-agent-loop.ts +113 -275
- package/src/daemon/session-dynamic-profile.ts +1 -1
- package/src/daemon/session-history.ts +1 -1
- package/src/daemon/session-media-retry.ts +1 -1
- package/src/daemon/session-messaging.ts +37 -2
- package/src/daemon/session-notifiers.ts +5 -25
- package/src/daemon/session-process.ts +99 -59
- package/src/daemon/session-queue-manager.ts +96 -4
- package/src/daemon/session-runtime-assembly.ts +149 -15
- package/src/daemon/session-surfaces.ts +19 -4
- package/src/daemon/session-tool-setup.ts +28 -30
- package/src/daemon/session-workspace.ts +1 -1
- package/src/daemon/session.ts +24 -1
- package/src/daemon/shutdown-handlers.ts +122 -0
- package/src/daemon/trace-emitter.ts +1 -1
- package/src/daemon/watch-handler.ts +36 -33
- package/src/doordash/cart-queries.ts +787 -0
- package/src/doordash/client.ts +144 -127
- package/src/doordash/order-queries.ts +85 -0
- package/src/doordash/queries.ts +10 -1308
- package/src/doordash/search-queries.ts +203 -0
- package/src/doordash/session.ts +3 -2
- package/src/doordash/store-queries.ts +246 -0
- package/src/doordash/types.ts +367 -0
- package/src/email/providers/agentmail.ts +2 -1
- package/src/email/providers/index.ts +3 -2
- package/src/email/service.ts +3 -2
- package/src/errors.ts +43 -0
- package/src/home-base/prebuilt/seed.ts +1 -1
- package/src/hooks/cli.ts +6 -5
- package/src/hooks/config.ts +6 -8
- package/src/hooks/discovery.ts +6 -5
- package/src/hooks/manager.ts +4 -3
- package/src/hooks/runner.ts +2 -2
- package/src/hooks/templates.ts +5 -5
- package/src/inbound/public-ingress-urls.ts +3 -1
- package/src/index.ts +4 -2
- package/src/influencer/client.ts +1104 -0
- package/src/instrument.ts +4 -3
- package/src/logfire.ts +4 -3
- package/src/memory/admin.ts +25 -35
- package/src/memory/attachments-store.ts +4 -7
- package/src/memory/channel-delivery-store.ts +30 -1
- package/src/memory/channel-guardian-store.ts +200 -1
- package/src/memory/clarification-resolver.ts +37 -33
- package/src/memory/conflict-store.ts +67 -61
- package/src/memory/contradiction-checker.ts +141 -117
- package/src/memory/conversation-store.ts +335 -51
- package/src/memory/db-connection.ts +27 -4
- package/src/memory/db-init.ts +121 -4
- package/src/memory/db.ts +14 -1
- package/src/memory/embedding-backend.ts +27 -5
- package/src/memory/embedding-ollama.ts +2 -1
- package/src/memory/entity-extractor.ts +38 -35
- package/src/memory/guardian-action-store.ts +430 -0
- package/src/memory/inbox-escalation-projection.ts +59 -0
- package/src/memory/inbox-thread-store.ts +218 -0
- package/src/memory/ingress-invite-store.ts +338 -0
- package/src/memory/ingress-member-store.ts +350 -0
- package/src/memory/items-extractor.ts +91 -97
- package/src/memory/job-handlers/index-maintenance.ts +3 -3
- package/src/memory/job-handlers/media-processing.ts +11 -42
- package/src/memory/job-handlers/summarization.ts +32 -26
- package/src/memory/job-utils.ts +3 -10
- package/src/memory/jobs-store.ts +6 -9
- package/src/memory/jobs-worker.ts +51 -36
- package/src/memory/migrations/001-job-deferrals.ts +45 -0
- package/src/memory/migrations/002-tool-invocations-fk.ts +43 -0
- package/src/memory/migrations/003-memory-fts-backfill.ts +24 -0
- package/src/memory/migrations/004-entity-relation-dedup.ts +87 -0
- package/src/memory/migrations/005-fingerprint-scope-unique.ts +80 -0
- package/src/memory/migrations/006-scope-salted-fingerprints.ts +62 -0
- package/src/memory/migrations/007-assistant-id-to-self.ts +254 -0
- package/src/memory/migrations/008-remove-assistant-id-columns.ts +208 -0
- package/src/memory/migrations/009-llm-usage-events-drop-assistant-id.ts +83 -0
- package/src/memory/migrations/010-ext-conv-bindings-channel-chat-unique.ts +56 -0
- package/src/memory/migrations/011-call-sessions-provider-sid-dedup.ts +63 -0
- package/src/memory/migrations/012-call-sessions-add-initiated-from.ts +19 -0
- package/src/memory/migrations/013-guardian-action-tables.ts +68 -0
- package/src/memory/migrations/014-backfill-inbox-thread-state.ts +76 -0
- package/src/memory/migrations/015-drop-active-search-index.ts +27 -0
- package/src/memory/migrations/016-memory-segments-indexes.ts +11 -0
- package/src/memory/migrations/017-memory-items-indexes.ts +10 -0
- package/src/memory/migrations/018-remaining-table-indexes.ts +13 -0
- package/src/memory/migrations/index.ts +24 -0
- package/src/memory/migrations/registry.ts +79 -0
- package/src/memory/migrations/validate-migration-state.ts +69 -0
- package/src/memory/qdrant-manager.ts +49 -8
- package/src/memory/query-builder.ts +1 -1
- package/src/memory/raw-query.ts +119 -0
- package/src/memory/recall-cache.ts +4 -1
- package/src/memory/retriever.ts +160 -47
- package/src/memory/schema-migration.ts +25 -984
- package/src/memory/schema.ts +130 -7
- package/src/memory/search/entity.ts +10 -19
- package/src/memory/search/lexical.ts +81 -52
- package/src/memory/search/ranking.ts +21 -22
- package/src/memory/search/semantic.ts +157 -19
- package/src/memory/shared-app-links-store.ts +4 -5
- package/src/memory/validation.ts +19 -0
- package/src/messaging/draft-store.ts +5 -6
- package/src/messaging/providers/sms/adapter.ts +3 -6
- package/src/messaging/providers/telegram-bot/adapter.ts +2 -5
- package/src/messaging/providers/whatsapp/adapter.ts +136 -0
- package/src/messaging/providers/whatsapp/client.ts +67 -0
- package/src/messaging/style-analyzer.ts +5 -4
- package/src/messaging/thread-summarizer.ts +61 -69
- package/src/messaging/triage-engine.ts +62 -71
- package/src/migrations/config-merge.ts +53 -0
- package/src/migrations/data-layout.ts +68 -0
- package/src/migrations/data-merge.ts +33 -0
- package/src/migrations/hooks-merge.ts +90 -0
- package/src/migrations/index.ts +6 -0
- package/src/migrations/log.ts +23 -0
- package/src/migrations/skills-merge.ts +33 -0
- package/src/migrations/workspace-layout.ts +79 -0
- package/src/permissions/checker.ts +119 -11
- package/src/permissions/prompter.ts +14 -0
- package/src/permissions/shell-identity.ts +31 -1
- package/src/permissions/trust-store.ts +21 -1
- package/src/providers/anthropic/client.ts +4 -4
- package/src/providers/failover.ts +2 -2
- package/src/providers/model-intents.ts +70 -0
- package/src/providers/ollama/client.ts +2 -1
- package/src/providers/provider-send-message.ts +176 -0
- package/src/providers/registry.ts +71 -30
- package/src/providers/retry.ts +35 -1
- package/src/providers/types.ts +12 -1
- package/src/runtime/approval-conversation-turn.ts +97 -0
- package/src/runtime/approval-message-composer.ts +115 -5
- package/src/runtime/channel-approval-parser.ts +36 -2
- package/src/runtime/channel-approvals.ts +0 -21
- package/src/runtime/channel-guardian-service.ts +48 -7
- package/src/runtime/channel-readiness-service.ts +160 -34
- package/src/runtime/channel-readiness-types.ts +10 -4
- package/src/runtime/channel-retry-sweep.ts +184 -0
- package/src/runtime/guardian-context-resolver.ts +108 -0
- package/src/runtime/http-server.ts +275 -743
- package/src/runtime/http-types.ts +56 -3
- package/src/runtime/middleware/auth.ts +116 -0
- package/src/runtime/middleware/error-handler.ts +33 -0
- package/src/runtime/middleware/twilio-validation.ts +127 -0
- package/src/runtime/routes/app-routes.ts +1 -1
- package/src/runtime/routes/call-routes.ts +49 -6
- package/src/runtime/routes/channel-delivery-routes.ts +170 -0
- package/src/runtime/routes/channel-guardian-routes.ts +1191 -0
- package/src/runtime/routes/channel-inbound-routes.ts +1152 -0
- package/src/runtime/routes/channel-route-shared.ts +144 -0
- package/src/runtime/routes/channel-routes.ts +32 -1634
- package/src/runtime/routes/conversation-routes.ts +50 -7
- package/src/runtime/routes/events-routes.ts +2 -2
- package/src/runtime/routes/identity-routes.ts +126 -0
- package/src/runtime/routes/pairing-routes.ts +143 -0
- package/src/runtime/routes/run-routes.ts +15 -1
- package/src/runtime/run-orchestrator.ts +52 -34
- package/src/schedule/schedule-store.ts +36 -32
- package/src/schedule/scheduler.ts +3 -3
- package/src/security/encrypted-store.ts +5 -7
- package/src/security/oauth2.ts +45 -15
- package/src/security/parental-control-store.ts +183 -0
- package/src/security/secret-allowlist.ts +4 -3
- package/src/security/secret-scanner.ts +5 -5
- package/src/security/secure-keys.ts +1 -1
- package/src/security/token-manager.ts +3 -2
- package/src/services/vercel-deploy.ts +6 -2
- package/src/skills/tool-manifest.ts +3 -3
- package/src/skills/vellum-catalog-remote.ts +75 -16
- package/src/slack/slack-webhook.ts +2 -1
- package/src/swarm/orchestrator.ts +92 -1
- package/src/swarm/router-planner.ts +6 -9
- package/src/swarm/worker-prompts.ts +9 -12
- package/src/tasks/task-compiler.ts +19 -28
- package/src/tasks/task-runner.ts +1 -1
- package/src/tools/assets/search.ts +15 -14
- package/src/tools/browser/__tests__/auth-detector.test.ts +1 -0
- package/src/tools/browser/auto-navigate.ts +1 -0
- package/src/tools/browser/browser-execution.ts +10 -1
- package/src/tools/browser/browser-manager.ts +119 -4
- package/src/tools/browser/network-recorder.ts +5 -0
- package/src/tools/credentials/broker.ts +11 -2
- package/src/tools/credentials/metadata-store.ts +18 -14
- package/src/tools/credentials/post-connect-hooks.ts +61 -0
- package/src/tools/credentials/vault.ts +49 -23
- package/src/tools/executor.ts +68 -9
- package/src/tools/host-terminal/cli-discover.ts +1 -1
- package/src/tools/network/script-proxy/http-forwarder.ts +1 -1
- package/src/tools/network/script-proxy/mitm-handler.ts +1 -1
- package/src/tools/network/script-proxy/server.ts +1 -1
- package/src/tools/network/script-proxy/session-manager.ts +6 -5
- package/src/tools/network/web-fetch.ts +18 -2
- package/src/tools/network/web-search.ts +7 -3
- package/src/tools/reminder/reminder-store.ts +14 -15
- package/src/tools/schedule/create.ts +1 -0
- package/src/tools/schedule/list.ts +2 -1
- package/src/tools/shared/filesystem/file-ops-service.ts +5 -7
- package/src/tools/skills/skill-script-runner.ts +24 -9
- package/src/tools/skills/skill-tool-factory.ts +1 -0
- package/src/tools/tasks/work-item-enqueue.ts +2 -2
- package/src/tools/terminal/evaluate-typescript.ts +21 -12
- package/src/tools/terminal/parser.ts +50 -0
- package/src/tools/watcher/delete.ts +6 -0
- package/src/tools/weather/service.ts +1 -1
- package/src/twitter/client.ts +190 -24
- package/src/twitter/session.ts +4 -3
- package/src/util/clipboard.ts +1 -1
- package/src/util/errors.ts +65 -8
- package/src/util/fs.ts +40 -0
- package/src/util/json.ts +10 -0
- package/src/util/log-redact.ts +189 -0
- package/src/util/logger.ts +19 -17
- package/src/util/object.ts +3 -0
- package/src/util/platform.ts +72 -365
- package/src/util/pricing.ts +1 -1
- package/src/util/promise-guard.ts +1 -1
- package/src/util/retry.ts +19 -0
- package/src/util/row-mapper.ts +79 -0
- package/src/util/silently.ts +21 -0
- package/src/watcher/engine.ts +5 -1
- package/src/watcher/provider-types.ts +20 -0
- package/src/watcher/providers/github.ts +156 -0
- package/src/watcher/providers/gmail.ts +1 -0
- package/src/watcher/providers/google-calendar.ts +1 -0
- package/src/watcher/providers/linear.ts +460 -0
- package/src/watcher/providers/slack.ts +1 -0
- package/src/work-items/work-item-runner.ts +1 -1
- package/src/workspace/git-service.ts +1 -1
- package/src/workspace/provider-commit-message-generator.ts +51 -22
- package/src/__tests__/call-bridge.test.ts +0 -517
- package/src/__tests__/session-process-bridge.test.ts +0 -244
- package/src/calls/call-bridge.ts +0 -168
- package/src/config/bundled-skills/media-processing/services/capability-registry.ts +0 -137
- package/src/config/bundled-skills/media-processing/services/event-detection-service.ts +0 -280
- package/src/config/bundled-skills/media-processing/services/feedback-aggregation.ts +0 -144
- package/src/config/bundled-skills/media-processing/services/feedback-store.ts +0 -136
- package/src/config/bundled-skills/media-processing/services/retrieval-service.ts +0 -95
- package/src/config/bundled-skills/media-processing/services/timeline-service.ts +0 -267
- package/src/config/bundled-skills/media-processing/tools/detect-events.ts +0 -110
- package/src/config/bundled-skills/media-processing/tools/recalibrate.ts +0 -235
- package/src/config/bundled-skills/media-processing/tools/select-tracking-profile.ts +0 -142
- package/src/config/bundled-skills/media-processing/tools/submit-feedback.ts +0 -150
- package/src/config/vellum-skills/google-oauth-setup/SKILL.md +0 -199
|
@@ -36,6 +36,28 @@ export interface ParsedCommand {
|
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
const SHELL_PROGRAMS = new Set(['sh', 'bash', 'zsh', 'dash', 'ksh', 'fish']);
|
|
39
|
+
// Script interpreters that can execute arbitrary code from stdin — piping
|
|
40
|
+
// untrusted data into these is as dangerous as piping into a shell.
|
|
41
|
+
const SCRIPT_INTERPRETERS = new Set([
|
|
42
|
+
'python', 'python3', 'ruby', 'perl', 'node', 'deno', 'bun',
|
|
43
|
+
]);
|
|
44
|
+
// Flags that make an interpreter execute code from an inline argument or stdin
|
|
45
|
+
// rather than from a file (e.g. `python -c 'code'`, `node -e 'code'`).
|
|
46
|
+
const STDIN_EXEC_FLAGS = new Set(['-c', '-e', '-']);
|
|
47
|
+
// Per-interpreter flags that consume the next argument as a value (not a filename).
|
|
48
|
+
// Mapped by interpreter name since flags differ across interpreters
|
|
49
|
+
// (e.g. -I is standalone in Python but takes a value in Ruby).
|
|
50
|
+
// Note: `-m` is intentionally excluded — it means "run module", so the next arg
|
|
51
|
+
// is a module name and the interpreter is NOT in stdin-exec mode.
|
|
52
|
+
const INTERPRETER_VALUE_FLAGS: ReadonlyMap<string, ReadonlySet<string>> = new Map([
|
|
53
|
+
['python', new Set(['-W', '-X', '-Q'])],
|
|
54
|
+
['python3', new Set(['-W', '-X', '-Q'])],
|
|
55
|
+
['ruby', new Set(['-r', '--require', '-I'])],
|
|
56
|
+
['node', new Set(['-r', '--require', '--import', '--conditions'])],
|
|
57
|
+
['deno', new Set()],
|
|
58
|
+
['bun', new Set()],
|
|
59
|
+
['perl', new Set(['-I'])],
|
|
60
|
+
]);
|
|
39
61
|
const OPAQUE_PROGRAMS = new Set(['eval', 'source', 'alias']);
|
|
40
62
|
const DANGEROUS_ENV_VARS = new Set([
|
|
41
63
|
'LD_PRELOAD', 'LD_LIBRARY_PATH',
|
|
@@ -239,6 +261,28 @@ function extractSegments(node: TSNode): CommandSegment[] {
|
|
|
239
261
|
return segments;
|
|
240
262
|
}
|
|
241
263
|
|
|
264
|
+
/**
|
|
265
|
+
* Returns true when the interpreter args indicate stdin-exec mode — i.e. the
|
|
266
|
+
* interpreter will read code from stdin (or from an inline -c/-e argument)
|
|
267
|
+
* rather than from a file. Concretely:
|
|
268
|
+
* - Any STDIN_EXEC_FLAGS present → stdin-exec
|
|
269
|
+
* - No positional (non-flag) arguments at all → stdin-exec (bare `python`)
|
|
270
|
+
* - Otherwise the first positional arg is a filename → NOT stdin-exec
|
|
271
|
+
*/
|
|
272
|
+
function isStdinExecMode(interpreter: string, args: string[]): boolean {
|
|
273
|
+
const valueFlags = INTERPRETER_VALUE_FLAGS.get(interpreter) ?? new Set<string>();
|
|
274
|
+
for (let i = 0; i < args.length; i++) {
|
|
275
|
+
const arg = args[i];
|
|
276
|
+
if (STDIN_EXEC_FLAGS.has(arg)) return true;
|
|
277
|
+
// First non-flag argument is a filename/module → file mode
|
|
278
|
+
if (!arg.startsWith('-')) return false;
|
|
279
|
+
// Flags like -W, -X consume the next token as their value — skip it
|
|
280
|
+
if (valueFlags.has(arg)) i++;
|
|
281
|
+
}
|
|
282
|
+
// No positional arguments at all → interpreter reads from stdin
|
|
283
|
+
return true;
|
|
284
|
+
}
|
|
285
|
+
|
|
242
286
|
function detectDangerousPatterns(node: TSNode, segments: CommandSegment[]): DangerousPattern[] {
|
|
243
287
|
const patterns: DangerousPattern[] = [];
|
|
244
288
|
|
|
@@ -251,6 +295,12 @@ function detectDangerousPatterns(node: TSNode, segments: CommandSegment[]): Dang
|
|
|
251
295
|
description: `Pipeline into ${prog}`,
|
|
252
296
|
text: segments[i].command,
|
|
253
297
|
});
|
|
298
|
+
} else if (SCRIPT_INTERPRETERS.has(prog) && isStdinExecMode(prog, segments[i].args)) {
|
|
299
|
+
patterns.push({
|
|
300
|
+
type: 'pipe_to_shell',
|
|
301
|
+
description: `Pipeline into ${prog}`,
|
|
302
|
+
text: segments[i].command,
|
|
303
|
+
});
|
|
254
304
|
}
|
|
255
305
|
}
|
|
256
306
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { ToolContext, ToolExecutionResult } from '../types.js';
|
|
2
2
|
import { getWatcher, deleteWatcher } from '../../watcher/watcher-store.js';
|
|
3
|
+
import { getWatcherProvider } from '../../watcher/provider-registry.js';
|
|
3
4
|
|
|
4
5
|
export async function executeWatcherDelete(
|
|
5
6
|
input: Record<string, unknown>,
|
|
@@ -20,6 +21,11 @@ export async function executeWatcherDelete(
|
|
|
20
21
|
return { content: `Error: Failed to delete watcher: ${watcherId}`, isError: true };
|
|
21
22
|
}
|
|
22
23
|
|
|
24
|
+
// Evict any in-process provider state (e.g. Linear issue-state cache) now
|
|
25
|
+
// that the watcher's DB row is gone, so its UUID doesn't leak memory.
|
|
26
|
+
const provider = getWatcherProvider(watcher.providerId);
|
|
27
|
+
provider?.cleanup?.(watcherId);
|
|
28
|
+
|
|
23
29
|
return {
|
|
24
30
|
content: `Watcher deleted: "${watcher.name}"`,
|
|
25
31
|
isError: false,
|
|
@@ -219,7 +219,7 @@ function buildWeatherPageHtml(d: WeatherPageInput): string {
|
|
|
219
219
|
const widthPctC = Math.max(((hc - lc) / cRange) * 100, 3);
|
|
220
220
|
const leftPct = isF ? leftPctF : leftPctC;
|
|
221
221
|
const widthPct = isF ? widthPctF : widthPctC;
|
|
222
|
-
const precipCell = f.precip
|
|
222
|
+
const precipCell = f.precip != null && f.precip > 0
|
|
223
223
|
? `<span style="font-size:12px;color:var(--v-accent);width:36px;text-align:right">${f.precip}%</span>`
|
|
224
224
|
: `<span style="width:36px"></span>`;
|
|
225
225
|
return `<div style="display:flex;align-items:center;gap:8px;padding:8px 0;border-bottom:1px solid var(--v-surface-border)">` +
|
package/src/twitter/client.ts
CHANGED
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
loadSession,
|
|
9
9
|
type TwitterSession,
|
|
10
10
|
} from './session.js';
|
|
11
|
+
import { ProviderError } from '../util/errors.js';
|
|
11
12
|
|
|
12
13
|
const CDP_BASE = 'http://localhost:9222';
|
|
13
14
|
|
|
@@ -325,17 +326,182 @@ async function graphqlGet(queryId: string, queryName: string, variables: Record<
|
|
|
325
326
|
const url = graphqlUrl(queryId, queryName, variables);
|
|
326
327
|
const json = await cdpGet(wsUrl, url) as { errors?: Array<{ message: string }> };
|
|
327
328
|
if (json.errors?.length) {
|
|
328
|
-
throw new
|
|
329
|
+
throw new ProviderError(`X API errors: ${json.errors.map(e => e.message).join('; ')}`, 'x');
|
|
329
330
|
}
|
|
330
331
|
return json;
|
|
331
332
|
}
|
|
332
333
|
|
|
333
|
-
// ───
|
|
334
|
+
// ─── Twitter API response types ──────────────────────────────────────────────
|
|
335
|
+
|
|
336
|
+
interface TwitterUserLegacy {
|
|
337
|
+
screen_name?: string;
|
|
338
|
+
name?: string;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
interface TwitterUserCore {
|
|
342
|
+
screen_name?: string;
|
|
343
|
+
name?: string;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
interface TwitterUserResult {
|
|
347
|
+
rest_id?: string;
|
|
348
|
+
legacy?: TwitterUserLegacy;
|
|
349
|
+
core?: TwitterUserCore;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
interface TwitterUserResults {
|
|
353
|
+
result?: TwitterUserResult;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
interface TweetLegacy {
|
|
357
|
+
full_text?: string;
|
|
358
|
+
created_at?: string;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
interface TweetResult {
|
|
362
|
+
__typename?: string;
|
|
363
|
+
rest_id?: string;
|
|
364
|
+
legacy?: TweetLegacy;
|
|
365
|
+
core?: { user_results?: TwitterUserResults };
|
|
366
|
+
tweet?: TweetResult;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
interface TweetResults {
|
|
370
|
+
result?: TweetResult;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
interface TimelineItemContent {
|
|
374
|
+
__typename?: string;
|
|
375
|
+
tweet_results?: TweetResults;
|
|
376
|
+
user_results?: TwitterUserResults;
|
|
377
|
+
// Notification-specific fields
|
|
378
|
+
id?: string;
|
|
379
|
+
rich_message?: { text?: string };
|
|
380
|
+
notification_text?: { text?: string };
|
|
381
|
+
timestamp_ms?: string;
|
|
382
|
+
notification_url?: { url?: string };
|
|
383
|
+
}
|
|
334
384
|
|
|
335
|
-
|
|
336
|
-
|
|
385
|
+
interface TimelineModuleItem {
|
|
386
|
+
item?: { itemContent?: TimelineItemContent };
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
interface TimelineEntryContent {
|
|
390
|
+
itemContent?: TimelineItemContent;
|
|
391
|
+
items?: TimelineModuleItem[];
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
interface TimelineEntry {
|
|
395
|
+
entryId?: string;
|
|
396
|
+
content?: TimelineEntryContent;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
interface TimelineInstruction {
|
|
400
|
+
entries?: TimelineEntry[];
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
interface TimelineContainer {
|
|
404
|
+
instructions?: TimelineInstruction[];
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
interface TimelineWrapper {
|
|
408
|
+
timeline?: TimelineContainer;
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
interface TwitterApiError {
|
|
412
|
+
message: string;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
/** Response from CreateTweet mutation. */
|
|
416
|
+
interface CreateTweetResponse {
|
|
417
|
+
errors?: TwitterApiError[];
|
|
418
|
+
data?: {
|
|
419
|
+
create_tweet?: {
|
|
420
|
+
tweet_results?: TweetResults;
|
|
421
|
+
};
|
|
422
|
+
};
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
/** Response from UserByScreenName query. */
|
|
426
|
+
interface UserByScreenNameResponse {
|
|
427
|
+
data?: {
|
|
428
|
+
user?: {
|
|
429
|
+
result?: TwitterUserResult;
|
|
430
|
+
};
|
|
431
|
+
};
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
/** Response from UserTweets query. */
|
|
435
|
+
interface UserTweetsResponse {
|
|
436
|
+
data?: {
|
|
437
|
+
user?: {
|
|
438
|
+
result?: {
|
|
439
|
+
timeline_v2?: TimelineWrapper;
|
|
440
|
+
timeline?: TimelineWrapper;
|
|
441
|
+
};
|
|
442
|
+
};
|
|
443
|
+
};
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
/** Response from TweetDetail query. */
|
|
447
|
+
interface TweetDetailResponse {
|
|
448
|
+
data?: {
|
|
449
|
+
threaded_conversation_with_injections_v2?: TimelineContainer;
|
|
450
|
+
};
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
/** Response from SearchTimeline query. */
|
|
454
|
+
interface SearchTimelineResponse {
|
|
455
|
+
data?: {
|
|
456
|
+
search_by_raw_query?: {
|
|
457
|
+
search_timeline?: TimelineWrapper;
|
|
458
|
+
};
|
|
459
|
+
};
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
/** Response from Bookmarks query. */
|
|
463
|
+
interface BookmarksResponse {
|
|
464
|
+
data?: {
|
|
465
|
+
bookmark_timeline_v2?: TimelineWrapper;
|
|
466
|
+
};
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
/** Response from HomeTimeline query. */
|
|
470
|
+
interface HomeTimelineResponse {
|
|
471
|
+
data?: {
|
|
472
|
+
home?: {
|
|
473
|
+
home_timeline_urt?: TimelineContainer;
|
|
474
|
+
};
|
|
475
|
+
};
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
/** Response from NotificationsTimeline query. */
|
|
479
|
+
interface NotificationsTimelineResponse {
|
|
480
|
+
data?: {
|
|
481
|
+
viewer_v2?: {
|
|
482
|
+
user_results?: {
|
|
483
|
+
result?: {
|
|
484
|
+
notification_timeline?: TimelineWrapper;
|
|
485
|
+
};
|
|
486
|
+
};
|
|
487
|
+
};
|
|
488
|
+
};
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
/** Response from Likes / Following / Followers / UserMedia queries. */
|
|
492
|
+
interface UserTimelineResponse {
|
|
493
|
+
data?: {
|
|
494
|
+
user?: {
|
|
495
|
+
result?: {
|
|
496
|
+
timeline?: TimelineWrapper;
|
|
497
|
+
};
|
|
498
|
+
};
|
|
499
|
+
};
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
// ─── Tweet extraction helpers ────────────────────────────────────────────────
|
|
337
503
|
|
|
338
|
-
function extractScreenName(tweetResult:
|
|
504
|
+
function extractScreenName(tweetResult: TweetResult): string {
|
|
339
505
|
return (
|
|
340
506
|
tweetResult?.core?.user_results?.result?.legacy?.screen_name ??
|
|
341
507
|
tweetResult?.core?.user_results?.result?.core?.screen_name ??
|
|
@@ -344,7 +510,7 @@ function extractScreenName(tweetResult: AnyJson): string {
|
|
|
344
510
|
}
|
|
345
511
|
|
|
346
512
|
/** Extract tweets from a timeline instructions array (shared by most endpoints). */
|
|
347
|
-
function extractTweetsFromInstructions(instructions:
|
|
513
|
+
function extractTweetsFromInstructions(instructions: TimelineInstruction[]): TweetEntry[] {
|
|
348
514
|
const tweets: TweetEntry[] = [];
|
|
349
515
|
for (const instruction of instructions) {
|
|
350
516
|
// Handle both array-style entries and direct entries
|
|
@@ -386,7 +552,7 @@ function extractTweetsFromInstructions(instructions: AnyJson[]): TweetEntry[] {
|
|
|
386
552
|
}
|
|
387
553
|
|
|
388
554
|
/** Extract users from a timeline instructions array (Followers/Following). */
|
|
389
|
-
function extractUsersFromInstructions(instructions:
|
|
555
|
+
function extractUsersFromInstructions(instructions: TimelineInstruction[]): UserInfo[] {
|
|
390
556
|
const users: UserInfo[] = [];
|
|
391
557
|
for (const instruction of instructions) {
|
|
392
558
|
for (const entry of instruction.entries ?? []) {
|
|
@@ -460,19 +626,19 @@ export async function postTweet(text: string, opts?: { inReplyToTweetId?: string
|
|
|
460
626
|
queryId: QUERY_IDS.CreateTweet,
|
|
461
627
|
});
|
|
462
628
|
|
|
463
|
-
const json = (await cdpFetch(wsUrl, url, body)) as
|
|
629
|
+
const json = (await cdpFetch(wsUrl, url, body)) as CreateTweetResponse;
|
|
464
630
|
|
|
465
631
|
if (json.errors?.length) {
|
|
466
|
-
throw new
|
|
632
|
+
throw new ProviderError(`X API errors: ${json.errors.map(e => e.message).join('; ')}`, 'x');
|
|
467
633
|
}
|
|
468
634
|
|
|
469
635
|
const tweetResults = json.data?.create_tweet?.tweet_results;
|
|
470
636
|
const result = tweetResults?.result;
|
|
471
637
|
if (!result?.rest_id) {
|
|
472
638
|
if (tweetResults && !result) {
|
|
473
|
-
throw new
|
|
639
|
+
throw new ProviderError('X rejected this post — it may be a duplicate of a recent post. Try different text.', 'x');
|
|
474
640
|
}
|
|
475
|
-
throw new
|
|
641
|
+
throw new ProviderError(`Unexpected response from X API. Response: ${JSON.stringify(json).slice(0, 500)}`, 'x');
|
|
476
642
|
}
|
|
477
643
|
|
|
478
644
|
return {
|
|
@@ -488,11 +654,11 @@ export async function getUserByScreenName(screenName: string): Promise<UserInfo>
|
|
|
488
654
|
const json = await graphqlGet(QUERY_IDS.UserByScreenName, 'UserByScreenName', {
|
|
489
655
|
screen_name: screenName,
|
|
490
656
|
withGrokTranslatedBio: true,
|
|
491
|
-
}) as
|
|
657
|
+
}) as UserByScreenNameResponse;
|
|
492
658
|
|
|
493
659
|
const user = json.data?.user?.result;
|
|
494
660
|
if (!user?.rest_id) {
|
|
495
|
-
throw new
|
|
661
|
+
throw new ProviderError(`User @${screenName} not found`, 'x');
|
|
496
662
|
}
|
|
497
663
|
|
|
498
664
|
return {
|
|
@@ -511,7 +677,7 @@ export async function getUserTweets(userId: string, count = 20): Promise<TweetEn
|
|
|
511
677
|
includePromotedContent: true,
|
|
512
678
|
withQuickPromoteEligibilityTweetFields: true,
|
|
513
679
|
withVoice: true,
|
|
514
|
-
}) as
|
|
680
|
+
}) as UserTweetsResponse;
|
|
515
681
|
|
|
516
682
|
// Response path: data.user.result.timeline_v2.timeline.instructions[]
|
|
517
683
|
// Fallback to data.user.result.timeline.timeline.instructions[]
|
|
@@ -533,7 +699,7 @@ export async function getTweetDetail(tweetId: string): Promise<TweetEntry[]> {
|
|
|
533
699
|
withQuickPromoteEligibilityTweetFields: true,
|
|
534
700
|
withBirdwatchNotes: true,
|
|
535
701
|
withVoice: true,
|
|
536
|
-
}) as
|
|
702
|
+
}) as TweetDetailResponse;
|
|
537
703
|
|
|
538
704
|
// Response path: data.threaded_conversation_with_injections_v2.instructions[]
|
|
539
705
|
const instructions = json.data?.threaded_conversation_with_injections_v2?.instructions ?? [];
|
|
@@ -553,7 +719,7 @@ export async function searchTweets(
|
|
|
553
719
|
// to the search page and capture the response from network events.
|
|
554
720
|
const productParam = product === 'Top' ? '' : `&f=${product.toLowerCase()}`;
|
|
555
721
|
const pageUrl = `https://x.com/search?q=${encodeURIComponent(query)}&src=typed_query${productParam}`;
|
|
556
|
-
const json = await cdpNavigateAndCapture(wsUrl, pageUrl, 'SearchTimeline') as
|
|
722
|
+
const json = await cdpNavigateAndCapture(wsUrl, pageUrl, 'SearchTimeline') as SearchTimelineResponse;
|
|
557
723
|
|
|
558
724
|
const instructions = json.data?.search_by_raw_query?.search_timeline?.timeline?.instructions ?? [];
|
|
559
725
|
return extractTweetsFromInstructions(instructions);
|
|
@@ -565,7 +731,7 @@ export async function getBookmarks(count = 20): Promise<TweetEntry[]> {
|
|
|
565
731
|
const json = await graphqlGet(QUERY_IDS.Bookmarks, 'Bookmarks', {
|
|
566
732
|
count,
|
|
567
733
|
includePromotedContent: true,
|
|
568
|
-
}) as
|
|
734
|
+
}) as BookmarksResponse;
|
|
569
735
|
|
|
570
736
|
// Response path: data.bookmark_timeline_v2.timeline.instructions[]
|
|
571
737
|
const instructions = json.data?.bookmark_timeline_v2?.timeline?.instructions ?? [];
|
|
@@ -580,7 +746,7 @@ export async function getHomeTimeline(count = 20): Promise<TweetEntry[]> {
|
|
|
580
746
|
includePromotedContent: true,
|
|
581
747
|
requestContext: 'launch',
|
|
582
748
|
withCommunity: true,
|
|
583
|
-
}) as
|
|
749
|
+
}) as HomeTimelineResponse;
|
|
584
750
|
|
|
585
751
|
// Response path: data.home.home_timeline_urt.instructions[]
|
|
586
752
|
const instructions = json.data?.home?.home_timeline_urt?.instructions ?? [];
|
|
@@ -593,7 +759,7 @@ export async function getNotifications(count = 20): Promise<NotificationEntry[]>
|
|
|
593
759
|
const json = await graphqlGet(QUERY_IDS.NotificationsTimeline, 'NotificationsTimeline', {
|
|
594
760
|
timeline_type: 'All',
|
|
595
761
|
count,
|
|
596
|
-
}) as
|
|
762
|
+
}) as NotificationsTimelineResponse;
|
|
597
763
|
|
|
598
764
|
// Response path: data.viewer_v2.user_results.result.notification_timeline.timeline.instructions[]
|
|
599
765
|
const instructions =
|
|
@@ -625,7 +791,7 @@ export async function getLikes(userId: string, count = 20): Promise<TweetEntry[]
|
|
|
625
791
|
withClientEventToken: false,
|
|
626
792
|
withBirdwatchNotes: false,
|
|
627
793
|
withVoice: true,
|
|
628
|
-
}) as
|
|
794
|
+
}) as UserTimelineResponse;
|
|
629
795
|
|
|
630
796
|
// Response path: data.user.result.timeline.timeline.instructions[]
|
|
631
797
|
const instructions = json.data?.user?.result?.timeline?.timeline?.instructions ?? [];
|
|
@@ -640,7 +806,7 @@ export async function getFollowers(userId: string, screenName?: string): Promise
|
|
|
640
806
|
if (screenName) {
|
|
641
807
|
requireSession();
|
|
642
808
|
const wsUrl = await findTwitterTab();
|
|
643
|
-
const json = await cdpNavigateAndCapture(wsUrl, `https://x.com/${screenName}/followers`, 'Followers') as
|
|
809
|
+
const json = await cdpNavigateAndCapture(wsUrl, `https://x.com/${screenName}/followers`, 'Followers') as UserTimelineResponse;
|
|
644
810
|
const instructions = json.data?.user?.result?.timeline?.timeline?.instructions ?? [];
|
|
645
811
|
return extractUsersFromInstructions(instructions);
|
|
646
812
|
}
|
|
@@ -650,7 +816,7 @@ export async function getFollowers(userId: string, screenName?: string): Promise
|
|
|
650
816
|
count: 20,
|
|
651
817
|
includePromotedContent: false,
|
|
652
818
|
withGrokTranslatedBio: false,
|
|
653
|
-
}) as
|
|
819
|
+
}) as UserTimelineResponse;
|
|
654
820
|
|
|
655
821
|
const instructions = json.data?.user?.result?.timeline?.timeline?.instructions ?? [];
|
|
656
822
|
return extractUsersFromInstructions(instructions);
|
|
@@ -664,7 +830,7 @@ export async function getFollowing(userId: string, count = 20): Promise<UserInfo
|
|
|
664
830
|
count,
|
|
665
831
|
includePromotedContent: false,
|
|
666
832
|
withGrokTranslatedBio: false,
|
|
667
|
-
}) as
|
|
833
|
+
}) as UserTimelineResponse;
|
|
668
834
|
|
|
669
835
|
// Response path: data.user.result.timeline.timeline.instructions[]
|
|
670
836
|
const instructions = json.data?.user?.result?.timeline?.timeline?.instructions ?? [];
|
|
@@ -681,7 +847,7 @@ export async function getUserMedia(userId: string, count = 20): Promise<TweetEnt
|
|
|
681
847
|
withClientEventToken: false,
|
|
682
848
|
withBirdwatchNotes: false,
|
|
683
849
|
withVoice: true,
|
|
684
|
-
}) as
|
|
850
|
+
}) as UserTimelineResponse;
|
|
685
851
|
|
|
686
852
|
// Response path: data.user.result.timeline.timeline.instructions[]
|
|
687
853
|
// (same as Likes — contains tweets that have media)
|
package/src/twitter/session.ts
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
import { existsSync, readFileSync, writeFileSync, mkdirSync, unlinkSync } from 'node:fs';
|
|
7
7
|
import { join } from 'node:path';
|
|
8
8
|
import { getDataDir } from '../util/platform.js';
|
|
9
|
+
import { ConfigError } from '../util/errors.js';
|
|
9
10
|
import type { SessionRecording, ExtractedCredential } from '../tools/browser/network-recording-types.js';
|
|
10
11
|
|
|
11
12
|
export interface TwitterSession {
|
|
@@ -50,17 +51,17 @@ export function clearSession(): void {
|
|
|
50
51
|
*/
|
|
51
52
|
export function importFromRecording(recordingPath: string): TwitterSession {
|
|
52
53
|
if (!existsSync(recordingPath)) {
|
|
53
|
-
throw new
|
|
54
|
+
throw new ConfigError(`Recording not found: ${recordingPath}`);
|
|
54
55
|
}
|
|
55
56
|
const recording = JSON.parse(readFileSync(recordingPath, 'utf-8')) as SessionRecording;
|
|
56
57
|
if (!recording.cookies?.length) {
|
|
57
|
-
throw new
|
|
58
|
+
throw new ConfigError('Recording contains no cookies');
|
|
58
59
|
}
|
|
59
60
|
// Require the two cookies that prove a logged-in Twitter session:
|
|
60
61
|
// the auth session cookie and the ct0 CSRF cookie.
|
|
61
62
|
const cookieNames = new Set(recording.cookies.map(c => c.name));
|
|
62
63
|
if (!cookieNames.has('ct0') || !cookieNames.has(`auth_${'token'}`)) {
|
|
63
|
-
throw new
|
|
64
|
+
throw new ConfigError(
|
|
64
65
|
'Recording is missing required Twitter session cookies. ' +
|
|
65
66
|
'Make sure you are logged in to x.com before recording.',
|
|
66
67
|
);
|
package/src/util/clipboard.ts
CHANGED
|
@@ -25,7 +25,7 @@ export function extractLastCodeBlock(text: string): string | null {
|
|
|
25
25
|
const re = /```[^\n]*\n((?:[\s\S]*?\n)?)```/g;
|
|
26
26
|
let last: RegExpExecArray | null = null;
|
|
27
27
|
let m: RegExpExecArray | null;
|
|
28
|
-
while ((m = re.exec(text))
|
|
28
|
+
while ((m = re.exec(text)) != null) {
|
|
29
29
|
last = m;
|
|
30
30
|
}
|
|
31
31
|
if (!last) return null;
|
package/src/util/errors.ts
CHANGED
|
@@ -33,7 +33,71 @@ export enum ErrorCode {
|
|
|
33
33
|
INTERNAL_ERROR = 'INTERNAL_ERROR',
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
-
|
|
36
|
+
// ── Root ──────────────────────────────────────────────────────────────────────
|
|
37
|
+
|
|
38
|
+
/** Root base class for all named Vellum errors. */
|
|
39
|
+
export class VellumError extends Error {
|
|
40
|
+
constructor(message: string, options?: ErrorOptions) {
|
|
41
|
+
super(message, options);
|
|
42
|
+
this.name = 'VellumError';
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// ── Backend errors ────────────────────────────────────────────────────────────
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Errors originating from infrastructure or external service calls.
|
|
50
|
+
* Catch this when you want to handle any backend failure uniformly.
|
|
51
|
+
*/
|
|
52
|
+
export class BackendError extends VellumError {
|
|
53
|
+
constructor(message: string, options?: ErrorOptions) {
|
|
54
|
+
super(message, options);
|
|
55
|
+
this.name = 'BackendError';
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* The embedding or vector-search backend is not configured or not reachable.
|
|
61
|
+
* Thrown before attempting an embedding operation so callers can skip or defer.
|
|
62
|
+
*/
|
|
63
|
+
export class BackendUnavailableError extends BackendError {
|
|
64
|
+
constructor(reason: string) {
|
|
65
|
+
super(reason);
|
|
66
|
+
this.name = 'BackendUnavailableError';
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* A request or token-budget quota was exceeded.
|
|
72
|
+
* Thrown by the provider rate-limiter and by domain-specific clients (e.g. DoorDash).
|
|
73
|
+
*/
|
|
74
|
+
export class RateLimitError extends BackendError {
|
|
75
|
+
constructor(message: string) {
|
|
76
|
+
super(message);
|
|
77
|
+
this.name = 'RateLimitError';
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// ── User errors ───────────────────────────────────────────────────────────────
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Errors caused by user input, policy violations, or user-facing constraints.
|
|
85
|
+
* Catch this when you want to present an actionable message to the user.
|
|
86
|
+
*/
|
|
87
|
+
export class UserError extends VellumError {
|
|
88
|
+
constructor(message: string, options?: ErrorOptions) {
|
|
89
|
+
super(message, options);
|
|
90
|
+
this.name = 'UserError';
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// ── AssistantError subtree ────────────────────────────────────────────────────
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Base class for errors originating from assistant logic (providers, tools,
|
|
98
|
+
* permissions, config). Extends VellumError and carries a structured ErrorCode.
|
|
99
|
+
*/
|
|
100
|
+
export class AssistantError extends VellumError {
|
|
37
101
|
constructor(
|
|
38
102
|
message: string,
|
|
39
103
|
public readonly code: ErrorCode,
|
|
@@ -111,13 +175,6 @@ export class IntegrityError extends AssistantError {
|
|
|
111
175
|
}
|
|
112
176
|
}
|
|
113
177
|
|
|
114
|
-
export class RateLimitError extends AssistantError {
|
|
115
|
-
constructor(message: string) {
|
|
116
|
-
super(message, ErrorCode.RATE_LIMIT_ERROR);
|
|
117
|
-
this.name = 'RateLimitError';
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
|
|
121
178
|
export class IngressBlockedError extends AssistantError {
|
|
122
179
|
constructor(
|
|
123
180
|
message: string,
|
package/src/util/fs.ts
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Centralized filesystem helpers — single source of truth for common
|
|
3
|
+
* existence-check and stat patterns scattered across the codebase.
|
|
4
|
+
*
|
|
5
|
+
* Modules should import from here instead of using raw existsSync/statSync
|
|
6
|
+
* from 'node:fs' for these patterns.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { existsSync, mkdirSync, readFileSync, statSync, type Stats } from 'node:fs';
|
|
10
|
+
|
|
11
|
+
/** Check whether a path (file or directory) exists on disk. */
|
|
12
|
+
export function pathExists(path: string): boolean {
|
|
13
|
+
return existsSync(path);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/** Create a directory (and parents) if it doesn't already exist. */
|
|
17
|
+
export function ensureDir(dir: string): void {
|
|
18
|
+
if (!existsSync(dir)) {
|
|
19
|
+
mkdirSync(dir, { recursive: true });
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** Read a UTF-8 text file, returning null if it doesn't exist or is unreadable. */
|
|
24
|
+
export function readTextFileSync(path: string): string | null {
|
|
25
|
+
try {
|
|
26
|
+
if (!existsSync(path)) return null;
|
|
27
|
+
return readFileSync(path, 'utf-8');
|
|
28
|
+
} catch {
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** Get file stats, returning null if the path doesn't exist or is inaccessible. */
|
|
34
|
+
export function safeStatSync(path: string): Stats | null {
|
|
35
|
+
try {
|
|
36
|
+
return statSync(path);
|
|
37
|
+
} catch {
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
}
|