@vellumai/assistant 0.3.14 → 0.3.16
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/ARCHITECTURE.md +142 -0
- package/Dockerfile +2 -2
- package/README.md +5 -5
- package/docs/architecture/http-token-refresh.md +252 -0
- package/docs/architecture/memory.md +5 -4
- package/docs/architecture/scheduling.md +4 -88
- package/docs/runbook-trusted-contacts.md +283 -0
- package/docs/trusted-contact-access.md +247 -0
- package/package.json +1 -1
- package/scripts/ipc/check-swift-decoder-drift.ts +2 -0
- package/src/__tests__/__snapshots__/ipc-snapshot.test.ts.snap +2 -6
- package/src/__tests__/access-request-decision.test.ts +331 -0
- package/src/__tests__/asset-materialize-tool.test.ts +7 -7
- package/src/__tests__/asset-search-tool.test.ts +15 -15
- package/src/__tests__/attachments-store.test.ts +13 -13
- package/src/__tests__/call-controller.test.ts +150 -4
- package/src/__tests__/call-conversation-messages.test.ts +2 -2
- package/src/__tests__/call-pointer-messages.test.ts +28 -0
- package/src/__tests__/call-start-guardian-guard.test.ts +93 -0
- package/src/__tests__/channel-approval-routes.test.ts +108 -12
- package/src/__tests__/channel-guardian.test.ts +16 -14
- package/src/__tests__/checker.test.ts +24 -0
- package/src/__tests__/computer-use-skill-manifest-regression.test.ts +2 -2
- package/src/__tests__/config-watcher.test.ts +358 -0
- package/src/__tests__/conversation-pairing.test.ts +24 -24
- package/src/__tests__/conversation-store.test.ts +36 -36
- package/src/__tests__/date-context.test.ts +179 -1
- package/src/__tests__/db-migration-rollback.test.ts +4 -7
- package/src/__tests__/deterministic-verification-control-plane.test.ts +5 -5
- package/src/__tests__/emit-signal-routing-intent.test.ts +179 -0
- package/src/__tests__/gateway-only-guard.test.ts +188 -0
- package/src/__tests__/guardian-action-conversation-turn.test.ts +451 -0
- package/src/__tests__/guardian-action-copy-generator.test.ts +197 -0
- package/src/__tests__/guardian-action-followup-executor.test.ts +379 -0
- package/src/__tests__/guardian-action-followup-store.test.ts +376 -0
- package/src/__tests__/guardian-action-late-reply.test.ts +294 -0
- package/src/__tests__/guardian-action-no-hardcoded-copy.test.ts +71 -0
- package/src/__tests__/guardian-action-sweep.test.ts +9 -9
- package/src/__tests__/guardian-control-plane-policy.test.ts +1 -3
- package/src/__tests__/guardian-outbound-http.test.ts +202 -10
- package/src/__tests__/guardian-verification-intent-routing.test.ts +179 -0
- package/src/__tests__/guardian-verify-setup-skill-regression.test.ts +141 -0
- package/src/__tests__/handlers-telegram-config.test.ts +6 -6
- package/src/__tests__/hooks-runner.test.ts +13 -4
- package/src/__tests__/ingress-routes-http.test.ts +443 -0
- package/src/__tests__/intent-routing.test.ts +14 -0
- package/src/__tests__/ipc-snapshot.test.ts +2 -5
- package/src/__tests__/media-reuse-story.e2e.test.ts +7 -7
- package/src/__tests__/memory-regressions.test.ts +16 -12
- package/src/__tests__/non-member-access-request.test.ts +282 -0
- package/src/__tests__/notification-decision-strategy.test.ts +136 -0
- package/src/__tests__/notification-routing-intent.test.ts +11 -2
- package/src/__tests__/notification-thread-candidates.test.ts +166 -0
- package/src/__tests__/recording-intent-fallback.test.ts +0 -1
- package/src/__tests__/recording-intent-handler.test.ts +6 -3
- package/src/__tests__/recording-intent.test.ts +3 -2
- package/src/__tests__/recording-state-machine.test.ts +337 -26
- package/src/__tests__/registry.test.ts +17 -8
- package/src/__tests__/relay-server.test.ts +105 -0
- package/src/__tests__/reminder.test.ts +13 -0
- package/src/__tests__/runtime-attachment-metadata.test.ts +4 -4
- package/src/__tests__/scheduler-recurrence.test.ts +50 -0
- package/src/__tests__/server-history-render.test.ts +8 -8
- package/src/__tests__/session-agent-loop.test.ts +1 -0
- package/src/__tests__/session-runtime-assembly.test.ts +49 -0
- package/src/__tests__/session-skill-tools.test.ts +1 -0
- package/src/__tests__/skill-projection.benchmark.test.ts +11 -3
- package/src/__tests__/slack-channel-config.test.ts +230 -0
- package/src/__tests__/subagent-manager-notify.test.ts +4 -4
- package/src/__tests__/swarm-session-integration.test.ts +2 -2
- package/src/__tests__/system-prompt.test.ts +43 -0
- package/src/__tests__/task-management-tools.test.ts +3 -3
- package/src/__tests__/task-tools.test.ts +3 -3
- package/src/__tests__/trust-store.test.ts +17 -1
- package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +491 -0
- package/src/__tests__/trusted-contact-multichannel.test.ts +409 -0
- package/src/__tests__/trusted-contact-verification.test.ts +360 -0
- package/src/__tests__/update-bulletin-format.test.ts +119 -0
- package/src/__tests__/update-bulletin-state.test.ts +129 -0
- package/src/__tests__/update-bulletin.test.ts +260 -0
- package/src/__tests__/update-template-contract.test.ts +29 -0
- package/src/agent/loop.ts +2 -2
- package/src/amazon/client.ts +2 -3
- package/src/calls/call-controller.ts +115 -34
- package/src/calls/call-conversation-messages.ts +2 -2
- package/src/calls/call-domain.ts +10 -3
- package/src/calls/call-pointer-messages.ts +17 -5
- package/src/calls/guardian-action-sweep.ts +77 -36
- package/src/calls/relay-server.ts +51 -12
- package/src/calls/twilio-routes.ts +3 -1
- package/src/calls/types.ts +1 -1
- package/src/calls/voice-session-bridge.ts +4 -4
- package/src/cli/core-commands.ts +3 -3
- package/src/cli/map.ts +8 -5
- package/src/config/bundled-skills/phone-calls/SKILL.md +16 -1
- package/src/config/bundled-skills/tasks/SKILL.md +1 -1
- package/src/config/bundled-skills/tasks/TOOLS.json +4 -4
- package/src/config/bundled-skills/time-based-actions/SKILL.md +11 -1
- package/src/config/computer-use-prompt.ts +1 -0
- package/src/config/core-schema.ts +16 -0
- package/src/config/env-registry.ts +1 -0
- package/src/config/env.ts +16 -1
- package/src/config/memory-schema.ts +5 -0
- package/src/config/schema.ts +4 -0
- package/src/config/system-prompt.ts +69 -2
- package/src/config/templates/BOOTSTRAP.md +1 -1
- package/src/config/templates/IDENTITY.md +8 -4
- package/src/config/templates/SOUL.md +14 -0
- package/src/config/templates/UPDATES.md +16 -0
- package/src/config/templates/USER.md +5 -1
- package/src/config/types.ts +1 -0
- package/src/config/update-bulletin-format.ts +52 -0
- package/src/config/update-bulletin-state.ts +49 -0
- package/src/config/update-bulletin.ts +82 -0
- package/src/config/vellum-skills/catalog.json +6 -0
- package/src/config/vellum-skills/chatgpt-import/tools/chatgpt-import.ts +1 -1
- package/src/config/vellum-skills/guardian-verify-setup/SKILL.md +44 -10
- package/src/config/vellum-skills/telegram-setup/SKILL.md +4 -4
- package/src/config/vellum-skills/trusted-contacts/SKILL.md +147 -0
- package/src/config/vellum-skills/twilio-setup/SKILL.md +2 -2
- package/src/context/window-manager.ts +43 -3
- package/src/daemon/config-watcher.ts +1 -0
- package/src/daemon/connection-policy.ts +21 -1
- package/src/daemon/daemon-control.ts +164 -7
- package/src/daemon/date-context.ts +174 -1
- package/src/daemon/guardian-action-generators.ts +175 -0
- package/src/daemon/guardian-verification-intent.ts +120 -0
- package/src/daemon/handlers/apps.ts +1 -3
- package/src/daemon/handlers/config-channels.ts +8 -8
- package/src/daemon/handlers/config-heartbeat.ts +1 -1
- package/src/daemon/handlers/config-inbox.ts +55 -159
- package/src/daemon/handlers/config-ingress.ts +1 -1
- package/src/daemon/handlers/config-integrations.ts +1 -1
- package/src/daemon/handlers/config-platform.ts +1 -1
- package/src/daemon/handlers/config-scheduling.ts +2 -2
- package/src/daemon/handlers/config-slack-channel.ts +190 -0
- package/src/daemon/handlers/config-telegram.ts +1 -1
- package/src/daemon/handlers/config-twilio.ts +1 -1
- package/src/daemon/handlers/config-voice.ts +100 -0
- package/src/daemon/handlers/config.ts +3 -0
- package/src/daemon/handlers/index.ts +1 -1
- package/src/daemon/handlers/misc.ts +84 -6
- package/src/daemon/handlers/navigate-settings.ts +27 -0
- package/src/daemon/handlers/recording.ts +270 -144
- package/src/daemon/handlers/sessions.ts +107 -24
- package/src/daemon/handlers/subagents.ts +3 -3
- package/src/daemon/handlers/work-items.ts +10 -7
- package/src/daemon/ipc-contract/integrations.ts +9 -1
- package/src/daemon/ipc-contract/messages.ts +4 -0
- package/src/daemon/ipc-contract/sessions.ts +1 -1
- package/src/daemon/ipc-contract/settings.ts +26 -0
- package/src/daemon/ipc-contract/shared.ts +2 -0
- package/src/daemon/ipc-contract/work-items.ts +1 -7
- package/src/daemon/ipc-contract-inventory.json +5 -1
- package/src/daemon/ipc-contract.ts +5 -1
- package/src/daemon/lifecycle.ts +306 -266
- package/src/daemon/recording-executor.ts +1 -1
- package/src/daemon/recording-intent.ts +0 -41
- package/src/daemon/response-tier.ts +2 -2
- package/src/daemon/server.ts +6 -6
- package/src/daemon/session-agent-loop-handlers.ts +34 -9
- package/src/daemon/session-agent-loop.ts +15 -8
- package/src/daemon/session-history.ts +3 -2
- package/src/daemon/session-media-retry.ts +3 -0
- package/src/daemon/session-messaging.ts +38 -4
- package/src/daemon/session-notifiers.ts +2 -2
- package/src/daemon/session-process.ts +256 -23
- package/src/daemon/session-queue-manager.ts +2 -0
- package/src/daemon/session-runtime-assembly.ts +39 -0
- package/src/daemon/session-skill-tools.ts +13 -4
- package/src/daemon/session-tool-setup.ts +6 -7
- package/src/daemon/session.ts +19 -8
- package/src/daemon/tls-certs.ts +55 -13
- package/src/daemon/tool-side-effects.ts +13 -5
- package/src/gallery/default-gallery.ts +32 -9
- package/src/influencer/client.ts +2 -1
- package/src/memory/channel-delivery-store.ts +37 -567
- package/src/memory/channel-guardian-store.ts +66 -1317
- package/src/memory/conflict-store.ts +4 -4
- package/src/memory/conversation-attention-store.ts +4 -7
- package/src/memory/conversation-crud.ts +668 -0
- package/src/memory/conversation-queries.ts +361 -0
- package/src/memory/conversation-store.ts +45 -983
- package/src/memory/db-connection.ts +3 -0
- package/src/memory/db-init.ts +25 -0
- package/src/memory/delivery-channels.ts +175 -0
- package/src/memory/delivery-crud.ts +211 -0
- package/src/memory/delivery-status.ts +199 -0
- package/src/memory/embedding-backend.ts +70 -4
- package/src/memory/embedding-local.ts +12 -2
- package/src/memory/entity-extractor.ts +3 -8
- package/src/memory/fts-reconciler.ts +121 -0
- package/src/memory/guardian-action-store.ts +366 -3
- package/src/memory/guardian-approvals.ts +569 -0
- package/src/memory/guardian-bindings.ts +130 -0
- package/src/memory/guardian-rate-limits.ts +196 -0
- package/src/memory/guardian-verification.ts +520 -0
- package/src/memory/job-handlers/index-maintenance.ts +2 -1
- package/src/memory/job-utils.ts +8 -5
- package/src/memory/jobs-store.ts +66 -6
- package/src/memory/jobs-worker.ts +23 -1
- package/src/memory/migrations/030-guardian-action-followup.ts +21 -0
- package/src/memory/migrations/030-guardian-verification-purpose.ts +17 -0
- package/src/memory/migrations/031-conversations-thread-type-index.ts +5 -0
- package/src/memory/migrations/100-core-tables.ts +1 -1
- package/src/memory/migrations/101-watchers-and-logs.ts +4 -0
- package/src/memory/migrations/108-tasks-and-work-items.ts +1 -1
- package/src/memory/migrations/112-assistant-inbox.ts +1 -1
- package/src/memory/migrations/113-late-migrations.ts +1 -1
- package/src/memory/migrations/116-messages-fts.ts +13 -0
- package/src/memory/migrations/119-schema-indexes-and-columns.ts +37 -0
- package/src/memory/migrations/120-fk-cascade-rebuilds.ts +161 -0
- package/src/memory/migrations/index.ts +8 -3
- package/src/memory/migrations/validate-migration-state.ts +114 -15
- package/src/memory/qdrant-circuit-breaker.ts +105 -0
- package/src/memory/retriever.ts +46 -13
- package/src/memory/schema-migration.ts +3 -0
- package/src/memory/schema.ts +25 -7
- package/src/memory/search/semantic.ts +8 -90
- package/src/notifications/README.md +1 -1
- package/src/notifications/broadcaster.ts +20 -2
- package/src/notifications/conversation-pairing.ts +3 -3
- package/src/notifications/decision-engine.ts +173 -8
- package/src/notifications/deliveries-store.ts +27 -8
- package/src/notifications/preferences-store.ts +7 -7
- package/src/notifications/thread-candidates.ts +234 -0
- package/src/notifications/types.ts +18 -0
- package/src/permissions/defaults.ts +11 -1
- package/src/permissions/prompter.ts +17 -0
- package/src/permissions/trust-store.ts +2 -0
- package/src/providers/failover.ts +19 -0
- package/src/providers/registry.ts +46 -1
- package/src/runtime/approval-message-composer.ts +1 -1
- package/src/runtime/channel-guardian-service.ts +15 -3
- package/src/runtime/channel-retry-sweep.ts +7 -2
- package/src/runtime/guardian-action-conversation-turn.ts +85 -0
- package/src/runtime/guardian-action-followup-executor.ts +301 -0
- package/src/runtime/guardian-action-message-composer.ts +245 -0
- package/src/runtime/guardian-outbound-actions.ts +35 -15
- package/src/runtime/guardian-verification-templates.ts +15 -9
- package/src/runtime/http-errors.ts +93 -0
- package/src/runtime/http-server.ts +140 -51
- package/src/runtime/http-types.ts +53 -0
- package/src/runtime/ingress-service.ts +237 -0
- package/src/runtime/middleware/error-handler.ts +4 -3
- package/src/runtime/middleware/rate-limiter.ts +160 -0
- package/src/runtime/middleware/request-logger.ts +71 -0
- package/src/runtime/middleware/twilio-validation.ts +7 -6
- package/src/runtime/pending-interactions.ts +12 -0
- package/src/runtime/routes/access-request-decision.ts +215 -0
- package/src/runtime/routes/app-routes.ts +25 -18
- package/src/runtime/routes/approval-routes.ts +18 -47
- package/src/runtime/routes/attachment-routes.ts +15 -41
- package/src/runtime/routes/call-routes.ts +20 -20
- package/src/runtime/routes/channel-delivery-routes.ts +6 -5
- package/src/runtime/routes/contact-routes.ts +4 -9
- package/src/runtime/routes/conversation-attention-routes.ts +5 -4
- package/src/runtime/routes/conversation-routes.ts +26 -57
- package/src/runtime/routes/debug-routes.ts +71 -0
- package/src/runtime/routes/events-routes.ts +3 -2
- package/src/runtime/routes/guardian-approval-interception.ts +221 -0
- package/src/runtime/routes/identity-routes.ts +14 -10
- package/src/runtime/routes/inbound-conversation.ts +3 -2
- package/src/runtime/routes/inbound-message-handler.ts +527 -62
- package/src/runtime/routes/ingress-routes.ts +174 -0
- package/src/runtime/routes/integration-routes.ts +82 -20
- package/src/runtime/routes/pairing-routes.ts +11 -10
- package/src/runtime/routes/secret-routes.ts +10 -18
- package/src/runtime/verification-rate-limiter.ts +83 -0
- package/src/schedule/schedule-store.ts +13 -1
- package/src/schedule/scheduler.ts +2 -2
- package/src/security/secret-ingress.ts +5 -2
- package/src/security/secret-scanner.ts +72 -6
- package/src/subagent/manager.ts +6 -4
- package/src/swarm/plan-validator.ts +4 -1
- package/src/tasks/task-runner.ts +3 -1
- package/src/tools/browser/api-map.ts +9 -6
- package/src/tools/calls/call-start.ts +20 -0
- package/src/tools/executor.ts +50 -568
- package/src/tools/permission-checker.ts +272 -0
- package/src/tools/registry.ts +14 -6
- package/src/tools/reminder/reminder-store.ts +7 -7
- package/src/tools/reminder/reminder.ts +6 -3
- package/src/tools/secret-detection-handler.ts +301 -0
- package/src/tools/subagent/message.ts +1 -1
- package/src/tools/system/voice-config.ts +62 -0
- package/src/tools/tasks/index.ts +3 -3
- package/src/tools/tasks/work-item-list.ts +3 -3
- package/src/tools/tasks/work-item-update.ts +4 -5
- package/src/tools/tool-approval-handler.ts +192 -0
- package/src/tools/tool-manifest.ts +2 -0
- package/src/watcher/watcher-store.ts +9 -9
- package/src/work-items/work-item-runner.ts +9 -6
- /package/src/memory/migrations/{026-embeddings-nullable-vector-json.ts → 026a-embeddings-nullable-vector-json.ts} +0 -0
- /package/src/memory/migrations/{027-guardian-bootstrap-token.ts → 027a-guardian-bootstrap-token.ts} +0 -0
package/src/daemon/lifecycle.ts
CHANGED
|
@@ -42,17 +42,21 @@ import {
|
|
|
42
42
|
getInterfacesDir,
|
|
43
43
|
getRootDir,
|
|
44
44
|
getSocketPath,
|
|
45
|
+
removeSocketFile,
|
|
45
46
|
} from '../util/platform.js';
|
|
46
47
|
import { listWorkItems, updateWorkItem } from '../work-items/work-item-store.js';
|
|
47
48
|
import { WorkspaceHeartbeatService } from '../workspace/heartbeat-service.js';
|
|
48
49
|
import { createApprovalConversationGenerator,createApprovalCopyGenerator } from './approval-generators.js';
|
|
49
|
-
import {
|
|
50
|
+
import { hasNoAuthOverride, hasUngatedNoAuthOverride } from './connection-policy.js';
|
|
51
|
+
import { cleanupPidFile, cleanupPidFileIfOwner, writePid } from './daemon-control.js';
|
|
52
|
+
import { createGuardianActionCopyGenerator, createGuardianFollowUpConversationGenerator } from './guardian-action-generators.js';
|
|
50
53
|
import { initPairingHandlers } from './handlers/pairing.js';
|
|
51
54
|
import { installCliLaunchers } from './install-cli-launchers.js';
|
|
52
55
|
import type { ServerMessage } from './ipc-protocol.js';
|
|
53
56
|
import { initializeProvidersAndTools, registerMessagingProviders,registerWatcherProviders } from './providers-setup.js';
|
|
54
57
|
import { seedInterfaceFiles } from './seed-files.js';
|
|
55
58
|
import { DaemonServer } from './server.js';
|
|
59
|
+
import { setGuardianActionCopyGenerator, setGuardianFollowUpConversationGenerator } from './session-process.js';
|
|
56
60
|
import { initSlashPairingContext } from './session-slash.js';
|
|
57
61
|
import { installShutdownHandlers } from './shutdown-handlers.js';
|
|
58
62
|
|
|
@@ -76,216 +80,255 @@ function loadDotEnv(): void {
|
|
|
76
80
|
export async function runDaemon(): Promise<void> {
|
|
77
81
|
loadDotEnv();
|
|
78
82
|
validateEnv();
|
|
79
|
-
initSentry();
|
|
80
|
-
await initLogfire();
|
|
81
83
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
ensureDataDir();
|
|
88
|
-
|
|
89
|
-
log.info('Daemon startup: migrations complete');
|
|
90
|
-
|
|
91
|
-
seedInterfaceFiles();
|
|
84
|
+
if (hasUngatedNoAuthOverride()) {
|
|
85
|
+
log.warn('VELLUM_DAEMON_NOAUTH is set but VELLUM_UNSAFE_AUTH_BYPASS=1 is not — auth bypass is IGNORED and authentication remains enabled. Set VELLUM_UNSAFE_AUTH_BYPASS=1 to confirm the bypass.');
|
|
86
|
+
} else if (hasNoAuthOverride()) {
|
|
87
|
+
log.warn('VELLUM_DAEMON_NOAUTH is set — IPC authentication is DISABLED. This should only be used for development or SSH-forwarded sockets. Do not use in production.');
|
|
88
|
+
}
|
|
92
89
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
90
|
+
// Track whether the IPC socket has been created so we can clean it up
|
|
91
|
+
// if init crashes after the socket is bound but before shutdown handlers
|
|
92
|
+
// are installed.
|
|
93
|
+
let socketCreated = false;
|
|
96
94
|
|
|
97
95
|
try {
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
96
|
+
initSentry();
|
|
97
|
+
await initLogfire();
|
|
98
|
+
|
|
99
|
+
// Migration order matters: first move legacy flat files into the data dir
|
|
100
|
+
// structure, then relocate the data dir into the active workspace, and
|
|
101
|
+
// finally create any directories that don't yet exist.
|
|
102
|
+
migrateToDataLayout();
|
|
103
|
+
migrateToWorkspaceLayout();
|
|
104
|
+
ensureDataDir();
|
|
105
|
+
|
|
106
|
+
// Resolve and write the bearer token as early as possible so the CLI
|
|
107
|
+
// (which polls for this file during gateway startup) doesn't time out
|
|
108
|
+
// waiting for Qdrant or other slow init steps to finish.
|
|
109
|
+
const httpTokenPath = getHttpTokenPath();
|
|
110
|
+
let bearerToken = getRuntimeProxyBearerToken();
|
|
111
|
+
if (!bearerToken) {
|
|
112
|
+
try {
|
|
113
|
+
const existing = readFileSync(httpTokenPath, 'utf-8').trim();
|
|
114
|
+
if (existing) bearerToken = existing;
|
|
115
|
+
} catch {
|
|
116
|
+
// File doesn't exist or can't be read — will generate below
|
|
117
|
+
}
|
|
112
118
|
}
|
|
113
|
-
|
|
114
|
-
|
|
119
|
+
if (!bearerToken) {
|
|
120
|
+
bearerToken = randomBytes(32).toString('hex');
|
|
121
|
+
}
|
|
122
|
+
writeFileSync(httpTokenPath, bearerToken, { mode: 0o600 });
|
|
123
|
+
chmodSync(httpTokenPath, 0o600);
|
|
124
|
+
log.info('Daemon startup: bearer token written');
|
|
115
125
|
|
|
116
|
-
|
|
117
|
-
const twilioProvider = new TwilioConversationRelayProvider();
|
|
118
|
-
await reconcileCallsOnStartup(twilioProvider, log);
|
|
119
|
-
} catch (err) {
|
|
120
|
-
log.warn({ err }, 'Call recovery failed — continuing startup');
|
|
121
|
-
}
|
|
126
|
+
log.info('Daemon startup: migrations complete');
|
|
122
127
|
|
|
123
|
-
|
|
124
|
-
const config = loadConfig();
|
|
128
|
+
seedInterfaceFiles();
|
|
125
129
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
130
|
+
log.info('Daemon startup: installing templates and initializing DB');
|
|
131
|
+
installTemplates();
|
|
132
|
+
ensurePromptFiles();
|
|
129
133
|
|
|
130
|
-
|
|
134
|
+
try {
|
|
135
|
+
installCliLaunchers();
|
|
136
|
+
} catch (err) {
|
|
137
|
+
log.warn({ err }, 'CLI launcher installation failed — continuing startup');
|
|
138
|
+
}
|
|
139
|
+
initializeDb();
|
|
140
|
+
log.info('Daemon startup: DB initialized');
|
|
141
|
+
|
|
142
|
+
// Recover orphaned work items that were left in 'running' state when the
|
|
143
|
+
// daemon previously crashed or was killed mid-task.
|
|
144
|
+
const orphanedRunning = listWorkItems({ status: 'running' });
|
|
145
|
+
if (orphanedRunning.length > 0) {
|
|
146
|
+
for (const item of orphanedRunning) {
|
|
147
|
+
updateWorkItem(item.id, { status: 'failed', lastRunStatus: 'interrupted' });
|
|
148
|
+
log.info({ workItemId: item.id, title: item.title }, 'Recovered orphaned running work item → failed (interrupted)');
|
|
149
|
+
}
|
|
150
|
+
log.info({ count: orphanedRunning.length }, 'Recovered orphaned running work items');
|
|
151
|
+
}
|
|
131
152
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
log.info('Daemon startup: DaemonServer started');
|
|
153
|
+
try {
|
|
154
|
+
const twilioProvider = new TwilioConversationRelayProvider();
|
|
155
|
+
await reconcileCallsOnStartup(twilioProvider, log);
|
|
156
|
+
} catch (err) {
|
|
157
|
+
log.warn({ err }, 'Call recovery failed — continuing startup');
|
|
158
|
+
}
|
|
139
159
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
log.info({ qdrantUrl }, 'Daemon startup: initializing Qdrant');
|
|
143
|
-
const qdrantManager = new QdrantManager({ url: qdrantUrl });
|
|
144
|
-
try {
|
|
145
|
-
await qdrantManager.start();
|
|
146
|
-
initQdrantClient({
|
|
147
|
-
url: qdrantUrl,
|
|
148
|
-
collection: config.memory.qdrant.collection,
|
|
149
|
-
vectorSize: config.memory.qdrant.vectorSize,
|
|
150
|
-
onDisk: config.memory.qdrant.onDisk,
|
|
151
|
-
quantization: config.memory.qdrant.quantization,
|
|
152
|
-
});
|
|
153
|
-
log.info('Qdrant vector store initialized');
|
|
154
|
-
} catch (err) {
|
|
155
|
-
log.warn({ err }, 'Qdrant failed to start — memory features will be unavailable');
|
|
156
|
-
}
|
|
160
|
+
log.info('Daemon startup: loading config');
|
|
161
|
+
const config = loadConfig();
|
|
157
162
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
attentionHints: {
|
|
178
|
-
requiresAction: true,
|
|
179
|
-
urgency: 'high',
|
|
180
|
-
isAsyncBackground: false,
|
|
181
|
-
visibleInSourceNow: false,
|
|
182
|
-
},
|
|
183
|
-
contextPayload: {
|
|
184
|
-
reminderId: reminder.id,
|
|
185
|
-
label: reminder.label,
|
|
186
|
-
message: reminder.message,
|
|
187
|
-
},
|
|
188
|
-
routingIntent: reminder.routingIntent,
|
|
189
|
-
routingHints: reminder.routingHints,
|
|
190
|
-
dedupeKey: `reminder:${reminder.id}`,
|
|
191
|
-
});
|
|
192
|
-
},
|
|
193
|
-
(schedule) => {
|
|
194
|
-
void emitNotificationSignal({
|
|
195
|
-
sourceEventName: 'schedule.complete',
|
|
196
|
-
sourceChannel: 'scheduler',
|
|
197
|
-
sourceSessionId: schedule.id,
|
|
198
|
-
attentionHints: {
|
|
199
|
-
requiresAction: false,
|
|
200
|
-
urgency: 'medium',
|
|
201
|
-
isAsyncBackground: true,
|
|
202
|
-
visibleInSourceNow: false,
|
|
203
|
-
},
|
|
204
|
-
contextPayload: {
|
|
205
|
-
scheduleId: schedule.id,
|
|
206
|
-
name: schedule.name,
|
|
207
|
-
},
|
|
208
|
-
});
|
|
209
|
-
},
|
|
210
|
-
(notification) => {
|
|
211
|
-
void emitNotificationSignal({
|
|
212
|
-
sourceEventName: 'watcher.notification',
|
|
213
|
-
sourceChannel: 'watcher',
|
|
214
|
-
sourceSessionId: `watcher-${Date.now()}`,
|
|
215
|
-
attentionHints: {
|
|
216
|
-
requiresAction: false,
|
|
217
|
-
urgency: 'low',
|
|
218
|
-
isAsyncBackground: true,
|
|
219
|
-
visibleInSourceNow: false,
|
|
220
|
-
},
|
|
221
|
-
contextPayload: {
|
|
222
|
-
title: notification.title,
|
|
223
|
-
body: notification.body,
|
|
224
|
-
},
|
|
225
|
-
});
|
|
226
|
-
},
|
|
227
|
-
(params) => {
|
|
228
|
-
void emitNotificationSignal({
|
|
229
|
-
sourceEventName: 'watcher.escalation',
|
|
230
|
-
sourceChannel: 'watcher',
|
|
231
|
-
sourceSessionId: `watcher-escalation-${Date.now()}`,
|
|
232
|
-
attentionHints: {
|
|
233
|
-
requiresAction: true,
|
|
234
|
-
urgency: 'high',
|
|
235
|
-
isAsyncBackground: false,
|
|
236
|
-
visibleInSourceNow: false,
|
|
237
|
-
},
|
|
238
|
-
contextPayload: {
|
|
239
|
-
title: params.title,
|
|
240
|
-
body: params.body,
|
|
241
|
-
},
|
|
242
|
-
});
|
|
243
|
-
},
|
|
244
|
-
);
|
|
245
|
-
|
|
246
|
-
// Start the runtime HTTP server. Required for iOS pairing (gateway proxies
|
|
247
|
-
// to it) and optional REST API access. Defaults to port 7821.
|
|
248
|
-
let runtimeHttp: RuntimeHttpServer | null = null;
|
|
249
|
-
const httpPort = getRuntimeHttpPort();
|
|
250
|
-
log.info({ httpPort }, 'Daemon startup: starting runtime HTTP server');
|
|
251
|
-
|
|
252
|
-
// Resolve the bearer token in priority order:
|
|
253
|
-
// 1. Explicit env var (e.g. cloud deploys)
|
|
254
|
-
// 2. Existing token file on disk (preserves QR-paired iOS devices across restarts)
|
|
255
|
-
// 3. Fresh random token (first-time startup)
|
|
256
|
-
const httpTokenPath = getHttpTokenPath();
|
|
257
|
-
let bearerToken = getRuntimeProxyBearerToken();
|
|
258
|
-
if (!bearerToken) {
|
|
163
|
+
if (config.logFile.dir) {
|
|
164
|
+
initLogger({ dir: config.logFile.dir, retentionDays: config.logFile.retentionDays });
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
await initializeProvidersAndTools(config);
|
|
168
|
+
|
|
169
|
+
// Start the IPC socket BEFORE Qdrant so that clients can connect
|
|
170
|
+
// immediately. Qdrant startup can take 30+ seconds (binary download,
|
|
171
|
+
// /readyz polling) which previously blocked the socket from appearing.
|
|
172
|
+
log.info('Daemon startup: starting DaemonServer (IPC socket)');
|
|
173
|
+
const server = new DaemonServer();
|
|
174
|
+
await server.start();
|
|
175
|
+
socketCreated = true;
|
|
176
|
+
log.info('Daemon startup: DaemonServer started');
|
|
177
|
+
|
|
178
|
+
// Initialize Qdrant vector store — non-fatal so the daemon stays up without it
|
|
179
|
+
const qdrantUrl = getQdrantUrlEnv() || config.memory.qdrant.url;
|
|
180
|
+
log.info({ qdrantUrl }, 'Daemon startup: initializing Qdrant');
|
|
181
|
+
const qdrantManager = new QdrantManager({ url: qdrantUrl });
|
|
259
182
|
try {
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
183
|
+
await qdrantManager.start();
|
|
184
|
+
initQdrantClient({
|
|
185
|
+
url: qdrantUrl,
|
|
186
|
+
collection: config.memory.qdrant.collection,
|
|
187
|
+
vectorSize: config.memory.qdrant.vectorSize,
|
|
188
|
+
onDisk: config.memory.qdrant.onDisk,
|
|
189
|
+
quantization: config.memory.qdrant.quantization,
|
|
190
|
+
});
|
|
191
|
+
log.info('Qdrant vector store initialized');
|
|
192
|
+
} catch (err) {
|
|
193
|
+
log.warn({ err }, 'Qdrant failed to start — memory features will be unavailable');
|
|
264
194
|
}
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
195
|
+
|
|
196
|
+
log.info('Daemon startup: starting memory worker');
|
|
197
|
+
const memoryWorker = startMemoryJobsWorker();
|
|
198
|
+
|
|
199
|
+
registerWatcherProviders();
|
|
200
|
+
registerMessagingProviders();
|
|
201
|
+
|
|
202
|
+
// Register the IPC broadcast function for the notification signal pipeline's
|
|
203
|
+
// macOS adapter so it can deliver notification_intent messages to desktop clients.
|
|
204
|
+
registerBroadcastFn((msg) => server.broadcast(msg));
|
|
205
|
+
|
|
206
|
+
const scheduler = startScheduler(
|
|
207
|
+
async (conversationId, message) => {
|
|
208
|
+
await server.processMessage(conversationId, message);
|
|
209
|
+
},
|
|
210
|
+
(reminder) => {
|
|
211
|
+
void emitNotificationSignal({
|
|
212
|
+
sourceEventName: 'reminder.fired',
|
|
213
|
+
sourceChannel: 'scheduler',
|
|
214
|
+
sourceSessionId: reminder.id,
|
|
215
|
+
attentionHints: {
|
|
216
|
+
requiresAction: true,
|
|
217
|
+
urgency: 'high',
|
|
218
|
+
isAsyncBackground: false,
|
|
219
|
+
visibleInSourceNow: false,
|
|
220
|
+
},
|
|
221
|
+
contextPayload: {
|
|
222
|
+
reminderId: reminder.id,
|
|
223
|
+
label: reminder.label,
|
|
224
|
+
message: reminder.message,
|
|
225
|
+
},
|
|
226
|
+
routingIntent: reminder.routingIntent,
|
|
227
|
+
routingHints: reminder.routingHints,
|
|
228
|
+
dedupeKey: `reminder:${reminder.id}`,
|
|
229
|
+
});
|
|
230
|
+
},
|
|
231
|
+
(schedule) => {
|
|
232
|
+
void emitNotificationSignal({
|
|
233
|
+
sourceEventName: 'schedule.complete',
|
|
234
|
+
sourceChannel: 'scheduler',
|
|
235
|
+
sourceSessionId: schedule.id,
|
|
236
|
+
attentionHints: {
|
|
237
|
+
requiresAction: false,
|
|
238
|
+
urgency: 'medium',
|
|
239
|
+
isAsyncBackground: true,
|
|
240
|
+
visibleInSourceNow: false,
|
|
241
|
+
},
|
|
242
|
+
contextPayload: {
|
|
243
|
+
scheduleId: schedule.id,
|
|
244
|
+
name: schedule.name,
|
|
245
|
+
},
|
|
246
|
+
});
|
|
247
|
+
},
|
|
248
|
+
(notification) => {
|
|
249
|
+
void emitNotificationSignal({
|
|
250
|
+
sourceEventName: 'watcher.notification',
|
|
251
|
+
sourceChannel: 'watcher',
|
|
252
|
+
sourceSessionId: `watcher-${Date.now()}`,
|
|
253
|
+
attentionHints: {
|
|
254
|
+
requiresAction: false,
|
|
255
|
+
urgency: 'low',
|
|
256
|
+
isAsyncBackground: true,
|
|
257
|
+
visibleInSourceNow: false,
|
|
258
|
+
},
|
|
259
|
+
contextPayload: {
|
|
260
|
+
title: notification.title,
|
|
261
|
+
body: notification.body,
|
|
262
|
+
},
|
|
263
|
+
});
|
|
264
|
+
},
|
|
265
|
+
(params) => {
|
|
266
|
+
void emitNotificationSignal({
|
|
267
|
+
sourceEventName: 'watcher.escalation',
|
|
268
|
+
sourceChannel: 'watcher',
|
|
269
|
+
sourceSessionId: `watcher-escalation-${Date.now()}`,
|
|
270
|
+
attentionHints: {
|
|
271
|
+
requiresAction: true,
|
|
272
|
+
urgency: 'high',
|
|
273
|
+
isAsyncBackground: false,
|
|
274
|
+
visibleInSourceNow: false,
|
|
275
|
+
},
|
|
276
|
+
contextPayload: {
|
|
277
|
+
title: params.title,
|
|
278
|
+
body: params.body,
|
|
279
|
+
},
|
|
280
|
+
});
|
|
281
|
+
},
|
|
282
|
+
);
|
|
283
|
+
|
|
284
|
+
// Start the runtime HTTP server. Required for iOS pairing (gateway proxies
|
|
285
|
+
// to it) and optional REST API access. Defaults to port 7821.
|
|
286
|
+
let runtimeHttp: RuntimeHttpServer | null = null;
|
|
287
|
+
const httpPort = getRuntimeHttpPort();
|
|
288
|
+
log.info({ httpPort }, 'Daemon startup: starting runtime HTTP server');
|
|
289
|
+
|
|
290
|
+
const hostname = getRuntimeHttpHost();
|
|
291
|
+
|
|
292
|
+
runtimeHttp = new RuntimeHttpServer({
|
|
293
|
+
port: httpPort,
|
|
294
|
+
hostname,
|
|
295
|
+
bearerToken,
|
|
296
|
+
processMessage: (conversationId, content, attachmentIds, options, sourceChannel, sourceInterface) =>
|
|
297
|
+
server.processMessage(conversationId, content, attachmentIds, options, sourceChannel, sourceInterface),
|
|
298
|
+
persistAndProcessMessage: (conversationId, content, attachmentIds, options, sourceChannel, sourceInterface) =>
|
|
299
|
+
server.persistAndProcessMessage(conversationId, content, attachmentIds, options, sourceChannel, sourceInterface),
|
|
300
|
+
interfacesDir: getInterfacesDir(),
|
|
301
|
+
approvalCopyGenerator: createApprovalCopyGenerator(),
|
|
302
|
+
approvalConversationGenerator: createApprovalConversationGenerator(),
|
|
303
|
+
guardianActionCopyGenerator: (() => {
|
|
304
|
+
const gen = createGuardianActionCopyGenerator();
|
|
305
|
+
setGuardianActionCopyGenerator(gen);
|
|
306
|
+
return gen;
|
|
307
|
+
})(),
|
|
308
|
+
guardianFollowUpConversationGenerator: (() => {
|
|
309
|
+
const gen = createGuardianFollowUpConversationGenerator();
|
|
310
|
+
setGuardianFollowUpConversationGenerator(gen);
|
|
311
|
+
return gen;
|
|
312
|
+
})(),
|
|
313
|
+
sendMessageDeps: {
|
|
314
|
+
getOrCreateSession: (conversationId) =>
|
|
315
|
+
server.getSessionForMessages(conversationId),
|
|
316
|
+
assistantEventHub,
|
|
317
|
+
resolveAttachments: (attachmentIds) =>
|
|
318
|
+
attachmentsStore.getAttachmentsByIds(attachmentIds).map((a) => ({
|
|
319
|
+
id: a.id,
|
|
320
|
+
filename: a.originalFilename,
|
|
321
|
+
mimeType: a.mimeType,
|
|
322
|
+
data: a.dataBase64,
|
|
323
|
+
})),
|
|
324
|
+
},
|
|
325
|
+
});
|
|
326
|
+
|
|
327
|
+
// Inject voice bridge deps BEFORE attempting to start the HTTP server.
|
|
328
|
+
// The bridge must be available even when the HTTP server fails to bind.
|
|
329
|
+
setVoiceBridgeDeps({
|
|
330
|
+
getOrCreateSession: (conversationId, _transport) =>
|
|
287
331
|
server.getSessionForMessages(conversationId),
|
|
288
|
-
assistantEventHub,
|
|
289
332
|
resolveAttachments: (attachmentIds) =>
|
|
290
333
|
attachmentsStore.getAttachmentsByIds(attachmentIds).map((a) => ({
|
|
291
334
|
id: a.id,
|
|
@@ -293,80 +336,77 @@ export async function runDaemon(): Promise<void> {
|
|
|
293
336
|
mimeType: a.mimeType,
|
|
294
337
|
data: a.dataBase64,
|
|
295
338
|
})),
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
server.
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
})
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
return threadType === 'private';
|
|
314
|
-
},
|
|
315
|
-
});
|
|
316
|
-
try {
|
|
317
|
-
await runtimeHttp.start();
|
|
318
|
-
setRelayBroadcast((msg) => server.broadcast(msg));
|
|
319
|
-
runtimeHttp.setPairingBroadcast((msg) => server.broadcast(msg as ServerMessage));
|
|
320
|
-
initPairingHandlers(runtimeHttp.getPairingStore(), bearerToken);
|
|
321
|
-
initSlashPairingContext(runtimeHttp.getPairingStore());
|
|
322
|
-
server.setHttpPort(httpPort);
|
|
323
|
-
log.info({ port: httpPort, hostname }, 'Daemon startup: runtime HTTP server listening');
|
|
324
|
-
} catch (err) {
|
|
325
|
-
log.warn({ err, port: httpPort }, 'Failed to start runtime HTTP server, continuing without it');
|
|
326
|
-
runtimeHttp = null;
|
|
327
|
-
}
|
|
339
|
+
deriveDefaultStrictSideEffects: (conversationId) => {
|
|
340
|
+
const threadType = conversationStore.getConversationThreadType(conversationId);
|
|
341
|
+
return threadType === 'private';
|
|
342
|
+
},
|
|
343
|
+
});
|
|
344
|
+
try {
|
|
345
|
+
await runtimeHttp.start();
|
|
346
|
+
setRelayBroadcast((msg) => server.broadcast(msg));
|
|
347
|
+
runtimeHttp.setPairingBroadcast((msg) => server.broadcast(msg as ServerMessage));
|
|
348
|
+
initPairingHandlers(runtimeHttp.getPairingStore(), bearerToken);
|
|
349
|
+
initSlashPairingContext(runtimeHttp.getPairingStore());
|
|
350
|
+
server.setHttpPort(httpPort);
|
|
351
|
+
log.info({ port: httpPort, hostname }, 'Daemon startup: runtime HTTP server listening');
|
|
352
|
+
} catch (err) {
|
|
353
|
+
log.warn({ err, port: httpPort }, 'Failed to start runtime HTTP server, continuing without it');
|
|
354
|
+
runtimeHttp = null;
|
|
355
|
+
}
|
|
328
356
|
|
|
329
|
-
|
|
330
|
-
|
|
357
|
+
writePid(process.pid);
|
|
358
|
+
log.info({ pid: process.pid }, 'Daemon started');
|
|
331
359
|
|
|
332
|
-
|
|
333
|
-
|
|
360
|
+
const hookManager = getHookManager();
|
|
361
|
+
hookManager.watch();
|
|
334
362
|
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
363
|
+
void hookManager.trigger('daemon-start', {
|
|
364
|
+
pid: process.pid,
|
|
365
|
+
socketPath: getSocketPath(),
|
|
366
|
+
});
|
|
339
367
|
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
368
|
+
if (config.auditLog.retentionDays > 0) {
|
|
369
|
+
try {
|
|
370
|
+
rotateToolInvocations(config.auditLog.retentionDays);
|
|
371
|
+
} catch (err) {
|
|
372
|
+
log.warn({ err }, 'Audit log rotation failed');
|
|
373
|
+
}
|
|
345
374
|
}
|
|
346
|
-
}
|
|
347
375
|
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
376
|
+
const workspaceHeartbeat = new WorkspaceHeartbeatService();
|
|
377
|
+
workspaceHeartbeat.start();
|
|
378
|
+
|
|
379
|
+
const heartbeatConfig = config.heartbeat;
|
|
380
|
+
const heartbeat = new HeartbeatService({
|
|
381
|
+
processMessage: (conversationId, content) =>
|
|
382
|
+
server.processMessage(conversationId, content),
|
|
383
|
+
alerter: (alert) => server.broadcast(alert),
|
|
384
|
+
});
|
|
385
|
+
heartbeat.start();
|
|
386
|
+
server.setHeartbeatService(heartbeat);
|
|
387
|
+
log.info({ enabled: heartbeatConfig.enabled, intervalMs: heartbeatConfig.intervalMs }, 'Heartbeat service configured');
|
|
388
|
+
|
|
389
|
+
installShutdownHandlers({
|
|
390
|
+
server,
|
|
391
|
+
workspaceHeartbeat,
|
|
392
|
+
heartbeat,
|
|
393
|
+
hookManager,
|
|
394
|
+
runtimeHttp,
|
|
395
|
+
scheduler,
|
|
396
|
+
memoryWorker,
|
|
397
|
+
qdrantManager,
|
|
398
|
+
cleanupPidFile,
|
|
399
|
+
});
|
|
400
|
+
} catch (err) {
|
|
401
|
+
log.error({ err }, 'Daemon startup failed — cleaning up');
|
|
402
|
+
cleanupPidFileIfOwner(process.pid);
|
|
403
|
+
if (socketCreated) {
|
|
404
|
+
try {
|
|
405
|
+
removeSocketFile(getSocketPath());
|
|
406
|
+
} catch {
|
|
407
|
+
// Best-effort socket cleanup
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
throw err;
|
|
411
|
+
}
|
|
372
412
|
}
|
|
@@ -5,7 +5,6 @@
|
|
|
5
5
|
|
|
6
6
|
import type * as net from 'node:net';
|
|
7
7
|
|
|
8
|
-
import type { HandlerContext } from './handlers/shared.js';
|
|
9
8
|
import {
|
|
10
9
|
handleRecordingPause,
|
|
11
10
|
handleRecordingRestart,
|
|
@@ -14,6 +13,7 @@ import {
|
|
|
14
13
|
handleRecordingStop,
|
|
15
14
|
isRecordingIdle,
|
|
16
15
|
} from './handlers/recording.js';
|
|
16
|
+
import type { HandlerContext } from './handlers/shared.js';
|
|
17
17
|
import type { RecordingIntentResult } from './recording-intent.js';
|
|
18
18
|
|
|
19
19
|
export interface RecordingExecutionContext {
|