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
package/src/daemon/server.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as net from 'node:net';
|
|
2
2
|
import { randomBytes } from 'node:crypto';
|
|
3
|
-
import { existsSync, chmodSync, writeFileSync, unlinkSync, readdirSync, watch, type FSWatcher } from 'node:fs';
|
|
3
|
+
import { existsSync, chmodSync, readFileSync, writeFileSync, unlinkSync, readdirSync, watch, type FSWatcher } from 'node:fs';
|
|
4
4
|
import { join } from 'node:path';
|
|
5
5
|
import { getSocketPath, getSessionTokenPath, getRootDir, getWorkspaceDir, getWorkspaceSkillsDir, getSandboxWorkingDir, removeSocketFile, getTCPPort, getTCPHost, isTCPEnabled } from '../util/platform.js';
|
|
6
6
|
import { hasNoAuthOverride } from './connection-policy.js';
|
|
@@ -10,7 +10,7 @@ import { RateLimitProvider } from '../providers/ratelimit.js';
|
|
|
10
10
|
import { getConfig, invalidateConfigCache } from '../config/loader.js';
|
|
11
11
|
import { buildSystemPrompt } from '../config/system-prompt.js';
|
|
12
12
|
import { clearCache as clearTrustCache } from '../permissions/trust-store.js';
|
|
13
|
-
import { resetAllowlist } from '../security/secret-allowlist.js';
|
|
13
|
+
import { resetAllowlist, validateAllowlistFile } from '../security/secret-allowlist.js';
|
|
14
14
|
import { checkIngressForSecrets } from '../security/secret-ingress.js';
|
|
15
15
|
import { IngressBlockedError } from '../util/errors.js';
|
|
16
16
|
import { clearEmbeddingBackendCache } from '../memory/embedding-backend.js';
|
|
@@ -36,9 +36,24 @@ import { assistantEventHub } from '../runtime/assistant-event-hub.js';
|
|
|
36
36
|
import { buildAssistantEvent } from '../runtime/assistant-event.js';
|
|
37
37
|
import { SessionEvictor } from './session-evictor.js';
|
|
38
38
|
import { getSubagentManager } from '../subagent/index.js';
|
|
39
|
+
import { tryHandlePendingCallAnswer } from '../calls/call-bridge.js';
|
|
40
|
+
import { resolveSlash } from './session-slash.js';
|
|
41
|
+
import { createUserMessage, createAssistantMessage } from '../agent/message-types.js';
|
|
39
42
|
|
|
40
43
|
const log = getLogger('server');
|
|
41
44
|
|
|
45
|
+
function readPackageVersion(): string | undefined {
|
|
46
|
+
try {
|
|
47
|
+
const pkgPath = join(import.meta.dir, '../../package.json');
|
|
48
|
+
const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8')) as { version?: string };
|
|
49
|
+
return pkg.version;
|
|
50
|
+
} catch {
|
|
51
|
+
return undefined;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const daemonVersion = readPackageVersion();
|
|
56
|
+
|
|
42
57
|
export class DaemonServer {
|
|
43
58
|
private server: net.Server | null = null;
|
|
44
59
|
private tcpServer: net.Server | null = null;
|
|
@@ -125,21 +140,23 @@ export class DaemonServer {
|
|
|
125
140
|
};
|
|
126
141
|
// When a subagent finishes, inject the result into the parent session
|
|
127
142
|
// so the LLM automatically informs the user.
|
|
128
|
-
getSubagentManager().onSubagentFinished = (parentSessionId, message, sendToClient) => {
|
|
143
|
+
getSubagentManager().onSubagentFinished = (parentSessionId, message, sendToClient, notification) => {
|
|
129
144
|
const parentSession = this.sessions.get(parentSessionId);
|
|
130
145
|
if (!parentSession) {
|
|
131
146
|
log.warn({ parentSessionId }, 'Subagent finished but parent session not found');
|
|
132
147
|
return;
|
|
133
148
|
}
|
|
134
149
|
const requestId = `subagent-notify-${Date.now()}`;
|
|
135
|
-
|
|
150
|
+
// Store structured notification data in the DB for history reconstruction
|
|
151
|
+
const metadata = { subagentNotification: notification };
|
|
152
|
+
const enqueueResult = parentSession.enqueueMessage(message, [], sendToClient, requestId, undefined, undefined, metadata);
|
|
136
153
|
if (enqueueResult.rejected) {
|
|
137
154
|
log.warn({ parentSessionId }, 'Parent session queue full, dropping subagent notification');
|
|
138
155
|
return;
|
|
139
156
|
}
|
|
140
157
|
if (!enqueueResult.queued) {
|
|
141
158
|
// Parent is idle — send directly.
|
|
142
|
-
const messageId = parentSession.persistUserMessage(message, []);
|
|
159
|
+
const messageId = parentSession.persistUserMessage(message, [], undefined, metadata);
|
|
143
160
|
parentSession.runAgentLoop(message, messageId, sendToClient).catch((err) => {
|
|
144
161
|
log.error({ parentSessionId, err }, 'Failed to process subagent notification in parent');
|
|
145
162
|
});
|
|
@@ -330,6 +347,16 @@ export class DaemonServer {
|
|
|
330
347
|
},
|
|
331
348
|
'secret-allowlist.json': () => {
|
|
332
349
|
resetAllowlist();
|
|
350
|
+
try {
|
|
351
|
+
const errors = validateAllowlistFile();
|
|
352
|
+
if (errors && errors.length > 0) {
|
|
353
|
+
for (const e of errors) {
|
|
354
|
+
log.warn({ index: e.index, pattern: e.pattern }, `Invalid regex in secret-allowlist.json: ${e.message}`);
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
} catch (err) {
|
|
358
|
+
log.warn({ err }, 'Failed to validate secret-allowlist.json');
|
|
359
|
+
}
|
|
333
360
|
},
|
|
334
361
|
};
|
|
335
362
|
|
|
@@ -381,6 +408,7 @@ export class DaemonServer {
|
|
|
381
408
|
this.broadcast({
|
|
382
409
|
type: 'daemon_status',
|
|
383
410
|
httpPort: port,
|
|
411
|
+
version: daemonVersion,
|
|
384
412
|
});
|
|
385
413
|
}
|
|
386
414
|
|
|
@@ -744,10 +772,7 @@ export class DaemonServer {
|
|
|
744
772
|
('sessionId' in msg && typeof msgRecord.sessionId === 'string'
|
|
745
773
|
? msgRecord.sessionId as string
|
|
746
774
|
: undefined) ?? this.socketToSession.get(socket);
|
|
747
|
-
|
|
748
|
-
const socketSession = sessionId ? this.sessions.get(sessionId) : undefined;
|
|
749
|
-
const assistantId = socketSession?.assistantId ?? this.assistantId;
|
|
750
|
-
this.publishAssistantEvent(msg, sessionId, assistantId);
|
|
775
|
+
this.publishAssistantEvent(msg, sessionId, this.assistantId);
|
|
751
776
|
}
|
|
752
777
|
|
|
753
778
|
broadcast(msg: ServerMessage, excludeSocket?: net.Socket): void {
|
|
@@ -763,10 +788,7 @@ export class DaemonServer {
|
|
|
763
788
|
('sessionId' in msg && typeof msgRecord.sessionId === 'string'
|
|
764
789
|
? msgRecord.sessionId as string
|
|
765
790
|
: undefined) ?? (excludeSocket ? this.socketToSession.get(excludeSocket) : undefined);
|
|
766
|
-
|
|
767
|
-
const originSession = sessionId ? this.sessions.get(sessionId) : undefined;
|
|
768
|
-
const assistantId = originSession?.assistantId ?? this.assistantId;
|
|
769
|
-
this.publishAssistantEvent(msg, sessionId, assistantId);
|
|
791
|
+
this.publishAssistantEvent(msg, sessionId, this.assistantId);
|
|
770
792
|
}
|
|
771
793
|
|
|
772
794
|
/**
|
|
@@ -797,6 +819,7 @@ export class DaemonServer {
|
|
|
797
819
|
this.send(socket, {
|
|
798
820
|
type: 'daemon_status',
|
|
799
821
|
httpPort: this.httpPort,
|
|
822
|
+
version: daemonVersion,
|
|
800
823
|
});
|
|
801
824
|
return;
|
|
802
825
|
}
|
|
@@ -815,6 +838,7 @@ export class DaemonServer {
|
|
|
815
838
|
this.send(socket, {
|
|
816
839
|
type: 'daemon_status',
|
|
817
840
|
httpPort: this.httpPort,
|
|
841
|
+
version: daemonVersion,
|
|
818
842
|
});
|
|
819
843
|
}
|
|
820
844
|
|
|
@@ -987,14 +1011,11 @@ export class DaemonServer {
|
|
|
987
1011
|
throw new Error('Session is already processing a message');
|
|
988
1012
|
}
|
|
989
1013
|
|
|
990
|
-
// Set the session identity AFTER the isProcessing check so a rejected
|
|
991
|
-
// request doesn't mutate the session state visible to an in-flight request.
|
|
992
|
-
session.setAssistantId('self');
|
|
993
1014
|
session.setChannelCapabilities(resolveChannelCapabilities(sourceChannel));
|
|
994
1015
|
|
|
995
1016
|
// Resolve attachment IDs to full attachment data for the session
|
|
996
1017
|
const attachments = attachmentIds
|
|
997
|
-
? attachmentsStore.getAttachmentsByIds(
|
|
1018
|
+
? attachmentsStore.getAttachmentsByIds(attachmentIds).map((a) => ({
|
|
998
1019
|
id: a.id,
|
|
999
1020
|
filename: a.originalFilename,
|
|
1000
1021
|
mimeType: a.mimeType,
|
|
@@ -1002,10 +1023,32 @@ export class DaemonServer {
|
|
|
1002
1023
|
}))
|
|
1003
1024
|
: [];
|
|
1004
1025
|
|
|
1005
|
-
//
|
|
1026
|
+
// Persist the user message immediately after the isProcessing() guard.
|
|
1027
|
+
// This synchronously sets session.processing = true, closing the race
|
|
1028
|
+
// window that previously existed between the guard and the async bridge
|
|
1029
|
+
// check (two concurrent requests could both pass isProcessing() and
|
|
1030
|
+
// race into message handling).
|
|
1006
1031
|
const requestId = crypto.randomUUID();
|
|
1007
1032
|
const messageId = session.persistUserMessage(content, attachments, requestId);
|
|
1008
1033
|
|
|
1034
|
+
// Now that the processing lock is held, check the call-answer bridge.
|
|
1035
|
+
let bridgeHandled = false;
|
|
1036
|
+
try {
|
|
1037
|
+
const bridgeResult = await tryHandlePendingCallAnswer(conversationId, content, messageId);
|
|
1038
|
+
bridgeHandled = bridgeResult.handled;
|
|
1039
|
+
} catch (err) {
|
|
1040
|
+
log.warn({ err, conversationId }, 'Call-answer bridge check failed (non-fatal), proceeding with agent loop');
|
|
1041
|
+
}
|
|
1042
|
+
|
|
1043
|
+
if (bridgeHandled) {
|
|
1044
|
+
// The message was consumed by the call system. Release the session.
|
|
1045
|
+
resetSessionProcessingState(session);
|
|
1046
|
+
// Drain any queued messages that arrived while processing was true.
|
|
1047
|
+
session.drainQueue('loop_complete');
|
|
1048
|
+
log.info({ conversationId, messageId }, 'User message consumed by call-answer bridge, skipping agent loop');
|
|
1049
|
+
return { messageId };
|
|
1050
|
+
}
|
|
1051
|
+
|
|
1009
1052
|
// Fire-and-forget the agent loop. Errors are logged but do not
|
|
1010
1053
|
// affect the HTTP response (the client polls GET /messages).
|
|
1011
1054
|
session.runAgentLoop(content, messageId, () => {}).catch((err) => {
|
|
@@ -1039,14 +1082,11 @@ export class DaemonServer {
|
|
|
1039
1082
|
throw new Error('Session is already processing a message');
|
|
1040
1083
|
}
|
|
1041
1084
|
|
|
1042
|
-
// Set the session identity AFTER the isProcessing check so a rejected
|
|
1043
|
-
// request doesn't mutate the session state visible to an in-flight request.
|
|
1044
|
-
session.setAssistantId('self');
|
|
1045
1085
|
session.setChannelCapabilities(resolveChannelCapabilities(sourceChannel));
|
|
1046
1086
|
|
|
1047
1087
|
// Resolve attachment IDs to full attachment data for the session
|
|
1048
1088
|
const attachments = attachmentIds
|
|
1049
|
-
? attachmentsStore.getAttachmentsByIds(
|
|
1089
|
+
? attachmentsStore.getAttachmentsByIds(attachmentIds).map((a) => ({
|
|
1050
1090
|
id: a.id,
|
|
1051
1091
|
filename: a.originalFilename,
|
|
1052
1092
|
mimeType: a.mimeType,
|
|
@@ -1054,12 +1094,74 @@ export class DaemonServer {
|
|
|
1054
1094
|
}))
|
|
1055
1095
|
: [];
|
|
1056
1096
|
|
|
1057
|
-
|
|
1097
|
+
// Resolve slash commands before persistence (synchronous — no race window).
|
|
1098
|
+
const slashResult = resolveSlash(content);
|
|
1099
|
+
|
|
1100
|
+
// Unknown slash command — persist the exchange (user + assistant) and
|
|
1101
|
+
// return immediately. This path doesn't set processing=true since no
|
|
1102
|
+
// agent loop runs, so there is no race concern.
|
|
1103
|
+
if (slashResult.kind === 'unknown') {
|
|
1104
|
+
const userMsg = createUserMessage(content, attachments);
|
|
1105
|
+
const persisted = conversationStore.addMessage(
|
|
1106
|
+
conversationId,
|
|
1107
|
+
'user',
|
|
1108
|
+
JSON.stringify(userMsg.content),
|
|
1109
|
+
);
|
|
1110
|
+
session.getMessages().push(userMsg);
|
|
1111
|
+
|
|
1112
|
+
const assistantMsg = createAssistantMessage(slashResult.message);
|
|
1113
|
+
conversationStore.addMessage(
|
|
1114
|
+
conversationId,
|
|
1115
|
+
'assistant',
|
|
1116
|
+
JSON.stringify(assistantMsg.content),
|
|
1117
|
+
);
|
|
1118
|
+
session.getMessages().push(assistantMsg);
|
|
1119
|
+
return { messageId: persisted.id };
|
|
1120
|
+
}
|
|
1058
1121
|
|
|
1059
|
-
|
|
1060
|
-
|
|
1122
|
+
const resolvedContent = slashResult.content;
|
|
1123
|
+
|
|
1124
|
+
// Preactivate skill tools when slash resolution identifies a known skill
|
|
1125
|
+
if (slashResult.kind === 'rewritten') {
|
|
1126
|
+
(session as unknown as { preactivatedSkillIds?: string[] }).preactivatedSkillIds = [slashResult.skillId];
|
|
1127
|
+
}
|
|
1128
|
+
|
|
1129
|
+
// Persist the user message immediately after the isProcessing() guard.
|
|
1130
|
+
// This synchronously sets session.processing = true, closing the race
|
|
1131
|
+
// window that previously existed between the guard and the async bridge
|
|
1132
|
+
// check.
|
|
1133
|
+
const requestId = crypto.randomUUID();
|
|
1134
|
+
let messageId: string;
|
|
1135
|
+
try {
|
|
1136
|
+
messageId = session.persistUserMessage(resolvedContent, attachments, requestId);
|
|
1137
|
+
} catch (err) {
|
|
1138
|
+
// runAgentLoop never ran, so its finally block won't clear this
|
|
1139
|
+
(session as unknown as { preactivatedSkillIds?: string[] }).preactivatedSkillIds = undefined;
|
|
1140
|
+
throw err;
|
|
1061
1141
|
}
|
|
1062
1142
|
|
|
1143
|
+
// Now that the processing lock is held, check the call-answer bridge.
|
|
1144
|
+
let bridgeHandled = false;
|
|
1145
|
+
try {
|
|
1146
|
+
const bridgeResult = await tryHandlePendingCallAnswer(conversationId, content, messageId);
|
|
1147
|
+
bridgeHandled = bridgeResult.handled;
|
|
1148
|
+
} catch (err) {
|
|
1149
|
+
log.warn({ err, conversationId }, 'Call-answer bridge check failed (non-fatal), proceeding with agent loop');
|
|
1150
|
+
}
|
|
1151
|
+
|
|
1152
|
+
if (bridgeHandled) {
|
|
1153
|
+
// The message was consumed by the call system. Release the session.
|
|
1154
|
+
(session as unknown as { preactivatedSkillIds?: string[] }).preactivatedSkillIds = undefined;
|
|
1155
|
+
resetSessionProcessingState(session);
|
|
1156
|
+
// Drain any queued messages that arrived while processing was true.
|
|
1157
|
+
session.drainQueue('loop_complete');
|
|
1158
|
+
log.info({ conversationId, messageId }, 'User message consumed by call-answer bridge, skipping agent loop');
|
|
1159
|
+
return { messageId };
|
|
1160
|
+
}
|
|
1161
|
+
|
|
1162
|
+
// Run the agent loop (blocking — the channel inbound endpoint needs the reply).
|
|
1163
|
+
await session.runAgentLoop(resolvedContent, messageId, () => {});
|
|
1164
|
+
|
|
1063
1165
|
return { messageId };
|
|
1064
1166
|
}
|
|
1065
1167
|
|
|
@@ -1071,7 +1173,7 @@ export class DaemonServer {
|
|
|
1071
1173
|
getOrCreateSession: (conversationId) =>
|
|
1072
1174
|
this.getOrCreateSession(conversationId),
|
|
1073
1175
|
resolveAttachments: (attachmentIds) =>
|
|
1074
|
-
attachmentsStore.getAttachmentsByIds(
|
|
1176
|
+
attachmentsStore.getAttachmentsByIds(attachmentIds).map((a) => ({
|
|
1075
1177
|
id: a.id,
|
|
1076
1178
|
filename: a.originalFilename,
|
|
1077
1179
|
mimeType: a.mimeType,
|
|
@@ -1081,3 +1183,18 @@ export class DaemonServer {
|
|
|
1081
1183
|
}
|
|
1082
1184
|
|
|
1083
1185
|
}
|
|
1186
|
+
|
|
1187
|
+
/**
|
|
1188
|
+
* Reset the processing state set by `persistUserMessage` when the agent loop
|
|
1189
|
+
* is intentionally skipped (e.g. call-answer bridge consumed the message).
|
|
1190
|
+
*/
|
|
1191
|
+
function resetSessionProcessingState(session: Session): void {
|
|
1192
|
+
const s = session as unknown as {
|
|
1193
|
+
processing: boolean;
|
|
1194
|
+
abortController: AbortController | null;
|
|
1195
|
+
currentRequestId: string | undefined;
|
|
1196
|
+
};
|
|
1197
|
+
s.processing = false;
|
|
1198
|
+
s.abortController = null;
|
|
1199
|
+
s.currentRequestId = undefined;
|
|
1200
|
+
}
|