vellum 0.2.1 → 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 +133 -34
- package/src/__tests__/account-registry.test.ts +2 -1
- package/src/__tests__/agent-heartbeat-service.test.ts +250 -0
- 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 +4 -3
- 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 +130 -4
- 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-store.test.ts +216 -1
- package/src/__tests__/cli-discover.test.ts +1 -1
- package/src/__tests__/commit-message-enrichment-service.test.ts +148 -7
- 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 +299 -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__/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 +62 -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 +5 -3
- 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 +8 -4
- package/src/__tests__/run-orchestrator.test.ts +4 -4
- package/src/__tests__/runtime-attachment-metadata.test.ts +7 -6
- package/src/__tests__/runtime-runs-http.test.ts +4 -4
- package/src/__tests__/runtime-runs.test.ts +4 -4
- 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 +71 -48
- 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 +218 -3
- 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 +186 -0
- package/src/__tests__/workspace-heartbeat-service.test.ts +13 -3
- package/src/agent-heartbeat/agent-heartbeat-service.ts +155 -0
- package/src/bundler/app-bundler.ts +12 -8
- package/src/calls/call-bridge.ts +95 -0
- package/src/calls/call-constants.ts +43 -5
- package/src/calls/call-domain.ts +276 -0
- package/src/calls/call-orchestrator.ts +43 -17
- package/src/calls/call-recovery.ts +207 -0
- package/src/calls/call-state-machine.ts +68 -0
- package/src/calls/call-store.ts +192 -5
- package/src/calls/relay-server.ts +41 -4
- package/src/calls/speaker-identification.ts +213 -0
- package/src/calls/twilio-provider.ts +10 -6
- package/src/calls/twilio-routes.ts +90 -76
- package/src/calls/types.ts +1 -1
- package/src/cli/config-commands.ts +334 -0
- package/src/cli/core-commands.ts +776 -0
- package/src/cli/doordash.ts +251 -1
- 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 +82 -23
- 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/media-generate-image.ts +1 -23
- 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 +33 -0
- package/src/config/loader.ts +4 -1
- package/src/config/schema.ts +161 -1
- package/src/config/system-prompt.ts +61 -16
- package/src/config/templates/IDENTITY.md +7 -0
- package/src/config/types.ts +4 -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 +163 -5
- 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 -277
- 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 +384 -68
- package/src/daemon/ipc-contract-inventory.json +28 -4
- package/src/daemon/ipc-contract.ts +133 -37
- package/src/daemon/ipc-protocol.ts +7 -2
- package/src/daemon/lifecycle.ts +21 -0
- package/src/daemon/main.ts +10 -4
- package/src/daemon/ride-shotgun-handler.ts +74 -10
- package/src/daemon/server.ts +143 -26
- 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 +216 -2
- package/src/daemon/session-usage.ts +0 -2
- package/src/daemon/session.ts +114 -1404
- 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 -1153
- 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 +96 -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 +23 -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 +108 -20
- package/src/runtime/routes/attachment-routes.ts +2 -3
- package/src/runtime/routes/call-routes.ts +140 -0
- package/src/runtime/routes/channel-routes.ts +5 -10
- package/src/runtime/routes/conversation-routes.ts +5 -5
- package/src/runtime/routes/run-routes.ts +2 -2
- package/src/runtime/run-orchestrator.ts +9 -3
- 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 +17 -67
- package/src/tools/calls/call-start.ts +24 -85
- package/src/tools/calls/call-status.ts +35 -51
- 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 +20 -4
- 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/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 -8
- package/src/tools/tasks/task-delete.ts +60 -88
- package/src/tools/tasks/task-list.ts +31 -52
- package/src/tools/tasks/task-run.ts +72 -108
- package/src/tools/tasks/task-save.ts +33 -65
- package/src/tools/tasks/work-item-enqueue.ts +183 -215
- package/src/tools/tasks/work-item-list.ts +33 -63
- package/src/tools/tasks/work-item-remove.ts +45 -97
- package/src/tools/tasks/work-item-update.ts +91 -163
- package/src/tools/terminal/backends/native.ts +3 -1
- package/src/tools/tool-manifest.ts +0 -62
- package/src/tools/types.ts +6 -0
- package/src/tools/ui-surface/definitions.ts +3 -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 +27 -2
- package/src/workspace/commit-message-enrichment-service.ts +31 -7
- package/src/workspace/git-service.ts +87 -22
- package/src/workspace/provider-commit-message-generator.ts +242 -0
- package/src/workspace/turn-commit.ts +62 -3
- 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
|
@@ -70,7 +70,7 @@ export function upsertContact(params: {
|
|
|
70
70
|
responseExpectation?: string | null;
|
|
71
71
|
preferredTone?: string | null;
|
|
72
72
|
channels?: Array<{ type: string; address: string; isPrimary?: boolean }>;
|
|
73
|
-
}): ContactWithChannels {
|
|
73
|
+
}): ContactWithChannels & { created: boolean } {
|
|
74
74
|
const db = getDb();
|
|
75
75
|
const now = Date.now();
|
|
76
76
|
|
|
@@ -96,7 +96,7 @@ export function upsertContact(params: {
|
|
|
96
96
|
syncChannels(contactId, params.channels, now);
|
|
97
97
|
}
|
|
98
98
|
|
|
99
|
-
return getContact(contactId)
|
|
99
|
+
return { ...getContact(contactId)!, created: false };
|
|
100
100
|
}
|
|
101
101
|
}
|
|
102
102
|
|
|
@@ -124,7 +124,7 @@ export function upsertContact(params: {
|
|
|
124
124
|
.run();
|
|
125
125
|
|
|
126
126
|
syncChannels(contactId, params.channels, now);
|
|
127
|
-
return getContact(contactId)
|
|
127
|
+
return { ...getContact(contactId)!, created: false };
|
|
128
128
|
}
|
|
129
129
|
}
|
|
130
130
|
}
|
|
@@ -148,7 +148,7 @@ export function upsertContact(params: {
|
|
|
148
148
|
syncChannels(contactId, params.channels, now);
|
|
149
149
|
}
|
|
150
150
|
|
|
151
|
-
return getContact(contactId)
|
|
151
|
+
return { ...getContact(contactId)!, created: true };
|
|
152
152
|
}
|
|
153
153
|
|
|
154
154
|
/**
|
|
@@ -313,6 +313,16 @@ export function drainDirectiveDisplayBuffer(buffer: string): DirectiveDisplayDra
|
|
|
313
313
|
|
|
314
314
|
if (!isValidDirective) {
|
|
315
315
|
emitText += tag;
|
|
316
|
+
} else {
|
|
317
|
+
// Only trim the trailing newline when the directive occupied its own
|
|
318
|
+
// line (preceded by \n and followed by \n or \r\n). We intentionally
|
|
319
|
+
// do NOT trim when nextChar is undefined (end-of-buffer) because in
|
|
320
|
+
// streaming mode more data may arrive in the next chunk — eagerly
|
|
321
|
+
// trimming would merge words across the directive boundary.
|
|
322
|
+
const nextChar = buffer[end + 2];
|
|
323
|
+
if (emitText.endsWith('\n') && (nextChar === '\n' || nextChar === '\r')) {
|
|
324
|
+
emitText = emitText.slice(0, -1);
|
|
325
|
+
}
|
|
316
326
|
}
|
|
317
327
|
|
|
318
328
|
cursor = end + 2;
|
package/src/daemon/classifier.ts
CHANGED
|
@@ -4,6 +4,8 @@ import { getLogger } from '../util/logger.js';
|
|
|
4
4
|
|
|
5
5
|
const log = getLogger('classifier');
|
|
6
6
|
|
|
7
|
+
const CLASSIFICATION_TIMEOUT_MS = 5000;
|
|
8
|
+
|
|
7
9
|
export type InteractionType = 'computer_use' | 'text_qa';
|
|
8
10
|
|
|
9
11
|
/**
|
|
@@ -53,7 +55,7 @@ export async function classifyInteraction(task: string, source?: 'voice' | 'text
|
|
|
53
55
|
messages: [{ role: 'user' as const, content: task }],
|
|
54
56
|
}),
|
|
55
57
|
new Promise<never>((_, reject) =>
|
|
56
|
-
setTimeout(() => reject(new Error('Classification timeout')),
|
|
58
|
+
setTimeout(() => reject(new Error('Classification timeout')), CLASSIFICATION_TIMEOUT_MS),
|
|
57
59
|
),
|
|
58
60
|
]);
|
|
59
61
|
|
|
@@ -21,7 +21,7 @@ import { registerSkillTools } from '../tools/registry.js';
|
|
|
21
21
|
import { buildComputerUseSystemPrompt } from '../config/computer-use-prompt.js';
|
|
22
22
|
import { getSandboxWorkingDir } from '../util/platform.js';
|
|
23
23
|
import { getConfig } from '../config/loader.js';
|
|
24
|
-
import { projectSkillTools, resetSkillToolProjection } from './session-skill-tools.js';
|
|
24
|
+
import { projectSkillTools, resetSkillToolProjection, type SkillProjectionCache } from './session-skill-tools.js';
|
|
25
25
|
import { getLogger } from '../util/logger.js';
|
|
26
26
|
|
|
27
27
|
const log = getLogger('computer-use-session');
|
|
@@ -60,6 +60,7 @@ export class ComputerUseSession {
|
|
|
60
60
|
private readonly onTerminal?: (sessionId: string) => void;
|
|
61
61
|
private readonly preactivatedSkillIds: string[];
|
|
62
62
|
private readonly skillProjectionState = new Map<string, string>();
|
|
63
|
+
private readonly skillProjectionCache: SkillProjectionCache = {};
|
|
63
64
|
|
|
64
65
|
private state: SessionState = 'idle';
|
|
65
66
|
private stepCount = 0;
|
|
@@ -235,6 +236,7 @@ export class ComputerUseSession {
|
|
|
235
236
|
const projection = projectSkillTools([], {
|
|
236
237
|
preactivatedSkillIds: this.preactivatedSkillIds,
|
|
237
238
|
previouslyActiveSkillIds: this.skillProjectionState,
|
|
239
|
+
cache: this.skillProjectionCache,
|
|
238
240
|
});
|
|
239
241
|
|
|
240
242
|
if (projection.toolDefinitions.length === 0) {
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Temporal context formatter for future weekday/weekend grounding.
|
|
3
|
+
*
|
|
4
|
+
* Produces a compact, deterministic payload describing the current date,
|
|
5
|
+
* upcoming weekend/work-week windows, and a short horizon of labelled
|
|
6
|
+
* future dates. Intended for runtime injection into the model context.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
export interface TemporalContextOptions {
|
|
10
|
+
/** Override current time (epoch ms) for deterministic tests. */
|
|
11
|
+
nowMs?: number;
|
|
12
|
+
/** IANA timezone (e.g. "America/New_York"). Defaults to host timezone. */
|
|
13
|
+
timeZone?: string;
|
|
14
|
+
/** Number of future days to list (default 14, hard-capped at 14). */
|
|
15
|
+
horizonDays?: number;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const MAX_OUTPUT_CHARS = 1500;
|
|
19
|
+
const MAX_HORIZON_ENTRIES = 14;
|
|
20
|
+
|
|
21
|
+
const WEEKDAY_NAMES = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'] as const;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Get the local date parts for a given instant in the specified timezone.
|
|
25
|
+
*/
|
|
26
|
+
function localDateParts(date: Date, timeZone: string): { year: number; month: number; day: number; weekday: number } {
|
|
27
|
+
const fmt = new Intl.DateTimeFormat('en-US', {
|
|
28
|
+
timeZone,
|
|
29
|
+
year: 'numeric',
|
|
30
|
+
month: '2-digit',
|
|
31
|
+
day: '2-digit',
|
|
32
|
+
weekday: 'short',
|
|
33
|
+
});
|
|
34
|
+
const parts = fmt.formatToParts(date);
|
|
35
|
+
const get = (t: string) => parts.find((p) => p.type === t)?.value ?? '';
|
|
36
|
+
// Weekday as 0-6 (Sun-Sat)
|
|
37
|
+
const weekdayShort = get('weekday');
|
|
38
|
+
const weekdayMap: Record<string, number> = { Sun: 0, Mon: 1, Tue: 2, Wed: 3, Thu: 4, Fri: 5, Sat: 6 };
|
|
39
|
+
return {
|
|
40
|
+
year: parseInt(get('year'), 10),
|
|
41
|
+
month: parseInt(get('month'), 10),
|
|
42
|
+
day: parseInt(get('day'), 10),
|
|
43
|
+
weekday: weekdayMap[weekdayShort] ?? 0,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Format a Date as YYYY-MM-DD in the given timezone.
|
|
49
|
+
*/
|
|
50
|
+
function formatLocalDate(date: Date, timeZone: string): string {
|
|
51
|
+
const p = localDateParts(date, timeZone);
|
|
52
|
+
return `${p.year}-${String(p.month).padStart(2, '0')}-${String(p.day).padStart(2, '0')}`;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Advance a date by `days` calendar days in the given timezone.
|
|
57
|
+
*
|
|
58
|
+
* Computes the local date, adds days to the day component, then anchors
|
|
59
|
+
* the result at noon local time to avoid DST-transition edge cases.
|
|
60
|
+
*/
|
|
61
|
+
function addDays(date: Date, days: number, timeZone: string): Date {
|
|
62
|
+
const parts = localDateParts(date, timeZone);
|
|
63
|
+
// Use Date.UTC for calendar overflow (e.g. Jan 32 → Feb 1).
|
|
64
|
+
const ref = new Date(Date.UTC(parts.year, parts.month - 1, parts.day + days));
|
|
65
|
+
const tY = ref.getUTCFullYear();
|
|
66
|
+
const tM = ref.getUTCMonth() + 1;
|
|
67
|
+
const tD = ref.getUTCDate();
|
|
68
|
+
// Noon UTC covers UTC-12 through ~UTC+11. For far-east timezones
|
|
69
|
+
// (UTC+12/+13/+14) noon UTC is already the next local day, so fall
|
|
70
|
+
// back to midnight UTC which resolves correctly there.
|
|
71
|
+
const noonUTC = new Date(Date.UTC(tY, tM - 1, tD, 12, 0, 0));
|
|
72
|
+
const r = localDateParts(noonUTC, timeZone);
|
|
73
|
+
if (r.year === tY && r.month === tM && r.day === tD) {
|
|
74
|
+
return noonUTC;
|
|
75
|
+
}
|
|
76
|
+
return new Date(Date.UTC(tY, tM - 1, tD, 0, 0, 0));
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Build a compact temporal context string for model injection.
|
|
81
|
+
*
|
|
82
|
+
* Output is hard-capped at {@link MAX_OUTPUT_CHARS} characters and
|
|
83
|
+
* {@link MAX_HORIZON_ENTRIES} horizon entries.
|
|
84
|
+
*/
|
|
85
|
+
export function buildTemporalContext(options: TemporalContextOptions = {}): string {
|
|
86
|
+
const now = new Date(options.nowMs ?? Date.now());
|
|
87
|
+
const timeZone = options.timeZone ?? Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
88
|
+
const horizonDays = Math.min(options.horizonDays ?? MAX_HORIZON_ENTRIES, MAX_HORIZON_ENTRIES);
|
|
89
|
+
|
|
90
|
+
const todayParts = localDateParts(now, timeZone);
|
|
91
|
+
const todayStr = formatLocalDate(now, timeZone);
|
|
92
|
+
const todayWeekday = WEEKDAY_NAMES[todayParts.weekday];
|
|
93
|
+
|
|
94
|
+
// ── Next weekend (Saturday-Sunday) ──
|
|
95
|
+
const daysUntilSaturday = (6 - todayParts.weekday + 7) % 7 || 7;
|
|
96
|
+
const nextSaturday = addDays(now, daysUntilSaturday, timeZone);
|
|
97
|
+
const nextSunday = addDays(now, daysUntilSaturday + 1, timeZone);
|
|
98
|
+
|
|
99
|
+
// ── Next work week (Monday-Friday) ──
|
|
100
|
+
const daysUntilMonday = (1 - todayParts.weekday + 7) % 7 || 7;
|
|
101
|
+
const nextMonday = addDays(now, daysUntilMonday, timeZone);
|
|
102
|
+
const nextFriday = addDays(now, daysUntilMonday + 4, timeZone);
|
|
103
|
+
|
|
104
|
+
// ── Horizon list ──
|
|
105
|
+
const horizonLines: string[] = [];
|
|
106
|
+
for (let i = 1; i <= horizonDays; i++) {
|
|
107
|
+
const futureDate = addDays(now, i, timeZone);
|
|
108
|
+
const futureParts = localDateParts(futureDate, timeZone);
|
|
109
|
+
const label = WEEKDAY_NAMES[futureParts.weekday];
|
|
110
|
+
horizonLines.push(` ${formatLocalDate(futureDate, timeZone)} ${label}`);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const lines = [
|
|
114
|
+
`<temporal_context>`,
|
|
115
|
+
`Today: ${todayStr} (${todayWeekday})`,
|
|
116
|
+
`Timezone: ${timeZone}`,
|
|
117
|
+
``,
|
|
118
|
+
`Week definitions: work week = Monday–Friday, weekend = Saturday–Sunday`,
|
|
119
|
+
``,
|
|
120
|
+
`Next weekend: ${formatLocalDate(nextSaturday, timeZone)} – ${formatLocalDate(nextSunday, timeZone)}`,
|
|
121
|
+
`Next work week: ${formatLocalDate(nextMonday, timeZone)} – ${formatLocalDate(nextFriday, timeZone)}`,
|
|
122
|
+
``,
|
|
123
|
+
`Upcoming dates:`,
|
|
124
|
+
...horizonLines,
|
|
125
|
+
`</temporal_context>`,
|
|
126
|
+
];
|
|
127
|
+
|
|
128
|
+
let output = lines.join('\n');
|
|
129
|
+
|
|
130
|
+
// Hard cap: truncate if somehow over budget (shouldn't happen with 14 entries).
|
|
131
|
+
if (output.length > MAX_OUTPUT_CHARS) {
|
|
132
|
+
output = output.slice(0, MAX_OUTPUT_CHARS - 25) + '\n</temporal_context>';
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
return output;
|
|
136
|
+
}
|
|
@@ -18,7 +18,7 @@ import type {
|
|
|
18
18
|
AppUpdatePreviewRequest,
|
|
19
19
|
UiSurfaceShow,
|
|
20
20
|
} from '../ipc-protocol.js';
|
|
21
|
-
import { log, compareSemver, createSigningCallback, type HandlerContext } from './shared.js';
|
|
21
|
+
import { log, compareSemver, createSigningCallback, defineHandlers, type HandlerContext } from './shared.js';
|
|
22
22
|
|
|
23
23
|
export function handleAppDataRequest(
|
|
24
24
|
msg: AppDataRequest,
|
|
@@ -444,3 +444,18 @@ export function handleGalleryInstall(
|
|
|
444
444
|
});
|
|
445
445
|
}
|
|
446
446
|
}
|
|
447
|
+
|
|
448
|
+
export const appHandlers = defineHandlers({
|
|
449
|
+
app_data_request: handleAppDataRequest,
|
|
450
|
+
app_open_request: handleAppOpenRequest,
|
|
451
|
+
app_update_preview: handleAppUpdatePreview,
|
|
452
|
+
app_preview_request: handleAppPreview,
|
|
453
|
+
apps_list: (_msg, socket, ctx) => handleAppsList(socket, ctx),
|
|
454
|
+
shared_apps_list: (_msg, socket, ctx) => handleSharedAppsList(socket, ctx),
|
|
455
|
+
shared_app_delete: handleSharedAppDelete,
|
|
456
|
+
fork_shared_app: handleForkSharedApp,
|
|
457
|
+
share_app_cloud: handleShareAppCloud,
|
|
458
|
+
bundle_app: handleBundleApp,
|
|
459
|
+
gallery_list: (_msg, socket, ctx) => handleGalleryList(socket, ctx),
|
|
460
|
+
gallery_install: handleGalleryInstall,
|
|
461
|
+
});
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { browserManager } from '../../tools/browser/browser-manager.js';
|
|
2
|
+
import { log, defineHandlers } from './shared.js';
|
|
3
|
+
|
|
4
|
+
export const browserHandlers = defineHandlers({
|
|
5
|
+
browser_cdp_response: (msg) => {
|
|
6
|
+
browserManager.resolveCDPResponse(msg.sessionId, msg.success, msg.declined);
|
|
7
|
+
},
|
|
8
|
+
|
|
9
|
+
browser_user_click: async (msg) => {
|
|
10
|
+
try {
|
|
11
|
+
const page = await browserManager.getOrCreateSessionPage(msg.sessionId);
|
|
12
|
+
const viewport = await page.evaluate('(() => ({ vw: window.innerWidth, vh: window.innerHeight }))()') as { vw: number; vh: number };
|
|
13
|
+
const scale = Math.min(1280 / viewport.vw, 960 / viewport.vh);
|
|
14
|
+
const pageX = msg.x / scale;
|
|
15
|
+
const pageY = msg.y / scale;
|
|
16
|
+
const options: Record<string, unknown> = {};
|
|
17
|
+
if (msg.button === 'right') options.button = 'right';
|
|
18
|
+
if (msg.doubleClick) options.clickCount = 2;
|
|
19
|
+
await page.mouse.click(pageX, pageY, options);
|
|
20
|
+
} catch (err) {
|
|
21
|
+
log.warn({ err, sessionId: msg.sessionId }, 'Failed to forward user click');
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
|
|
25
|
+
browser_user_scroll: async (msg) => {
|
|
26
|
+
try {
|
|
27
|
+
const page = await browserManager.getOrCreateSessionPage(msg.sessionId);
|
|
28
|
+
await page.mouse.wheel(msg.deltaX, msg.deltaY);
|
|
29
|
+
} catch (err) {
|
|
30
|
+
log.warn({ err, sessionId: msg.sessionId }, 'Failed to forward user scroll');
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
|
|
34
|
+
browser_user_keypress: async (msg) => {
|
|
35
|
+
try {
|
|
36
|
+
const page = await browserManager.getOrCreateSessionPage(msg.sessionId);
|
|
37
|
+
const combo = msg.modifiers?.length ? [...msg.modifiers, msg.key].join('+') : msg.key;
|
|
38
|
+
await page.keyboard.press(combo);
|
|
39
|
+
} catch (err) {
|
|
40
|
+
log.warn({ err, sessionId: msg.sessionId }, 'Failed to forward user keypress');
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
|
|
44
|
+
browser_interactive_mode: (msg, socket, ctx) => {
|
|
45
|
+
log.info({ sessionId: msg.sessionId, enabled: msg.enabled }, 'Interactive mode toggled');
|
|
46
|
+
browserManager.setInteractiveMode(msg.sessionId, msg.enabled);
|
|
47
|
+
ctx.send(socket, {
|
|
48
|
+
type: 'browser_interactive_mode_changed',
|
|
49
|
+
sessionId: msg.sessionId,
|
|
50
|
+
surfaceId: msg.surfaceId,
|
|
51
|
+
enabled: msg.enabled,
|
|
52
|
+
});
|
|
53
|
+
},
|
|
54
|
+
});
|
|
@@ -10,7 +10,7 @@ import type {
|
|
|
10
10
|
CuObservation,
|
|
11
11
|
ServerMessage,
|
|
12
12
|
} from '../ipc-protocol.js';
|
|
13
|
-
import { log, type HandlerContext } from './shared.js';
|
|
13
|
+
import { log, defineHandlers, type HandlerContext } from './shared.js';
|
|
14
14
|
|
|
15
15
|
const cuObservationSequenceBySession = new Map<string, number>();
|
|
16
16
|
|
|
@@ -179,3 +179,9 @@ export async function handleCuObservation(
|
|
|
179
179
|
log.error({ err, sessionId: msg.sessionId }, 'Error handling CU observation');
|
|
180
180
|
});
|
|
181
181
|
}
|
|
182
|
+
|
|
183
|
+
export const computerUseHandlers = defineHandlers({
|
|
184
|
+
cu_session_create: handleCuSessionCreate,
|
|
185
|
+
cu_session_abort: handleCuSessionAbort,
|
|
186
|
+
cu_observation: handleCuObservation,
|
|
187
|
+
});
|
|
@@ -5,7 +5,7 @@ import { addRule, removeRule, updateRule, getAllRules, acceptStarterBundle } fro
|
|
|
5
5
|
import { listSchedules, updateSchedule, deleteSchedule, describeCronExpression } from '../../schedule/schedule-store.js';
|
|
6
6
|
import { listReminders, cancelReminder } from '../../tools/reminder/reminder-store.js';
|
|
7
7
|
import { getSecureKey, setSecureKey, deleteSecureKey } from '../../security/secure-keys.js';
|
|
8
|
-
import { upsertCredentialMetadata, deleteCredentialMetadata } from '../../tools/credentials/metadata-store.js';
|
|
8
|
+
import { upsertCredentialMetadata, deleteCredentialMetadata, getCredentialMetadata } from '../../tools/credentials/metadata-store.js';
|
|
9
9
|
import { postToSlackWebhook } from '../../slack/slack-webhook.js';
|
|
10
10
|
import { getApp } from '../../memory/app-store.js';
|
|
11
11
|
import type {
|
|
@@ -20,8 +20,9 @@ import type {
|
|
|
20
20
|
ShareToSlackRequest,
|
|
21
21
|
SlackWebhookConfigRequest,
|
|
22
22
|
VercelApiConfigRequest,
|
|
23
|
+
TwitterIntegrationConfigRequest,
|
|
23
24
|
} from '../ipc-protocol.js';
|
|
24
|
-
import { log, type HandlerContext } from './shared.js';
|
|
25
|
+
import { log, CONFIG_RELOAD_DEBOUNCE_MS, defineHandlers, type HandlerContext } from './shared.js';
|
|
25
26
|
import { MODEL_TO_PROVIDER } from '../session-slash.js';
|
|
26
27
|
|
|
27
28
|
export function handleModelGet(socket: net.Socket, ctx: HandlerContext): void {
|
|
@@ -96,7 +97,7 @@ export function handleModelSet(
|
|
|
96
97
|
}
|
|
97
98
|
const existingSuppressTimer = ctx.debounceTimers.get('__suppress_reset__');
|
|
98
99
|
if (existingSuppressTimer) clearTimeout(existingSuppressTimer);
|
|
99
|
-
const resetTimer = setTimeout(() => { ctx.setSuppressConfigReload(false); },
|
|
100
|
+
const resetTimer = setTimeout(() => { ctx.setSuppressConfigReload(false); }, CONFIG_RELOAD_DEBOUNCE_MS);
|
|
100
101
|
ctx.debounceTimers.set('__suppress_reset__', resetTimer);
|
|
101
102
|
|
|
102
103
|
// Re-initialize provider with the new model so LLM calls use it
|
|
@@ -145,7 +146,7 @@ export function handleImageGenModelSet(
|
|
|
145
146
|
}
|
|
146
147
|
const existingSuppressTimer = ctx.debounceTimers.get('__suppress_reset__');
|
|
147
148
|
if (existingSuppressTimer) clearTimeout(existingSuppressTimer);
|
|
148
|
-
const resetTimer = setTimeout(() => { ctx.setSuppressConfigReload(false); },
|
|
149
|
+
const resetTimer = setTimeout(() => { ctx.setSuppressConfigReload(false); }, CONFIG_RELOAD_DEBOUNCE_MS);
|
|
149
150
|
ctx.debounceTimers.set('__suppress_reset__', resetTimer);
|
|
150
151
|
|
|
151
152
|
ctx.updateConfigFingerprint();
|
|
@@ -237,13 +238,15 @@ export function handleSchedulesList(socket: net.Socket, ctx: HandlerContext): vo
|
|
|
237
238
|
id: j.id,
|
|
238
239
|
name: j.name,
|
|
239
240
|
enabled: j.enabled,
|
|
241
|
+
syntax: j.syntax,
|
|
242
|
+
expression: j.expression,
|
|
240
243
|
cronExpression: j.cronExpression,
|
|
241
244
|
timezone: j.timezone,
|
|
242
245
|
message: j.message,
|
|
243
246
|
nextRunAt: j.nextRunAt,
|
|
244
247
|
lastRunAt: j.lastRunAt,
|
|
245
248
|
lastStatus: j.lastStatus,
|
|
246
|
-
description: describeCronExpression(j.cronExpression),
|
|
249
|
+
description: j.syntax === 'cron' ? describeCronExpression(j.cronExpression) : j.expression,
|
|
247
250
|
})),
|
|
248
251
|
});
|
|
249
252
|
}
|
|
@@ -455,6 +458,140 @@ export function handleVercelApiConfig(
|
|
|
455
458
|
}
|
|
456
459
|
}
|
|
457
460
|
|
|
461
|
+
export function handleTwitterIntegrationConfig(
|
|
462
|
+
msg: TwitterIntegrationConfigRequest,
|
|
463
|
+
socket: net.Socket,
|
|
464
|
+
ctx: HandlerContext,
|
|
465
|
+
): void {
|
|
466
|
+
try {
|
|
467
|
+
if (msg.action === 'get') {
|
|
468
|
+
const raw = loadRawConfig();
|
|
469
|
+
const mode = (raw.twitterIntegrationMode as 'local_byo' | 'managed' | undefined) ?? 'local_byo';
|
|
470
|
+
const localClientConfigured = !!getSecureKey('credential:integration:twitter:oauth_client_id');
|
|
471
|
+
const connected = !!getSecureKey('credential:integration:twitter:access_token');
|
|
472
|
+
const meta = getCredentialMetadata('integration:twitter', 'access_token');
|
|
473
|
+
ctx.send(socket, {
|
|
474
|
+
type: 'twitter_integration_config_response',
|
|
475
|
+
success: true,
|
|
476
|
+
mode,
|
|
477
|
+
managedAvailable: false,
|
|
478
|
+
localClientConfigured,
|
|
479
|
+
connected,
|
|
480
|
+
accountInfo: meta?.accountInfo ?? undefined,
|
|
481
|
+
});
|
|
482
|
+
} else if (msg.action === 'set_mode') {
|
|
483
|
+
const raw = loadRawConfig();
|
|
484
|
+
raw.twitterIntegrationMode = msg.mode ?? 'local_byo';
|
|
485
|
+
saveRawConfig(raw);
|
|
486
|
+
ctx.send(socket, {
|
|
487
|
+
type: 'twitter_integration_config_response',
|
|
488
|
+
success: true,
|
|
489
|
+
mode: msg.mode ?? 'local_byo',
|
|
490
|
+
managedAvailable: false,
|
|
491
|
+
localClientConfigured: !!getSecureKey('credential:integration:twitter:oauth_client_id'),
|
|
492
|
+
connected: !!getSecureKey('credential:integration:twitter:access_token'),
|
|
493
|
+
});
|
|
494
|
+
} else if (msg.action === 'set_local_client') {
|
|
495
|
+
if (!msg.clientId) {
|
|
496
|
+
ctx.send(socket, {
|
|
497
|
+
type: 'twitter_integration_config_response',
|
|
498
|
+
success: false,
|
|
499
|
+
managedAvailable: false,
|
|
500
|
+
localClientConfigured: false,
|
|
501
|
+
connected: false,
|
|
502
|
+
error: 'clientId is required for set_local_client action',
|
|
503
|
+
});
|
|
504
|
+
return;
|
|
505
|
+
}
|
|
506
|
+
const storedId = setSecureKey('credential:integration:twitter:oauth_client_id', msg.clientId);
|
|
507
|
+
if (!storedId) {
|
|
508
|
+
ctx.send(socket, {
|
|
509
|
+
type: 'twitter_integration_config_response',
|
|
510
|
+
success: false,
|
|
511
|
+
managedAvailable: false,
|
|
512
|
+
localClientConfigured: false,
|
|
513
|
+
connected: false,
|
|
514
|
+
error: 'Failed to store client ID in secure storage',
|
|
515
|
+
});
|
|
516
|
+
return;
|
|
517
|
+
}
|
|
518
|
+
if (msg.clientSecret) {
|
|
519
|
+
const storedSecret = setSecureKey('credential:integration:twitter:oauth_client_secret', msg.clientSecret);
|
|
520
|
+
if (!storedSecret) {
|
|
521
|
+
// Roll back the already-persisted client ID to avoid inconsistent OAuth state
|
|
522
|
+
deleteSecureKey('credential:integration:twitter:oauth_client_id');
|
|
523
|
+
ctx.send(socket, {
|
|
524
|
+
type: 'twitter_integration_config_response',
|
|
525
|
+
success: false,
|
|
526
|
+
managedAvailable: false,
|
|
527
|
+
localClientConfigured: false,
|
|
528
|
+
connected: false,
|
|
529
|
+
error: 'Failed to store client secret in secure storage',
|
|
530
|
+
});
|
|
531
|
+
return;
|
|
532
|
+
}
|
|
533
|
+
} else {
|
|
534
|
+
// Clear any stale secret when updating client without a secret (e.g. switching to PKCE)
|
|
535
|
+
deleteSecureKey('credential:integration:twitter:oauth_client_secret');
|
|
536
|
+
}
|
|
537
|
+
ctx.send(socket, {
|
|
538
|
+
type: 'twitter_integration_config_response',
|
|
539
|
+
success: true,
|
|
540
|
+
managedAvailable: false,
|
|
541
|
+
localClientConfigured: true,
|
|
542
|
+
connected: !!getSecureKey('credential:integration:twitter:access_token'),
|
|
543
|
+
});
|
|
544
|
+
} else if (msg.action === 'clear_local_client') {
|
|
545
|
+
// If connected, disconnect first
|
|
546
|
+
if (getSecureKey('credential:integration:twitter:access_token')) {
|
|
547
|
+
deleteSecureKey('credential:integration:twitter:access_token');
|
|
548
|
+
deleteSecureKey('credential:integration:twitter:refresh_token');
|
|
549
|
+
deleteCredentialMetadata('integration:twitter', 'access_token');
|
|
550
|
+
}
|
|
551
|
+
deleteSecureKey('credential:integration:twitter:oauth_client_id');
|
|
552
|
+
deleteSecureKey('credential:integration:twitter:oauth_client_secret');
|
|
553
|
+
ctx.send(socket, {
|
|
554
|
+
type: 'twitter_integration_config_response',
|
|
555
|
+
success: true,
|
|
556
|
+
managedAvailable: false,
|
|
557
|
+
localClientConfigured: false,
|
|
558
|
+
connected: false,
|
|
559
|
+
});
|
|
560
|
+
} else if (msg.action === 'disconnect') {
|
|
561
|
+
deleteSecureKey('credential:integration:twitter:access_token');
|
|
562
|
+
deleteSecureKey('credential:integration:twitter:refresh_token');
|
|
563
|
+
deleteCredentialMetadata('integration:twitter', 'access_token');
|
|
564
|
+
ctx.send(socket, {
|
|
565
|
+
type: 'twitter_integration_config_response',
|
|
566
|
+
success: true,
|
|
567
|
+
managedAvailable: false,
|
|
568
|
+
localClientConfigured: !!getSecureKey('credential:integration:twitter:oauth_client_id'),
|
|
569
|
+
connected: false,
|
|
570
|
+
});
|
|
571
|
+
} else {
|
|
572
|
+
ctx.send(socket, {
|
|
573
|
+
type: 'twitter_integration_config_response',
|
|
574
|
+
success: false,
|
|
575
|
+
managedAvailable: false,
|
|
576
|
+
localClientConfigured: false,
|
|
577
|
+
connected: false,
|
|
578
|
+
error: `Unknown action: ${String((msg as unknown as Record<string, unknown>).action)}`,
|
|
579
|
+
});
|
|
580
|
+
}
|
|
581
|
+
} catch (err) {
|
|
582
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
583
|
+
log.error({ err }, 'Failed to handle Twitter integration config');
|
|
584
|
+
ctx.send(socket, {
|
|
585
|
+
type: 'twitter_integration_config_response',
|
|
586
|
+
success: false,
|
|
587
|
+
managedAvailable: false,
|
|
588
|
+
localClientConfigured: false,
|
|
589
|
+
connected: false,
|
|
590
|
+
error: message,
|
|
591
|
+
});
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
|
|
458
595
|
export function handleEnvVarsRequest(socket: net.Socket, ctx: HandlerContext): void {
|
|
459
596
|
const vars: Record<string, string> = {};
|
|
460
597
|
for (const [key, value] of Object.entries(process.env)) {
|
|
@@ -462,3 +599,24 @@ export function handleEnvVarsRequest(socket: net.Socket, ctx: HandlerContext): v
|
|
|
462
599
|
}
|
|
463
600
|
ctx.send(socket, { type: 'env_vars_response', vars });
|
|
464
601
|
}
|
|
602
|
+
|
|
603
|
+
export const configHandlers = defineHandlers({
|
|
604
|
+
model_get: (_msg, socket, ctx) => handleModelGet(socket, ctx),
|
|
605
|
+
model_set: handleModelSet,
|
|
606
|
+
image_gen_model_set: handleImageGenModelSet,
|
|
607
|
+
add_trust_rule: handleAddTrustRule,
|
|
608
|
+
trust_rules_list: (_msg, socket, ctx) => handleTrustRulesList(socket, ctx),
|
|
609
|
+
remove_trust_rule: handleRemoveTrustRule,
|
|
610
|
+
update_trust_rule: handleUpdateTrustRule,
|
|
611
|
+
accept_starter_bundle: (_msg, socket, ctx) => handleAcceptStarterBundle(socket, ctx),
|
|
612
|
+
schedules_list: (_msg, socket, ctx) => handleSchedulesList(socket, ctx),
|
|
613
|
+
schedule_toggle: handleScheduleToggle,
|
|
614
|
+
schedule_remove: handleScheduleRemove,
|
|
615
|
+
reminders_list: (_msg, socket, ctx) => handleRemindersList(socket, ctx),
|
|
616
|
+
reminder_cancel: handleReminderCancel,
|
|
617
|
+
share_to_slack: handleShareToSlack,
|
|
618
|
+
slack_webhook_config: handleSlackWebhookConfig,
|
|
619
|
+
vercel_api_config: handleVercelApiConfig,
|
|
620
|
+
twitter_integration_config: handleTwitterIntegrationConfig,
|
|
621
|
+
env_vars_request: (_msg, socket, ctx) => handleEnvVarsRequest(socket, ctx),
|
|
622
|
+
});
|
|
@@ -9,7 +9,7 @@ import archiver from 'archiver';
|
|
|
9
9
|
import { getDb } from '../../memory/db.js';
|
|
10
10
|
import { messages, toolInvocations, llmUsageEvents, llmRequestLogs } from '../../memory/schema.js';
|
|
11
11
|
import type { DiagnosticsExportRequest } from '../ipc-protocol.js';
|
|
12
|
-
import { log, type HandlerContext } from './shared.js';
|
|
12
|
+
import { log, defineHandlers, type HandlerContext } from './shared.js';
|
|
13
13
|
|
|
14
14
|
const MAX_CONTENT_LENGTH = 500;
|
|
15
15
|
|
|
@@ -332,3 +332,7 @@ export async function handleDiagnosticsExport(
|
|
|
332
332
|
});
|
|
333
333
|
}
|
|
334
334
|
}
|
|
335
|
+
|
|
336
|
+
export const diagnosticsHandlers = defineHandlers({
|
|
337
|
+
diagnostics_export_request: handleDiagnosticsExport,
|
|
338
|
+
});
|