@vellumai/assistant 0.3.4 → 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/Dockerfile +2 -0
- package/README.md +88 -2
- 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 +31 -2
- package/src/__tests__/__snapshots__/ipc-snapshot.test.ts.snap +438 -1
- package/src/__tests__/approval-conversation-turn.test.ts +214 -0
- package/src/__tests__/approval-hardcoded-copy-guard.test.ts +41 -0
- package/src/__tests__/approval-message-composer.test.ts +253 -0
- package/src/__tests__/browser-manager.test.ts +1 -0
- package/src/__tests__/call-conversation-messages.test.ts +130 -0
- package/src/__tests__/call-domain.test.ts +12 -2
- package/src/__tests__/call-orchestrator.test.ts +799 -249
- 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 +32 -2
- package/src/__tests__/call-store.test.ts +3 -0
- package/src/__tests__/channel-approval-routes.test.ts +1277 -98
- package/src/__tests__/channel-approval.test.ts +37 -0
- package/src/__tests__/channel-approvals.test.ts +36 -50
- package/src/__tests__/channel-guardian.test.ts +630 -22
- package/src/__tests__/channel-readiness-service.test.ts +324 -0
- 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 +14 -8
- 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 +7 -2
- package/src/__tests__/daemon-lifecycle.test.ts +13 -12
- package/src/__tests__/db-migration-rollback.test.ts +752 -0
- package/src/__tests__/dictation-mode-detection.test.ts +63 -0
- package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +2 -0
- package/src/__tests__/entity-search.test.ts +615 -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 +533 -0
- package/src/__tests__/intent-routing.test.ts +2 -0
- package/src/__tests__/ipc-snapshot.test.ts +291 -1
- package/src/__tests__/memory-upsert-concurrency.test.ts +828 -0
- package/src/__tests__/messaging-send-tool.test.ts +65 -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 +6 -0
- package/src/__tests__/run-orchestrator.test.ts +42 -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 +321 -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 +126 -0
- 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 +167 -11
- package/src/__tests__/twitter-cli-error-shaping.test.ts +2 -2
- 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 +46 -30
- package/src/__tests__/work-item-output.test.ts +110 -0
- 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 +114 -10
- package/src/calls/call-orchestrator.ts +268 -59
- 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 +22 -14
- package/src/calls/twilio-provider.ts +6 -4
- package/src/calls/twilio-rest.ts +308 -7
- package/src/calls/twilio-routes.ts +65 -12
- 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/knowledge-graph/SKILL.md +15 -0
- package/src/config/bundled-skills/knowledge-graph/TOOLS.json +56 -0
- package/src/config/bundled-skills/knowledge-graph/tools/graph-query.ts +185 -0
- package/src/config/bundled-skills/macos-automation/icon.svg +12 -0
- package/src/config/bundled-skills/media-processing/SKILL.md +176 -0
- package/src/config/bundled-skills/media-processing/TOOLS.json +230 -0
- 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 +259 -0
- package/src/config/bundled-skills/media-processing/services/reduce.ts +197 -0
- package/src/config/bundled-skills/media-processing/tools/analyze-keyframes.ts +136 -0
- package/src/config/bundled-skills/media-processing/tools/extract-keyframes.ts +59 -0
- package/src/config/bundled-skills/media-processing/tools/generate-clip.ts +195 -0
- package/src/config/bundled-skills/media-processing/tools/ingest-media.ts +197 -0
- package/src/config/bundled-skills/media-processing/tools/media-diagnostics.ts +143 -0
- package/src/config/bundled-skills/media-processing/tools/media-status.ts +75 -0
- package/src/config/bundled-skills/media-processing/tools/query-media-events.ts +65 -0
- package/src/config/bundled-skills/messaging/SKILL.md +33 -8
- 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/messaging/tools/messaging-send.ts +5 -1
- package/src/config/bundled-skills/phone-calls/SKILL.md +88 -23
- package/src/config/bundled-skills/twitter/SKILL.md +19 -3
- 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 +28 -3
- 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 +158 -1133
- 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 +131 -56
- package/src/config/templates/IDENTITY.md +2 -2
- 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 +6 -7
- package/src/config/vellum-skills/chatgpt-import/tools/chatgpt-import.ts +5 -1
- package/src/config/vellum-skills/slack-oauth-setup/SKILL.md +4 -3
- package/src/config/vellum-skills/sms-setup/SKILL.md +216 -0
- package/src/config/vellum-skills/twilio-setup/SKILL.md +40 -8
- 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 -1689
- package/src/daemon/handlers/diagnostics.ts +1 -1
- package/src/daemon/handlers/dictation.ts +180 -0
- package/src/daemon/handlers/documents.ts +18 -32
- package/src/daemon/handlers/identity.ts +14 -23
- package/src/daemon/handlers/index.ts +11 -0
- package/src/daemon/handlers/misc.ts +3 -5
- package/src/daemon/handlers/pairing.ts +98 -0
- package/src/daemon/handlers/sessions.ts +56 -5
- package/src/daemon/handlers/shared.ts +6 -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 +17 -9
- 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 +70 -0
- package/src/daemon/ipc-contract-inventory.ts +55 -29
- package/src/daemon/ipc-contract.ts +229 -2426
- package/src/daemon/ipc-protocol.ts +1 -1
- package/src/daemon/ipc-validate.ts +7 -0
- package/src/daemon/lifecycle.ts +97 -377
- package/src/daemon/pairing-store.ts +177 -0
- package/src/daemon/providers-setup.ts +43 -0
- package/src/daemon/ride-shotgun-handler.ts +68 -3
- package/src/daemon/server.ts +66 -46
- package/src/daemon/session-agent-loop-handlers.ts +421 -0
- package/src/daemon/session-agent-loop.ts +117 -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 +199 -10
- package/src/daemon/session-surfaces.ts +19 -4
- package/src/daemon/session-tool-setup.ts +30 -30
- package/src/daemon/session-workspace.ts +1 -1
- package/src/daemon/session.ts +35 -2
- 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 +6 -4
- 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 +202 -2
- 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 +265 -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 +69 -0
- package/src/memory/job-handlers/summarization.ts +32 -26
- package/src/memory/job-utils.ts +3 -10
- package/src/memory/jobs-store.ts +8 -10
- package/src/memory/jobs-worker.ts +55 -36
- package/src/memory/media-store.ts +759 -0
- 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 +165 -47
- package/src/memory/schema-migration.ts +25 -984
- package/src/memory/schema.ts +228 -7
- package/src/memory/search/entity.ts +205 -31
- package/src/memory/search/lexical.ts +81 -52
- package/src/memory/search/ranking.ts +27 -23
- package/src/memory/search/semantic.ts +157 -19
- package/src/memory/search/types.ts +24 -0
- 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/provider-types.ts +2 -0
- package/src/messaging/providers/sms/adapter.ts +201 -0
- package/src/messaging/providers/sms/client.ts +93 -0
- package/src/messaging/providers/sms/types.ts +7 -0
- 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 +133 -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 +253 -0
- package/src/runtime/channel-approval-parser.ts +36 -2
- package/src/runtime/channel-approvals.ts +11 -24
- package/src/runtime/channel-guardian-service.ts +88 -21
- package/src/runtime/channel-readiness-service.ts +418 -0
- package/src/runtime/channel-readiness-types.ts +35 -0
- 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 -717
- package/src/runtime/http-types.ts +59 -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 +51 -7
- 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 -1588
- 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 +86 -35
- 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/materialize.ts +2 -2
- 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/calls/call-start.ts +1 -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/execution-target.ts +11 -1
- 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 +8 -4
- 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/types.ts +2 -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/router.ts +1 -1
- 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 +105 -363
- 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/vellum-skills/google-oauth-setup/SKILL.md +0 -199
|
@@ -81,7 +81,7 @@ export function registerConfigCommand(program: Command): void {
|
|
|
81
81
|
const { validateAllowlistFile } = require('../security/secret-allowlist.js') as typeof import('../security/secret-allowlist.js');
|
|
82
82
|
try {
|
|
83
83
|
const errors = validateAllowlistFile();
|
|
84
|
-
if (errors
|
|
84
|
+
if (errors == null) {
|
|
85
85
|
log.info('No secret-allowlist.json file found');
|
|
86
86
|
return;
|
|
87
87
|
}
|
|
@@ -256,7 +256,7 @@ export function registerMemoryCommand(program: Command): void {
|
|
|
256
256
|
log.info(`Embeddings: ${status.counts.embeddings.toLocaleString()}`);
|
|
257
257
|
log.info(`Pending conflicts: ${status.conflicts.pending.toLocaleString()}`);
|
|
258
258
|
log.info(`Resolved conflicts: ${status.conflicts.resolved.toLocaleString()}`);
|
|
259
|
-
if (status.conflicts.oldestPendingAgeMs
|
|
259
|
+
if (status.conflicts.oldestPendingAgeMs != null) {
|
|
260
260
|
const oldestMinutes = Math.floor(status.conflicts.oldestPendingAgeMs / 60_000);
|
|
261
261
|
log.info(`Oldest pending conflict age: ${oldestMinutes} min`);
|
|
262
262
|
} else {
|
package/src/cli/core-commands.ts
CHANGED
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
} from '../daemon/lifecycle.js';
|
|
14
14
|
import { startCli } from '../cli.js';
|
|
15
15
|
import { getSocketPath, getRootDir, getDataDir, getDbPath, getLogPath, getWorkspaceDir, getWorkspaceSkillsDir, getWorkspaceHooksDir } from '../util/platform.js';
|
|
16
|
+
import { getQdrantUrlEnv } from '../config/env.js';
|
|
16
17
|
import { IpcError } from '../util/errors.js';
|
|
17
18
|
import { getCliLogger } from '../util/logger.js';
|
|
18
19
|
import { timeAgo } from '../util/time.js';
|
|
@@ -271,7 +272,7 @@ export function registerSessionsCommand(program: Command): void {
|
|
|
271
272
|
}
|
|
272
273
|
|
|
273
274
|
const config = getConfig();
|
|
274
|
-
const qdrantUrl =
|
|
275
|
+
const qdrantUrl = getQdrantUrlEnv() || config.memory.qdrant.url;
|
|
275
276
|
const qdrant = initQdrantClient({
|
|
276
277
|
url: qdrantUrl,
|
|
277
278
|
collection: config.memory.qdrant.collection,
|
|
@@ -526,7 +527,7 @@ export function registerDoctorCommand(program: Command): void {
|
|
|
526
527
|
try {
|
|
527
528
|
const rawTrust = readFileSync(trustPath, 'utf-8');
|
|
528
529
|
const data = JSON.parse(rawTrust);
|
|
529
|
-
if (typeof data !== 'object' || data
|
|
530
|
+
if (typeof data !== 'object' || data == null) {
|
|
530
531
|
fail('Trust rule syntax', 'trust.json is not a JSON object');
|
|
531
532
|
} else if (typeof data.version !== 'number') {
|
|
532
533
|
fail('Trust rule syntax', 'missing or invalid "version" field');
|
|
@@ -535,7 +536,7 @@ export function registerDoctorCommand(program: Command): void {
|
|
|
535
536
|
} else {
|
|
536
537
|
const invalid = data.rules.filter(
|
|
537
538
|
(r: unknown) =>
|
|
538
|
-
typeof r !== 'object' || r
|
|
539
|
+
typeof r !== 'object' || r == null ||
|
|
539
540
|
typeof (r as Record<string, unknown>).tool !== 'string' ||
|
|
540
541
|
typeof (r as Record<string, unknown>).pattern !== 'string' ||
|
|
541
542
|
typeof (r as Record<string, unknown>).scope !== 'string',
|
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI command group: `vellum influencer`
|
|
3
|
+
*
|
|
4
|
+
* Research influencers on Instagram, TikTok, and X/Twitter via the Chrome extension relay.
|
|
5
|
+
* All commands output JSON to stdout. Use --json for machine-readable output.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { Command } from 'commander';
|
|
9
|
+
import {
|
|
10
|
+
searchInfluencers,
|
|
11
|
+
getInfluencerProfile,
|
|
12
|
+
compareInfluencers,
|
|
13
|
+
type InfluencerSearchCriteria,
|
|
14
|
+
} from '../influencer/client.js';
|
|
15
|
+
|
|
16
|
+
// ---------------------------------------------------------------------------
|
|
17
|
+
// Helpers
|
|
18
|
+
// ---------------------------------------------------------------------------
|
|
19
|
+
|
|
20
|
+
function output(data: unknown, json: boolean): void {
|
|
21
|
+
process.stdout.write(
|
|
22
|
+
json ? JSON.stringify(data) + '\n' : JSON.stringify(data, null, 2) + '\n',
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function outputError(message: string, code = 1): void {
|
|
27
|
+
output({ ok: false, error: message }, true);
|
|
28
|
+
process.exitCode = code;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function getJson(cmd: Command): boolean {
|
|
32
|
+
let c: Command | null = cmd;
|
|
33
|
+
while (c) {
|
|
34
|
+
if ((c.opts() as { json?: boolean }).json) return true;
|
|
35
|
+
c = c.parent;
|
|
36
|
+
}
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
async function run(cmd: Command, fn: () => Promise<unknown>): Promise<void> {
|
|
41
|
+
try {
|
|
42
|
+
const result = await fn();
|
|
43
|
+
output(
|
|
44
|
+
{ ok: true, ...(result as Record<string, unknown>) },
|
|
45
|
+
getJson(cmd),
|
|
46
|
+
);
|
|
47
|
+
} catch (err) {
|
|
48
|
+
outputError(err instanceof Error ? err.message : String(err));
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// ---------------------------------------------------------------------------
|
|
53
|
+
// Command registration
|
|
54
|
+
// ---------------------------------------------------------------------------
|
|
55
|
+
|
|
56
|
+
export function registerInfluencerCommand(program: Command): void {
|
|
57
|
+
const inf = program
|
|
58
|
+
.command('influencer')
|
|
59
|
+
.description(
|
|
60
|
+
'Research influencers on Instagram, TikTok, and X/Twitter. ' +
|
|
61
|
+
'Uses the Chrome extension relay to browse each platform. ' +
|
|
62
|
+
'Requires the user to be logged in on each platform in Chrome.',
|
|
63
|
+
)
|
|
64
|
+
.option('--json', 'Machine-readable JSON output');
|
|
65
|
+
|
|
66
|
+
// =========================================================================
|
|
67
|
+
// search — search for influencers across platforms
|
|
68
|
+
// =========================================================================
|
|
69
|
+
inf
|
|
70
|
+
.command('search')
|
|
71
|
+
.description(
|
|
72
|
+
'Search for influencers matching criteria across Instagram, TikTok, and X/Twitter',
|
|
73
|
+
)
|
|
74
|
+
.argument('<query>', 'Search query — niche, topic, or keywords (e.g. "fitness coach", "vegan food")')
|
|
75
|
+
.option(
|
|
76
|
+
'--platforms <platforms>',
|
|
77
|
+
'Comma-separated list of platforms to search (instagram,tiktok,twitter)',
|
|
78
|
+
'instagram,tiktok,twitter',
|
|
79
|
+
)
|
|
80
|
+
.option('--min-followers <n>', 'Minimum follower count (e.g. 10000, 10k, 1m)')
|
|
81
|
+
.option('--max-followers <n>', 'Maximum follower count (e.g. 100000, 100k, 1m)')
|
|
82
|
+
.option('--limit <n>', 'Max results per platform', '10')
|
|
83
|
+
.option('--verified', 'Only return verified accounts')
|
|
84
|
+
.action(
|
|
85
|
+
async (
|
|
86
|
+
query: string,
|
|
87
|
+
opts: {
|
|
88
|
+
platforms: string;
|
|
89
|
+
minFollowers?: string;
|
|
90
|
+
maxFollowers?: string;
|
|
91
|
+
limit: string;
|
|
92
|
+
verified?: boolean;
|
|
93
|
+
},
|
|
94
|
+
cmd: Command,
|
|
95
|
+
) => {
|
|
96
|
+
await run(cmd, async () => {
|
|
97
|
+
const platforms = opts.platforms
|
|
98
|
+
.split(',')
|
|
99
|
+
.map((p) => p.trim().toLowerCase())
|
|
100
|
+
.filter((p): p is 'instagram' | 'tiktok' | 'twitter' =>
|
|
101
|
+
['instagram', 'tiktok', 'twitter'].includes(p),
|
|
102
|
+
);
|
|
103
|
+
|
|
104
|
+
const criteria: InfluencerSearchCriteria = {
|
|
105
|
+
query,
|
|
106
|
+
platforms,
|
|
107
|
+
minFollowers: opts.minFollowers
|
|
108
|
+
? parseHumanNumber(opts.minFollowers)
|
|
109
|
+
: undefined,
|
|
110
|
+
maxFollowers: opts.maxFollowers
|
|
111
|
+
? parseHumanNumber(opts.maxFollowers)
|
|
112
|
+
: undefined,
|
|
113
|
+
limit: parseInt(opts.limit, 10),
|
|
114
|
+
verifiedOnly: opts.verified,
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
const results = await searchInfluencers(criteria);
|
|
118
|
+
|
|
119
|
+
const totalProfiles = results.reduce((sum, r) => sum + r.count, 0);
|
|
120
|
+
|
|
121
|
+
return {
|
|
122
|
+
results,
|
|
123
|
+
totalProfiles,
|
|
124
|
+
platforms: platforms.length,
|
|
125
|
+
query,
|
|
126
|
+
};
|
|
127
|
+
});
|
|
128
|
+
},
|
|
129
|
+
);
|
|
130
|
+
|
|
131
|
+
// =========================================================================
|
|
132
|
+
// profile — get detailed profile data for a specific influencer
|
|
133
|
+
// =========================================================================
|
|
134
|
+
inf
|
|
135
|
+
.command('profile')
|
|
136
|
+
.description('Get detailed profile data for a specific influencer')
|
|
137
|
+
.argument('<username>', 'Username/handle (without @ prefix)')
|
|
138
|
+
.option(
|
|
139
|
+
'--platform <platform>',
|
|
140
|
+
'Platform (instagram, tiktok, or twitter)',
|
|
141
|
+
'instagram',
|
|
142
|
+
)
|
|
143
|
+
.action(
|
|
144
|
+
async (
|
|
145
|
+
username: string,
|
|
146
|
+
opts: { platform: string },
|
|
147
|
+
cmd: Command,
|
|
148
|
+
) => {
|
|
149
|
+
await run(cmd, async () => {
|
|
150
|
+
const platform = opts.platform.toLowerCase() as
|
|
151
|
+
| 'instagram'
|
|
152
|
+
| 'tiktok'
|
|
153
|
+
| 'twitter';
|
|
154
|
+
if (!['instagram', 'tiktok', 'twitter'].includes(platform)) {
|
|
155
|
+
throw new Error(
|
|
156
|
+
`Invalid platform: ${opts.platform}. Use instagram, tiktok, or twitter.`,
|
|
157
|
+
);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const cleanUsername = username.replace(/^@/, '');
|
|
161
|
+
const profile = await getInfluencerProfile(platform, cleanUsername);
|
|
162
|
+
|
|
163
|
+
if (!profile) {
|
|
164
|
+
throw new Error(
|
|
165
|
+
`Could not find profile @${cleanUsername} on ${platform}`,
|
|
166
|
+
);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
return { profile };
|
|
170
|
+
});
|
|
171
|
+
},
|
|
172
|
+
);
|
|
173
|
+
|
|
174
|
+
// =========================================================================
|
|
175
|
+
// compare — compare multiple influencers side by side
|
|
176
|
+
// =========================================================================
|
|
177
|
+
inf
|
|
178
|
+
.command('compare')
|
|
179
|
+
.description(
|
|
180
|
+
'Compare multiple influencers side by side. ' +
|
|
181
|
+
'Provide usernames as platform:username pairs.',
|
|
182
|
+
)
|
|
183
|
+
.argument(
|
|
184
|
+
'<influencers...>',
|
|
185
|
+
'Space-separated list of platform:username pairs (e.g. instagram:nike twitter:nike tiktok:nike)',
|
|
186
|
+
)
|
|
187
|
+
.action(async (influencers: string[], _opts: unknown, cmd: Command) => {
|
|
188
|
+
await run(cmd, async () => {
|
|
189
|
+
const parsed = influencers.map((inf) => {
|
|
190
|
+
const [platform, username] = inf.includes(':')
|
|
191
|
+
? inf.split(':', 2)
|
|
192
|
+
: ['instagram', inf];
|
|
193
|
+
|
|
194
|
+
const cleanPlatform = platform.toLowerCase() as
|
|
195
|
+
| 'instagram'
|
|
196
|
+
| 'tiktok'
|
|
197
|
+
| 'twitter';
|
|
198
|
+
if (!['instagram', 'tiktok', 'twitter'].includes(cleanPlatform)) {
|
|
199
|
+
throw new Error(
|
|
200
|
+
`Invalid platform "${platform}" in "${inf}". Use instagram, tiktok, or twitter.`,
|
|
201
|
+
);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
return {
|
|
205
|
+
platform: cleanPlatform,
|
|
206
|
+
username: username.replace(/^@/, ''),
|
|
207
|
+
};
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
const profiles = await compareInfluencers(parsed);
|
|
211
|
+
|
|
212
|
+
return {
|
|
213
|
+
profiles,
|
|
214
|
+
count: profiles.length,
|
|
215
|
+
requested: parsed.length,
|
|
216
|
+
};
|
|
217
|
+
});
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// ---------------------------------------------------------------------------
|
|
222
|
+
// Utilities
|
|
223
|
+
// ---------------------------------------------------------------------------
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Parse human-friendly numbers like "10k", "1.5m", "100000" into integers.
|
|
227
|
+
*/
|
|
228
|
+
function parseHumanNumber(text: string): number {
|
|
229
|
+
const cleaned = text.toLowerCase().replace(/,/g, '').trim();
|
|
230
|
+
const match = cleaned.match(/^([\d.]+)\s*([kmbt]?)$/);
|
|
231
|
+
if (!match) return parseInt(text, 10) || 0;
|
|
232
|
+
|
|
233
|
+
const num = parseFloat(match[1]);
|
|
234
|
+
const suffix = match[2];
|
|
235
|
+
const multipliers: Record<string, number> = {
|
|
236
|
+
'': 1,
|
|
237
|
+
k: 1_000,
|
|
238
|
+
m: 1_000_000,
|
|
239
|
+
b: 1_000_000_000,
|
|
240
|
+
t: 1_000_000_000_000,
|
|
241
|
+
};
|
|
242
|
+
|
|
243
|
+
return Math.round(num * (multipliers[suffix] || 1));
|
|
244
|
+
}
|
package/src/cli/map.ts
CHANGED
|
@@ -72,6 +72,75 @@ async function isCdpReady(): Promise<boolean> {
|
|
|
72
72
|
}
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
+
/**
|
|
76
|
+
* Bring the Chrome CDP tab to the foreground so the user sees the right window.
|
|
77
|
+
* Optionally navigates to a URL first (used when Chrome was already running).
|
|
78
|
+
*/
|
|
79
|
+
async function bringChromeToFront(navigateUrl?: string): Promise<string | null> {
|
|
80
|
+
try {
|
|
81
|
+
const res = await fetch(`${CDP_BASE}/json/list`);
|
|
82
|
+
if (!res.ok) return null;
|
|
83
|
+
const targets = (await res.json()) as Array<{ type: string; url: string; webSocketDebuggerUrl: string }>;
|
|
84
|
+
const pageTarget = targets.find(t => t.type === 'page');
|
|
85
|
+
if (!pageTarget?.webSocketDebuggerUrl) return null;
|
|
86
|
+
|
|
87
|
+
const ws = new WebSocket(pageTarget.webSocketDebuggerUrl);
|
|
88
|
+
await new Promise<void>((resolve, reject) => {
|
|
89
|
+
ws.onopen = () => resolve();
|
|
90
|
+
ws.onerror = (e) => reject(new Error(`CDP WebSocket error: ${e}`));
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
let nextId = 1;
|
|
94
|
+
const cdpSend = (method: string, params?: Record<string, unknown>): Promise<unknown> =>
|
|
95
|
+
new Promise((resolve, reject) => {
|
|
96
|
+
const id = nextId++;
|
|
97
|
+
const cleanup = () => {
|
|
98
|
+
clearTimeout(timeout);
|
|
99
|
+
ws.removeEventListener('message', handler);
|
|
100
|
+
ws.removeEventListener('close', onClose);
|
|
101
|
+
ws.removeEventListener('error', onError);
|
|
102
|
+
};
|
|
103
|
+
const timeout = setTimeout(() => {
|
|
104
|
+
cleanup();
|
|
105
|
+
reject(new Error(`CDP command ${method} timed out`));
|
|
106
|
+
}, 5000);
|
|
107
|
+
const onClose = () => {
|
|
108
|
+
cleanup();
|
|
109
|
+
reject(new Error('WebSocket closed before CDP response'));
|
|
110
|
+
};
|
|
111
|
+
const onError = (e: Event) => {
|
|
112
|
+
cleanup();
|
|
113
|
+
reject(new Error(`WebSocket error: ${e}`));
|
|
114
|
+
};
|
|
115
|
+
const handler = (event: MessageEvent) => {
|
|
116
|
+
const msg = JSON.parse(String(event.data));
|
|
117
|
+
if (msg.id === id) {
|
|
118
|
+
cleanup();
|
|
119
|
+
if (msg.error) reject(new Error(msg.error.message));
|
|
120
|
+
else resolve(msg.result);
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
ws.addEventListener('message', handler);
|
|
124
|
+
ws.addEventListener('close', onClose);
|
|
125
|
+
ws.addEventListener('error', onError);
|
|
126
|
+
ws.send(JSON.stringify({ id, method, params }));
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
if (navigateUrl) {
|
|
130
|
+
await cdpSend('Page.navigate', { url: navigateUrl });
|
|
131
|
+
// Brief wait for navigation to start
|
|
132
|
+
await new Promise(r => setTimeout(r, 500));
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
await cdpSend('Page.bringToFront');
|
|
136
|
+
const tabUrl = navigateUrl ?? pageTarget.url;
|
|
137
|
+
ws.close();
|
|
138
|
+
return tabUrl;
|
|
139
|
+
} catch {
|
|
140
|
+
return null;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
75
144
|
async function ensureChromeWithCDP(domain: string): Promise<void> {
|
|
76
145
|
// Already running with CDP?
|
|
77
146
|
if (await isCdpReady()) return;
|
|
@@ -110,9 +179,16 @@ async function startLearnSession(
|
|
|
110
179
|
navigateDomain: string,
|
|
111
180
|
recordDomain: string,
|
|
112
181
|
durationSeconds: number,
|
|
182
|
+
autoNavigate: boolean = true,
|
|
113
183
|
): Promise<LearnResult> {
|
|
114
184
|
await ensureChromeWithCDP(navigateDomain);
|
|
115
185
|
|
|
186
|
+
// Activate the Chrome window so the user knows which tab to watch
|
|
187
|
+
const tabUrl = await bringChromeToFront(`https://${navigateDomain}/`);
|
|
188
|
+
if (tabUrl) {
|
|
189
|
+
process.stderr.write(`Chrome is ready — using tab at ${tabUrl}\n`);
|
|
190
|
+
}
|
|
191
|
+
|
|
116
192
|
return new Promise((resolve, reject) => {
|
|
117
193
|
const socketPath = getSocketPath();
|
|
118
194
|
const sessionToken = readSessionToken();
|
|
@@ -140,7 +216,7 @@ async function startLearnSession(
|
|
|
140
216
|
mode: 'learn',
|
|
141
217
|
targetDomain: recordDomain,
|
|
142
218
|
navigateDomain,
|
|
143
|
-
autoNavigate
|
|
219
|
+
autoNavigate,
|
|
144
220
|
} as unknown as import('../daemon/ipc-protocol.js').ClientMessage),
|
|
145
221
|
);
|
|
146
222
|
};
|
|
@@ -211,11 +287,15 @@ export function registerMapCommand(program: Command): void {
|
|
|
211
287
|
'then analyzes captured network traffic.',
|
|
212
288
|
)
|
|
213
289
|
.argument('<domain>', 'Domain to map (e.g., example.com)')
|
|
214
|
-
.option('--duration <seconds>', 'Recording duration in seconds'
|
|
290
|
+
.option('--duration <seconds>', 'Recording duration in seconds')
|
|
291
|
+
.option('--manual', 'Manual mode: browse the site yourself while network traffic is recorded')
|
|
215
292
|
.option('--json', 'Machine-readable JSON output')
|
|
216
|
-
.action(async (domain: string, opts: { duration
|
|
293
|
+
.action(async (domain: string, opts: { duration?: string; manual?: boolean; json?: boolean }, cmd: Command) => {
|
|
217
294
|
const json = getJson(cmd);
|
|
218
|
-
const
|
|
295
|
+
const manual = opts.manual ?? false;
|
|
296
|
+
const duration = opts.duration
|
|
297
|
+
? parseInt(opts.duration, 10)
|
|
298
|
+
: manual ? 60 : 120;
|
|
219
299
|
|
|
220
300
|
try {
|
|
221
301
|
// Split into navigation domain (what Chrome browses) and recording domain (network filter).
|
|
@@ -224,13 +304,16 @@ export function registerMapCommand(program: Command): void {
|
|
|
224
304
|
const recordDomain = getBaseDomain(domain);
|
|
225
305
|
|
|
226
306
|
if (!json) {
|
|
227
|
-
if (
|
|
307
|
+
if (manual) {
|
|
308
|
+
console.log(`Starting manual API map session for ${domain} (${duration}s)...`);
|
|
309
|
+
console.log('Browse the site manually. Press Ctrl+C or wait for idle detection to stop recording.');
|
|
310
|
+
} else if (navigateDomain !== recordDomain) {
|
|
228
311
|
console.log(`Starting API map session: navigating ${navigateDomain}, recording *.${recordDomain} (${duration}s)...`);
|
|
229
312
|
} else {
|
|
230
313
|
console.log(`Starting API map session for ${domain} (${duration}s)...`);
|
|
231
314
|
}
|
|
232
315
|
}
|
|
233
|
-
const result = await startLearnSession(navigateDomain, recordDomain, duration);
|
|
316
|
+
const result = await startLearnSession(navigateDomain, recordDomain, duration, !manual);
|
|
234
317
|
|
|
235
318
|
if (!result.recordingId) {
|
|
236
319
|
outputError('Recording completed but no recording ID returned');
|
package/src/cli.ts
CHANGED
|
@@ -785,7 +785,7 @@ export async function startCli(): Promise<void> {
|
|
|
785
785
|
|
|
786
786
|
if (content === '/copy-code') {
|
|
787
787
|
const code = extractLastCodeBlock(lastResponse);
|
|
788
|
-
if (code
|
|
788
|
+
if (code == null) {
|
|
789
789
|
process.stdout.write('No code block found.\n');
|
|
790
790
|
} else {
|
|
791
791
|
try {
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
|
|
3
|
+
export const AgentHeartbeatConfigSchema = z.object({
|
|
4
|
+
enabled: z
|
|
5
|
+
.boolean({ error: 'agentHeartbeat.enabled must be a boolean' })
|
|
6
|
+
.default(false),
|
|
7
|
+
intervalMs: z
|
|
8
|
+
.number({ error: 'agentHeartbeat.intervalMs must be a number' })
|
|
9
|
+
.int('agentHeartbeat.intervalMs must be an integer')
|
|
10
|
+
.positive('agentHeartbeat.intervalMs must be a positive integer')
|
|
11
|
+
.default(3_600_000),
|
|
12
|
+
activeHoursStart: z
|
|
13
|
+
.number({ error: 'agentHeartbeat.activeHoursStart must be a number' })
|
|
14
|
+
.int('agentHeartbeat.activeHoursStart must be an integer')
|
|
15
|
+
.min(0, 'agentHeartbeat.activeHoursStart must be >= 0')
|
|
16
|
+
.max(23, 'agentHeartbeat.activeHoursStart must be <= 23')
|
|
17
|
+
.optional(),
|
|
18
|
+
activeHoursEnd: z
|
|
19
|
+
.number({ error: 'agentHeartbeat.activeHoursEnd must be a number' })
|
|
20
|
+
.int('agentHeartbeat.activeHoursEnd must be an integer')
|
|
21
|
+
.min(0, 'agentHeartbeat.activeHoursEnd must be >= 0')
|
|
22
|
+
.max(23, 'agentHeartbeat.activeHoursEnd must be <= 23')
|
|
23
|
+
.optional(),
|
|
24
|
+
}).superRefine((config, ctx) => {
|
|
25
|
+
const hasStart = config.activeHoursStart != null;
|
|
26
|
+
const hasEnd = config.activeHoursEnd != null;
|
|
27
|
+
if (hasStart !== hasEnd) {
|
|
28
|
+
ctx.addIssue({
|
|
29
|
+
code: z.ZodIssueCode.custom,
|
|
30
|
+
path: [hasStart ? 'activeHoursEnd' : 'activeHoursStart'],
|
|
31
|
+
message: 'agentHeartbeat.activeHoursStart and agentHeartbeat.activeHoursEnd must both be set or both be omitted',
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
if (hasStart && hasEnd && config.activeHoursStart === config.activeHoursEnd) {
|
|
35
|
+
ctx.addIssue({
|
|
36
|
+
code: z.ZodIssueCode.custom,
|
|
37
|
+
path: ['activeHoursEnd'],
|
|
38
|
+
message: 'agentHeartbeat.activeHoursStart and agentHeartbeat.activeHoursEnd must not be equal (would create an empty window)',
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
export const SwarmConfigSchema = z.object({
|
|
44
|
+
enabled: z
|
|
45
|
+
.boolean({ error: 'swarm.enabled must be a boolean' })
|
|
46
|
+
.default(true),
|
|
47
|
+
maxWorkers: z
|
|
48
|
+
.number({ error: 'swarm.maxWorkers must be a number' })
|
|
49
|
+
.int('swarm.maxWorkers must be an integer')
|
|
50
|
+
.positive('swarm.maxWorkers must be a positive integer')
|
|
51
|
+
.max(6, 'swarm.maxWorkers must be at most 6')
|
|
52
|
+
.default(3),
|
|
53
|
+
maxTasks: z
|
|
54
|
+
.number({ error: 'swarm.maxTasks must be a number' })
|
|
55
|
+
.int('swarm.maxTasks must be an integer')
|
|
56
|
+
.positive('swarm.maxTasks must be a positive integer')
|
|
57
|
+
.max(20, 'swarm.maxTasks must be at most 20')
|
|
58
|
+
.default(8),
|
|
59
|
+
maxRetriesPerTask: z
|
|
60
|
+
.number({ error: 'swarm.maxRetriesPerTask must be a number' })
|
|
61
|
+
.int('swarm.maxRetriesPerTask must be an integer')
|
|
62
|
+
.nonnegative('swarm.maxRetriesPerTask must be a non-negative integer')
|
|
63
|
+
.max(3, 'swarm.maxRetriesPerTask must be at most 3')
|
|
64
|
+
.default(1),
|
|
65
|
+
workerTimeoutSec: z
|
|
66
|
+
.number({ error: 'swarm.workerTimeoutSec must be a number' })
|
|
67
|
+
.int('swarm.workerTimeoutSec must be an integer')
|
|
68
|
+
.positive('swarm.workerTimeoutSec must be a positive integer')
|
|
69
|
+
.default(900),
|
|
70
|
+
plannerModel: z
|
|
71
|
+
.string({ error: 'swarm.plannerModel must be a string' })
|
|
72
|
+
.default('claude-haiku-4-5-20251001'),
|
|
73
|
+
synthesizerModel: z
|
|
74
|
+
.string({ error: 'swarm.synthesizerModel must be a string' })
|
|
75
|
+
.default('claude-sonnet-4-6'),
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
export const WorkspaceGitConfigSchema = z.object({
|
|
79
|
+
turnCommitMaxWaitMs: z
|
|
80
|
+
.number({ error: 'workspaceGit.turnCommitMaxWaitMs must be a number' })
|
|
81
|
+
.int('workspaceGit.turnCommitMaxWaitMs must be an integer')
|
|
82
|
+
.positive('workspaceGit.turnCommitMaxWaitMs must be a positive integer')
|
|
83
|
+
.default(4000),
|
|
84
|
+
failureBackoffBaseMs: z
|
|
85
|
+
.number({ error: 'workspaceGit.failureBackoffBaseMs must be a number' })
|
|
86
|
+
.int('workspaceGit.failureBackoffBaseMs must be an integer')
|
|
87
|
+
.positive('workspaceGit.failureBackoffBaseMs must be a positive integer')
|
|
88
|
+
.default(2000),
|
|
89
|
+
failureBackoffMaxMs: z
|
|
90
|
+
.number({ error: 'workspaceGit.failureBackoffMaxMs must be a number' })
|
|
91
|
+
.int('workspaceGit.failureBackoffMaxMs must be an integer')
|
|
92
|
+
.positive('workspaceGit.failureBackoffMaxMs must be a positive integer')
|
|
93
|
+
.default(60000),
|
|
94
|
+
interactiveGitTimeoutMs: z
|
|
95
|
+
.number({ error: 'workspaceGit.interactiveGitTimeoutMs must be a number' })
|
|
96
|
+
.int('workspaceGit.interactiveGitTimeoutMs must be an integer')
|
|
97
|
+
.positive('workspaceGit.interactiveGitTimeoutMs must be a positive integer')
|
|
98
|
+
.default(10000),
|
|
99
|
+
enrichmentQueueSize: z
|
|
100
|
+
.number({ error: 'workspaceGit.enrichmentQueueSize must be a number' })
|
|
101
|
+
.int('workspaceGit.enrichmentQueueSize must be an integer')
|
|
102
|
+
.positive('workspaceGit.enrichmentQueueSize must be a positive integer')
|
|
103
|
+
.default(50),
|
|
104
|
+
enrichmentConcurrency: z
|
|
105
|
+
.number({ error: 'workspaceGit.enrichmentConcurrency must be a number' })
|
|
106
|
+
.int('workspaceGit.enrichmentConcurrency must be an integer')
|
|
107
|
+
.positive('workspaceGit.enrichmentConcurrency must be a positive integer')
|
|
108
|
+
.default(1),
|
|
109
|
+
enrichmentJobTimeoutMs: z
|
|
110
|
+
.number({ error: 'workspaceGit.enrichmentJobTimeoutMs must be a number' })
|
|
111
|
+
.int('workspaceGit.enrichmentJobTimeoutMs must be an integer')
|
|
112
|
+
.positive('workspaceGit.enrichmentJobTimeoutMs must be a positive integer')
|
|
113
|
+
.default(30000),
|
|
114
|
+
enrichmentMaxRetries: z
|
|
115
|
+
.number({ error: 'workspaceGit.enrichmentMaxRetries must be a number' })
|
|
116
|
+
.int('workspaceGit.enrichmentMaxRetries must be an integer')
|
|
117
|
+
.nonnegative('workspaceGit.enrichmentMaxRetries must be non-negative')
|
|
118
|
+
.default(2),
|
|
119
|
+
commitMessageLLM: z.object({
|
|
120
|
+
enabled: z.boolean({ error: 'workspaceGit.commitMessageLLM.enabled must be a boolean' }).default(false),
|
|
121
|
+
useConfiguredProvider: z.boolean({ error: 'workspaceGit.commitMessageLLM.useConfiguredProvider must be a boolean' }).default(true),
|
|
122
|
+
providerFastModelOverrides: z.record(z.string(), z.string()).default({}),
|
|
123
|
+
timeoutMs: z.number({ error: 'workspaceGit.commitMessageLLM.timeoutMs must be a number' })
|
|
124
|
+
.int('workspaceGit.commitMessageLLM.timeoutMs must be an integer')
|
|
125
|
+
.positive('workspaceGit.commitMessageLLM.timeoutMs must be a positive integer')
|
|
126
|
+
.default(600),
|
|
127
|
+
maxTokens: z.number({ error: 'workspaceGit.commitMessageLLM.maxTokens must be a number' })
|
|
128
|
+
.int('workspaceGit.commitMessageLLM.maxTokens must be an integer')
|
|
129
|
+
.positive('workspaceGit.commitMessageLLM.maxTokens must be a positive integer')
|
|
130
|
+
.default(120),
|
|
131
|
+
temperature: z.number({ error: 'workspaceGit.commitMessageLLM.temperature must be a number' })
|
|
132
|
+
.min(0, 'workspaceGit.commitMessageLLM.temperature must be >= 0')
|
|
133
|
+
.max(2, 'workspaceGit.commitMessageLLM.temperature must be <= 2')
|
|
134
|
+
.default(0.2),
|
|
135
|
+
maxFilesInPrompt: z.number({ error: 'workspaceGit.commitMessageLLM.maxFilesInPrompt must be a number' })
|
|
136
|
+
.int('workspaceGit.commitMessageLLM.maxFilesInPrompt must be an integer')
|
|
137
|
+
.positive('workspaceGit.commitMessageLLM.maxFilesInPrompt must be a positive integer')
|
|
138
|
+
.default(30),
|
|
139
|
+
maxDiffBytes: z.number({ error: 'workspaceGit.commitMessageLLM.maxDiffBytes must be a number' })
|
|
140
|
+
.int('workspaceGit.commitMessageLLM.maxDiffBytes must be an integer')
|
|
141
|
+
.positive('workspaceGit.commitMessageLLM.maxDiffBytes must be a positive integer')
|
|
142
|
+
.default(12000),
|
|
143
|
+
minRemainingTurnBudgetMs: z.number({ error: 'workspaceGit.commitMessageLLM.minRemainingTurnBudgetMs must be a number' })
|
|
144
|
+
.int('workspaceGit.commitMessageLLM.minRemainingTurnBudgetMs must be an integer')
|
|
145
|
+
.nonnegative('workspaceGit.commitMessageLLM.minRemainingTurnBudgetMs must be non-negative')
|
|
146
|
+
.default(1000),
|
|
147
|
+
breaker: z.object({
|
|
148
|
+
openAfterFailures: z.number({ error: 'workspaceGit.commitMessageLLM.breaker.openAfterFailures must be a number' })
|
|
149
|
+
.int().positive().default(3),
|
|
150
|
+
backoffBaseMs: z.number({ error: 'workspaceGit.commitMessageLLM.breaker.backoffBaseMs must be a number' })
|
|
151
|
+
.int().positive().default(2000),
|
|
152
|
+
backoffMaxMs: z.number({ error: 'workspaceGit.commitMessageLLM.breaker.backoffMaxMs must be a number' })
|
|
153
|
+
.int().positive().default(60000),
|
|
154
|
+
}).default({ openAfterFailures: 3, backoffBaseMs: 2000, backoffMaxMs: 60000 }),
|
|
155
|
+
}).default({
|
|
156
|
+
enabled: false,
|
|
157
|
+
useConfiguredProvider: true,
|
|
158
|
+
providerFastModelOverrides: {},
|
|
159
|
+
timeoutMs: 600,
|
|
160
|
+
maxTokens: 120,
|
|
161
|
+
temperature: 0.2,
|
|
162
|
+
maxFilesInPrompt: 30,
|
|
163
|
+
maxDiffBytes: 12000,
|
|
164
|
+
minRemainingTurnBudgetMs: 1000,
|
|
165
|
+
breaker: { openAfterFailures: 3, backoffBaseMs: 2000, backoffMaxMs: 60000 },
|
|
166
|
+
}),
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
export type AgentHeartbeatConfig = z.infer<typeof AgentHeartbeatConfigSchema>;
|
|
170
|
+
export type SwarmConfig = z.infer<typeof SwarmConfigSchema>;
|
|
171
|
+
export type WorkspaceGitConfig = z.infer<typeof WorkspaceGitConfigSchema>;
|