vellum 0.2.0 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +15 -2
- package/bun.lock +5 -2
- package/package.json +4 -2
- package/scripts/capture-x-graphql.ts +562 -0
- package/scripts/ipc/check-swift-decoder-drift.ts +2 -1
- package/scripts/test.sh +5 -0
- package/src/__tests__/__snapshots__/ipc-snapshot.test.ts.snap +161 -34
- package/src/__tests__/account-registry.test.ts +2 -1
- package/src/__tests__/agent-heartbeat-service.test.ts +250 -0
- package/src/__tests__/app-bundler.test.ts +12 -33
- package/src/__tests__/asset-materialize-tool.test.ts +16 -15
- package/src/__tests__/asset-search-tool.test.ts +23 -22
- package/src/__tests__/attachments-store.test.ts +56 -127
- package/src/__tests__/browser-skill-baseline-tool-payload.test.ts +5 -4
- package/src/__tests__/browser-skill-endstate.test.ts +5 -8
- package/src/__tests__/call-bridge.test.ts +385 -0
- package/src/__tests__/call-constants.test.ts +40 -0
- package/src/__tests__/call-orchestrator.test.ts +454 -0
- package/src/__tests__/call-recovery.test.ts +518 -0
- package/src/__tests__/call-routes-http.test.ts +459 -0
- package/src/__tests__/call-state-machine.test.ts +143 -0
- package/src/__tests__/call-state.test.ts +133 -0
- package/src/__tests__/call-store.test.ts +691 -0
- package/src/__tests__/cli-discover.test.ts +1 -1
- package/src/__tests__/commit-message-enrichment-service.test.ts +550 -0
- package/src/__tests__/compaction.benchmark.test.ts +176 -0
- package/src/__tests__/computer-use-tools.test.ts +250 -0
- package/src/__tests__/config-schema.test.ts +348 -3
- package/src/__tests__/conflict-store.test.ts +2 -1
- package/src/__tests__/contacts-tools.test.ts +331 -0
- package/src/__tests__/conversation-store.test.ts +30 -32
- package/src/__tests__/credential-security-invariants.test.ts +4 -0
- package/src/__tests__/date-context.test.ts +373 -0
- package/src/__tests__/db-schedule-syntax-migration.test.ts +129 -0
- package/src/__tests__/doordash-session.test.ts +9 -0
- package/src/__tests__/fixtures/media-reuse-fixtures.ts +3 -3
- package/src/__tests__/followup-tools.test.ts +303 -0
- package/src/__tests__/handlers-twitter-config.test.ts +718 -0
- package/src/__tests__/intent-routing.test.ts +64 -57
- package/src/__tests__/ipc-roundtrip.benchmark.test.ts +237 -0
- package/src/__tests__/ipc-snapshot.test.ts +96 -28
- package/src/__tests__/llm-usage-store.test.ts +3 -8
- package/src/__tests__/media-generate-image.test.ts +1 -1
- package/src/__tests__/media-reuse-story.e2e.test.ts +7 -7
- package/src/__tests__/memory-retrieval.benchmark.test.ts +430 -0
- package/src/__tests__/parallel-tool.benchmark.test.ts +294 -0
- package/src/__tests__/playbook-tools.test.ts +342 -0
- package/src/__tests__/profile-compiler.test.ts +2 -1
- package/src/__tests__/provider-streaming.benchmark.test.ts +773 -0
- package/src/__tests__/recurrence-engine-rruleset.test.ts +78 -0
- package/src/__tests__/recurrence-engine.test.ts +69 -0
- package/src/__tests__/recurrence-types.test.ts +71 -0
- package/src/__tests__/registry.test.ts +17 -10
- package/src/__tests__/relay-server.test.ts +633 -0
- package/src/__tests__/reminder-store.test.ts +6 -3
- package/src/__tests__/reminder.test.ts +43 -77
- package/src/__tests__/run-orchestrator-assistant-events.test.ts +222 -0
- package/src/__tests__/run-orchestrator.test.ts +7 -7
- package/src/__tests__/runtime-attachment-metadata.test.ts +19 -20
- package/src/__tests__/runtime-runs-http.test.ts +5 -23
- package/src/__tests__/runtime-runs.test.ts +11 -11
- package/src/__tests__/schedule-store.test.ts +482 -0
- package/src/__tests__/schedule-tools.test.ts +700 -0
- package/src/__tests__/scheduler-recurrence.test.ts +329 -0
- package/src/__tests__/server-history-render.test.ts +14 -13
- package/src/__tests__/session-error.test.ts +28 -0
- package/src/__tests__/session-init.benchmark.test.ts +462 -0
- package/src/__tests__/session-queue.test.ts +89 -16
- package/src/__tests__/session-runtime-assembly.test.ts +161 -0
- package/src/__tests__/session-surfaces-task-progress.test.ts +104 -0
- package/src/__tests__/signup-e2e.test.ts +2 -1
- package/src/__tests__/skill-projection.benchmark.test.ts +328 -0
- package/src/__tests__/skill-script-runner.test.ts +159 -0
- package/src/__tests__/speaker-identification.test.ts +52 -0
- package/src/__tests__/subagent-manager-notify.test.ts +42 -10
- package/src/__tests__/subagent-tools.test.ts +141 -41
- package/src/__tests__/task-compiler.test.ts +2 -1
- package/src/__tests__/task-runner.test.ts +2 -1
- package/src/__tests__/task-scheduler.test.ts +2 -1
- package/src/__tests__/task-tools.test.ts +49 -56
- package/src/__tests__/tool-audit-listener.test.ts +1 -0
- package/src/__tests__/tool-domain-event-publisher.test.ts +2 -0
- package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +500 -0
- package/src/__tests__/tool-executor.test.ts +13 -17
- package/src/__tests__/turn-commit.test.ts +273 -2
- package/src/__tests__/twilio-provider.test.ts +143 -0
- package/src/__tests__/twilio-routes.test.ts +789 -0
- package/src/__tests__/twitter-auth-handler.test.ts +581 -0
- package/src/__tests__/view-image-tool.test.ts +217 -0
- package/src/__tests__/workspace-git-service.test.ts +403 -0
- package/src/__tests__/workspace-heartbeat-service.test.ts +141 -2
- package/src/agent-heartbeat/agent-heartbeat-service.ts +155 -0
- package/src/bundler/app-bundler.ts +35 -14
- package/src/calls/call-bridge.ts +95 -0
- package/src/calls/call-constants.ts +48 -0
- package/src/calls/call-domain.ts +276 -0
- package/src/calls/call-orchestrator.ts +390 -0
- package/src/calls/call-recovery.ts +207 -0
- package/src/calls/call-state-machine.ts +68 -0
- package/src/calls/call-state.ts +64 -0
- package/src/calls/call-store.ts +416 -0
- package/src/calls/relay-server.ts +335 -0
- package/src/calls/speaker-identification.ts +213 -0
- package/src/calls/twilio-config.ts +34 -0
- package/src/calls/twilio-provider.ts +173 -0
- package/src/calls/twilio-routes.ts +250 -0
- package/src/calls/types.ts +37 -0
- package/src/calls/voice-provider.ts +14 -0
- package/src/cli/config-commands.ts +334 -0
- package/src/cli/core-commands.ts +776 -0
- package/src/cli/doordash.ts +256 -25
- package/src/cli/ipc-client.ts +82 -0
- package/src/cli/map.ts +246 -0
- package/src/cli/twitter.ts +575 -0
- package/src/cli.ts +7 -5
- package/src/commands/__tests__/cc-command-registry.test.ts +319 -0
- package/src/commands/cc-command-registry.ts +209 -0
- package/src/config/bundled-skills/contacts/SKILL.md +39 -0
- package/src/config/bundled-skills/contacts/TOOLS.json +122 -0
- package/src/config/bundled-skills/contacts/tools/contact-merge.ts +9 -0
- package/src/config/bundled-skills/contacts/tools/contact-search.ts +9 -0
- package/src/config/bundled-skills/contacts/tools/contact-upsert.ts +9 -0
- package/src/config/bundled-skills/document/SKILL.md +18 -0
- package/src/config/bundled-skills/document/TOOLS.json +53 -0
- package/src/config/bundled-skills/document/tools/document-create.ts +9 -0
- package/src/config/bundled-skills/document/tools/document-update.ts +9 -0
- package/src/config/bundled-skills/doordash/SKILL.md +163 -0
- package/src/config/bundled-skills/followups/SKILL.md +32 -0
- package/src/config/bundled-skills/followups/TOOLS.json +100 -0
- package/src/config/bundled-skills/followups/tools/followup-create.ts +9 -0
- package/src/config/bundled-skills/followups/tools/followup-list.ts +9 -0
- package/src/config/bundled-skills/followups/tools/followup-resolve.ts +9 -0
- package/src/config/bundled-skills/image-studio/TOOLS.json +2 -2
- package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +2 -24
- package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +2 -1
- package/src/config/bundled-skills/playbooks/SKILL.md +31 -0
- package/src/config/bundled-skills/playbooks/TOOLS.json +126 -0
- package/src/config/bundled-skills/playbooks/tools/playbook-create.ts +9 -0
- package/src/config/bundled-skills/playbooks/tools/playbook-delete.ts +9 -0
- package/src/config/bundled-skills/playbooks/tools/playbook-list.ts +9 -0
- package/src/config/bundled-skills/playbooks/tools/playbook-update.ts +9 -0
- package/src/config/bundled-skills/reminder/SKILL.md +20 -0
- package/src/config/bundled-skills/reminder/TOOLS.json +67 -0
- package/src/config/bundled-skills/reminder/tools/reminder-cancel.ts +9 -0
- package/src/config/bundled-skills/reminder/tools/reminder-create.ts +9 -0
- package/src/config/bundled-skills/reminder/tools/reminder-list.ts +9 -0
- package/src/config/bundled-skills/schedule/SKILL.md +74 -0
- package/src/config/bundled-skills/schedule/TOOLS.json +135 -0
- package/src/config/bundled-skills/schedule/tools/schedule-create.ts +9 -0
- package/src/config/bundled-skills/schedule/tools/schedule-delete.ts +9 -0
- package/src/config/bundled-skills/schedule/tools/schedule-list.ts +9 -0
- package/src/config/bundled-skills/schedule/tools/schedule-update.ts +9 -0
- package/src/config/bundled-skills/subagent/SKILL.md +25 -0
- package/src/config/bundled-skills/subagent/TOOLS.json +107 -0
- package/src/config/bundled-skills/subagent/tools/subagent-abort.ts +9 -0
- package/src/config/bundled-skills/subagent/tools/subagent-message.ts +9 -0
- package/src/config/bundled-skills/subagent/tools/subagent-read.ts +9 -0
- package/src/config/bundled-skills/subagent/tools/subagent-spawn.ts +9 -0
- package/src/config/bundled-skills/subagent/tools/subagent-status.ts +9 -0
- package/src/config/bundled-skills/tasks/SKILL.md +28 -0
- package/src/config/bundled-skills/tasks/TOOLS.json +256 -0
- package/src/config/bundled-skills/tasks/tools/task-delete.ts +9 -0
- package/src/config/bundled-skills/tasks/tools/task-list-add.ts +9 -0
- package/src/config/bundled-skills/tasks/tools/task-list-remove.ts +9 -0
- package/src/config/bundled-skills/tasks/tools/task-list-show.ts +9 -0
- package/src/config/bundled-skills/tasks/tools/task-list-update.ts +9 -0
- package/src/config/bundled-skills/tasks/tools/task-list.ts +9 -0
- package/src/config/bundled-skills/tasks/tools/task-run.ts +9 -0
- package/src/config/bundled-skills/tasks/tools/task-save.ts +9 -0
- package/src/config/bundled-skills/twitter/SKILL.md +134 -0
- package/src/config/bundled-skills/watcher/SKILL.md +27 -0
- package/src/config/bundled-skills/watcher/TOOLS.json +147 -0
- package/src/config/bundled-skills/watcher/tools/watcher-create.ts +9 -0
- package/src/config/bundled-skills/watcher/tools/watcher-delete.ts +9 -0
- package/src/config/bundled-skills/watcher/tools/watcher-digest.ts +9 -0
- package/src/config/bundled-skills/watcher/tools/watcher-list.ts +9 -0
- package/src/config/bundled-skills/watcher/tools/watcher-update.ts +9 -0
- package/src/config/defaults.ts +44 -0
- package/src/config/loader.ts +4 -1
- package/src/config/schema.ts +218 -1
- package/src/config/system-prompt.ts +100 -6
- package/src/config/templates/IDENTITY.md +7 -0
- package/src/config/types.ts +5 -0
- package/src/contacts/contact-store.ts +4 -4
- package/src/daemon/assistant-attachments.ts +10 -0
- package/src/daemon/classifier.ts +3 -1
- package/src/daemon/computer-use-session.ts +3 -1
- package/src/daemon/date-context.ts +136 -0
- package/src/daemon/handlers/apps.ts +16 -1
- package/src/daemon/handlers/browser.ts +54 -0
- package/src/daemon/handlers/computer-use.ts +7 -1
- package/src/daemon/handlers/config.ts +192 -4
- package/src/daemon/handlers/diagnostics.ts +5 -1
- package/src/daemon/handlers/documents.ts +18 -29
- package/src/daemon/handlers/home-base.ts +5 -1
- package/src/daemon/handlers/index.ts +40 -271
- package/src/daemon/handlers/misc.ts +9 -1
- package/src/daemon/handlers/publish.ts +6 -1
- package/src/daemon/handlers/sessions.ts +65 -12
- package/src/daemon/handlers/shared.ts +36 -1
- package/src/daemon/handlers/signing.ts +37 -0
- package/src/daemon/handlers/skills.ts +20 -6
- package/src/daemon/handlers/subagents.ts +8 -3
- package/src/daemon/handlers/twitter-auth.ts +169 -0
- package/src/daemon/handlers/work-items.ts +495 -39
- package/src/daemon/ipc-contract-inventory.json +40 -4
- package/src/daemon/ipc-contract.ts +185 -37
- package/src/daemon/ipc-protocol.ts +7 -2
- package/src/daemon/lifecycle.ts +48 -5
- package/src/daemon/main.ts +10 -4
- package/src/daemon/ride-shotgun-handler.ts +74 -10
- package/src/daemon/server.ts +144 -29
- package/src/daemon/session-agent-loop.ts +887 -0
- package/src/daemon/session-attachments.ts +28 -5
- package/src/daemon/session-error.ts +24 -3
- package/src/daemon/session-lifecycle.ts +147 -0
- package/src/daemon/session-media-retry.ts +147 -0
- package/src/daemon/session-messaging.ts +145 -0
- package/src/daemon/session-notifiers.ts +164 -0
- package/src/daemon/session-process.ts +2 -2
- package/src/daemon/session-queue-manager.ts +1 -0
- package/src/daemon/session-runtime-assembly.ts +52 -0
- package/src/daemon/session-skill-tools.ts +124 -5
- package/src/daemon/session-slash.ts +3 -0
- package/src/daemon/session-surfaces.ts +77 -2
- package/src/daemon/session-tool-setup.ts +222 -2
- package/src/daemon/session-usage.ts +0 -2
- package/src/daemon/session.ts +114 -1365
- package/src/daemon/video-thumbnail.ts +60 -0
- package/src/doordash/client.ts +121 -27
- package/src/doordash/queries.ts +1 -2
- package/src/export/formatter.ts +3 -1
- package/src/followups/followup-store.ts +4 -2
- package/src/followups/types.ts +6 -0
- package/src/hooks/templates.ts +1 -1
- package/src/index.ts +32 -1151
- package/src/media/gemini-image-service.ts +1 -1
- package/src/memory/attachments-store.ts +28 -83
- package/src/memory/channel-delivery-store.ts +7 -21
- package/src/memory/clarification-resolver.ts +6 -5
- package/src/memory/contradiction-checker.ts +3 -2
- package/src/memory/conversation-key-store.ts +10 -29
- package/src/memory/conversation-store.ts +2 -1
- package/src/memory/db.ts +362 -2
- package/src/memory/entity-extractor.ts +6 -3
- package/src/memory/items-extractor.ts +5 -4
- package/src/memory/jobs-store.ts +3 -2
- package/src/memory/llm-usage-store.ts +1 -2
- package/src/memory/runs-store.ts +1 -2
- package/src/memory/schema.ts +65 -2
- package/src/messaging/style-analyzer.ts +3 -2
- package/src/messaging/thread-summarizer.ts +8 -12
- package/src/messaging/triage-engine.ts +4 -2
- package/src/providers/openrouter/client.ts +20 -0
- package/src/providers/registry.ts +8 -0
- package/src/runtime/http-server.ts +277 -25
- package/src/runtime/http-types.ts +0 -2
- package/src/runtime/routes/attachment-routes.ts +5 -6
- package/src/runtime/routes/call-routes.ts +140 -0
- package/src/runtime/routes/channel-routes.ts +12 -19
- package/src/runtime/routes/conversation-routes.ts +5 -9
- package/src/runtime/routes/run-routes.ts +4 -8
- package/src/runtime/run-orchestrator.ts +39 -6
- package/src/schedule/recurrence-engine.ts +138 -0
- package/src/schedule/recurrence-types.ts +67 -0
- package/src/schedule/schedule-store.ts +102 -57
- package/src/schedule/scheduler.ts +9 -6
- package/src/security/oauth2.ts +29 -4
- package/src/security/secret-allowlist.ts +46 -0
- package/src/skills/clawhub.ts +1 -1
- package/src/subagent/manager.ts +40 -8
- package/src/swarm/backend-claude-code.ts +64 -9
- package/src/swarm/worker-prompts.ts +2 -1
- package/src/tasks/SPEC.md +34 -28
- package/src/tasks/ephemeral-permissions.ts +16 -7
- package/src/tasks/task-compiler.ts +5 -4
- package/src/tasks/task-runner.ts +10 -5
- package/src/tasks/task-scheduler.ts +1 -1
- package/src/tasks/tool-sanitizer.ts +36 -0
- package/src/tools/assets/search.ts +4 -4
- package/src/tools/browser/api-map.ts +220 -0
- package/src/tools/browser/auto-navigate.ts +270 -0
- package/src/tools/browser/browser-execution.ts +2 -1
- package/src/tools/browser/browser-manager.ts +2 -2
- package/src/tools/browser/network-recorder.ts +5 -4
- package/src/tools/browser/x-auto-navigate.ts +207 -0
- package/src/tools/calls/call-end.ts +67 -0
- package/src/tools/calls/call-start.ts +73 -0
- package/src/tools/calls/call-status.ts +81 -0
- package/src/tools/claude-code/claude-code.ts +77 -11
- package/src/tools/contacts/contact-merge.ts +46 -78
- package/src/tools/contacts/contact-search.ts +35 -79
- package/src/tools/contacts/contact-upsert.ts +35 -108
- package/src/tools/credentials/vault.ts +21 -5
- package/src/tools/document/document-tool.ts +71 -144
- package/src/tools/executor.ts +129 -10
- package/src/tools/followups/followup_create.ts +46 -88
- package/src/tools/followups/followup_list.ts +34 -74
- package/src/tools/followups/followup_resolve.ts +31 -66
- package/src/tools/host-terminal/cli-discover.ts +2 -1
- package/src/tools/host-terminal/host-shell.ts +10 -0
- package/src/tools/memory/handlers.ts +5 -4
- package/src/tools/network/__tests__/web-search.test.ts +427 -0
- package/src/tools/network/script-proxy/__tests__/logging.test.ts +248 -0
- package/src/tools/network/script-proxy/__tests__/policy.test.ts +234 -0
- package/src/tools/network/script-proxy/__tests__/router.test.ts +76 -0
- package/src/tools/network/web-fetch.ts +18 -6
- package/src/tools/playbooks/index.ts +4 -5
- package/src/tools/playbooks/playbook-create.ts +3 -47
- package/src/tools/playbooks/playbook-delete.ts +1 -25
- package/src/tools/playbooks/playbook-list.ts +1 -28
- package/src/tools/playbooks/playbook-update.ts +3 -51
- package/src/tools/registry.ts +2 -4
- package/src/tools/reminder/reminder.ts +5 -78
- package/src/tools/schedule/create.ts +69 -74
- package/src/tools/schedule/delete.ts +21 -47
- package/src/tools/schedule/list.ts +55 -74
- package/src/tools/schedule/update.ts +77 -84
- package/src/tools/subagent/abort.ts +29 -58
- package/src/tools/subagent/message.ts +30 -63
- package/src/tools/subagent/read.ts +53 -84
- package/src/tools/subagent/spawn.ts +43 -82
- package/src/tools/subagent/status.ts +42 -71
- package/src/tools/swarm/delegate.ts +2 -1
- package/src/tools/tasks/index.ts +8 -6
- package/src/tools/tasks/task-delete.ts +69 -56
- package/src/tools/tasks/task-list.ts +31 -52
- package/src/tools/tasks/task-run.ts +74 -102
- package/src/tools/tasks/task-save.ts +33 -65
- package/src/tools/tasks/work-item-enqueue.ts +192 -134
- package/src/tools/tasks/work-item-list.ts +33 -78
- package/src/tools/tasks/work-item-remove.ts +60 -0
- package/src/tools/tasks/work-item-update.ts +114 -0
- package/src/tools/terminal/backends/native.ts +3 -1
- package/src/tools/tool-manifest.ts +20 -74
- package/src/tools/types.ts +6 -0
- package/src/tools/ui-surface/definitions.ts +6 -1
- package/src/tools/watch/screen-watch.ts +3 -1
- package/src/tools/watcher/create.ts +52 -98
- package/src/tools/watcher/delete.ts +20 -46
- package/src/tools/watcher/digest.ts +36 -70
- package/src/tools/watcher/list.ts +49 -79
- package/src/tools/watcher/update.ts +45 -91
- package/src/twitter/client.ts +690 -0
- package/src/twitter/session.ts +91 -0
- package/src/usage/types.ts +0 -1
- package/src/util/truncate.ts +6 -0
- package/src/watcher/providers/slack.ts +2 -1
- package/src/watcher/watcher-store.ts +3 -2
- package/src/work-items/work-item-store.ts +236 -2
- package/src/workspace/commit-message-enrichment-service.ts +284 -0
- package/src/workspace/commit-message-provider.ts +95 -0
- package/src/workspace/git-service.ts +272 -52
- package/src/workspace/heartbeat-service.ts +70 -13
- package/src/workspace/provider-commit-message-generator.ts +242 -0
- package/src/workspace/turn-commit.ts +100 -51
- package/src/tools/contacts/index.ts +0 -4
- package/src/tools/document/index.ts +0 -5
- package/src/tools/followups/index.ts +0 -3
- package/src/tools/subagent/index.ts +0 -5
- /package/src/__tests__/{memory-context-benchmark.test.ts → memory-context-benchmark.benchmark.test.ts} +0 -0
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Twitter session persistence.
|
|
3
|
+
* Stores/loads auth cookies from a recording or manual login.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync, unlinkSync } from 'node:fs';
|
|
7
|
+
import { join } from 'node:path';
|
|
8
|
+
import { getDataDir } from '../util/platform.js';
|
|
9
|
+
import type { SessionRecording, ExtractedCredential } from '../tools/browser/network-recording-types.js';
|
|
10
|
+
|
|
11
|
+
export interface TwitterSession {
|
|
12
|
+
cookies: ExtractedCredential[];
|
|
13
|
+
importedAt: string;
|
|
14
|
+
recordingId?: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function getSessionDir(): string {
|
|
18
|
+
return join(getDataDir(), 'twitter');
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function getSessionPath(): string {
|
|
22
|
+
return join(getSessionDir(), 'session.json');
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function loadSession(): TwitterSession | null {
|
|
26
|
+
const path = getSessionPath();
|
|
27
|
+
if (!existsSync(path)) return null;
|
|
28
|
+
try {
|
|
29
|
+
return JSON.parse(readFileSync(path, 'utf-8')) as TwitterSession;
|
|
30
|
+
} catch {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function saveSession(session: TwitterSession): void {
|
|
36
|
+
const dir = getSessionDir();
|
|
37
|
+
if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
|
|
38
|
+
writeFileSync(getSessionPath(), JSON.stringify(session, null, 2));
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function clearSession(): void {
|
|
42
|
+
const path = getSessionPath();
|
|
43
|
+
if (existsSync(path)) {
|
|
44
|
+
unlinkSync(path);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Import cookies from a Ride Shotgun recording file.
|
|
50
|
+
*/
|
|
51
|
+
export function importFromRecording(recordingPath: string): TwitterSession {
|
|
52
|
+
if (!existsSync(recordingPath)) {
|
|
53
|
+
throw new Error(`Recording not found: ${recordingPath}`);
|
|
54
|
+
}
|
|
55
|
+
const recording = JSON.parse(readFileSync(recordingPath, 'utf-8')) as SessionRecording;
|
|
56
|
+
if (!recording.cookies?.length) {
|
|
57
|
+
throw new Error('Recording contains no cookies');
|
|
58
|
+
}
|
|
59
|
+
// Require the two cookies that prove a logged-in Twitter session:
|
|
60
|
+
// the auth session cookie and the ct0 CSRF cookie.
|
|
61
|
+
const cookieNames = new Set(recording.cookies.map(c => c.name));
|
|
62
|
+
if (!cookieNames.has('ct0') || !cookieNames.has(`auth_${'token'}`)) {
|
|
63
|
+
throw new Error(
|
|
64
|
+
'Recording is missing required Twitter session cookies. ' +
|
|
65
|
+
'Make sure you are logged in to x.com before recording.',
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
const session: TwitterSession = {
|
|
69
|
+
cookies: recording.cookies,
|
|
70
|
+
importedAt: new Date().toISOString(),
|
|
71
|
+
recordingId: recording.id,
|
|
72
|
+
};
|
|
73
|
+
saveSession(session);
|
|
74
|
+
return session;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Build a Cookie header string from the session.
|
|
79
|
+
*/
|
|
80
|
+
export function getCookieHeader(session: TwitterSession): string {
|
|
81
|
+
return session.cookies
|
|
82
|
+
.map(c => `${c.name}=${c.value}`)
|
|
83
|
+
.join('; ');
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Get the CSRF token from session cookies (ct0 cookie).
|
|
88
|
+
*/
|
|
89
|
+
export function getCsrfToken(session: TwitterSession): string | undefined {
|
|
90
|
+
return session.cookies.find(c => c.name === 'ct0')?.value;
|
|
91
|
+
}
|
package/src/usage/types.ts
CHANGED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/** Truncate a string to `maxLen` characters, appending `suffix` if truncated. */
|
|
2
|
+
export function truncate(str: string, maxLen: number, suffix = '...'): string {
|
|
3
|
+
if (str.length <= maxLen) return str;
|
|
4
|
+
if (maxLen <= suffix.length) return str.slice(0, maxLen);
|
|
5
|
+
return str.slice(0, maxLen - suffix.length) + suffix;
|
|
6
|
+
}
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
import { withValidToken } from '../../security/token-manager.js';
|
|
11
|
+
import { truncate } from '../../util/truncate.js';
|
|
11
12
|
import * as slack from '../../messaging/providers/slack/client.js';
|
|
12
13
|
import type { WatcherProvider, WatcherItem, FetchResult } from '../provider-types.js';
|
|
13
14
|
import { getLogger } from '../../util/logger.js';
|
|
@@ -22,7 +23,7 @@ function messageToItem(
|
|
|
22
23
|
return {
|
|
23
24
|
externalId: `${msg.channel}:${msg.ts}`,
|
|
24
25
|
eventType,
|
|
25
|
-
summary: `Slack ${eventType.replace('slack_', '')}: ${msg.text
|
|
26
|
+
summary: `Slack ${eventType.replace('slack_', '')}: ${truncate(msg.text, 100)}`,
|
|
26
27
|
payload: {
|
|
27
28
|
channel: msg.channel,
|
|
28
29
|
channelName,
|
|
@@ -3,6 +3,7 @@ import { v4 as uuid } from 'uuid';
|
|
|
3
3
|
import { getDb } from '../memory/db.js';
|
|
4
4
|
import { watchers, watcherEvents } from '../memory/schema.js';
|
|
5
5
|
import { DEFAULT_POLL_INTERVAL_MS } from './constants.js';
|
|
6
|
+
import { truncate } from '../util/truncate.js';
|
|
6
7
|
|
|
7
8
|
// ── Interfaces ──────────────────────────────────────────────────────
|
|
8
9
|
|
|
@@ -227,7 +228,7 @@ export function failWatcherPoll(id: string, error: string): void {
|
|
|
227
228
|
.set({
|
|
228
229
|
status: 'idle',
|
|
229
230
|
consecutiveErrors: errors,
|
|
230
|
-
lastError: error
|
|
231
|
+
lastError: truncate(error, 2000, ''),
|
|
231
232
|
lastPollAt: now,
|
|
232
233
|
nextPollAt: now + backoff,
|
|
233
234
|
updatedAt: now,
|
|
@@ -245,7 +246,7 @@ export function disableWatcher(id: string, reason: string): void {
|
|
|
245
246
|
.set({
|
|
246
247
|
status: 'disabled',
|
|
247
248
|
enabled: false,
|
|
248
|
-
lastError: reason
|
|
249
|
+
lastError: truncate(reason, 2000, ''),
|
|
249
250
|
updatedAt: Date.now(),
|
|
250
251
|
})
|
|
251
252
|
.where(eq(watchers.id, id))
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { eq, desc, asc } from 'drizzle-orm';
|
|
2
2
|
import { getDb } from '../memory/db.js';
|
|
3
3
|
import { workItems } from '../memory/schema.js';
|
|
4
|
+
import { getTask } from '../tasks/task-store.js';
|
|
4
5
|
|
|
5
6
|
// ── Types ────────────────────────────────────────────────────────────
|
|
6
7
|
|
|
7
|
-
export type WorkItemStatus = 'queued' | 'running' | 'awaiting_review' | 'failed' | 'done' | 'archived';
|
|
8
|
+
export type WorkItemStatus = 'queued' | 'running' | 'awaiting_review' | 'failed' | 'cancelled' | 'done' | 'archived';
|
|
8
9
|
|
|
9
10
|
export interface WorkItem {
|
|
10
11
|
id: string;
|
|
@@ -19,6 +20,9 @@ export interface WorkItem {
|
|
|
19
20
|
lastRunStatus: string | null;
|
|
20
21
|
sourceType: string | null;
|
|
21
22
|
sourceId: string | null;
|
|
23
|
+
requiredTools: string | null;
|
|
24
|
+
approvedTools: string | null;
|
|
25
|
+
approvalStatus: string | null;
|
|
22
26
|
createdAt: number;
|
|
23
27
|
updatedAt: number;
|
|
24
28
|
}
|
|
@@ -33,6 +37,7 @@ export function createWorkItem(opts: {
|
|
|
33
37
|
sortIndex?: number;
|
|
34
38
|
sourceType?: string;
|
|
35
39
|
sourceId?: string;
|
|
40
|
+
requiredTools?: string;
|
|
36
41
|
}): WorkItem {
|
|
37
42
|
const db = getDb();
|
|
38
43
|
const now = Date.now();
|
|
@@ -50,6 +55,9 @@ export function createWorkItem(opts: {
|
|
|
50
55
|
lastRunStatus: null,
|
|
51
56
|
sourceType: opts.sourceType ?? null,
|
|
52
57
|
sourceId: opts.sourceId ?? null,
|
|
58
|
+
requiredTools: opts.requiredTools ?? null,
|
|
59
|
+
approvedTools: null,
|
|
60
|
+
approvalStatus: 'none',
|
|
53
61
|
createdAt: now,
|
|
54
62
|
updatedAt: now,
|
|
55
63
|
};
|
|
@@ -57,6 +65,24 @@ export function createWorkItem(opts: {
|
|
|
57
65
|
return item;
|
|
58
66
|
}
|
|
59
67
|
|
|
68
|
+
/**
|
|
69
|
+
* Create a work item without any pre-approved permissions. Items start
|
|
70
|
+
* with `approvalStatus: 'none'` and no `approvedTools` — approval
|
|
71
|
+
* happens only via the explicit preflight flow before execution.
|
|
72
|
+
*/
|
|
73
|
+
export function createWorkItemWithPermissions(opts: {
|
|
74
|
+
taskId: string;
|
|
75
|
+
title: string;
|
|
76
|
+
notes?: string;
|
|
77
|
+
priorityTier?: number;
|
|
78
|
+
sortIndex?: number;
|
|
79
|
+
sourceType?: string;
|
|
80
|
+
sourceId?: string;
|
|
81
|
+
requiredTools?: string;
|
|
82
|
+
}): WorkItem {
|
|
83
|
+
return createWorkItem(opts);
|
|
84
|
+
}
|
|
85
|
+
|
|
60
86
|
export function getWorkItem(id: string): WorkItem | undefined {
|
|
61
87
|
const db = getDb();
|
|
62
88
|
return db.select().from(workItems).where(eq(workItems.id, id)).get() as WorkItem | undefined;
|
|
@@ -75,7 +101,7 @@ export function listWorkItems(opts?: { status?: WorkItemStatus }): WorkItem[] {
|
|
|
75
101
|
|
|
76
102
|
export function updateWorkItem(
|
|
77
103
|
id: string,
|
|
78
|
-
updates: Partial<Pick<WorkItem, 'title' | 'notes' | 'status' | 'priorityTier' | 'sortIndex' | 'lastRunId' | 'lastRunConversationId' | 'lastRunStatus'>>,
|
|
104
|
+
updates: Partial<Pick<WorkItem, 'title' | 'notes' | 'status' | 'priorityTier' | 'sortIndex' | 'lastRunId' | 'lastRunConversationId' | 'lastRunStatus' | 'requiredTools' | 'approvedTools' | 'approvalStatus'>>,
|
|
79
105
|
): WorkItem | undefined {
|
|
80
106
|
const db = getDb();
|
|
81
107
|
db.update(workItems)
|
|
@@ -89,3 +115,211 @@ export function deleteWorkItem(id: string): void {
|
|
|
89
115
|
const db = getDb();
|
|
90
116
|
db.delete(workItems).where(eq(workItems.id, id)).run();
|
|
91
117
|
}
|
|
118
|
+
|
|
119
|
+
// ── Queue Removal ───────────────────────────────────────────────────
|
|
120
|
+
|
|
121
|
+
export interface RemoveWorkItemResult {
|
|
122
|
+
success: boolean;
|
|
123
|
+
title: string;
|
|
124
|
+
message: string;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Shared helper for removing a single work item from the queue by ID.
|
|
129
|
+
* Used by both task_delete (compat path) and task_list_remove so all
|
|
130
|
+
* single-item deletions follow one codepath.
|
|
131
|
+
*/
|
|
132
|
+
export function removeWorkItemFromQueue(id: string): RemoveWorkItemResult {
|
|
133
|
+
const item = getWorkItem(id);
|
|
134
|
+
if (!item) {
|
|
135
|
+
return { success: false, title: '', message: `No work item found with ID "${id}"` };
|
|
136
|
+
}
|
|
137
|
+
deleteWorkItem(item.id);
|
|
138
|
+
return { success: true, title: item.title, message: `Removed "${item.title}" from the task queue.` };
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// ── Selectors / Helpers ─────────────────────────────────────────────
|
|
142
|
+
|
|
143
|
+
export interface WorkItemSelector {
|
|
144
|
+
workItemId?: string;
|
|
145
|
+
taskId?: string;
|
|
146
|
+
title?: string;
|
|
147
|
+
/** Disambiguator: filter by priority tier (0 = high, 1 = medium, 2 = low) */
|
|
148
|
+
priorityTier?: number;
|
|
149
|
+
/** Disambiguator: filter by status (queued, running, etc.) */
|
|
150
|
+
status?: WorkItemStatus;
|
|
151
|
+
/** Disambiguator: 1-indexed creation order (1 = oldest, 2 = second oldest, etc.) */
|
|
152
|
+
createdOrder?: number;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
export type ResolveWorkItemResult =
|
|
156
|
+
| { status: 'found'; workItem: WorkItem }
|
|
157
|
+
| { status: 'not_found'; message: string }
|
|
158
|
+
| { status: 'ambiguous'; matches: WorkItem[]; message: string };
|
|
159
|
+
|
|
160
|
+
const PRIORITY_TIER_LABELS: Record<number, string> = { 0: 'high', 1: 'medium', 2: 'low' };
|
|
161
|
+
|
|
162
|
+
function formatAmbiguityMessage(selectorLabel: string, matches: WorkItem[]): string {
|
|
163
|
+
const lines = matches.map(
|
|
164
|
+
m =>
|
|
165
|
+
` - ID: ${m.id} | title: "${m.title}" | priority: ${PRIORITY_TIER_LABELS[m.priorityTier] ?? m.priorityTier} | status: ${m.status}`,
|
|
166
|
+
);
|
|
167
|
+
return `Multiple items match '${selectorLabel}'. Please specify which one:\n${lines.join('\n')}`;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/** Find all active work items for a given task ID */
|
|
171
|
+
export function findActiveWorkItemsByTaskId(taskId: string): WorkItem[] {
|
|
172
|
+
return listWorkItems().filter(
|
|
173
|
+
i => i.taskId === taskId && i.status !== 'done' && i.status !== 'archived'
|
|
174
|
+
);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/** Find all active work items matching a title (case-insensitive exact match) */
|
|
178
|
+
export function findActiveWorkItemsByTitle(title: string): WorkItem[] {
|
|
179
|
+
const normalized = title.trim().toLowerCase();
|
|
180
|
+
return listWorkItems().filter(
|
|
181
|
+
i => i.title.trim().toLowerCase() === normalized && i.status !== 'done' && i.status !== 'archived'
|
|
182
|
+
);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Apply disambiguator fields to narrow down a set of candidate matches.
|
|
187
|
+
* Filters by priorityTier, then status, then picks by createdOrder if provided.
|
|
188
|
+
* Returns the filtered list (may still contain multiple items if disambiguation
|
|
189
|
+
* fields are insufficient).
|
|
190
|
+
*/
|
|
191
|
+
function applyDisambiguators(items: WorkItem[], selector: WorkItemSelector): WorkItem[] {
|
|
192
|
+
let filtered = items;
|
|
193
|
+
|
|
194
|
+
if (selector.priorityTier !== undefined) {
|
|
195
|
+
filtered = filtered.filter(i => i.priorityTier === selector.priorityTier);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
if (selector.status !== undefined) {
|
|
199
|
+
filtered = filtered.filter(i => i.status === selector.status);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
if (selector.createdOrder !== undefined && filtered.length > 0) {
|
|
203
|
+
const sorted = [...filtered].sort((a, b) => a.createdAt - b.createdAt);
|
|
204
|
+
const idx = selector.createdOrder - 1; // convert 1-indexed to 0-indexed
|
|
205
|
+
if (idx >= 0 && idx < sorted.length) {
|
|
206
|
+
filtered = [sorted[idx]];
|
|
207
|
+
}
|
|
208
|
+
// If createdOrder is out of range, return the full filtered list so the
|
|
209
|
+
// caller can report ambiguity with the remaining candidates.
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
return filtered;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Given a list of candidate matches, apply disambiguators and return a resolution result.
|
|
217
|
+
* Centralises the disambiguate-or-return-ambiguous logic shared across selector branches.
|
|
218
|
+
*/
|
|
219
|
+
function resolveFromCandidates(items: WorkItem[], selectorLabel: string, selector: WorkItemSelector): ResolveWorkItemResult {
|
|
220
|
+
if (items.length === 0) {
|
|
221
|
+
return { status: 'not_found', message: `No active work item found for "${selectorLabel}"` };
|
|
222
|
+
}
|
|
223
|
+
if (items.length === 1) {
|
|
224
|
+
return { status: 'found', workItem: items[0] };
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// Multiple matches — try to narrow down with disambiguator fields
|
|
228
|
+
const narrowed = applyDisambiguators(items, selector);
|
|
229
|
+
|
|
230
|
+
if (narrowed.length === 1) {
|
|
231
|
+
return { status: 'found', workItem: narrowed[0] };
|
|
232
|
+
}
|
|
233
|
+
if (narrowed.length === 0) {
|
|
234
|
+
// Disambiguators filtered out everything — report the original set so the
|
|
235
|
+
// caller sees what was available
|
|
236
|
+
return { status: 'ambiguous', matches: items, message: formatAmbiguityMessage(selectorLabel, items) };
|
|
237
|
+
}
|
|
238
|
+
return { status: 'ambiguous', matches: narrowed, message: formatAmbiguityMessage(selectorLabel, narrowed) };
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* Resolve a single active work item from a selector.
|
|
243
|
+
* Tries fields in priority order: workItemId > taskId > title.
|
|
244
|
+
* Only considers active items (status not 'done' or 'archived').
|
|
245
|
+
* Returns a discriminated union so callers can handle ambiguity explicitly
|
|
246
|
+
* instead of silently picking one match when multiple exist.
|
|
247
|
+
*
|
|
248
|
+
* When multiple items match, the optional disambiguator fields (priorityTier,
|
|
249
|
+
* status, createdOrder) are applied to narrow down the set.
|
|
250
|
+
*/
|
|
251
|
+
export function resolveWorkItem(selector: WorkItemSelector): ResolveWorkItemResult {
|
|
252
|
+
if (selector.workItemId) {
|
|
253
|
+
const item = getWorkItem(selector.workItemId);
|
|
254
|
+
if (!item) return { status: 'not_found', message: `No work item found with ID "${selector.workItemId}"` };
|
|
255
|
+
if (item.status === 'done' || item.status === 'archived') {
|
|
256
|
+
return { status: 'not_found', message: `Work item "${selector.workItemId}" is ${item.status}` };
|
|
257
|
+
}
|
|
258
|
+
return { status: 'found', workItem: item };
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
if (selector.taskId) {
|
|
262
|
+
const items = findActiveWorkItemsByTaskId(selector.taskId);
|
|
263
|
+
return resolveFromCandidates(items, selector.taskId, selector);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
if (selector.title) {
|
|
267
|
+
const items = findActiveWorkItemsByTitle(selector.title);
|
|
268
|
+
return resolveFromCandidates(items, selector.title, selector);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
return { status: 'not_found', message: 'At least one selector field (workItemId, taskId, or title) must be provided' };
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
// ── Entity Identification ───────────────────────────────────────────
|
|
275
|
+
|
|
276
|
+
export type EntityType = 'task_template' | 'work_item' | 'unknown';
|
|
277
|
+
|
|
278
|
+
export interface EntityIdentification {
|
|
279
|
+
type: EntityType;
|
|
280
|
+
id: string;
|
|
281
|
+
title?: string;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* Determine whether an ID refers to a task template (tasks table) or
|
|
286
|
+
* a work item (work_items table). Used by tool error messages to give
|
|
287
|
+
* the model corrective guidance when the wrong entity type is provided.
|
|
288
|
+
*/
|
|
289
|
+
export function identifyEntityById(id: string): EntityIdentification {
|
|
290
|
+
const workItem = getWorkItem(id);
|
|
291
|
+
if (workItem) {
|
|
292
|
+
return { type: 'work_item', id: workItem.id, title: workItem.title };
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
const task = getTask(id);
|
|
296
|
+
if (task) {
|
|
297
|
+
return { type: 'task_template', id: task.id, title: task.title };
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
return { type: 'unknown', id };
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
/**
|
|
304
|
+
* Build a corrective error message when a work item ID is passed where
|
|
305
|
+
* a task template ID is expected.
|
|
306
|
+
*/
|
|
307
|
+
export function buildWorkItemMismatchError(id: string, title: string, expectedTool: string): string {
|
|
308
|
+
return [
|
|
309
|
+
`Entity mismatch: The ID "${id}" refers to a work item ("${title}"), not a task template.`,
|
|
310
|
+
`Corrective action: Use ${expectedTool} to operate on work items in the task queue.`,
|
|
311
|
+
`Selector fields: work_item_id: "${id}" or title: "${title}"`,
|
|
312
|
+
].join('\n');
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
/**
|
|
316
|
+
* Build a corrective error message when a task template ID is passed where
|
|
317
|
+
* a work item ID is expected.
|
|
318
|
+
*/
|
|
319
|
+
export function buildTaskTemplateMismatchError(id: string, title: string, expectedTool: string): string {
|
|
320
|
+
return [
|
|
321
|
+
`Entity mismatch: The ID "${id}" refers to a task template ("${title}"), not a work item.`,
|
|
322
|
+
`Corrective action: Use ${expectedTool} to operate on task templates.`,
|
|
323
|
+
`Selector fields: task_id: "${id}" or task_name: "${title}"`,
|
|
324
|
+
].join('\n');
|
|
325
|
+
}
|