@vellumai/assistant 0.4.43 → 0.4.45
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/.prettierignore +4 -0
- package/ARCHITECTURE.md +46 -44
- package/README.md +15 -16
- package/bun.lock +10 -35
- package/docs/architecture/integrations.md +102 -215
- package/docs/architecture/keychain-broker.md +1 -1
- package/docs/architecture/memory.md +2 -2
- package/docs/architecture/scheduling.md +1 -1
- package/docs/architecture/security.md +11 -11
- package/docs/error-handling.md +1 -1
- package/docs/trusted-contact-access.md +3 -3
- package/drizzle/meta/0000_snapshot.json +34 -100
- package/drizzle/meta/_journal.json +1 -1
- package/drizzle.config.ts +4 -4
- package/package.json +3 -2
- package/scripts/capture-x-graphql.ts +237 -141
- package/scripts/generate-bundled-tool-registry.ts +223 -0
- package/src/__tests__/access-request-decision.test.ts +0 -1
- package/src/__tests__/actor-token-service.test.ts +23 -24
- package/src/__tests__/agent-loop.test.ts +0 -131
- package/src/__tests__/always-loaded-tools-guard.test.ts +71 -0
- package/src/__tests__/amazon-cdp-integration.test.ts +11 -9
- package/src/__tests__/approval-primitive.test.ts +0 -1
- package/src/__tests__/approval-routes-http.test.ts +11 -3
- package/src/__tests__/asset-materialize-tool.test.ts +0 -1
- package/src/__tests__/asset-search-tool.test.ts +0 -1
- package/src/__tests__/assistant-attachment-directive.test.ts +1 -1
- package/src/__tests__/assistant-events-sse-hardening.test.ts +0 -1
- package/src/__tests__/assistant-feature-flag-guardrails.test.ts +0 -2
- package/src/__tests__/assistant-feature-flags-integration.test.ts +70 -18
- package/src/__tests__/assistant-id-boundary-guard.test.ts +6 -6
- package/src/__tests__/attachments-store.test.ts +0 -1
- package/src/__tests__/avatar-e2e.test.ts +74 -115
- package/src/__tests__/avatar-router.test.ts +25 -62
- package/src/__tests__/browser-manager.test.ts +24 -0
- package/src/__tests__/browser-skill-baseline-tool-payload.test.ts +4 -3
- package/src/__tests__/browser-skill-endstate.test.ts +8 -11
- package/src/__tests__/btw-routes.test.ts +326 -0
- package/src/__tests__/bundled-asset.test.ts +1 -1
- package/src/__tests__/bundled-skill-retrieval-guard.test.ts +23 -9
- package/src/__tests__/call-controller.test.ts +0 -1
- package/src/__tests__/call-conversation-messages.test.ts +0 -1
- package/src/__tests__/call-domain.test.ts +0 -1
- package/src/__tests__/call-pointer-messages.test.ts +0 -1
- package/src/__tests__/call-recovery.test.ts +0 -1
- package/src/__tests__/call-routes-http.test.ts +0 -1
- package/src/__tests__/call-store.test.ts +0 -1
- package/src/__tests__/canonical-guardian-store.test.ts +0 -1
- package/src/__tests__/channel-approval-routes.test.ts +1 -1
- package/src/__tests__/channel-approvals.test.ts +1 -1
- package/src/__tests__/channel-delivery-store.test.ts +0 -1
- package/src/__tests__/channel-guardian.test.ts +5 -7
- package/src/__tests__/channel-retry-sweep.test.ts +0 -1
- package/src/__tests__/checker.test.ts +32 -36
- package/src/__tests__/compaction.benchmark.test.ts +16 -14
- package/src/__tests__/computer-use-session-lifecycle.test.ts +10 -11
- package/src/__tests__/computer-use-session-working-dir.test.ts +2 -6
- package/src/__tests__/computer-use-skill-lifecycle-cleanup.test.ts +2 -5
- package/src/__tests__/computer-use-tools.test.ts +35 -31
- package/src/__tests__/config-schema.test.ts +11 -15
- package/src/__tests__/config-watcher.test.ts +0 -1
- package/src/__tests__/confirmation-request-guardian-bridge.test.ts +0 -1
- package/src/__tests__/conflict-store.test.ts +0 -1
- package/src/__tests__/connection-policy.test.ts +4 -7
- package/src/__tests__/contacts-tools.test.ts +0 -1
- package/src/__tests__/context-memory-e2e.test.ts +2 -4
- package/src/__tests__/context-overflow-reducer.test.ts +2 -4
- package/src/__tests__/context-window-manager.test.ts +147 -60
- package/src/__tests__/contradiction-checker.test.ts +0 -1
- package/src/__tests__/conversation-attention-store.test.ts +0 -1
- package/src/__tests__/conversation-attention-telegram.test.ts +1 -1
- package/src/__tests__/conversation-pairing.test.ts +2 -2
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +31 -7
- package/src/__tests__/conversation-routes-slash-commands.test.ts +381 -0
- package/src/__tests__/conversation-store.test.ts +0 -1
- package/src/__tests__/conversation-unread-route.test.ts +1 -2
- package/src/__tests__/credential-security-invariants.test.ts +8 -8
- package/src/__tests__/cross-provider-web-search.test.ts +353 -0
- package/src/__tests__/daemon-assistant-events.test.ts +6 -7
- package/src/__tests__/db-schedule-syntax-migration.test.ts +15 -3
- package/src/__tests__/delete-managed-skill-tool.test.ts +5 -9
- package/src/__tests__/deterministic-verification-control-plane.test.ts +0 -1
- package/src/__tests__/diagnostics-export.test.ts +189 -0
- package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +0 -1
- package/src/__tests__/emit-signal-routing-intent.test.ts +3 -3
- package/src/__tests__/entity-extractor.test.ts +0 -1
- package/src/__tests__/entity-search.test.ts +0 -1
- package/src/__tests__/ephemeral-permissions.test.ts +2 -4
- package/src/__tests__/error-handler-friendly-messages.test.ts +46 -0
- package/src/__tests__/file-read-tool.test.ts +86 -0
- package/src/__tests__/followup-tools.test.ts +0 -1
- package/src/__tests__/frontmatter.test.ts +77 -34
- package/src/__tests__/gateway-only-enforcement.test.ts +0 -1
- package/src/__tests__/gateway-only-guard.test.ts +1 -1
- package/src/__tests__/guardian-action-conversation-turn.test.ts +0 -1
- package/src/__tests__/guardian-action-followup-executor.test.ts +0 -1
- package/src/__tests__/guardian-action-followup-store.test.ts +0 -1
- package/src/__tests__/guardian-action-grant-mint-consume.test.ts +0 -1
- package/src/__tests__/guardian-action-late-reply.test.ts +0 -1
- package/src/__tests__/guardian-action-store.test.ts +0 -1
- package/src/__tests__/guardian-action-sweep.test.ts +0 -1
- package/src/__tests__/guardian-decision-primitive-canonical.test.ts +0 -1
- package/src/__tests__/guardian-dispatch.test.ts +1 -2
- package/src/__tests__/guardian-grant-minting.test.ts +1 -1
- package/src/__tests__/guardian-outbound-http.test.ts +0 -1
- package/src/__tests__/guardian-principal-id-roundtrip.test.ts +0 -1
- package/src/__tests__/guardian-routing-invariants.test.ts +1 -1
- package/src/__tests__/guardian-routing-state.test.ts +0 -1
- package/src/__tests__/guardian-verification-voice-binding.test.ts +0 -1
- package/src/__tests__/guardian-verify-setup-skill-regression.test.ts +3 -5
- package/src/__tests__/handlers-user-message-approval-consumption.test.ts +28 -426
- package/src/__tests__/host-bash-proxy.test.ts +335 -0
- package/src/__tests__/host-file-proxy.test.ts +374 -0
- package/src/__tests__/host-shell-tool.test.ts +147 -1
- package/src/__tests__/http-user-message-parity.test.ts +361 -0
- package/src/__tests__/inbound-invite-redemption.test.ts +0 -1
- package/src/__tests__/integration-status.test.ts +3 -8
- package/src/__tests__/intent-routing.test.ts +7 -46
- package/src/__tests__/invite-redemption-service.test.ts +0 -1
- package/src/__tests__/invite-routes-http.test.ts +0 -1
- package/src/__tests__/llm-usage-store.test.ts +0 -1
- package/src/__tests__/managed-avatar-client.test.ts +101 -55
- package/src/__tests__/managed-skill-lifecycle.test.ts +9 -18
- package/src/__tests__/managed-store.test.ts +94 -21
- package/src/__tests__/media-reuse-story.e2e.test.ts +0 -1
- package/src/__tests__/memory-context-benchmark.benchmark.test.ts +2 -4
- package/src/__tests__/memory-lifecycle-e2e.test.ts +0 -1
- package/src/__tests__/memory-recall-quality.test.ts +0 -1
- package/src/__tests__/memory-regressions.experimental.test.ts +0 -1
- package/src/__tests__/memory-regressions.test.ts +0 -1
- package/src/__tests__/memory-retrieval.benchmark.test.ts +0 -1
- package/src/__tests__/memory-upsert-concurrency.test.ts +0 -1
- package/src/__tests__/messaging-send-tool.test.ts +35 -0
- package/src/__tests__/messaging-skill-split.test.ts +138 -0
- package/src/__tests__/migration-cross-version-compatibility.test.ts +0 -1
- package/src/__tests__/migration-export-http.test.ts +2 -3
- package/src/__tests__/migration-import-commit-http.test.ts +1 -2
- package/src/__tests__/migration-import-preflight-http.test.ts +1 -2
- package/src/__tests__/migration-validate-http.test.ts +1 -2
- package/src/__tests__/native-web-search.test.ts +475 -0
- package/src/__tests__/navigate-settings-tab.test.ts +84 -0
- package/src/__tests__/non-member-access-request.test.ts +0 -1
- package/src/__tests__/notification-broadcaster.test.ts +15 -15
- package/src/__tests__/notification-decision-strategy.test.ts +6 -6
- package/src/__tests__/notification-deep-link.test.ts +7 -7
- package/src/__tests__/notification-guardian-path.test.ts +2 -3
- package/src/__tests__/notification-telegram-adapter.test.ts +1 -1
- package/src/__tests__/notification-thread-candidates.test.ts +4 -4
- package/src/__tests__/onboarding-starter-tasks.test.ts +0 -1
- package/src/__tests__/onboarding-template-contract.test.ts +0 -10
- package/src/__tests__/playbook-execution.test.ts +0 -1
- package/src/__tests__/playbook-tools.test.ts +0 -1
- package/src/__tests__/profile-compiler.test.ts +0 -1
- package/src/__tests__/provider-fail-open-selection.test.ts +12 -2
- package/src/__tests__/provider-managed-proxy-integration.test.ts +25 -0
- package/src/__tests__/qdrant-collection-migration.test.ts +223 -0
- package/src/__tests__/recording-handler.test.ts +30 -94
- package/src/__tests__/registry.test.ts +28 -35
- package/src/__tests__/relay-server.test.ts +0 -1
- package/src/__tests__/ride-shotgun-handler.test.ts +4 -20
- package/src/__tests__/runtime-attachment-metadata.test.ts +0 -1
- package/src/__tests__/runtime-events-sse-parity.test.ts +3 -4
- package/src/__tests__/runtime-events-sse.test.ts +0 -1
- package/src/__tests__/sandbox-diagnostics.test.ts +0 -1
- package/src/__tests__/scaffold-managed-skill-tool.test.ts +30 -28
- package/src/__tests__/schedule-store.test.ts +441 -1
- package/src/__tests__/schedule-tools.test.ts +468 -7
- package/src/__tests__/scheduler-recurrence.test.ts +196 -23
- package/src/__tests__/scoped-approval-grants.test.ts +0 -1
- package/src/__tests__/scoped-grant-security-matrix.test.ts +0 -1
- package/src/__tests__/secret-prompt-log-hygiene.test.ts +6 -3
- package/src/__tests__/secret-response-routing.test.ts +4 -1
- package/src/__tests__/send-endpoint-busy.test.ts +14 -5
- package/src/__tests__/send-notification-tool.test.ts +0 -7
- package/src/__tests__/sequence-store.test.ts +0 -1
- package/src/__tests__/server-history-render.test.ts +1 -2
- package/src/__tests__/session-abort-tool-results.test.ts +0 -1
- package/src/__tests__/session-agent-loop.test.ts +46 -6
- package/src/__tests__/session-confirmation-signals.test.ts +7 -46
- package/src/__tests__/session-conflict-gate.test.ts +2 -6
- package/src/__tests__/session-error.test.ts +5 -14
- package/src/__tests__/session-init.benchmark.test.ts +3 -5
- package/src/__tests__/session-load-history-repair.test.ts +0 -1
- package/src/__tests__/session-media-retry.test.ts +12 -74
- package/src/__tests__/session-pre-run-repair.test.ts +0 -1
- package/src/__tests__/session-profile-injection.test.ts +2 -6
- package/src/__tests__/session-provider-retry-repair.test.ts +2 -6
- package/src/__tests__/session-queue.test.ts +94 -139
- package/src/__tests__/session-skill-tools.test.ts +115 -115
- package/src/__tests__/session-slash-known.test.ts +0 -1
- package/src/__tests__/session-slash-queue.test.ts +0 -1
- package/src/__tests__/session-slash-unknown.test.ts +0 -1
- package/src/__tests__/session-surfaces-task-progress.test.ts +34 -0
- package/src/__tests__/session-usage.test.ts +0 -1
- package/src/__tests__/session-workspace-cache-state.test.ts +2 -6
- package/src/__tests__/session-workspace-injection.test.ts +2 -6
- package/src/__tests__/session-workspace-tool-tracking.test.ts +2 -6
- package/src/__tests__/skill-feature-flags-integration.test.ts +180 -184
- package/src/__tests__/skill-feature-flags.test.ts +125 -18
- package/src/__tests__/skill-load-feature-flag.test.ts +1 -2
- package/src/__tests__/skill-load-tool.test.ts +194 -2
- package/src/__tests__/skill-projection-feature-flag.test.ts +27 -16
- package/src/__tests__/skill-projection.benchmark.test.ts +15 -14
- package/src/__tests__/skills.test.ts +14 -53
- package/src/__tests__/slack-channel-config.test.ts +0 -1
- package/src/__tests__/slack-inbound-verification.test.ts +0 -1
- package/src/__tests__/slack-skill.test.ts +1 -1
- package/src/__tests__/starter-task-flow.test.ts +9 -19
- package/src/__tests__/subagent-tools.test.ts +2 -2
- package/src/__tests__/system-prompt.test.ts +7 -7
- package/src/__tests__/task-compiler.test.ts +0 -1
- package/src/__tests__/task-management-tools.test.ts +0 -1
- package/src/__tests__/task-memory-cleanup.test.ts +0 -1
- package/src/__tests__/task-runner.test.ts +0 -1
- package/src/__tests__/task-scheduler.test.ts +0 -1
- package/src/__tests__/terminal-tools.test.ts +0 -1
- package/src/__tests__/test-support/computer-use-skill-harness.ts +2 -4
- package/src/__tests__/thread-seed-composer.test.ts +5 -5
- package/src/__tests__/tool-approval-handler.test.ts +0 -1
- package/src/__tests__/tool-execution-abort-cleanup.test.ts +0 -1
- package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +0 -1
- package/src/__tests__/tool-executor.test.ts +8 -86
- package/src/__tests__/tool-grant-request-escalation.test.ts +0 -1
- package/src/__tests__/tool-notification-listener.test.ts +1 -1
- package/src/__tests__/tool-preview-lifecycle.test.ts +416 -0
- package/src/__tests__/trust-store.test.ts +84 -8
- package/src/__tests__/trusted-contact-approval-notifier.test.ts +0 -1
- package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +0 -1
- package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +0 -1
- package/src/__tests__/trusted-contact-multichannel.test.ts +0 -1
- package/src/__tests__/trusted-contact-verification.test.ts +0 -1
- package/src/__tests__/twilio-provider.test.ts +0 -1
- package/src/__tests__/twilio-routes.test.ts +0 -1
- package/src/__tests__/{request-file-tool.test.ts → ui-file-upload-surface.test.ts} +11 -72
- package/src/__tests__/update-bulletin.test.ts +0 -1
- package/src/__tests__/usage-cache-backfill-migration.test.ts +0 -1
- package/src/__tests__/usage-routes.test.ts +0 -1
- package/src/__tests__/verification-control-plane-policy.test.ts +4 -4
- package/src/__tests__/voice-invite-redemption.test.ts +0 -1
- package/src/__tests__/voice-scoped-grant-consumer.test.ts +0 -1
- package/src/__tests__/voice-session-bridge.test.ts +9 -1
- package/src/__tests__/web-fetch.test.ts +57 -0
- package/src/__tests__/workspace-git-service.test.ts +5 -14
- package/src/__tests__/workspace-policy.test.ts +0 -1
- package/src/agent/loop.ts +22 -34
- package/src/bundler/bundle-signer.ts +4 -4
- package/src/calls/call-controller.ts +1 -1
- package/src/calls/relay-server.ts +1 -1
- package/src/calls/twilio-rest.ts +1 -1
- package/src/calls/voice-session-bridge.ts +3 -1
- package/src/cli/__tests__/notifications.test.ts +3 -4
- package/src/cli/commands/map.ts +2 -6
- package/src/cli/commands/mcp.ts +73 -15
- package/src/cli/commands/notifications.ts +4 -4
- package/src/cli/commands/sessions.ts +9 -1
- package/src/cli/commands/skills.ts +6 -10
- package/src/cli/http-client.ts +2 -3
- package/src/cli/main-screen.tsx +10 -10
- package/src/cli/program.ts +0 -4
- package/src/cli/reference.ts +0 -2
- package/src/cli.ts +15 -9
- package/src/config/__tests__/bundled-tool-registry-guard.test.ts +120 -0
- package/src/config/bundled-skills/_shared/CLI_RETRIEVAL_PATTERN.md +11 -0
- package/src/config/bundled-skills/app-builder/SKILL.md +6 -7
- package/src/config/bundled-skills/app-builder/TOOLS.json +0 -4
- package/src/config/bundled-skills/browser/SKILL.md +6 -1
- package/src/config/bundled-skills/chatgpt-import/SKILL.md +5 -1
- package/src/config/bundled-skills/claude-code/SKILL.md +5 -1
- package/src/config/bundled-skills/computer-use/SKILL.md +6 -1
- package/src/config/bundled-skills/computer-use/TOOLS.json +6 -69
- package/src/config/bundled-skills/computer-use/tools/computer-use-click.ts +10 -1
- package/src/config/bundled-skills/contacts/SKILL.md +10 -1
- package/src/config/bundled-skills/contacts/TOOLS.json +35 -0
- package/src/config/bundled-skills/{messaging → contacts}/tools/google-contacts.ts +9 -2
- package/src/config/bundled-skills/document/SKILL.md +4 -1
- package/src/config/bundled-skills/doordash/SKILL.md +8 -2
- package/src/config/bundled-skills/doordash/__tests__/doordash-session.test.ts +1 -82
- package/src/config/bundled-skills/doordash/doordash-cli.ts +17 -28
- package/src/config/bundled-skills/doordash/lib/session.ts +21 -17
- package/src/config/bundled-skills/doordash/lib/shared/platform.ts +4 -1
- package/src/config/bundled-skills/followups/SKILL.md +4 -1
- package/src/config/bundled-skills/gmail/SKILL.md +180 -0
- package/src/config/bundled-skills/gmail/TOOLS.json +506 -0
- package/src/config/bundled-skills/gmail/tools/gmail-archive.ts +149 -0
- package/src/config/bundled-skills/gmail/tools/gmail-attachments.ts +110 -0
- package/src/config/bundled-skills/{messaging → gmail}/tools/gmail-draft.ts +1 -1
- package/src/config/bundled-skills/{messaging → gmail}/tools/gmail-filters.ts +1 -1
- package/src/config/bundled-skills/{messaging → gmail}/tools/gmail-follow-up.ts +1 -1
- package/src/config/bundled-skills/{messaging → gmail}/tools/gmail-forward.ts +1 -1
- package/src/config/bundled-skills/gmail/tools/gmail-label.ts +50 -0
- package/src/config/bundled-skills/{messaging → gmail}/tools/gmail-outreach-scan.ts +8 -90
- package/src/config/bundled-skills/{messaging → gmail}/tools/gmail-send-draft.ts +1 -1
- package/src/config/bundled-skills/{messaging → gmail}/tools/gmail-sender-digest.ts +2 -2
- package/src/config/bundled-skills/{messaging → gmail}/tools/gmail-trash.ts +1 -1
- package/src/config/bundled-skills/{messaging → gmail}/tools/gmail-unsubscribe.ts +1 -1
- package/src/config/bundled-skills/{messaging → gmail}/tools/gmail-vacation.ts +1 -1
- package/src/config/bundled-skills/gmail/tools/shared.ts +47 -0
- package/src/config/bundled-skills/google-calendar/SKILL.md +5 -1
- package/src/config/bundled-skills/image-studio/SKILL.md +5 -1
- package/src/config/bundled-skills/knowledge-graph/SKILL.md +4 -1
- package/src/config/bundled-skills/media-processing/SKILL.md +7 -13
- package/src/config/bundled-skills/media-processing/TOOLS.json +0 -22
- package/src/config/bundled-skills/media-processing/tools/generate-clip.ts +12 -1
- package/src/config/bundled-skills/messaging/SKILL.md +23 -139
- package/src/config/bundled-skills/messaging/TOOLS.json +33 -1215
- package/src/config/bundled-skills/messaging/tools/gmail-mime-helpers.ts +42 -0
- package/src/config/bundled-skills/messaging/tools/messaging-send.ts +165 -2
- package/src/config/bundled-skills/messaging/tools/messaging-sender-digest.ts +1 -13
- package/src/config/bundled-skills/messaging/tools/shared.ts +81 -34
- package/src/config/bundled-skills/notifications/SKILL.md +5 -1
- package/src/config/bundled-skills/orchestration/SKILL.md +30 -0
- package/src/config/bundled-skills/orchestration/TOOLS.json +35 -0
- package/src/config/bundled-skills/{reminder/tools/reminder-cancel.ts → orchestration/tools/swarm-delegate.ts} +3 -3
- package/src/config/bundled-skills/phone-calls/SKILL.md +9 -1
- package/src/config/bundled-skills/playbooks/SKILL.md +4 -1
- package/src/config/bundled-skills/schedule/SKILL.md +70 -9
- package/src/config/bundled-skills/schedule/TOOLS.json +38 -6
- package/src/config/bundled-skills/screen-watch/SKILL.md +28 -0
- package/src/config/bundled-skills/screen-watch/TOOLS.json +35 -0
- package/src/config/bundled-skills/{reminder/tools/reminder-create.ts → screen-watch/tools/start-screen-watch.ts} +3 -3
- package/src/config/bundled-skills/sequences/SKILL.md +47 -0
- package/src/config/bundled-skills/sequences/TOOLS.json +340 -0
- package/src/config/bundled-skills/sequences/tools/sequence-update.ts +128 -0
- package/src/config/bundled-skills/sequences/tools/shared.ts +9 -0
- package/src/config/bundled-skills/settings/SKILL.md +12 -0
- package/src/config/bundled-skills/settings/TOOLS.json +112 -0
- package/src/config/bundled-skills/settings/tools/navigate-settings-tab.ts +43 -0
- package/src/config/bundled-skills/settings/tools/open-system-settings.ts +52 -0
- package/src/config/bundled-skills/{computer-use/tools/computer-use-right-click.ts → settings/tools/set-avatar.ts} +2 -6
- package/src/{tools/system/voice-config.ts → config/bundled-skills/settings/tools/voice-config-update.ts} +59 -96
- package/src/config/bundled-skills/skill-management/SKILL.md +18 -0
- package/src/config/bundled-skills/skill-management/TOOLS.json +90 -0
- package/src/config/bundled-skills/{computer-use/tools/computer-use-double-click.ts → skill-management/tools/delete-managed.ts} +2 -6
- package/src/config/bundled-skills/skill-management/tools/scaffold-managed.ts +12 -0
- package/src/config/bundled-skills/slack/SKILL.md +5 -1
- package/src/config/bundled-skills/subagent/SKILL.md +4 -1
- package/src/config/bundled-skills/tasks/SKILL.md +5 -2
- package/src/config/bundled-skills/transcribe/SKILL.md +4 -1
- package/src/config/bundled-skills/watcher/SKILL.md +4 -1
- package/src/config/bundled-tool-registry.ts +118 -107
- package/src/config/env.ts +5 -2
- package/src/config/feature-flag-registry.json +33 -9
- package/src/config/loader.ts +10 -2
- package/src/config/schema.ts +19 -16
- package/src/config/schemas/inference.ts +12 -22
- package/src/config/schemas/memory-storage.ts +19 -1
- package/src/config/schemas/platform.ts +0 -16
- package/src/config/skill-state.ts +11 -8
- package/src/config/skills.ts +83 -32
- package/src/context/token-estimator.ts +11 -0
- package/src/context/window-manager.ts +180 -151
- package/src/daemon/computer-use-session.ts +11 -43
- package/src/daemon/daemon-control.ts +4 -1
- package/src/daemon/handlers/config-channels.ts +5 -9
- package/src/daemon/handlers/config-ingress.ts +0 -4
- package/src/daemon/handlers/config-model.ts +7 -13
- package/src/daemon/handlers/config-telegram.ts +4 -8
- package/src/daemon/handlers/config-voice.ts +2 -5
- package/src/daemon/handlers/dictation.ts +2 -12
- package/src/daemon/handlers/identity.ts +0 -105
- package/src/daemon/handlers/recording.ts +3 -23
- package/src/daemon/handlers/session-history.ts +42 -10
- package/src/daemon/handlers/sessions.ts +53 -72
- package/src/daemon/handlers/shared.ts +7 -28
- package/src/daemon/handlers/skills.ts +31 -27
- package/src/daemon/host-bash-proxy.ts +148 -0
- package/src/daemon/host-file-proxy.ts +135 -0
- package/src/daemon/lifecycle.ts +53 -41
- package/src/daemon/mcp-reload-service.ts +123 -0
- package/src/daemon/message-protocol.ts +6 -0
- package/src/daemon/message-types/apps.ts +0 -25
- package/src/daemon/message-types/browser.ts +1 -1
- package/src/daemon/message-types/computer-use.ts +1 -4
- package/src/daemon/message-types/guardian-actions.ts +1 -1
- package/src/daemon/message-types/host-bash.ts +18 -0
- package/src/daemon/message-types/host-file.ts +44 -0
- package/src/daemon/message-types/integrations.ts +1 -73
- package/src/daemon/message-types/messages.ts +15 -0
- package/src/daemon/message-types/schedules.ts +11 -27
- package/src/daemon/message-types/sessions.ts +8 -2
- package/src/daemon/message-types/settings.ts +1 -1
- package/src/daemon/message-types/shared.ts +1 -1
- package/src/daemon/message-types/surfaces.ts +2 -0
- package/src/daemon/ride-shotgun-handler.ts +35 -43
- package/src/daemon/seed-files.ts +3 -27
- package/src/daemon/server.ts +45 -28
- package/src/daemon/session-agent-loop-handlers.ts +72 -9
- package/src/daemon/session-agent-loop.ts +97 -66
- package/src/daemon/session-attachments.ts +1 -1
- package/src/daemon/session-error.ts +17 -16
- package/src/daemon/session-lifecycle.ts +20 -1
- package/src/daemon/session-media-retry.ts +1 -15
- package/src/daemon/session-messaging.ts +14 -6
- package/src/daemon/session-process.ts +36 -7
- package/src/daemon/session-queue-manager.ts +62 -103
- package/src/daemon/session-runtime-assembly.ts +27 -7
- package/src/daemon/session-skill-tools.ts +12 -11
- package/src/daemon/session-slash.ts +7 -0
- package/src/daemon/session-surfaces.ts +192 -118
- package/src/daemon/session-tool-setup.ts +146 -6
- package/src/daemon/session.ts +75 -37
- package/src/errors.ts +0 -2
- package/src/export/formatter.ts +6 -0
- package/src/mcp/mcp-oauth-provider.ts +1 -3
- package/src/media/avatar-router.ts +20 -28
- package/src/media/avatar-types.ts +7 -14
- package/src/media/managed-avatar-client.ts +70 -34
- package/src/memory/app-store.ts +0 -18
- package/src/memory/conversation-title-service.ts +1 -2
- package/src/memory/db-init.ts +16 -0
- package/src/memory/embedding-backend.ts +129 -27
- package/src/memory/embedding-gemini.test.ts +256 -0
- package/src/memory/embedding-gemini.ts +47 -13
- package/src/memory/embedding-local.ts +14 -2
- package/src/memory/embedding-ollama.ts +15 -2
- package/src/memory/embedding-openai.ts +15 -2
- package/src/memory/embedding-types.test.ts +116 -0
- package/src/memory/embedding-types.ts +61 -0
- package/src/memory/fingerprint.ts +1 -1
- package/src/memory/indexer.ts +25 -1
- package/src/memory/job-handlers/embedding.test.ts +258 -0
- package/src/memory/job-handlers/embedding.ts +81 -1
- package/src/memory/job-handlers/index-maintenance.ts +35 -1
- package/src/memory/job-handlers/media-processing.ts +11 -1
- package/src/memory/job-utils.ts +21 -6
- package/src/memory/jobs-store.ts +5 -1
- package/src/memory/jobs-worker.ts +8 -0
- package/src/memory/message-content.ts +66 -0
- package/src/memory/migrations/100-core-tables.ts +1 -31
- package/src/memory/migrations/104-core-indexes.ts +0 -11
- package/src/memory/migrations/145-drop-accounts-table.ts +19 -0
- package/src/memory/migrations/146-schedule-oneshot-routing.ts +94 -0
- package/src/memory/migrations/147-migrate-reminders-to-schedules.ts +129 -0
- package/src/memory/migrations/148-drop-reminders-table.ts +18 -0
- package/src/memory/migrations/index.ts +4 -0
- package/src/memory/migrations/registry.ts +19 -0
- package/src/memory/qdrant-client.ts +158 -43
- package/src/memory/retriever.test.ts +0 -1
- package/src/memory/retriever.ts +12 -2
- package/src/memory/schema/infrastructure.ts +5 -37
- package/src/memory/search/formatting.ts +34 -9
- package/src/memory/search/semantic.ts +57 -2
- package/src/memory/search/types.ts +2 -1
- package/src/notifications/AGENTS.md +2 -2
- package/src/notifications/README.md +59 -58
- package/src/notifications/adapters/macos.ts +1 -1
- package/src/notifications/broadcaster.ts +5 -5
- package/src/notifications/copy-composer.ts +1 -1
- package/src/notifications/decision-engine.ts +2 -2
- package/src/notifications/destination-resolver.ts +2 -2
- package/src/notifications/emit-signal.ts +8 -8
- package/src/notifications/signal.ts +1 -1
- package/src/notifications/thread-seed-composer.ts +1 -1
- package/src/oauth/connect-orchestrator.ts +1 -1
- package/src/oauth/token-persistence.ts +1 -1
- package/src/permissions/checker.ts +12 -1
- package/src/permissions/defaults.ts +13 -17
- package/src/permissions/trust-store.ts +37 -0
- package/src/permissions/workspace-policy.ts +0 -1
- package/src/prompts/__tests__/build-cli-reference-section.test.ts +11 -0
- package/src/prompts/computer-use-prompt.ts +1 -1
- package/src/prompts/system-prompt.ts +33 -35
- package/src/prompts/templates/BOOTSTRAP.md +0 -3
- package/src/prompts/templates/SOUL.md +1 -2
- package/src/prompts/templates/UPDATES.md +16 -7
- package/src/providers/anthropic/client.ts +87 -33
- package/src/providers/gemini/client.ts +6 -0
- package/src/providers/managed-proxy/constants.ts +5 -0
- package/src/providers/openai/client.ts +15 -0
- package/src/providers/registry.ts +4 -6
- package/src/providers/types.ts +24 -2
- package/src/runtime/AGENTS.md +18 -0
- package/src/runtime/assistant-event-hub.ts +2 -3
- package/src/runtime/assistant-event.ts +4 -4
- package/src/runtime/auth/__tests__/context.test.ts +5 -5
- package/src/runtime/auth/__tests__/credential-service.test.ts +0 -1
- package/src/runtime/auth/__tests__/guard-tests.test.ts +3 -2
- package/src/runtime/auth/__tests__/{ipc-auth-context.test.ts → local-auth-context.test.ts} +21 -21
- package/src/runtime/auth/__tests__/route-policy.test.ts +2 -2
- package/src/runtime/auth/__tests__/scopes.test.ts +9 -8
- package/src/runtime/auth/__tests__/subject.test.ts +8 -8
- package/src/runtime/auth/__tests__/token-service.test.ts +0 -1
- package/src/runtime/auth/route-policy.ts +8 -8
- package/src/runtime/auth/scopes.ts +2 -1
- package/src/runtime/auth/subject.ts +4 -4
- package/src/runtime/auth/token-service.ts +1 -24
- package/src/runtime/auth/types.ts +3 -3
- package/src/runtime/guardian-action-followup-executor.ts +1 -1
- package/src/runtime/guardian-action-grant-minter.ts +1 -1
- package/src/runtime/guardian-action-service.ts +3 -3
- package/src/runtime/http-server.ts +15 -2
- package/src/runtime/http-types.ts +10 -0
- package/src/runtime/invite-service.ts +3 -3
- package/src/runtime/local-actor-identity.ts +17 -22
- package/src/runtime/middleware/error-handler.ts +14 -1
- package/src/runtime/pending-interactions.ts +21 -9
- package/src/runtime/routes/app-management-routes.ts +63 -67
- package/src/runtime/routes/approval-routes.ts +1 -3
- package/src/runtime/routes/brain-graph/brain-graph.html +1845 -0
- package/src/runtime/routes/brain-graph-routes.ts +4 -42
- package/src/runtime/routes/btw-routes.ts +155 -0
- package/src/runtime/routes/computer-use-routes.ts +77 -31
- package/src/runtime/routes/conversation-routes.ts +234 -47
- package/src/runtime/routes/diagnostics-routes.ts +154 -43
- package/src/runtime/routes/documents-routes.ts +2 -2
- package/src/runtime/routes/global-search-routes.ts +1 -1
- package/src/runtime/routes/host-bash-routes.ts +83 -0
- package/src/runtime/routes/host-file-routes.ts +79 -0
- package/src/runtime/routes/integrations/slack/share.ts +1 -1
- package/src/runtime/routes/log-export-routes.ts +120 -0
- package/src/runtime/routes/mcp-routes.ts +20 -0
- package/src/runtime/routes/migration-routes.ts +3 -3
- package/src/runtime/routes/pairing-routes.ts +1 -1
- package/src/runtime/routes/recording-routes.ts +6 -4
- package/src/runtime/routes/schedule-routes.ts +31 -5
- package/src/runtime/routes/session-management-routes.ts +2 -6
- package/src/runtime/routes/session-query-routes.ts +18 -15
- package/src/runtime/routes/settings-routes.ts +7 -351
- package/src/runtime/routes/skills-routes.ts +7 -6
- package/src/runtime/routes/subagents-routes.ts +4 -10
- package/src/runtime/routes/surface-action-routes.ts +3 -14
- package/src/runtime/routes/surface-content-routes.ts +22 -5
- package/src/runtime/routes/work-items-routes.ts +21 -25
- package/src/runtime/routes/workspace-routes.test.ts +3 -3
- package/src/runtime/routes/workspace-utils.ts +1 -1
- package/src/runtime/telegram-streaming-delivery.ts +3 -0
- package/src/runtime/verification-outbound-actions.ts +2 -2
- package/src/schedule/integration-status.ts +0 -6
- package/src/schedule/schedule-store.ts +234 -43
- package/src/schedule/scheduler.ts +73 -74
- package/src/security/oauth2.ts +1 -1
- package/src/sequence/store.ts +12 -2
- package/src/skills/frontmatter.ts +19 -77
- package/src/skills/managed-store.ts +11 -2
- package/src/subagent/manager.ts +5 -3
- package/src/tasks/ephemeral-permissions.ts +3 -5
- package/src/tools/AGENTS.md +37 -0
- package/src/tools/apps/executors.ts +0 -6
- package/src/tools/browser/browser-manager.ts +17 -11
- package/src/tools/browser/jit-auth.ts +4 -1
- package/src/tools/claude-code/claude-code.ts +1 -1
- package/src/tools/computer-use/definitions.ts +48 -60
- package/src/tools/document/document-tool.ts +6 -6
- package/src/tools/document/editor-template.ts +10 -8
- package/src/tools/filesystem/edit.ts +2 -1
- package/src/tools/filesystem/read.ts +20 -2
- package/src/tools/filesystem/write.ts +2 -1
- package/src/tools/host-filesystem/edit.ts +17 -1
- package/src/tools/host-filesystem/read.ts +16 -1
- package/src/tools/host-filesystem/write.ts +15 -1
- package/src/tools/host-terminal/host-shell.ts +24 -0
- package/src/tools/memory/definitions.ts +45 -81
- package/src/tools/memory/handlers.test.ts +0 -1
- package/src/tools/memory/handlers.ts +1 -1
- package/src/tools/memory/register.ts +26 -60
- package/src/tools/network/script-proxy/session-manager.ts +6 -8
- package/src/tools/network/web-fetch.ts +7 -1
- package/src/tools/network/web-search.ts +2 -1
- package/src/tools/registry.ts +23 -0
- package/src/tools/schedule/create.ts +113 -5
- package/src/tools/schedule/list.ts +57 -15
- package/src/tools/schedule/update.ts +73 -3
- package/src/tools/shared/filesystem/image-read.ts +192 -0
- package/src/tools/side-effects.ts +1 -7
- package/src/tools/skills/delete-managed.ts +27 -64
- package/src/tools/skills/execute.ts +54 -0
- package/src/tools/skills/load.ts +127 -5
- package/src/tools/skills/scaffold-managed.ts +93 -172
- package/src/tools/subagent/message.ts +0 -7
- package/src/tools/subagent/spawn.ts +1 -1
- package/src/tools/swarm/delegate.ts +0 -3
- package/src/tools/system/avatar-generator.ts +13 -19
- package/src/tools/system/request-permission.ts +2 -1
- package/src/tools/terminal/safe-env.ts +1 -0
- package/src/tools/tool-manifest.ts +41 -47
- package/src/tools/types.ts +6 -2
- package/src/tools/ui-surface/definitions.ts +0 -55
- package/src/util/errors.ts +12 -10
- package/src/workspace/git-service.ts +0 -2
- package/src/__tests__/account-registry.test.ts +0 -258
- package/src/__tests__/email-classifier.test.ts +0 -25
- package/src/__tests__/gmail-integration.test.ts +0 -97
- package/src/__tests__/handle-user-message-secret-resume.test.ts +0 -172
- package/src/__tests__/home-base-bootstrap.test.ts +0 -84
- package/src/__tests__/managed-twitter-guardrails.test.ts +0 -353
- package/src/__tests__/prebuilt-home-base-seed.test.ts +0 -79
- package/src/__tests__/recording-intent-fallback.test.ts +0 -199
- package/src/__tests__/recording-intent.test.ts +0 -985
- package/src/__tests__/recording-state-machine.test.ts +0 -1574
- package/src/__tests__/reminder-store.test.ts +0 -350
- package/src/__tests__/reminder.test.ts +0 -337
- package/src/__tests__/scan-result-store.test.ts +0 -121
- package/src/__tests__/twitter-platform-proxy-client.test.ts +0 -450
- package/src/__tests__/view-image-tool.test.ts +0 -241
- package/src/cli/commands/amazon/cart.ts +0 -513
- package/src/cli/commands/amazon/checkout.ts +0 -394
- package/src/cli/commands/amazon/client.ts +0 -513
- package/src/cli/commands/amazon/index.ts +0 -920
- package/src/cli/commands/amazon/product-details.ts +0 -145
- package/src/cli/commands/amazon/request-extractor.ts +0 -187
- package/src/cli/commands/amazon/search.ts +0 -76
- package/src/cli/commands/amazon/session.ts +0 -116
- package/src/cli/commands/twitter/__tests__/cli-error-shaping.test.ts +0 -265
- package/src/cli/commands/twitter/__tests__/cli-read-routing.test.ts +0 -483
- package/src/cli/commands/twitter/__tests__/cli-routing.test.ts +0 -412
- package/src/cli/commands/twitter/__tests__/oauth-client.test.ts +0 -197
- package/src/cli/commands/twitter/client.ts +0 -989
- package/src/cli/commands/twitter/index.ts +0 -1160
- package/src/cli/commands/twitter/oauth-client.ts +0 -94
- package/src/cli/commands/twitter/router.ts +0 -396
- package/src/cli/commands/twitter/session.ts +0 -121
- package/src/config/bundled-skills/agentmail/SKILL.md +0 -132
- package/src/config/bundled-skills/agentmail/icon.svg +0 -21
- package/src/config/bundled-skills/amazon/SKILL.md +0 -137
- package/src/config/bundled-skills/amazon/icon.svg +0 -13
- package/src/config/bundled-skills/api-mapping/SKILL.md +0 -78
- package/src/config/bundled-skills/api-mapping/icon.svg +0 -18
- package/src/config/bundled-skills/cli-discover/SKILL.md +0 -68
- package/src/config/bundled-skills/deploy-fullstack-vercel/SKILL.md +0 -179
- package/src/config/bundled-skills/document-writer/SKILL.md +0 -195
- package/src/config/bundled-skills/elevenlabs-voice/SKILL.md +0 -140
- package/src/config/bundled-skills/email-setup/SKILL.md +0 -68
- package/src/config/bundled-skills/frontend-design/SKILL.md +0 -44
- package/src/config/bundled-skills/frontend-design/icon.svg +0 -16
- package/src/config/bundled-skills/google-oauth-setup/SKILL.md +0 -452
- package/src/config/bundled-skills/guardian-verify-setup/SKILL.md +0 -203
- package/src/config/bundled-skills/influencer/SKILL.md +0 -144
- package/src/config/bundled-skills/influencer/scripts/client.ts +0 -1269
- package/src/config/bundled-skills/influencer/scripts/influencer.ts +0 -267
- package/src/config/bundled-skills/macos-automation/SKILL.md +0 -65
- package/src/config/bundled-skills/macos-automation/icon.svg +0 -12
- package/src/config/bundled-skills/mcp-setup/SKILL.md +0 -75
- package/src/config/bundled-skills/media-processing/tools/media-diagnostics.ts +0 -184
- package/src/config/bundled-skills/messaging/tools/gmail-archive-by-query.ts +0 -80
- package/src/config/bundled-skills/messaging/tools/gmail-archive.ts +0 -29
- package/src/config/bundled-skills/messaging/tools/gmail-batch-archive.ts +0 -56
- package/src/config/bundled-skills/messaging/tools/gmail-batch-label.ts +0 -34
- package/src/config/bundled-skills/messaging/tools/gmail-download-attachment.ts +0 -47
- package/src/config/bundled-skills/messaging/tools/gmail-label.ts +0 -31
- package/src/config/bundled-skills/messaging/tools/gmail-list-attachments.ts +0 -67
- package/src/config/bundled-skills/messaging/tools/gmail-send-with-attachments.ts +0 -97
- package/src/config/bundled-skills/messaging/tools/gmail-summarize-thread.ts +0 -87
- package/src/config/bundled-skills/messaging/tools/gmail-triage.ts +0 -135
- package/src/config/bundled-skills/messaging/tools/messaging-analyze-activity.ts +0 -24
- package/src/config/bundled-skills/messaging/tools/messaging-reply.ts +0 -201
- package/src/config/bundled-skills/messaging/tools/send-notification.ts +0 -1
- package/src/config/bundled-skills/messaging/tools/sequence-cancel.ts +0 -27
- package/src/config/bundled-skills/messaging/tools/sequence-pause.ts +0 -48
- package/src/config/bundled-skills/messaging/tools/sequence-resume.ts +0 -27
- package/src/config/bundled-skills/messaging/tools/sequence-update.ts +0 -56
- package/src/config/bundled-skills/notion/SKILL.md +0 -240
- package/src/config/bundled-skills/notion-oauth-setup/SKILL.md +0 -126
- package/src/config/bundled-skills/oauth-setup/SKILL.md +0 -143
- package/src/config/bundled-skills/public-ingress/SKILL.md +0 -258
- package/src/config/bundled-skills/reminder/SKILL.md +0 -79
- package/src/config/bundled-skills/reminder/TOOLS.json +0 -89
- package/src/config/bundled-skills/reminder/tools/reminder-list.ts +0 -12
- package/src/config/bundled-skills/restaurant-reservation/SKILL.md +0 -141
- package/src/config/bundled-skills/screen-recording/SKILL.md +0 -148
- package/src/config/bundled-skills/self-upgrade/SKILL.md +0 -69
- package/src/config/bundled-skills/skills-catalog/SKILL.md +0 -78
- package/src/config/bundled-skills/slack-app-setup/SKILL.md +0 -178
- package/src/config/bundled-skills/slack-digest-setup/SKILL.md +0 -163
- package/src/config/bundled-skills/slack-oauth-setup/SKILL.md +0 -157
- package/src/config/bundled-skills/start-the-day/SKILL.md +0 -70
- package/src/config/bundled-skills/start-the-day/icon.svg +0 -13
- package/src/config/bundled-skills/telegram-setup/SKILL.md +0 -105
- package/src/config/bundled-skills/time-based-actions/SKILL.md +0 -142
- package/src/config/bundled-skills/twilio-setup/SKILL.md +0 -232
- package/src/config/bundled-skills/twitter/SKILL.md +0 -319
- package/src/config/bundled-skills/twitter/icon.svg +0 -14
- package/src/config/bundled-skills/typescript-eval/SKILL.md +0 -60
- package/src/config/bundled-skills/vercel-token-setup/SKILL.md +0 -214
- package/src/config/bundled-skills/voice-setup/SKILL.md +0 -131
- package/src/config/bundled-skills/voice-setup/icon.svg +0 -20
- package/src/daemon/handlers/pairing.ts +0 -119
- package/src/daemon/handlers/session-user-message.ts +0 -961
- package/src/daemon/recording-executor.ts +0 -180
- package/src/daemon/recording-intent-fallback.ts +0 -162
- package/src/daemon/recording-intent.ts +0 -493
- package/src/home-base/app-link-store.ts +0 -78
- package/src/home-base/bootstrap.ts +0 -74
- package/src/home-base/prebuilt/brain-graph.html +0 -1483
- package/src/home-base/prebuilt/index.html +0 -702
- package/src/home-base/prebuilt/seed-metadata.json +0 -21
- package/src/home-base/prebuilt/seed.ts +0 -122
- package/src/home-base/prebuilt-home-base-updater.ts +0 -36
- package/src/memory/account-store.ts +0 -117
- package/src/messaging/activity-analyzer.ts +0 -76
- package/src/messaging/email-classifier.ts +0 -208
- package/src/messaging/index.ts +0 -2
- package/src/messaging/outreach-classifier.ts +0 -185
- package/src/messaging/thread-summarizer.ts +0 -346
- package/src/messaging/types.ts +0 -17
- package/src/tools/browser/x-auto-navigate.ts +0 -254
- package/src/tools/credentials/account-registry.ts +0 -144
- package/src/tools/filesystem/view-image.ts +0 -244
- package/src/tools/reminder/reminder-store.ts +0 -194
- package/src/tools/reminder/reminder.ts +0 -158
- package/src/tools/system/navigate-settings.ts +0 -74
- package/src/tools/system/open-system-settings.ts +0 -85
- package/src/tools/system/version.ts +0 -54
- package/src/twitter/platform-proxy-client.ts +0 -405
- package/src/util/cookie-session.ts +0 -98
- /package/src/config/bundled-skills/{messaging → gmail}/tools/scan-result-store.ts +0 -0
- /package/src/config/bundled-skills/{messaging → sequences}/tools/sequence-analytics.ts +0 -0
- /package/src/config/bundled-skills/{messaging → sequences}/tools/sequence-create.ts +0 -0
- /package/src/config/bundled-skills/{messaging → sequences}/tools/sequence-delete.ts +0 -0
- /package/src/config/bundled-skills/{messaging → sequences}/tools/sequence-enroll.ts +0 -0
- /package/src/config/bundled-skills/{messaging → sequences}/tools/sequence-enrollment-list.ts +0 -0
- /package/src/config/bundled-skills/{messaging → sequences}/tools/sequence-get.ts +0 -0
- /package/src/config/bundled-skills/{messaging → sequences}/tools/sequence-import.ts +0 -0
- /package/src/config/bundled-skills/{messaging → sequences}/tools/sequence-list.ts +0 -0
|
@@ -1,1160 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* CLI command group: `assistant twitter`
|
|
3
|
-
*
|
|
4
|
-
* Post tweets and manage Twitter sessions via the command line.
|
|
5
|
-
* All commands output JSON to stdout. Use --json for machine-readable output.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import { execFile } from "node:child_process";
|
|
9
|
-
import { promisify } from "node:util";
|
|
10
|
-
|
|
11
|
-
import { Command } from "commander";
|
|
12
|
-
|
|
13
|
-
const execFileAsync = promisify(execFile);
|
|
14
|
-
|
|
15
|
-
import { httpSend } from "../../http-client.js";
|
|
16
|
-
import {
|
|
17
|
-
getBookmarks,
|
|
18
|
-
getFollowers,
|
|
19
|
-
getFollowing,
|
|
20
|
-
getHomeTimeline,
|
|
21
|
-
getLikes,
|
|
22
|
-
getNotifications,
|
|
23
|
-
getUserByScreenName,
|
|
24
|
-
getUserMedia,
|
|
25
|
-
SessionExpiredError,
|
|
26
|
-
} from "./client.js";
|
|
27
|
-
import type { TwitterStrategy } from "./router.js";
|
|
28
|
-
import {
|
|
29
|
-
routedGetTweetDetail,
|
|
30
|
-
routedGetUserByScreenName,
|
|
31
|
-
routedGetUserTweets,
|
|
32
|
-
routedPostTweet,
|
|
33
|
-
routedSearchTweets,
|
|
34
|
-
} from "./router.js";
|
|
35
|
-
import { clearSession, importFromRecording, loadSession } from "./session.js";
|
|
36
|
-
|
|
37
|
-
// ---------------------------------------------------------------------------
|
|
38
|
-
// Helpers
|
|
39
|
-
// ---------------------------------------------------------------------------
|
|
40
|
-
|
|
41
|
-
function output(data: unknown, json: boolean): void {
|
|
42
|
-
process.stdout.write(
|
|
43
|
-
json ? JSON.stringify(data) + "\n" : JSON.stringify(data, null, 2) + "\n",
|
|
44
|
-
);
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
function outputError(message: string, code = 1): void {
|
|
48
|
-
output({ ok: false, error: message }, true);
|
|
49
|
-
process.exitCode = code;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
function getJson(cmd: Command): boolean {
|
|
53
|
-
let c: Command | null = cmd;
|
|
54
|
-
while (c) {
|
|
55
|
-
if ((c.opts() as { json?: boolean }).json) return true;
|
|
56
|
-
c = c.parent;
|
|
57
|
-
}
|
|
58
|
-
return false;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
const SESSION_EXPIRED_MSG =
|
|
62
|
-
"Your Twitter session has expired. Please sign in to Twitter in Chrome — " +
|
|
63
|
-
"run `assistant twitter refresh` to capture your session automatically.";
|
|
64
|
-
|
|
65
|
-
async function run(cmd: Command, fn: () => Promise<unknown>): Promise<void> {
|
|
66
|
-
try {
|
|
67
|
-
const result = await fn();
|
|
68
|
-
output({ ok: true, ...(result as Record<string, unknown>) }, getJson(cmd));
|
|
69
|
-
} catch (err) {
|
|
70
|
-
const meta = err as Record<string, unknown>;
|
|
71
|
-
if (err instanceof SessionExpiredError) {
|
|
72
|
-
// Preserve backward-compatible error code while surfacing router metadata
|
|
73
|
-
const payload: Record<string, unknown> = {
|
|
74
|
-
ok: false,
|
|
75
|
-
error: "session_expired",
|
|
76
|
-
message: SESSION_EXPIRED_MSG,
|
|
77
|
-
};
|
|
78
|
-
if (meta.pathUsed !== undefined) payload.pathUsed = meta.pathUsed;
|
|
79
|
-
if (meta.suggestAlternative !== undefined)
|
|
80
|
-
payload.suggestAlternative = meta.suggestAlternative;
|
|
81
|
-
if (meta.oauthError !== undefined) payload.oauthError = meta.oauthError;
|
|
82
|
-
output(payload, getJson(cmd));
|
|
83
|
-
process.exitCode = 1;
|
|
84
|
-
return;
|
|
85
|
-
}
|
|
86
|
-
// For routed errors with any router metadata, emit structured JSON
|
|
87
|
-
// so callers can see dual-path diagnostics (pathUsed, oauthError, etc.)
|
|
88
|
-
if (
|
|
89
|
-
err instanceof Error &&
|
|
90
|
-
(meta.pathUsed !== undefined ||
|
|
91
|
-
meta.suggestAlternative !== undefined ||
|
|
92
|
-
meta.oauthError !== undefined ||
|
|
93
|
-
meta.proxyErrorCode !== undefined)
|
|
94
|
-
) {
|
|
95
|
-
const payload: Record<string, unknown> = {
|
|
96
|
-
ok: false,
|
|
97
|
-
error: err.message,
|
|
98
|
-
};
|
|
99
|
-
if (meta.pathUsed !== undefined) payload.pathUsed = meta.pathUsed;
|
|
100
|
-
if (meta.suggestAlternative !== undefined)
|
|
101
|
-
payload.suggestAlternative = meta.suggestAlternative;
|
|
102
|
-
if (meta.oauthError !== undefined) payload.oauthError = meta.oauthError;
|
|
103
|
-
if (meta.proxyErrorCode !== undefined)
|
|
104
|
-
payload.proxyErrorCode = meta.proxyErrorCode;
|
|
105
|
-
if (meta.retryable !== undefined) payload.retryable = meta.retryable;
|
|
106
|
-
output(payload, getJson(cmd));
|
|
107
|
-
process.exitCode = 1;
|
|
108
|
-
return;
|
|
109
|
-
}
|
|
110
|
-
outputError(err instanceof Error ? err.message : String(err));
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
// ---------------------------------------------------------------------------
|
|
115
|
-
// Command registration
|
|
116
|
-
// ---------------------------------------------------------------------------
|
|
117
|
-
|
|
118
|
-
export function registerTwitterCommand(program: Command): void {
|
|
119
|
-
const tw = program
|
|
120
|
-
.command("x")
|
|
121
|
-
.alias("twitter")
|
|
122
|
-
.description(
|
|
123
|
-
"Post on X and manage connections. Supports managed (platform proxy), OAuth (official API), and browser session paths.",
|
|
124
|
-
)
|
|
125
|
-
.option("--json", "Machine-readable JSON output");
|
|
126
|
-
|
|
127
|
-
tw.addHelpText(
|
|
128
|
-
"after",
|
|
129
|
-
`
|
|
130
|
-
Twitter (X) supports multiple paths for interacting with the platform:
|
|
131
|
-
|
|
132
|
-
1. Managed (platform proxy) — routes Twitter API calls through the platform,
|
|
133
|
-
which holds the OAuth credentials. Used when integrationMode is "managed".
|
|
134
|
-
2. OAuth (official API) — uses an authenticated Twitter OAuth application for
|
|
135
|
-
posting and replying. Requires a connected OAuth credential.
|
|
136
|
-
3. Browser session (Ride Shotgun) — uses cookies captured from a real Chrome
|
|
137
|
-
session to call Twitter's internal GraphQL API. Supports all read operations
|
|
138
|
-
and posting as a fallback.
|
|
139
|
-
|
|
140
|
-
The strategy system controls which path is used for operations that support multiple:
|
|
141
|
-
managed — route through the platform proxy (platform holds credentials)
|
|
142
|
-
oauth — always use the OAuth API; fail if unavailable
|
|
143
|
-
browser — always use the browser session; fail if unavailable
|
|
144
|
-
auto — try OAuth first, fall back to browser session (default)
|
|
145
|
-
|
|
146
|
-
Session management:
|
|
147
|
-
- "login" imports cookies from a Ride Shotgun recording file
|
|
148
|
-
- "refresh" launches Chrome with CDP, navigates to x.com/login, and runs a
|
|
149
|
-
Ride Shotgun learn session to capture fresh cookies automatically
|
|
150
|
-
- "status" shows whether browser session and OAuth are active
|
|
151
|
-
- "logout" clears the saved browser session cookies
|
|
152
|
-
|
|
153
|
-
Examples:
|
|
154
|
-
$ assistant x status
|
|
155
|
-
$ assistant x post "Hello world" --strategy managed
|
|
156
|
-
$ assistant x post "Hello world" --strategy auto
|
|
157
|
-
$ assistant x timeline elonmusk --count 10
|
|
158
|
-
$ assistant x search "from:vaborsh AI agents" --product Latest
|
|
159
|
-
$ assistant x strategy set oauth`,
|
|
160
|
-
);
|
|
161
|
-
|
|
162
|
-
// =========================================================================
|
|
163
|
-
// login — import session from a recording
|
|
164
|
-
// =========================================================================
|
|
165
|
-
tw.command("login")
|
|
166
|
-
.description("Import a Twitter session from a Ride Shotgun recording")
|
|
167
|
-
.requiredOption("--recording <path>", "Path to the recording JSON file")
|
|
168
|
-
.addHelpText(
|
|
169
|
-
"after",
|
|
170
|
-
`
|
|
171
|
-
Imports cookies from a Ride Shotgun recording file to establish a browser
|
|
172
|
-
session. The recording file is a JSON file produced by a Ride Shotgun learn
|
|
173
|
-
session that contains captured cookies for x.com.
|
|
174
|
-
|
|
175
|
-
After import, all browser-path commands (timeline, search, bookmarks, etc.)
|
|
176
|
-
will use these cookies for authentication.
|
|
177
|
-
|
|
178
|
-
Examples:
|
|
179
|
-
$ assistant x login --recording /tmp/ride-shotgun/recording-abc123.json
|
|
180
|
-
$ assistant x login --recording ~/recordings/twitter-session.json`,
|
|
181
|
-
)
|
|
182
|
-
.action(async (opts: { recording: string }, cmd: Command) => {
|
|
183
|
-
await run(cmd, async () => {
|
|
184
|
-
const session = await importFromRecording(opts.recording);
|
|
185
|
-
return {
|
|
186
|
-
message: "Session imported successfully",
|
|
187
|
-
cookieCount: session.cookies.length,
|
|
188
|
-
};
|
|
189
|
-
});
|
|
190
|
-
});
|
|
191
|
-
|
|
192
|
-
// =========================================================================
|
|
193
|
-
// logout — clear saved session
|
|
194
|
-
// =========================================================================
|
|
195
|
-
tw.command("logout")
|
|
196
|
-
.description("Clear the saved Twitter session")
|
|
197
|
-
.addHelpText(
|
|
198
|
-
"after",
|
|
199
|
-
`
|
|
200
|
-
Deletes all saved browser session cookies. After logout, browser-path commands
|
|
201
|
-
will fail until a new session is imported via "login" or captured via "refresh".
|
|
202
|
-
OAuth credentials are not affected.
|
|
203
|
-
|
|
204
|
-
Examples:
|
|
205
|
-
$ assistant x logout`,
|
|
206
|
-
)
|
|
207
|
-
.action(async (_opts: unknown, cmd: Command) => {
|
|
208
|
-
await clearSession();
|
|
209
|
-
output({ ok: true, message: "Session cleared" }, getJson(cmd));
|
|
210
|
-
});
|
|
211
|
-
|
|
212
|
-
// =========================================================================
|
|
213
|
-
// refresh — start Ride Shotgun learn to capture fresh cookies
|
|
214
|
-
// =========================================================================
|
|
215
|
-
tw.command("refresh")
|
|
216
|
-
.description(
|
|
217
|
-
"Start a Ride Shotgun learn session to capture fresh Twitter cookies. " +
|
|
218
|
-
"Opens x.com in Chrome — sign in when prompted. " +
|
|
219
|
-
"NOTE: Chrome will restart with debugging enabled; your tabs will be restored.",
|
|
220
|
-
)
|
|
221
|
-
.option("--duration <seconds>", "Recording duration in seconds", "180")
|
|
222
|
-
.addHelpText(
|
|
223
|
-
"after",
|
|
224
|
-
`
|
|
225
|
-
Restarts Chrome with CDP (Chrome DevTools Protocol) enabled, navigates to
|
|
226
|
-
x.com/login, and runs a Ride Shotgun learn session to capture fresh cookies.
|
|
227
|
-
Sign in when Chrome opens — the session will be recorded automatically.
|
|
228
|
-
|
|
229
|
-
The --duration flag sets how long (in seconds) the recording runs before
|
|
230
|
-
stopping. Default is 180 seconds (3 minutes). After the recording completes,
|
|
231
|
-
cookies are imported automatically and Chrome is minimized.
|
|
232
|
-
|
|
233
|
-
Requires the assistant to be running (Ride Shotgun runs via the assistant).
|
|
234
|
-
|
|
235
|
-
Examples:
|
|
236
|
-
$ assistant x refresh
|
|
237
|
-
$ assistant x refresh --duration 120
|
|
238
|
-
$ assistant x refresh --duration 300`,
|
|
239
|
-
)
|
|
240
|
-
.action(async (opts: { duration: string }, cmd: Command) => {
|
|
241
|
-
const json = getJson(cmd);
|
|
242
|
-
const duration = parseInt(opts.duration, 10);
|
|
243
|
-
|
|
244
|
-
try {
|
|
245
|
-
const result = await startLearnSession(duration);
|
|
246
|
-
if (result.recordingPath) {
|
|
247
|
-
const session = await importFromRecording(result.recordingPath);
|
|
248
|
-
|
|
249
|
-
// Hide Chrome after capturing session
|
|
250
|
-
try {
|
|
251
|
-
await minimizeChrome();
|
|
252
|
-
} catch {
|
|
253
|
-
/* best-effort */
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
output(
|
|
257
|
-
{
|
|
258
|
-
ok: true,
|
|
259
|
-
message: "Session refreshed successfully",
|
|
260
|
-
cookieCount: session.cookies.length,
|
|
261
|
-
},
|
|
262
|
-
json,
|
|
263
|
-
);
|
|
264
|
-
} else {
|
|
265
|
-
output(
|
|
266
|
-
{
|
|
267
|
-
ok: false,
|
|
268
|
-
error: "Recording completed but no recording path returned",
|
|
269
|
-
},
|
|
270
|
-
json,
|
|
271
|
-
);
|
|
272
|
-
process.exitCode = 1;
|
|
273
|
-
}
|
|
274
|
-
} catch (err) {
|
|
275
|
-
outputError(err instanceof Error ? err.message : String(err));
|
|
276
|
-
}
|
|
277
|
-
});
|
|
278
|
-
|
|
279
|
-
// =========================================================================
|
|
280
|
-
// status — check session status + OAuth and strategy info
|
|
281
|
-
// =========================================================================
|
|
282
|
-
tw.command("status")
|
|
283
|
-
.description("Check Twitter session, OAuth, and strategy status")
|
|
284
|
-
.addHelpText(
|
|
285
|
-
"after",
|
|
286
|
-
`
|
|
287
|
-
Shows the current state of both authentication paths:
|
|
288
|
-
|
|
289
|
-
Browser session — whether cookies are loaded and the cookie count.
|
|
290
|
-
OAuth — whether an OAuth credential is connected, the linked account, the
|
|
291
|
-
current strategy setting, and whether a strategy has been explicitly configured.
|
|
292
|
-
|
|
293
|
-
If the assistant is not running, OAuth fields will be reported as undefined.
|
|
294
|
-
|
|
295
|
-
Examples:
|
|
296
|
-
$ assistant x status
|
|
297
|
-
$ assistant x status --json`,
|
|
298
|
-
)
|
|
299
|
-
.action(async (_opts: unknown, cmd: Command) => {
|
|
300
|
-
const session = await loadSession();
|
|
301
|
-
const browserInfo: Record<string, unknown> = session
|
|
302
|
-
? {
|
|
303
|
-
browserSessionActive: true,
|
|
304
|
-
cookieCount: session.cookies.length,
|
|
305
|
-
}
|
|
306
|
-
: { browserSessionActive: false };
|
|
307
|
-
|
|
308
|
-
// Query daemon for OAuth / strategy config
|
|
309
|
-
let oauthInfo: Record<string, unknown> = {};
|
|
310
|
-
try {
|
|
311
|
-
const r = await sendTwitterConfigRequest("get");
|
|
312
|
-
oauthInfo = {
|
|
313
|
-
oauthConnected: r.connected ?? false,
|
|
314
|
-
oauthAccount: r.accountInfo ?? undefined,
|
|
315
|
-
preferredStrategy: r.strategy ?? "auto",
|
|
316
|
-
strategyConfigured: r.strategyConfigured ?? false,
|
|
317
|
-
};
|
|
318
|
-
} catch {
|
|
319
|
-
// Daemon may not be running; report what we can from the local session
|
|
320
|
-
oauthInfo = {
|
|
321
|
-
oauthConnected: undefined,
|
|
322
|
-
oauthAccount: undefined,
|
|
323
|
-
preferredStrategy: undefined,
|
|
324
|
-
strategyConfigured: undefined,
|
|
325
|
-
};
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
output(
|
|
329
|
-
{
|
|
330
|
-
ok: true,
|
|
331
|
-
loggedIn: !!session,
|
|
332
|
-
...browserInfo,
|
|
333
|
-
...oauthInfo,
|
|
334
|
-
},
|
|
335
|
-
getJson(cmd),
|
|
336
|
-
);
|
|
337
|
-
});
|
|
338
|
-
|
|
339
|
-
// =========================================================================
|
|
340
|
-
// strategy — get or set the Twitter operation strategy
|
|
341
|
-
// =========================================================================
|
|
342
|
-
const strategyCli = tw
|
|
343
|
-
.command("strategy")
|
|
344
|
-
.description(
|
|
345
|
-
"Get or set the Twitter operation strategy (managed, oauth, browser, auto)",
|
|
346
|
-
)
|
|
347
|
-
.addHelpText(
|
|
348
|
-
"after",
|
|
349
|
-
`
|
|
350
|
-
The strategy controls which authentication path is used for operations that
|
|
351
|
-
support both OAuth and browser session:
|
|
352
|
-
|
|
353
|
-
managed — route through the platform proxy (platform holds OAuth credentials).
|
|
354
|
-
oauth — always use the official Twitter OAuth API. Fails if no OAuth
|
|
355
|
-
credential is connected. Best for reliable posting.
|
|
356
|
-
browser — always use the browser session (captured cookies). Fails if no
|
|
357
|
-
session is loaded. Required for read-only endpoints not available
|
|
358
|
-
via OAuth (bookmarks, notifications, search).
|
|
359
|
-
auto — try OAuth first, fall back to browser session. This is the default.
|
|
360
|
-
|
|
361
|
-
Run without a subcommand to display the current strategy. Use "set" to change it.
|
|
362
|
-
|
|
363
|
-
Examples:
|
|
364
|
-
$ assistant x strategy
|
|
365
|
-
$ assistant x strategy set oauth
|
|
366
|
-
$ assistant x strategy set auto`,
|
|
367
|
-
)
|
|
368
|
-
.action(async (_opts: unknown, cmd: Command) => {
|
|
369
|
-
const json = getJson(cmd);
|
|
370
|
-
try {
|
|
371
|
-
const r = await sendTwitterConfigRequest("get_strategy");
|
|
372
|
-
output({ ok: true, strategy: r.strategy ?? "auto" }, json);
|
|
373
|
-
} catch (err) {
|
|
374
|
-
outputError(err instanceof Error ? err.message : String(err));
|
|
375
|
-
}
|
|
376
|
-
});
|
|
377
|
-
|
|
378
|
-
strategyCli
|
|
379
|
-
.command("set")
|
|
380
|
-
.description("Set the Twitter operation strategy")
|
|
381
|
-
.argument("<value>", "Strategy value: oauth, browser, or auto")
|
|
382
|
-
.addHelpText(
|
|
383
|
-
"after",
|
|
384
|
-
`
|
|
385
|
-
Arguments:
|
|
386
|
-
value Strategy to use: "oauth", "browser", or "auto"
|
|
387
|
-
|
|
388
|
-
Sets the preferred strategy for Twitter operations that support dual-path
|
|
389
|
-
routing. The setting is persisted by the assistant and applies to all subsequent
|
|
390
|
-
operations until changed. Note: "managed" is determined by integration mode
|
|
391
|
-
and cannot be set manually.
|
|
392
|
-
|
|
393
|
-
Examples:
|
|
394
|
-
$ assistant x strategy set oauth
|
|
395
|
-
$ assistant x strategy set browser
|
|
396
|
-
$ assistant x strategy set auto`,
|
|
397
|
-
)
|
|
398
|
-
.action(async (value: string, _opts: unknown, cmd: Command) => {
|
|
399
|
-
const json = getJson(cmd);
|
|
400
|
-
try {
|
|
401
|
-
const r = await sendTwitterConfigRequest("set_strategy", {
|
|
402
|
-
strategy: value,
|
|
403
|
-
});
|
|
404
|
-
if (r.success) {
|
|
405
|
-
output({ ok: true, strategy: r.strategy }, json);
|
|
406
|
-
} else {
|
|
407
|
-
output(
|
|
408
|
-
{ ok: false, error: r.error ?? "Failed to set strategy" },
|
|
409
|
-
json,
|
|
410
|
-
);
|
|
411
|
-
process.exitCode = 1;
|
|
412
|
-
}
|
|
413
|
-
} catch (err) {
|
|
414
|
-
outputError(err instanceof Error ? err.message : String(err));
|
|
415
|
-
}
|
|
416
|
-
});
|
|
417
|
-
|
|
418
|
-
// =========================================================================
|
|
419
|
-
// post — post a tweet
|
|
420
|
-
// =========================================================================
|
|
421
|
-
tw.command("post")
|
|
422
|
-
.description("Post a tweet")
|
|
423
|
-
.argument("<text>", "Tweet text")
|
|
424
|
-
.requiredOption(
|
|
425
|
-
"--strategy <strategy>",
|
|
426
|
-
"Operation strategy: oauth, browser, auto, or managed",
|
|
427
|
-
)
|
|
428
|
-
.option(
|
|
429
|
-
"--oauth-token <token>",
|
|
430
|
-
"OAuth access token (required when strategy is oauth or auto)",
|
|
431
|
-
)
|
|
432
|
-
.addHelpText(
|
|
433
|
-
"after",
|
|
434
|
-
`
|
|
435
|
-
Arguments:
|
|
436
|
-
text The tweet text to post (max 280 characters)
|
|
437
|
-
|
|
438
|
-
Posts a new tweet using the routed system. The --strategy flag controls which
|
|
439
|
-
path is used. The response includes the tweet ID, URL, and which path was used.
|
|
440
|
-
|
|
441
|
-
Strategies:
|
|
442
|
-
oauth — use the local OAuth token directly
|
|
443
|
-
browser — use the browser session (CDP)
|
|
444
|
-
auto — try OAuth first, fall back to browser
|
|
445
|
-
managed — route through the platform proxy (platform holds OAuth credentials)
|
|
446
|
-
|
|
447
|
-
Examples:
|
|
448
|
-
$ assistant x post "Hello world" --strategy browser
|
|
449
|
-
$ assistant x post "Hello world" --strategy oauth --oauth-token "$TOKEN"
|
|
450
|
-
$ assistant x post "Hello world" --strategy auto --oauth-token "$TOKEN"
|
|
451
|
-
$ assistant x post "Hello world" --strategy managed`,
|
|
452
|
-
)
|
|
453
|
-
.action(
|
|
454
|
-
async (
|
|
455
|
-
text: string,
|
|
456
|
-
opts: { strategy: string; oauthToken?: string },
|
|
457
|
-
cmd: Command,
|
|
458
|
-
) => {
|
|
459
|
-
await run(cmd, async () => {
|
|
460
|
-
const strategy = opts.strategy as TwitterStrategy;
|
|
461
|
-
if (
|
|
462
|
-
strategy !== "oauth" &&
|
|
463
|
-
strategy !== "browser" &&
|
|
464
|
-
strategy !== "auto" &&
|
|
465
|
-
strategy !== "managed"
|
|
466
|
-
) {
|
|
467
|
-
throw new Error(
|
|
468
|
-
`Invalid strategy "${opts.strategy}". Must be oauth, browser, auto, or managed.`,
|
|
469
|
-
);
|
|
470
|
-
}
|
|
471
|
-
const { result, pathUsed } = await routedPostTweet(text, {
|
|
472
|
-
strategy,
|
|
473
|
-
oauthToken: opts.oauthToken,
|
|
474
|
-
});
|
|
475
|
-
return {
|
|
476
|
-
tweetId: result.tweetId,
|
|
477
|
-
text: result.text,
|
|
478
|
-
url: result.url,
|
|
479
|
-
pathUsed,
|
|
480
|
-
};
|
|
481
|
-
});
|
|
482
|
-
},
|
|
483
|
-
);
|
|
484
|
-
|
|
485
|
-
// =========================================================================
|
|
486
|
-
// reply — reply to a tweet
|
|
487
|
-
// =========================================================================
|
|
488
|
-
tw.command("reply")
|
|
489
|
-
.description("Reply to a tweet")
|
|
490
|
-
.argument("<tweetUrl>", "Tweet URL or tweet ID")
|
|
491
|
-
.argument("<text>", "Reply text")
|
|
492
|
-
.requiredOption(
|
|
493
|
-
"--strategy <strategy>",
|
|
494
|
-
"Operation strategy: oauth, browser, auto, or managed",
|
|
495
|
-
)
|
|
496
|
-
.option(
|
|
497
|
-
"--oauth-token <token>",
|
|
498
|
-
"OAuth access token (required when strategy is oauth or auto)",
|
|
499
|
-
)
|
|
500
|
-
.addHelpText(
|
|
501
|
-
"after",
|
|
502
|
-
`
|
|
503
|
-
Arguments:
|
|
504
|
-
tweetUrl Full tweet URL (e.g. https://x.com/user/status/123456) or a bare tweet ID
|
|
505
|
-
text The reply text to post (max 280 characters)
|
|
506
|
-
|
|
507
|
-
Posts a reply to the specified tweet. Accepts either a full tweet URL or a bare
|
|
508
|
-
numeric tweet ID. The tweet ID is extracted from the last numeric segment of the
|
|
509
|
-
URL. The --strategy flag controls which path is used.
|
|
510
|
-
|
|
511
|
-
Examples:
|
|
512
|
-
$ assistant x reply https://x.com/elonmusk/status/1234567890 "Great point!" --strategy browser
|
|
513
|
-
$ assistant x reply 1234567890 "Interesting thread" --strategy oauth --oauth-token "$TOKEN"
|
|
514
|
-
$ assistant x reply 1234567890 "Nice!" --strategy managed`,
|
|
515
|
-
)
|
|
516
|
-
.action(
|
|
517
|
-
async (
|
|
518
|
-
tweetUrl: string,
|
|
519
|
-
text: string,
|
|
520
|
-
opts: { strategy: string; oauthToken?: string },
|
|
521
|
-
cmd: Command,
|
|
522
|
-
) => {
|
|
523
|
-
await run(cmd, async () => {
|
|
524
|
-
const strategy = opts.strategy as TwitterStrategy;
|
|
525
|
-
if (
|
|
526
|
-
strategy !== "oauth" &&
|
|
527
|
-
strategy !== "browser" &&
|
|
528
|
-
strategy !== "auto" &&
|
|
529
|
-
strategy !== "managed"
|
|
530
|
-
) {
|
|
531
|
-
throw new Error(
|
|
532
|
-
`Invalid strategy "${opts.strategy}". Must be oauth, browser, auto, or managed.`,
|
|
533
|
-
);
|
|
534
|
-
}
|
|
535
|
-
// Extract tweet ID: either a bare numeric ID or the last numeric segment of a URL
|
|
536
|
-
const idMatch = tweetUrl.match(/(\d+)\s*$/);
|
|
537
|
-
if (!idMatch) {
|
|
538
|
-
throw new Error(`Could not extract tweet ID from: ${tweetUrl}`);
|
|
539
|
-
}
|
|
540
|
-
const inReplyToTweetId = idMatch[1];
|
|
541
|
-
const { result, pathUsed } = await routedPostTweet(text, {
|
|
542
|
-
inReplyToTweetId,
|
|
543
|
-
strategy,
|
|
544
|
-
oauthToken: opts.oauthToken,
|
|
545
|
-
});
|
|
546
|
-
return {
|
|
547
|
-
tweetId: result.tweetId,
|
|
548
|
-
text: result.text,
|
|
549
|
-
url: result.url,
|
|
550
|
-
inReplyToTweetId,
|
|
551
|
-
pathUsed,
|
|
552
|
-
};
|
|
553
|
-
});
|
|
554
|
-
},
|
|
555
|
-
);
|
|
556
|
-
// =========================================================================
|
|
557
|
-
// timeline — fetch a user's recent tweets
|
|
558
|
-
// =========================================================================
|
|
559
|
-
tw.command("timeline")
|
|
560
|
-
.description("Fetch a user's recent tweets")
|
|
561
|
-
.argument("<screenName>", "Twitter screen name (without @)")
|
|
562
|
-
.option("--count <n>", "Number of tweets to fetch", "20")
|
|
563
|
-
.option(
|
|
564
|
-
"--strategy <strategy>",
|
|
565
|
-
"Operation strategy: managed or browser (default: browser)",
|
|
566
|
-
)
|
|
567
|
-
.addHelpText(
|
|
568
|
-
"after",
|
|
569
|
-
`
|
|
570
|
-
Arguments:
|
|
571
|
-
screenName Twitter screen name without the @ prefix (e.g. "elonmusk", not "@elonmusk")
|
|
572
|
-
|
|
573
|
-
Fetches a user's recent tweets. Resolves the screen name to a user ID first,
|
|
574
|
-
then retrieves their tweet timeline. The --count flag controls how many tweets
|
|
575
|
-
to return (default: 20). Use --strategy managed to route through the platform proxy.
|
|
576
|
-
|
|
577
|
-
Examples:
|
|
578
|
-
$ assistant x timeline elonmusk
|
|
579
|
-
$ assistant x timeline vaborsh --count 50
|
|
580
|
-
$ assistant x timeline openai --count 10 --json
|
|
581
|
-
$ assistant x timeline elonmusk --strategy managed`,
|
|
582
|
-
)
|
|
583
|
-
.action(
|
|
584
|
-
async (
|
|
585
|
-
screenName: string,
|
|
586
|
-
opts: { count: string; strategy?: string },
|
|
587
|
-
cmd: Command,
|
|
588
|
-
) => {
|
|
589
|
-
await run(cmd, async () => {
|
|
590
|
-
const strategy = (opts.strategy ?? "browser") as TwitterStrategy;
|
|
591
|
-
if (
|
|
592
|
-
strategy !== "oauth" &&
|
|
593
|
-
strategy !== "browser" &&
|
|
594
|
-
strategy !== "auto" &&
|
|
595
|
-
strategy !== "managed"
|
|
596
|
-
) {
|
|
597
|
-
throw new Error(
|
|
598
|
-
`Invalid strategy "${opts.strategy}". Must be oauth, browser, auto, or managed.`,
|
|
599
|
-
);
|
|
600
|
-
}
|
|
601
|
-
const { result: user, pathUsed } = await routedGetUserByScreenName(
|
|
602
|
-
screenName.replace(/^@/, ""),
|
|
603
|
-
{ strategy },
|
|
604
|
-
);
|
|
605
|
-
const { result: tweets } = await routedGetUserTweets(
|
|
606
|
-
user.userId,
|
|
607
|
-
parseInt(opts.count, 10),
|
|
608
|
-
{ strategy },
|
|
609
|
-
);
|
|
610
|
-
return { user, tweets, pathUsed };
|
|
611
|
-
});
|
|
612
|
-
},
|
|
613
|
-
);
|
|
614
|
-
|
|
615
|
-
// =========================================================================
|
|
616
|
-
// tweet — fetch a single tweet and its replies
|
|
617
|
-
// =========================================================================
|
|
618
|
-
tw.command("tweet")
|
|
619
|
-
.description("Fetch a tweet and its reply thread")
|
|
620
|
-
.argument("<tweetIdOrUrl>", "Tweet ID or URL")
|
|
621
|
-
.option(
|
|
622
|
-
"--strategy <strategy>",
|
|
623
|
-
"Operation strategy: managed or browser (default: browser)",
|
|
624
|
-
)
|
|
625
|
-
.addHelpText(
|
|
626
|
-
"after",
|
|
627
|
-
`
|
|
628
|
-
Arguments:
|
|
629
|
-
tweetIdOrUrl A bare tweet ID (e.g. 1234567890) or a full tweet URL
|
|
630
|
-
(e.g. https://x.com/user/status/1234567890)
|
|
631
|
-
|
|
632
|
-
Fetches a single tweet and its reply thread. The tweet ID is extracted from the
|
|
633
|
-
last numeric segment of the input. Returns an array of tweets representing the
|
|
634
|
-
conversation thread. Use --strategy managed to route through the platform proxy.
|
|
635
|
-
|
|
636
|
-
Examples:
|
|
637
|
-
$ assistant x tweet 1234567890
|
|
638
|
-
$ assistant x tweet https://x.com/elonmusk/status/1234567890
|
|
639
|
-
$ assistant x tweet https://x.com/openai/status/9876543210 --json
|
|
640
|
-
$ assistant x tweet 1234567890 --strategy managed`,
|
|
641
|
-
)
|
|
642
|
-
.action(
|
|
643
|
-
async (
|
|
644
|
-
tweetIdOrUrl: string,
|
|
645
|
-
opts: { strategy?: string },
|
|
646
|
-
cmd: Command,
|
|
647
|
-
) => {
|
|
648
|
-
await run(cmd, async () => {
|
|
649
|
-
const idMatch = tweetIdOrUrl.match(/(\d+)\s*$/);
|
|
650
|
-
if (!idMatch)
|
|
651
|
-
throw new Error(`Could not extract tweet ID from: ${tweetIdOrUrl}`);
|
|
652
|
-
const strategy = (opts.strategy ?? "browser") as TwitterStrategy;
|
|
653
|
-
if (
|
|
654
|
-
strategy !== "oauth" &&
|
|
655
|
-
strategy !== "browser" &&
|
|
656
|
-
strategy !== "auto" &&
|
|
657
|
-
strategy !== "managed"
|
|
658
|
-
) {
|
|
659
|
-
throw new Error(
|
|
660
|
-
`Invalid strategy "${opts.strategy}". Must be oauth, browser, auto, or managed.`,
|
|
661
|
-
);
|
|
662
|
-
}
|
|
663
|
-
const { result: tweets, pathUsed } = await routedGetTweetDetail(
|
|
664
|
-
idMatch[1],
|
|
665
|
-
{ strategy },
|
|
666
|
-
);
|
|
667
|
-
return { tweets, pathUsed };
|
|
668
|
-
});
|
|
669
|
-
},
|
|
670
|
-
);
|
|
671
|
-
|
|
672
|
-
// =========================================================================
|
|
673
|
-
// search — search tweets
|
|
674
|
-
// =========================================================================
|
|
675
|
-
tw.command("search")
|
|
676
|
-
.description("Search tweets")
|
|
677
|
-
.argument("<query>", "Search query")
|
|
678
|
-
.option("--product <type>", "Top, Latest, People, or Media", "Top")
|
|
679
|
-
.option(
|
|
680
|
-
"--strategy <strategy>",
|
|
681
|
-
"Operation strategy: managed or browser (default: browser)",
|
|
682
|
-
)
|
|
683
|
-
.addHelpText(
|
|
684
|
-
"after",
|
|
685
|
-
`
|
|
686
|
-
Arguments:
|
|
687
|
-
query Twitter search query string. Supports Twitter search operators
|
|
688
|
-
(e.g. "from:user", "to:user", "min_faves:100", quoted phrases)
|
|
689
|
-
|
|
690
|
-
The --product flag selects the search result type:
|
|
691
|
-
Top — most relevant tweets (default)
|
|
692
|
-
Latest — most recent tweets, reverse chronological
|
|
693
|
-
People — user accounts matching the query
|
|
694
|
-
Media — tweets containing images or video
|
|
695
|
-
|
|
696
|
-
Use --strategy managed to route through the platform proxy (uses Twitter's
|
|
697
|
-
recent search API).
|
|
698
|
-
|
|
699
|
-
Examples:
|
|
700
|
-
$ assistant x search "AI agents"
|
|
701
|
-
$ assistant x search "from:elonmusk SpaceX" --product Latest
|
|
702
|
-
$ assistant x search "machine learning" --product Media --json
|
|
703
|
-
$ assistant x search "AI agents" --strategy managed`,
|
|
704
|
-
)
|
|
705
|
-
.action(
|
|
706
|
-
async (
|
|
707
|
-
query: string,
|
|
708
|
-
opts: { product: string; strategy?: string },
|
|
709
|
-
cmd: Command,
|
|
710
|
-
) => {
|
|
711
|
-
await run(cmd, async () => {
|
|
712
|
-
const strategy = (opts.strategy ?? "browser") as TwitterStrategy;
|
|
713
|
-
if (
|
|
714
|
-
strategy !== "oauth" &&
|
|
715
|
-
strategy !== "browser" &&
|
|
716
|
-
strategy !== "auto" &&
|
|
717
|
-
strategy !== "managed"
|
|
718
|
-
) {
|
|
719
|
-
throw new Error(
|
|
720
|
-
`Invalid strategy "${opts.strategy}". Must be oauth, browser, auto, or managed.`,
|
|
721
|
-
);
|
|
722
|
-
}
|
|
723
|
-
const product = opts.product as "Top" | "Latest" | "People" | "Media";
|
|
724
|
-
const { result: tweets, pathUsed } = await routedSearchTweets(
|
|
725
|
-
query,
|
|
726
|
-
product,
|
|
727
|
-
{ strategy },
|
|
728
|
-
);
|
|
729
|
-
return { query, tweets, pathUsed };
|
|
730
|
-
});
|
|
731
|
-
},
|
|
732
|
-
);
|
|
733
|
-
|
|
734
|
-
// =========================================================================
|
|
735
|
-
// bookmarks — fetch bookmarks
|
|
736
|
-
// =========================================================================
|
|
737
|
-
tw.command("bookmarks")
|
|
738
|
-
.description("Fetch your bookmarks")
|
|
739
|
-
.option("--count <n>", "Number of bookmarks", "20")
|
|
740
|
-
.addHelpText(
|
|
741
|
-
"after",
|
|
742
|
-
`
|
|
743
|
-
Fetches the authenticated user's bookmarked tweets via the browser session.
|
|
744
|
-
The --count flag controls how many bookmarks to return (default: 20).
|
|
745
|
-
|
|
746
|
-
Requires an active browser session. Bookmarks are private and only available
|
|
747
|
-
for the logged-in account.
|
|
748
|
-
|
|
749
|
-
Examples:
|
|
750
|
-
$ assistant x bookmarks
|
|
751
|
-
$ assistant x bookmarks --count 50
|
|
752
|
-
$ assistant x bookmarks --json`,
|
|
753
|
-
)
|
|
754
|
-
.action(async (opts: { count: string }, cmd: Command) => {
|
|
755
|
-
await run(cmd, async () => {
|
|
756
|
-
const tweets = await getBookmarks(parseInt(opts.count, 10));
|
|
757
|
-
return { tweets };
|
|
758
|
-
});
|
|
759
|
-
});
|
|
760
|
-
|
|
761
|
-
// =========================================================================
|
|
762
|
-
// home — fetch home timeline
|
|
763
|
-
// =========================================================================
|
|
764
|
-
tw.command("home")
|
|
765
|
-
.description("Fetch your home timeline")
|
|
766
|
-
.option("--count <n>", "Number of tweets", "20")
|
|
767
|
-
.addHelpText(
|
|
768
|
-
"after",
|
|
769
|
-
`
|
|
770
|
-
Fetches the authenticated user's home timeline (the "For You" feed) via the
|
|
771
|
-
browser session. The --count flag controls how many tweets to return (default: 20).
|
|
772
|
-
|
|
773
|
-
Requires an active browser session.
|
|
774
|
-
|
|
775
|
-
Examples:
|
|
776
|
-
$ assistant x home
|
|
777
|
-
$ assistant x home --count 50
|
|
778
|
-
$ assistant x home --json`,
|
|
779
|
-
)
|
|
780
|
-
.action(async (opts: { count: string }, cmd: Command) => {
|
|
781
|
-
await run(cmd, async () => {
|
|
782
|
-
const tweets = await getHomeTimeline(parseInt(opts.count, 10));
|
|
783
|
-
return { tweets };
|
|
784
|
-
});
|
|
785
|
-
});
|
|
786
|
-
|
|
787
|
-
// =========================================================================
|
|
788
|
-
// notifications — fetch notifications
|
|
789
|
-
// =========================================================================
|
|
790
|
-
tw.command("notifications")
|
|
791
|
-
.description("Fetch your notifications")
|
|
792
|
-
.option("--count <n>", "Number of notifications", "20")
|
|
793
|
-
.addHelpText(
|
|
794
|
-
"after",
|
|
795
|
-
`
|
|
796
|
-
Fetches the authenticated user's Twitter notifications (mentions, likes,
|
|
797
|
-
retweets, follows, etc.) via the browser session. The --count flag controls
|
|
798
|
-
how many notifications to return (default: 20).
|
|
799
|
-
|
|
800
|
-
Requires an active browser session.
|
|
801
|
-
|
|
802
|
-
Examples:
|
|
803
|
-
$ assistant x notifications
|
|
804
|
-
$ assistant x notifications --count 50
|
|
805
|
-
$ assistant x notifications --json`,
|
|
806
|
-
)
|
|
807
|
-
.action(async (opts: { count: string }, cmd: Command) => {
|
|
808
|
-
await run(cmd, async () => {
|
|
809
|
-
const notifications = await getNotifications(parseInt(opts.count, 10));
|
|
810
|
-
return { notifications };
|
|
811
|
-
});
|
|
812
|
-
});
|
|
813
|
-
|
|
814
|
-
// =========================================================================
|
|
815
|
-
// likes — fetch a user's liked tweets
|
|
816
|
-
// =========================================================================
|
|
817
|
-
tw.command("likes")
|
|
818
|
-
.description("Fetch a user's liked tweets")
|
|
819
|
-
.argument("<screenName>", "Twitter screen name (without @)")
|
|
820
|
-
.option("--count <n>", "Number of likes", "20")
|
|
821
|
-
.addHelpText(
|
|
822
|
-
"after",
|
|
823
|
-
`
|
|
824
|
-
Arguments:
|
|
825
|
-
screenName Twitter screen name without the @ prefix (e.g. "elonmusk", not "@elonmusk")
|
|
826
|
-
|
|
827
|
-
Fetches tweets liked by the specified user via the browser session. Resolves the
|
|
828
|
-
screen name to a user ID first. The --count flag controls how many liked tweets
|
|
829
|
-
to return (default: 20).
|
|
830
|
-
|
|
831
|
-
Examples:
|
|
832
|
-
$ assistant x likes elonmusk
|
|
833
|
-
$ assistant x likes vaborsh --count 50
|
|
834
|
-
$ assistant x likes openai --json`,
|
|
835
|
-
)
|
|
836
|
-
.action(
|
|
837
|
-
async (screenName: string, opts: { count: string }, cmd: Command) => {
|
|
838
|
-
await run(cmd, async () => {
|
|
839
|
-
const user = await getUserByScreenName(screenName.replace(/^@/, ""));
|
|
840
|
-
const tweets = await getLikes(user.userId, parseInt(opts.count, 10));
|
|
841
|
-
return { user, tweets };
|
|
842
|
-
});
|
|
843
|
-
},
|
|
844
|
-
);
|
|
845
|
-
|
|
846
|
-
// =========================================================================
|
|
847
|
-
// followers — fetch a user's followers
|
|
848
|
-
// =========================================================================
|
|
849
|
-
tw.command("followers")
|
|
850
|
-
.description("Fetch a user's followers")
|
|
851
|
-
.argument("<screenName>", "Twitter screen name (without @)")
|
|
852
|
-
.addHelpText(
|
|
853
|
-
"after",
|
|
854
|
-
`
|
|
855
|
-
Arguments:
|
|
856
|
-
screenName Twitter screen name without the @ prefix (e.g. "elonmusk", not "@elonmusk")
|
|
857
|
-
|
|
858
|
-
Fetches the list of accounts following the specified user via the browser session.
|
|
859
|
-
Resolves the screen name to a user ID first.
|
|
860
|
-
|
|
861
|
-
Examples:
|
|
862
|
-
$ assistant x followers elonmusk
|
|
863
|
-
$ assistant x followers vaborsh --json`,
|
|
864
|
-
)
|
|
865
|
-
.action(async (screenName: string, _opts: unknown, cmd: Command) => {
|
|
866
|
-
await run(cmd, async () => {
|
|
867
|
-
const cleanName = screenName.replace(/^@/, "");
|
|
868
|
-
const user = await getUserByScreenName(cleanName);
|
|
869
|
-
const followers = await getFollowers(user.userId, cleanName);
|
|
870
|
-
return { user, followers };
|
|
871
|
-
});
|
|
872
|
-
});
|
|
873
|
-
|
|
874
|
-
// =========================================================================
|
|
875
|
-
// following — fetch who a user follows
|
|
876
|
-
// =========================================================================
|
|
877
|
-
tw.command("following")
|
|
878
|
-
.description("Fetch who a user follows")
|
|
879
|
-
.argument("<screenName>", "Twitter screen name (without @)")
|
|
880
|
-
.option("--count <n>", "Number of following", "20")
|
|
881
|
-
.addHelpText(
|
|
882
|
-
"after",
|
|
883
|
-
`
|
|
884
|
-
Arguments:
|
|
885
|
-
screenName Twitter screen name without the @ prefix (e.g. "elonmusk", not "@elonmusk")
|
|
886
|
-
|
|
887
|
-
Fetches the list of accounts the specified user follows via the browser session.
|
|
888
|
-
Resolves the screen name to a user ID first. The --count flag controls how many
|
|
889
|
-
results to return (default: 20).
|
|
890
|
-
|
|
891
|
-
Examples:
|
|
892
|
-
$ assistant x following elonmusk
|
|
893
|
-
$ assistant x following vaborsh --count 100
|
|
894
|
-
$ assistant x following openai --json`,
|
|
895
|
-
)
|
|
896
|
-
.action(
|
|
897
|
-
async (screenName: string, opts: { count: string }, cmd: Command) => {
|
|
898
|
-
await run(cmd, async () => {
|
|
899
|
-
const user = await getUserByScreenName(screenName.replace(/^@/, ""));
|
|
900
|
-
const following = await getFollowing(
|
|
901
|
-
user.userId,
|
|
902
|
-
parseInt(opts.count, 10),
|
|
903
|
-
);
|
|
904
|
-
return { user, following };
|
|
905
|
-
});
|
|
906
|
-
},
|
|
907
|
-
);
|
|
908
|
-
|
|
909
|
-
// =========================================================================
|
|
910
|
-
// media — fetch a user's media tweets
|
|
911
|
-
// =========================================================================
|
|
912
|
-
tw.command("media")
|
|
913
|
-
.description("Fetch a user's media tweets")
|
|
914
|
-
.argument("<screenName>", "Twitter screen name (without @)")
|
|
915
|
-
.option("--count <n>", "Number of media tweets", "20")
|
|
916
|
-
.addHelpText(
|
|
917
|
-
"after",
|
|
918
|
-
`
|
|
919
|
-
Arguments:
|
|
920
|
-
screenName Twitter screen name without the @ prefix (e.g. "elonmusk", not "@elonmusk")
|
|
921
|
-
|
|
922
|
-
Fetches tweets containing images or video from the specified user via the browser
|
|
923
|
-
session. Resolves the screen name to a user ID first. The --count flag controls
|
|
924
|
-
how many media tweets to return (default: 20).
|
|
925
|
-
|
|
926
|
-
Examples:
|
|
927
|
-
$ assistant x media elonmusk
|
|
928
|
-
$ assistant x media nasa --count 50
|
|
929
|
-
$ assistant x media openai --json`,
|
|
930
|
-
)
|
|
931
|
-
.action(
|
|
932
|
-
async (screenName: string, opts: { count: string }, cmd: Command) => {
|
|
933
|
-
await run(cmd, async () => {
|
|
934
|
-
const user = await getUserByScreenName(screenName.replace(/^@/, ""));
|
|
935
|
-
const tweets = await getUserMedia(
|
|
936
|
-
user.userId,
|
|
937
|
-
parseInt(opts.count, 10),
|
|
938
|
-
);
|
|
939
|
-
return { user, tweets };
|
|
940
|
-
});
|
|
941
|
-
},
|
|
942
|
-
);
|
|
943
|
-
}
|
|
944
|
-
|
|
945
|
-
// ---------------------------------------------------------------------------
|
|
946
|
-
// Daemon HTTP helper — send requests to the daemon's HTTP API
|
|
947
|
-
// ---------------------------------------------------------------------------
|
|
948
|
-
|
|
949
|
-
/**
|
|
950
|
-
* Send a Twitter integration config request to the daemon via HTTP.
|
|
951
|
-
*
|
|
952
|
-
* Maps the old IPC `twitter_integration_config` message actions to HTTP
|
|
953
|
-
* endpoints on the settings routes:
|
|
954
|
-
* - "get" / "get_strategy" → GET /v1/integrations/twitter/auth/status
|
|
955
|
-
* - "set_strategy" → PUT /v1/settings/client (key=twitter.strategy)
|
|
956
|
-
*/
|
|
957
|
-
async function sendTwitterConfigRequest(
|
|
958
|
-
action: string,
|
|
959
|
-
extra?: Record<string, unknown>,
|
|
960
|
-
): Promise<Record<string, unknown>> {
|
|
961
|
-
if (action === "get" || action === "get_strategy") {
|
|
962
|
-
const response = await httpSend("/v1/integrations/twitter/auth/status", {
|
|
963
|
-
method: "GET",
|
|
964
|
-
});
|
|
965
|
-
if (!response.ok) {
|
|
966
|
-
const text = await response.text();
|
|
967
|
-
throw new Error(`Assistant returned an error: ${text}`);
|
|
968
|
-
}
|
|
969
|
-
const data = (await response.json()) as Record<string, unknown>;
|
|
970
|
-
// Map the HTTP response shape to the old IPC response shape
|
|
971
|
-
return {
|
|
972
|
-
type: "twitter_integration_config_response",
|
|
973
|
-
success: true,
|
|
974
|
-
connected: data.connected ?? false,
|
|
975
|
-
accountInfo: data.accountInfo,
|
|
976
|
-
strategy: data.strategy ?? "auto",
|
|
977
|
-
strategyConfigured: data.strategyConfigured ?? false,
|
|
978
|
-
mode: data.mode,
|
|
979
|
-
managedAvailable: data.managedAvailable ?? false,
|
|
980
|
-
managedPrerequisites: data.managedPrerequisites,
|
|
981
|
-
localClientConfigured: data.localClientConfigured ?? false,
|
|
982
|
-
};
|
|
983
|
-
}
|
|
984
|
-
|
|
985
|
-
if (action === "set_strategy") {
|
|
986
|
-
const strategy = extra?.strategy as string | undefined;
|
|
987
|
-
if (!strategy) throw new Error("strategy is required for set_strategy");
|
|
988
|
-
const response = await httpSend("/v1/settings/client", {
|
|
989
|
-
method: "PUT",
|
|
990
|
-
body: JSON.stringify({ key: "twitter.strategy", value: strategy }),
|
|
991
|
-
});
|
|
992
|
-
if (!response.ok) {
|
|
993
|
-
const text = await response.text();
|
|
994
|
-
throw new Error(`Assistant returned an error: ${text}`);
|
|
995
|
-
}
|
|
996
|
-
return {
|
|
997
|
-
type: "twitter_integration_config_response",
|
|
998
|
-
success: true,
|
|
999
|
-
strategy,
|
|
1000
|
-
};
|
|
1001
|
-
}
|
|
1002
|
-
|
|
1003
|
-
throw new Error(`Unsupported twitter_integration_config action: ${action}`);
|
|
1004
|
-
}
|
|
1005
|
-
|
|
1006
|
-
// ---------------------------------------------------------------------------
|
|
1007
|
-
// Chrome CDP helpers (via `assistant browser chrome` CLI)
|
|
1008
|
-
// ---------------------------------------------------------------------------
|
|
1009
|
-
|
|
1010
|
-
async function launchChromeCdp(
|
|
1011
|
-
startUrl?: string,
|
|
1012
|
-
): Promise<{ baseUrl: string }> {
|
|
1013
|
-
const args = ["browser", "chrome", "launch"];
|
|
1014
|
-
if (startUrl) args.push("--start-url", startUrl);
|
|
1015
|
-
const { stdout } = await execFileAsync("assistant", args);
|
|
1016
|
-
const result = JSON.parse(stdout) as {
|
|
1017
|
-
ok: boolean;
|
|
1018
|
-
baseUrl?: string;
|
|
1019
|
-
error?: string;
|
|
1020
|
-
};
|
|
1021
|
-
if (!result.ok || !result.baseUrl) {
|
|
1022
|
-
throw new Error(result.error ?? "Failed to launch Chrome with CDP");
|
|
1023
|
-
}
|
|
1024
|
-
return { baseUrl: result.baseUrl };
|
|
1025
|
-
}
|
|
1026
|
-
|
|
1027
|
-
async function minimizeChrome(): Promise<void> {
|
|
1028
|
-
try {
|
|
1029
|
-
await execFileAsync("assistant", ["browser", "chrome", "minimize"]);
|
|
1030
|
-
} catch {
|
|
1031
|
-
// best-effort — same as the original
|
|
1032
|
-
}
|
|
1033
|
-
}
|
|
1034
|
-
|
|
1035
|
-
// ---------------------------------------------------------------------------
|
|
1036
|
-
// Ride Shotgun learn session helper
|
|
1037
|
-
// ---------------------------------------------------------------------------
|
|
1038
|
-
|
|
1039
|
-
interface LearnResult {
|
|
1040
|
-
recordingId?: string;
|
|
1041
|
-
recordingPath?: string;
|
|
1042
|
-
}
|
|
1043
|
-
|
|
1044
|
-
async function navigateToX(cdpBase: string): Promise<void> {
|
|
1045
|
-
try {
|
|
1046
|
-
const res = await fetch(`${cdpBase}/json/list`);
|
|
1047
|
-
if (!res.ok) return;
|
|
1048
|
-
const targets = (await res.json()) as Array<{
|
|
1049
|
-
id: string;
|
|
1050
|
-
type: string;
|
|
1051
|
-
url: string;
|
|
1052
|
-
}>;
|
|
1053
|
-
const tab = targets.find((t) => t.type === "page");
|
|
1054
|
-
if (!tab) return;
|
|
1055
|
-
await fetch(
|
|
1056
|
-
`${cdpBase}/json/navigate?url=${encodeURIComponent(
|
|
1057
|
-
"https://x.com/login",
|
|
1058
|
-
)}&id=${tab.id}`,
|
|
1059
|
-
{ method: "PUT" },
|
|
1060
|
-
);
|
|
1061
|
-
} catch {
|
|
1062
|
-
// best-effort
|
|
1063
|
-
}
|
|
1064
|
-
}
|
|
1065
|
-
|
|
1066
|
-
async function startLearnSession(
|
|
1067
|
-
durationSeconds: number,
|
|
1068
|
-
): Promise<LearnResult> {
|
|
1069
|
-
const cdpSession = await launchChromeCdp("https://x.com/login");
|
|
1070
|
-
await navigateToX(cdpSession.baseUrl);
|
|
1071
|
-
|
|
1072
|
-
// Start ride shotgun via HTTP
|
|
1073
|
-
const response = await httpSend("/v1/computer-use/ride-shotgun/start", {
|
|
1074
|
-
method: "POST",
|
|
1075
|
-
body: JSON.stringify({
|
|
1076
|
-
durationSeconds,
|
|
1077
|
-
intervalSeconds: 5,
|
|
1078
|
-
mode: "learn",
|
|
1079
|
-
targetDomain: "x.com",
|
|
1080
|
-
}),
|
|
1081
|
-
});
|
|
1082
|
-
|
|
1083
|
-
if (!response.ok) {
|
|
1084
|
-
const body = await response.text();
|
|
1085
|
-
throw new Error(
|
|
1086
|
-
`Cannot connect to assistant: ${response.status} ${body}. Is the assistant running?`,
|
|
1087
|
-
);
|
|
1088
|
-
}
|
|
1089
|
-
|
|
1090
|
-
const startResult = (await response.json()) as {
|
|
1091
|
-
watchId?: string;
|
|
1092
|
-
sessionId?: string;
|
|
1093
|
-
};
|
|
1094
|
-
|
|
1095
|
-
if (!startResult.watchId) {
|
|
1096
|
-
throw new Error("Ride-shotgun start response missing watchId");
|
|
1097
|
-
}
|
|
1098
|
-
|
|
1099
|
-
// Poll the status endpoint using watchId to correlate completion
|
|
1100
|
-
const { watchId } = startResult;
|
|
1101
|
-
const timeoutMs = (durationSeconds + 30) * 1000;
|
|
1102
|
-
const pollIntervalMs = 2000;
|
|
1103
|
-
const startTime = Date.now();
|
|
1104
|
-
|
|
1105
|
-
return new Promise<LearnResult>((resolve, reject) => {
|
|
1106
|
-
const tick = async () => {
|
|
1107
|
-
if (Date.now() - startTime > timeoutMs) {
|
|
1108
|
-
reject(
|
|
1109
|
-
new Error(`Learn session timed out after ${durationSeconds + 30}s`),
|
|
1110
|
-
);
|
|
1111
|
-
return;
|
|
1112
|
-
}
|
|
1113
|
-
|
|
1114
|
-
try {
|
|
1115
|
-
const statusRes = await httpSend(
|
|
1116
|
-
`/v1/computer-use/ride-shotgun/status/${watchId}`,
|
|
1117
|
-
{ method: "GET" },
|
|
1118
|
-
);
|
|
1119
|
-
if (!statusRes.ok) {
|
|
1120
|
-
setTimeout(tick, pollIntervalMs);
|
|
1121
|
-
return;
|
|
1122
|
-
}
|
|
1123
|
-
|
|
1124
|
-
const status = (await statusRes.json()) as {
|
|
1125
|
-
status: string;
|
|
1126
|
-
recordingId?: string;
|
|
1127
|
-
savedRecordingPath?: string;
|
|
1128
|
-
bootstrapFailureReason?: string;
|
|
1129
|
-
};
|
|
1130
|
-
|
|
1131
|
-
if (status.bootstrapFailureReason) {
|
|
1132
|
-
reject(
|
|
1133
|
-
new Error(`Learn session failed: ${status.bootstrapFailureReason}`),
|
|
1134
|
-
);
|
|
1135
|
-
return;
|
|
1136
|
-
}
|
|
1137
|
-
|
|
1138
|
-
if (status.status === "completed") {
|
|
1139
|
-
if (status.recordingId) {
|
|
1140
|
-
resolve({
|
|
1141
|
-
recordingId: status.recordingId,
|
|
1142
|
-
recordingPath: status.savedRecordingPath,
|
|
1143
|
-
});
|
|
1144
|
-
} else {
|
|
1145
|
-
reject(
|
|
1146
|
-
new Error("Learn session completed but no recording was saved."),
|
|
1147
|
-
);
|
|
1148
|
-
}
|
|
1149
|
-
return;
|
|
1150
|
-
}
|
|
1151
|
-
} catch {
|
|
1152
|
-
// Status endpoint not reachable — continue polling
|
|
1153
|
-
}
|
|
1154
|
-
|
|
1155
|
-
setTimeout(tick, pollIntervalMs);
|
|
1156
|
-
};
|
|
1157
|
-
|
|
1158
|
-
setTimeout(tick, pollIntervalMs);
|
|
1159
|
-
});
|
|
1160
|
-
}
|