@vellumai/assistant 0.10.4 → 0.10.5-dev.202607022329.d89bf2f
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 +94 -91
- package/Dockerfile +5 -16
- package/README.md +7 -10
- package/bun.lock +0 -4
- package/docs/architecture/security.md +20 -20
- package/docs/stt-provider-onboarding.md +4 -5
- package/docs/trusted-contact-access.md +7 -7
- package/eslint-rules/cli-no-daemon-internals.js +4 -0
- package/eslint.config.mjs +7 -1
- package/knip.json +0 -1
- package/node_modules/@vellumai/gateway-client/src/__tests__/contact-read-contracts.test.ts +36 -0
- package/node_modules/@vellumai/gateway-client/src/__tests__/invite-contract.test.ts +233 -0
- package/node_modules/@vellumai/gateway-client/src/__tests__/trust-verdict-contract.test.ts +40 -0
- package/node_modules/@vellumai/gateway-client/src/gateway-ipc-contracts.ts +20 -8
- package/node_modules/@vellumai/gateway-client/src/inbound-contract.ts +10 -0
- package/node_modules/@vellumai/gateway-client/src/index.ts +33 -0
- package/node_modules/@vellumai/gateway-client/src/invite-contract.ts +216 -0
- package/node_modules/@vellumai/gateway-client/src/outbound-contract.ts +91 -0
- package/node_modules/@vellumai/gateway-client/src/trust-verdict-contract.ts +39 -3
- package/node_modules/@vellumai/service-contracts/src/__tests__/ingress.test.ts +0 -8
- package/node_modules/@vellumai/service-contracts/src/__tests__/package-boundary.test.ts +1 -5
- package/node_modules/@vellumai/service-contracts/src/twilio-ingress.ts +3 -14
- package/openapi.yaml +1073 -225
- package/package.json +1 -4
- package/scripts/test.sh +35 -13
- package/src/__tests__/access-request-seed-content-blocks.test.ts +60 -4
- package/src/__tests__/acp-session.test.ts +4 -1
- package/src/__tests__/actor-trust-resolver-address-fallback.test.ts +0 -6
- package/src/__tests__/add-message-preassigned-id.test.ts +56 -0
- package/src/__tests__/agent-loop-set-system-prompt.test.ts +139 -0
- package/src/__tests__/app-conversation-ids-backfill.test.ts +3 -0
- package/src/__tests__/app-source-watcher.test.ts +11 -0
- package/src/__tests__/approval-interception-trust-gates.test.ts +148 -3
- package/src/__tests__/assistant-attachments.test.ts +62 -4
- package/src/__tests__/assistant-id-boundary-guard.test.ts +0 -1
- package/src/__tests__/attachments-store-heic-normalize.test.ts +230 -0
- package/src/__tests__/attachments-store.test.ts +3 -0
- package/src/__tests__/background-shell-bash.test.ts +34 -0
- package/src/__tests__/background-shell-host-bash.test.ts +12 -0
- package/src/__tests__/background-tool-registry.test.ts +97 -0
- package/src/__tests__/background-tool-routes.test.ts +72 -1
- package/src/__tests__/background-workers-disk-pressure.test.ts +2 -1
- package/src/__tests__/btw-routes.test.ts +57 -3
- package/src/__tests__/call-controller.test.ts +474 -84
- package/src/__tests__/call-domain.test.ts +48 -1
- package/src/__tests__/call-pointer-messages.test.ts +57 -19
- package/src/__tests__/call-pointer-no-hardcoded-copy.guard.test.ts +2 -6
- package/src/__tests__/call-routes-http.test.ts +15 -14
- package/src/__tests__/call-setup-flow-invite.test.ts +568 -0
- package/src/__tests__/call-setup-flow-midcall-trust.test.ts +231 -0
- package/src/__tests__/call-setup-flow-name-capture.test.ts +754 -0
- package/src/__tests__/call-setup-flow-verification.test.ts +925 -0
- package/src/__tests__/call-setup-flow.test.ts +311 -0
- package/src/__tests__/cancel-resolves-conversation-key.test.ts +0 -1
- package/src/__tests__/channel-guardian.test.ts +4 -7
- package/src/__tests__/channel-readiness-service.test.ts +0 -6
- package/src/__tests__/channel-readiness-slack-remote.test.ts +0 -4
- package/src/__tests__/channel-retry-sweep.test.ts +76 -64
- package/src/__tests__/channel-setup-panel-ack.test.ts +184 -0
- package/src/__tests__/clear-all-lexical.test.ts +90 -0
- package/src/__tests__/compactor-media-strip.test.ts +177 -0
- package/src/__tests__/config-loader-backfill.test.ts +5 -5
- package/src/__tests__/config-schema.test.ts +17 -0
- package/src/__tests__/contact-store-interaction-info.test.ts +27 -70
- package/src/__tests__/contacts-relay-reads.test.ts +188 -23
- package/src/__tests__/contacts-tools.test.ts +42 -1
- package/src/__tests__/contacts-write.test.ts +181 -0
- package/src/__tests__/context-search-conversations-source.test.ts +220 -81
- package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +1 -0
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +1 -0
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +1 -0
- package/src/__tests__/conversation-agent-loop.test.ts +39 -0
- package/src/__tests__/conversation-analysis-routes.test.ts +1 -1
- package/src/__tests__/conversation-app-control-instantiation.test.ts +2 -0
- package/src/__tests__/conversation-clear-safety.test.ts +0 -1
- package/src/__tests__/conversation-crud-enabled-plugins.test.ts +60 -0
- package/src/__tests__/conversation-delete-schedule-cleanup.test.ts +0 -1
- package/src/__tests__/conversation-disk-view.test.ts +1 -0
- package/src/__tests__/conversation-enabledplugins-route.test.ts +184 -0
- package/src/__tests__/conversation-error.test.ts +0 -18
- package/src/__tests__/conversation-fork-crud.test.ts +67 -0
- package/src/__tests__/conversation-history-web-search.test.ts +7 -137
- package/src/__tests__/conversation-initial-prompt.test.ts +110 -0
- package/src/__tests__/conversation-loop-db-lock-resilience.test.ts +191 -0
- package/src/__tests__/conversation-process-callsite.test.ts +37 -0
- package/src/__tests__/conversation-queue.test.ts +149 -0
- package/src/__tests__/conversation-routes-enabled-plugins.test.ts +392 -0
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +84 -0
- package/src/__tests__/conversation-routes-hidden-queue.test.ts +407 -0
- package/src/__tests__/conversation-runtime-assembly.test.ts +36 -16
- package/src/__tests__/conversation-skill-tools.test.ts +73 -0
- package/src/__tests__/conversation-wipe.test.ts +20 -5
- package/src/__tests__/credential-prompt-route.test.ts +69 -0
- package/src/__tests__/credential-security-invariants.test.ts +1 -3
- package/src/__tests__/db-drop-messages-fts.test.ts +115 -0
- package/src/__tests__/deterministic-verification-control-plane.test.ts +1 -62
- package/src/__tests__/edit-propagation.test.ts +56 -2
- package/src/__tests__/empty-state-greeting-cache.test.ts +9 -0
- package/src/__tests__/gateway-only-enforcement.test.ts +15 -110
- package/src/__tests__/guardian-expiry-notifier.test.ts +1 -0
- package/src/__tests__/guardian-question-mode.test.ts +57 -0
- package/src/__tests__/guardian-verification-voice-binding.test.ts +1 -1
- package/src/__tests__/guardian-wait-controller.test.ts +619 -0
- package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +33 -2
- package/src/__tests__/heic-fixture.ts +55 -0
- package/src/__tests__/helpers/seed-contact-channel.ts +0 -2
- package/src/__tests__/http-conversation-lineage.test.ts +6 -1
- package/src/__tests__/image-conversion.test.ts +170 -0
- package/src/__tests__/inbound-invite-redemption.test.ts +72 -341
- package/src/__tests__/introduction-card-resolver.test.ts +354 -0
- package/src/__tests__/invite-redeemed-ipc.test.ts +97 -0
- package/src/__tests__/invite-routes-http.test.ts +246 -420
- package/src/__tests__/job-handler-registration-guard.test.ts +104 -0
- package/src/__tests__/lexical-index-dual-write.test.ts +426 -0
- package/src/__tests__/lifecycle-memory-v2-seed.test.ts +2 -2
- package/src/__tests__/list-messages-attachments.test.ts +159 -0
- package/src/__tests__/list-messages-background-tool-completion.test.ts +141 -0
- package/src/__tests__/list-messages-queued.test.ts +25 -0
- package/src/__tests__/managed-store.test.ts +129 -1
- package/src/__tests__/media-stream-audio-transcode.test.ts +113 -0
- package/src/__tests__/media-stream-output.test.ts +350 -19
- package/src/__tests__/media-stream-server-integration.test.ts +943 -169
- package/src/__tests__/media-stream-stt-session.test.ts +498 -1
- package/src/__tests__/memory-jobs-worker-lanes.test.ts +2 -2
- package/src/__tests__/model-intents.test.ts +1 -1
- package/src/__tests__/mtime-cache.test.ts +19 -0
- package/src/__tests__/non-member-access-request.test.ts +349 -3
- package/src/__tests__/notification-decision-fallback.test.ts +104 -8
- package/src/__tests__/notification-decision-strategy.test.ts +57 -8
- package/src/__tests__/onboarding-template-contract.test.ts +27 -43
- package/src/__tests__/openai-provider.test.ts +33 -0
- package/src/__tests__/openai-responses-provider.test.ts +40 -0
- package/src/__tests__/persistence-layering-guard.test.ts +29 -20
- package/src/__tests__/persona-resolver.test.ts +56 -2
- package/src/__tests__/personal-memory-auth-bypass.test.ts +62 -0
- package/src/__tests__/phone.test.ts +1 -15
- package/src/__tests__/plugin-bootstrap.test.ts +25 -196
- package/src/__tests__/plugin-disabled-state.test.ts +33 -0
- package/src/__tests__/plugin-effective-enabled-set.test.ts +227 -0
- package/src/__tests__/plugin-event-hub-facade.test.ts +323 -0
- package/src/__tests__/plugin-import-boundary-guard.test.ts +156 -42
- package/src/__tests__/plugin-injector-contribution.test.ts +4 -20
- package/src/__tests__/plugin-pipeline.test.ts +63 -1
- package/src/__tests__/plugin-route-contribution.test.ts +62 -115
- package/src/__tests__/plugin-tool-contribution.test.ts +0 -22
- package/src/__tests__/plugin-types.test.ts +0 -1
- package/src/__tests__/pointer-conversation-trust.test.ts +38 -6
- package/src/__tests__/pre-model-call-sanitize.test.ts +1 -1
- package/src/__tests__/prune-old-tool-invocations-job.test.ts +97 -0
- package/src/__tests__/public-ingress-urls.test.ts +0 -48
- package/src/__tests__/qdrant-collection-migration.test.ts +145 -2
- package/src/__tests__/reaction-intercept-member-verdict-warm.test.ts +0 -1
- package/src/__tests__/resolve-trust-class.test.ts +28 -10
- package/src/__tests__/scaffold-managed-skill-tool.test.ts +137 -0
- package/src/__tests__/schedule-retry.test.ts +38 -14
- package/src/__tests__/schedule-routes-workflow-validation.test.ts +3 -3
- package/src/__tests__/schedule-routes.test.ts +14 -6
- package/src/__tests__/schedule-store.test.ts +3 -1
- package/src/__tests__/scheduler-disk-pressure.test.ts +17 -6
- package/src/__tests__/scheduler-recurrence.test.ts +57 -107
- package/src/__tests__/scheduler-reuse-conversation.test.ts +51 -46
- package/src/__tests__/scheduler-wake.test.ts +13 -23
- package/src/__tests__/scheduler-worker-standdown.test.ts +220 -0
- package/src/__tests__/secret-routes-platform-proxy.test.ts +1 -1
- package/src/__tests__/shell-observability.test.ts +1 -0
- package/src/__tests__/skill-boundary-guard.test.ts +3 -4
- package/src/__tests__/skill-load-plugin-scope.test.ts +238 -0
- package/src/__tests__/skill-projection-feature-flag.test.ts +2 -0
- package/src/__tests__/skill-script-runner-host.test.ts +53 -0
- package/src/__tests__/skill-script-runner-sandbox.test.ts +5 -2
- package/src/__tests__/skill-tool-factory.test.ts +73 -1
- package/src/__tests__/slack-app-setup-skill-regression.test.ts +37 -14
- package/src/__tests__/slack-inbound-verification.test.ts +36 -0
- package/src/__tests__/slack-notification-approval-card.test.ts +89 -2
- package/src/__tests__/slack-reaction-canonical-approval.test.ts +51 -1
- package/src/__tests__/stt-hints.test.ts +2 -256
- package/src/__tests__/subagent-allowlist-validation.test.ts +47 -0
- package/src/__tests__/subagent-call-site-routing.test.ts +72 -0
- package/src/__tests__/subagent-fork-notifications.test.ts +14 -2
- package/src/__tests__/subagent-persistence.test.ts +122 -0
- package/src/__tests__/subagent-spawn-and-await.test.ts +1 -0
- package/src/__tests__/subagent-terminal-message.test.ts +99 -0
- package/src/__tests__/subagent-tool-gate-mode.test.ts +78 -1
- package/src/__tests__/system-prompt.test.ts +17 -118
- package/src/__tests__/task-scheduler.test.ts +68 -89
- package/src/__tests__/telephony-credential-preflight.test.ts +312 -0
- package/src/__tests__/telephony-tts-guard.test.ts +538 -0
- package/src/__tests__/title-generate-hook.test.ts +16 -0
- package/src/__tests__/tool-approval-handler.test.ts +87 -1
- package/src/__tests__/tool-approval-seed-content-blocks.test.ts +45 -20
- package/src/__tests__/tool-grant-request-escalation.test.ts +39 -0
- package/src/__tests__/trust-context-guards.test.ts +21 -10
- package/src/__tests__/trusted-contact-multichannel.test.ts +4 -0
- package/src/__tests__/twilio-provider.test.ts +17 -17
- package/src/__tests__/twilio-routes-twiml.test.ts +6 -543
- package/src/__tests__/twilio-routes.test.ts +257 -387
- package/src/__tests__/twilio-validation.test.ts +1 -1
- package/src/__tests__/unified-turn-context-client-os.test.ts +45 -0
- package/src/__tests__/usage-cache-backfill-migration.test.ts +5 -0
- package/src/__tests__/voice-approval-resolver-relay.test.ts +150 -0
- package/src/__tests__/voice-ingress-preflight.test.ts +61 -0
- package/src/__tests__/voice-quality.test.ts +2 -2
- package/src/__tests__/voice-scoped-grant-consumer.test.ts +1 -7
- package/src/__tests__/voice-session-bridge-processing-wait.test.ts +27 -0
- package/src/__tests__/voice-session-bridge.test.ts +1 -10
- package/src/__tests__/workspace-git-service.test.ts +1 -1
- package/src/__tests__/workspace-migration-013-repair-conversation-disk-view.test.ts +1 -0
- package/src/__tests__/workspace-migration-118-seed-now-md.test.ts +120 -0
- package/src/__tests__/workspace-migration-120-revise-onboarding-threads.test.ts +175 -0
- package/src/__tests__/workspace-migration-121-seed-default-user-guardrails.test.ts +118 -0
- package/src/__tests__/workspace-migration-122-relocate-default-user-boundary.test.ts +119 -0
- package/src/__tests__/workspace-migration-123-swap-quality-profile-to-fable.test.ts +191 -0
- package/src/__tests__/workspace-migration-backfill-installation-id.test.ts +235 -241
- package/src/acp/__tests__/prepare-agent-env.test.ts +0 -97
- package/src/acp/__tests__/session-manager-persistence.test.ts +2 -0
- package/src/acp/__tests__/session-manager-resume.test.ts +8 -0
- package/src/acp/__tests__/session-manager-usage.test.ts +6 -0
- package/src/acp/__tests__/session-manager.test.ts +6 -0
- package/src/acp/agent-process.test.ts +116 -0
- package/src/acp/agent-process.ts +71 -0
- package/src/acp/auto-install.ts +12 -8
- package/src/acp/failure-error.test.ts +109 -0
- package/src/acp/failure-error.ts +111 -0
- package/src/acp/prepare-agent-env.ts +0 -12
- package/src/acp/resolve-agent.test.ts +6 -45
- package/src/acp/resolve-agent.ts +2 -4
- package/src/acp/session-manager.test.ts +312 -0
- package/src/acp/session-manager.ts +102 -46
- package/src/agent/ax-tree-compaction.test.ts +4 -1
- package/src/agent/image-optimize.ts +17 -127
- package/src/agent/loop.ts +45 -192
- package/src/api/events/background-tool-completed.test.ts +51 -0
- package/src/api/events/background-tool-completed.ts +29 -0
- package/src/api/events/background-tool-started.test.ts +36 -0
- package/src/api/events/background-tool-started.ts +28 -0
- package/src/api/events/conversation-error.ts +0 -1
- package/src/api/events/open-panel.ts +33 -0
- package/src/api/events/subagent-status-changed.ts +4 -1
- package/src/api/index.ts +19 -0
- package/src/api/responses/conversation-message.ts +34 -0
- package/src/approvals/guardian-decision-primitive.ts +74 -24
- package/src/approvals/guardian-request-resolvers.ts +450 -122
- package/src/apps/app-store.ts +1 -0
- package/src/apps/shared-app-links-store.ts +1 -0
- package/src/avatar/identity-avatar.ts +3 -7
- package/src/background-wake/wake-intent-hooks.test.ts +1 -1
- package/src/calls/__tests__/fish-audio-client.test.ts +73 -0
- package/src/calls/__tests__/gateway-invite-reader.test.ts +170 -0
- package/src/calls/__tests__/relay-setup-router.test.ts +126 -102
- package/src/calls/call-controller.ts +134 -48
- package/src/calls/call-domain.ts +18 -42
- package/src/calls/call-pointer-messages.ts +51 -67
- package/src/calls/call-setup-flow-types.ts +76 -0
- package/src/calls/call-setup-flow.ts +1743 -0
- package/src/calls/call-speech-output.ts +87 -23
- package/src/calls/call-store.ts +4 -0
- package/src/calls/call-transport.ts +22 -36
- package/src/calls/fish-audio-client.ts +3 -0
- package/src/calls/gateway-invite-reader.ts +98 -0
- package/src/calls/guardian-wait-controller.ts +451 -0
- package/src/calls/media-stream-audio-transcode.ts +82 -2
- package/src/calls/media-stream-output.ts +142 -36
- package/src/calls/media-stream-server.ts +297 -178
- package/src/calls/media-stream-stt-session.ts +393 -50
- package/src/calls/media-turn-detector.ts +4 -6
- package/src/calls/relay-access-wait.ts +3 -4
- package/src/calls/relay-setup-router.ts +22 -43
- package/src/calls/relay-verification.ts +17 -24
- package/src/calls/resolve-call-tts-provider.ts +96 -29
- package/src/calls/stt-hints.ts +24 -87
- package/src/calls/telephony-credential-preflight.ts +159 -0
- package/src/calls/telephony-tts-capability.ts +183 -0
- package/src/calls/tts-call-strategy.ts +18 -20
- package/src/calls/twilio-provider.ts +3 -2
- package/src/calls/twilio-routes.ts +47 -351
- package/src/calls/types.ts +5 -3
- package/src/calls/voice-ingress-preflight.ts +9 -0
- package/src/calls/voice-quality.ts +13 -18
- package/src/calls/voice-session-bridge.ts +25 -35
- package/src/channels/__tests__/types.test.ts +28 -0
- package/src/channels/channel-verification-sessions.ts +7 -2
- package/src/channels/config.ts +0 -42
- package/src/channels/slack-thread-store.ts +12 -0
- package/src/channels/types.ts +23 -0
- package/src/cli/commands/__tests__/conversations-slack.test.ts +1 -1
- package/src/cli/commands/__tests__/schedules.test.ts +83 -34
- package/src/cli/commands/__tests__/status.test.ts +42 -2
- package/src/cli/commands/contacts.ts +2 -2
- package/src/cli/commands/credentials.ts +17 -0
- package/src/cli/commands/monitoring.ts +191 -0
- package/src/cli/commands/schedules-worker.ts +175 -0
- package/src/cli/commands/schedules.ts +169 -43
- package/src/cli/commands/status.ts +12 -1
- package/src/cli/commands/tools.ts +5 -1
- package/src/cli/lib/__tests__/plugin-catalog-cache.test.ts +1 -0
- package/src/cli/lib/__tests__/search-plugins.test.ts +29 -1
- package/src/cli/lib/__tests__/toggle-plugin.test.ts +7 -0
- package/src/cli/lib/search-plugins.ts +6 -0
- package/src/cli/lib/toggle-plugin.ts +21 -2
- package/src/cli/program.ts +3 -1
- package/src/config/__tests__/deployment-context-defaults.test.ts +23 -0
- package/src/config/acp-defaults.test.ts +0 -10
- package/src/config/acp-defaults.ts +0 -6
- package/src/config/bundled-skills/acp/SKILL.md +13 -45
- package/src/config/bundled-skills/acp/TOOLS.json +3 -3
- package/src/config/bundled-skills/app-builder/SKILL.md +3 -3
- package/src/config/bundled-skills/app-builder/references/RESPONSIVE.md +9 -9
- package/src/config/bundled-skills/contacts/tools/contact-merge.ts +1 -1
- package/src/config/bundled-skills/contacts/tools/contact-search.ts +1 -1
- package/src/config/bundled-skills/phone-calls/SKILL.md +1 -1
- package/src/config/bundled-skills/phone-calls/references/CONFIG.md +9 -9
- package/src/config/bundled-skills/phone-calls/references/TROUBLESHOOTING.md +10 -7
- package/src/config/bundled-skills/skill-management/TOOLS.json +10 -0
- package/src/config/call-site-defaults.ts +0 -2
- package/src/config/feature-flag-registry.json +16 -8
- package/src/config/loader.ts +11 -0
- package/src/config/schema.ts +9 -1
- package/src/config/schemas/__tests__/memory-v2.test.ts +2 -2
- package/src/config/schemas/__tests__/memory-v3.test.ts +64 -0
- package/src/config/schemas/call-site-catalog.ts +0 -12
- package/src/config/schemas/calls.ts +8 -0
- package/src/config/schemas/elevenlabs.ts +1 -1
- package/src/config/schemas/llm.ts +0 -2
- package/src/config/schemas/memory-v2.ts +1 -1
- package/src/config/schemas/memory-v3.ts +82 -0
- package/src/config/schemas/monitoring.ts +61 -0
- package/src/config/schemas/schedules.ts +35 -0
- package/src/config/seed-inference-profiles.ts +2 -2
- package/src/config/skills-plugin-filter.test.ts +96 -0
- package/src/config/skills.ts +26 -0
- package/src/contacts/__tests__/member-write-relay.test.ts +156 -4
- package/src/contacts/canonical-guardian-store.ts +5 -0
- package/src/contacts/contact-store.ts +81 -35
- package/src/contacts/contacts-write.ts +50 -25
- package/src/contacts/member-write-relay.ts +115 -31
- package/src/contacts/types.ts +0 -8
- package/src/context/compactor.ts +29 -15
- package/src/context/outbound-sanitize.ts +202 -0
- package/src/daemon/__tests__/abort-null-controller.test.ts +167 -0
- package/src/daemon/__tests__/conversation-tool-setup-plugin-scope.test.ts +122 -0
- package/src/daemon/__tests__/embedding-reconcile.test.ts +99 -16
- package/src/daemon/__tests__/wake-conversation-ops-completion.test.ts +107 -0
- package/src/daemon/abort-watchdog.ts +7 -0
- package/src/daemon/app-source-watcher.ts +9 -0
- package/src/daemon/assistant-attachments.ts +42 -0
- package/src/daemon/conversation-agent-loop-handlers.ts +256 -147
- package/src/daemon/conversation-agent-loop.ts +61 -68
- package/src/daemon/conversation-error.ts +1 -15
- package/src/daemon/conversation-history.ts +32 -236
- package/src/daemon/conversation-initial-prompt.ts +77 -0
- package/src/daemon/conversation-lifecycle.ts +25 -1
- package/src/daemon/conversation-messaging.ts +2 -2
- package/src/daemon/conversation-plugin-scope.ts +38 -0
- package/src/daemon/conversation-process.ts +50 -14
- package/src/daemon/conversation-runtime-assembly.ts +36 -6
- package/src/daemon/conversation-skill-tools.ts +19 -3
- package/src/daemon/conversation-store.ts +3 -3
- package/src/daemon/conversation-surfaces.ts +171 -0
- package/src/daemon/conversation-tool-setup.test.ts +95 -0
- package/src/daemon/conversation-tool-setup.ts +116 -1
- package/src/daemon/conversation-turn-finalize.ts +211 -0
- package/src/daemon/conversation.ts +92 -1
- package/src/daemon/disk-pressure-policy.ts +2 -1
- package/src/daemon/event-loop-watchdog.ts +22 -6
- package/src/daemon/external-plugins-bootstrap.ts +47 -134
- package/src/daemon/handlers/__tests__/config-a2a-accept.test.ts +1 -1
- package/src/daemon/handlers/__tests__/config-a2a-complete.test.ts +26 -14
- package/src/daemon/handlers/__tests__/config-a2a-invite.test.ts +27 -14
- package/src/daemon/handlers/__tests__/config-channels.test.ts +0 -5
- package/src/daemon/handlers/config-a2a.ts +7 -14
- package/src/daemon/handlers/config-channels.ts +2 -10
- package/src/daemon/handlers/conversation-history.ts +3 -1
- package/src/daemon/handlers/conversations.ts +0 -52
- package/src/daemon/handlers/shared.ts +4 -24
- package/src/daemon/handlers/skills.ts +4 -1
- package/src/daemon/host-cu-proxy.ts +1 -1
- package/src/daemon/lifecycle.ts +59 -472
- package/src/daemon/message-protocol.ts +3 -3
- package/src/daemon/message-provenance.ts +12 -14
- package/src/daemon/message-types/background-tools.ts +28 -0
- package/src/daemon/message-types/contacts.ts +2 -10
- package/src/daemon/message-types/conversations.ts +10 -0
- package/src/daemon/message-types/integrations.ts +2 -0
- package/src/daemon/message-types/surfaces.ts +1 -0
- package/src/daemon/message-types/sync.ts +1 -0
- package/src/daemon/pointer-conversation-trust.ts +23 -9
- package/src/daemon/pointer-turn-runner.ts +174 -0
- package/src/daemon/providers-setup.ts +16 -0
- package/src/daemon/shutdown-handlers.ts +139 -47
- package/src/daemon/skill-memory-refresh.ts +2 -2
- package/src/daemon/sqlite-corruption-watchdog.test.ts +217 -0
- package/src/daemon/sqlite-corruption-watchdog.ts +155 -0
- package/src/daemon/tool-setup-types.ts +8 -0
- package/src/daemon/trust-context.ts +21 -6
- package/src/daemon/turn-latency-tracker.test.ts +93 -0
- package/src/daemon/turn-latency-tracker.ts +38 -0
- package/src/daemon/wake-conversation-ops.ts +10 -8
- package/src/documents/document-comments-store.test.ts +7 -1
- package/src/documents/document-comments-store.ts +8 -0
- package/src/documents/document-store.ts +15 -0
- package/src/export/__tests__/transcript-formatter.test.ts +11 -0
- package/src/export/transcript-formatter.ts +49 -67
- package/src/home/__tests__/feed-writer.test.ts +247 -1
- package/src/home/conversation-starter-checkpoints.ts +1 -0
- package/src/home/feed-writer.ts +61 -0
- package/src/home/job-handlers/conversation-starters.ts +1 -0
- package/src/hooks/hook-loader.ts +12 -0
- package/src/hooks/registry.ts +32 -4
- package/src/inbound/public-ingress-urls.ts +0 -17
- package/src/ipc/__tests__/contacts-info-ipc.test.ts +285 -0
- package/src/ipc/assistant-server.ts +28 -7
- package/src/ipc/routes/__tests__/contacts-mirror-apply-atomicity.test.ts +62 -0
- package/src/ipc/routes/__tests__/contacts-mirror-apply.test.ts +272 -0
- package/src/ipc/routes/__tests__/contacts-mirror-ipc-routes.test.ts +322 -0
- package/src/ipc/routes/__tests__/invite-ipc-routes.test.ts +60 -4
- package/src/ipc/routes/contacts-info-ipc-routes.ts +239 -0
- package/src/ipc/routes/contacts-mirror-ipc-routes.ts +202 -0
- package/src/ipc/routes/db-proxy.ts +5 -2
- package/src/ipc/routes/invite-ipc-routes.ts +53 -39
- package/src/jobs/worker.ts +9 -2
- package/src/live-voice/__tests__/live-voice-archive.test.ts +10 -1
- package/src/live-voice/live-voice-archive.ts +5 -0
- package/src/messaging/providers/__tests__/transport-dispatch.test.ts +22 -6
- package/src/messaging/providers/channel-transport.ts +6 -0
- package/src/messaging/providers/index.ts +3 -0
- package/src/messaging/providers/slack/api.test.ts +49 -1
- package/src/messaging/providers/slack/api.ts +110 -0
- package/src/messaging/providers/slack/send.test.ts +85 -0
- package/src/messaging/providers/slack/send.ts +100 -28
- package/src/messaging/providers/slack/transport.ts +7 -13
- package/src/messaging/providers/whatsapp/send.ts +29 -9
- package/src/monitoring/__tests__/control.test.ts +235 -0
- package/src/monitoring/__tests__/sample-ring-buffer.test.ts +96 -0
- package/src/monitoring/control.ts +105 -0
- package/src/monitoring/resource-sampler.ts +258 -0
- package/src/monitoring/sample-ring-buffer.ts +108 -0
- package/src/monitoring/worker.ts +94 -0
- package/src/notifications/README.md +1 -1
- package/src/notifications/access-request-copy.ts +94 -23
- package/src/notifications/adapters/slack.ts +89 -21
- package/src/notifications/approval-card-builder.ts +33 -18
- package/src/notifications/approval-card-data.ts +48 -15
- package/src/notifications/broadcaster.ts +25 -16
- package/src/notifications/decision-engine.ts +131 -32
- package/src/notifications/guardian-question-mode.ts +58 -10
- package/src/permissions/approval-policy.ts +8 -1
- package/src/permissions/checker.ts +2 -0
- package/src/permissions/gateway-threshold-reader.ts +7 -6
- package/src/permissions/ipc-risk-types.ts +1 -0
- package/src/permissions/secret-prompter.ts +11 -3
- package/src/permissions/types.ts +2 -2
- package/src/persistence/__tests__/conversation-queries-search.test.ts +397 -0
- package/src/persistence/__tests__/conversation-search-lexical.test.ts +103 -0
- package/src/persistence/__tests__/jobs-worker-memory-disabled.test.ts +95 -0
- package/src/persistence/__tests__/slow-query-log.test.ts +266 -0
- package/src/persistence/__tests__/slow-sync-log.test.ts +155 -0
- package/src/persistence/a2a-invite-store.ts +205 -0
- package/src/persistence/attachments-store.ts +94 -10
- package/src/persistence/checkpoints.ts +45 -0
- package/src/persistence/conversation-crud.ts +453 -260
- package/src/persistence/conversation-display-order-migration.ts +8 -2
- package/src/persistence/conversation-group-migration.test.ts +8 -0
- package/src/persistence/conversation-group-migration.ts +9 -0
- package/src/persistence/conversation-queries.ts +244 -125
- package/src/persistence/conversation-row-batch-delete.ts +9 -5
- package/src/persistence/conversation-search-lexical.ts +49 -0
- package/src/persistence/db-async-query.ts +42 -0
- package/src/persistence/db-connection.ts +13 -0
- package/src/persistence/delivery-channels.ts +0 -82
- package/src/persistence/delivery-crud.ts +27 -6
- package/src/persistence/embeddings/__tests__/embedding-identity.test.ts +18 -5
- package/src/persistence/embeddings/__tests__/messages-lexical-index.test.ts +334 -0
- package/src/persistence/embeddings/embedding-identity.ts +17 -5
- package/src/persistence/embeddings/embedding-runtime-manager.ts +31 -0
- package/src/persistence/embeddings/messages-lexical-index.ts +396 -0
- package/src/persistence/embeddings/qdrant-client.ts +81 -5
- package/src/persistence/group-crud.ts +13 -1
- package/src/persistence/job-handlers/__tests__/message-lexical-backfill.test.ts +506 -0
- package/src/persistence/job-handlers/__tests__/message-lexical-enqueue.test.ts +164 -0
- package/src/persistence/job-handlers/__tests__/message-lexical.test.ts +259 -0
- package/src/persistence/job-handlers/cleanup.ts +57 -9
- package/src/persistence/job-handlers/message-lexical-backfill.ts +187 -0
- package/src/persistence/job-handlers/message-lexical.ts +251 -0
- package/src/persistence/jobs-store.ts +102 -8
- package/src/persistence/jobs-worker.ts +68 -28
- package/src/persistence/llm-request-log-store.ts +35 -19
- package/src/persistence/llm-usage-store.ts +11 -0
- package/src/persistence/memory-lifecycle-hooks.test.ts +65 -0
- package/src/persistence/memory-lifecycle-hooks.ts +55 -1
- package/src/persistence/migrations/028-call-session-mode.ts +1 -1
- package/src/persistence/migrations/116-messages-fts.ts +8 -1
- package/src/persistence/migrations/311-create-subagents-table.ts +50 -0
- package/src/persistence/migrations/312-drop-inbox-conversation-state-table.ts +15 -0
- package/src/persistence/migrations/313-drop-messages-fts.ts +17 -0
- package/src/persistence/migrations/314-add-conversation-enabled-plugins.ts +25 -0
- package/src/persistence/migrations/315-create-a2a-invites.ts +58 -0
- package/src/persistence/migrations/316-drop-contact-channels-invite-id.ts +28 -0
- package/src/persistence/migrations/317-canonical-guardian-requester-signals.ts +24 -0
- package/src/persistence/migrations/318-drop-contact-channel-telemetry.ts +32 -0
- package/src/persistence/migrations/__tests__/315-create-a2a-invites.test.ts +161 -0
- package/src/persistence/migrations/__tests__/316-drop-contact-channels-invite-id.test.ts +156 -0
- package/src/persistence/migrations/__tests__/318-drop-contact-channel-telemetry.test.ts +134 -0
- package/src/persistence/migrations/__tests__/migration-prefix-guard.test.ts +99 -0
- package/src/persistence/raw-query.ts +50 -11
- package/src/persistence/schema/a2a.ts +14 -0
- package/src/persistence/schema/contacts.ts +0 -62
- package/src/persistence/schema/conversation-groups.ts +12 -0
- package/src/persistence/schema/conversations.ts +2 -0
- package/src/persistence/schema/documents.ts +65 -0
- package/src/persistence/schema/guardian.ts +4 -0
- package/src/persistence/schema/index.ts +4 -0
- package/src/persistence/schema/memory-injection.ts +62 -0
- package/src/persistence/schema/workflows.ts +55 -0
- package/src/persistence/slow-query-log.ts +437 -0
- package/src/persistence/slow-sync-log.ts +204 -0
- package/src/persistence/steps.ts +16 -0
- package/src/persistence/subagent-store.ts +125 -0
- package/src/persistence/worker-control.ts +45 -238
- package/src/plugin-api/event-hub-facade.ts +172 -0
- package/src/plugin-api/index.ts +9 -1
- package/src/plugin-api/types.ts +40 -9
- package/src/plugins/defaults/default-plugin-names.ts +60 -0
- package/src/plugins/defaults/index.ts +19 -29
- package/src/plugins/defaults/memory/__tests__/conversation-queries.test.ts +46 -67
- package/src/plugins/defaults/memory/__tests__/db-async-query.test.ts +36 -1
- package/src/plugins/defaults/memory/__tests__/find-most-recent-retrospective-for.test.ts +2 -4
- package/src/plugins/defaults/memory/__tests__/jobs-worker-v2-graph-trigger-embed.test.ts +2 -2
- package/src/plugins/defaults/memory/__tests__/jobs-worker-v2-schedule.test.ts +9 -0
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +7 -4
- package/src/plugins/defaults/memory/config.ts +11 -0
- package/src/plugins/defaults/memory/context-search/agent-runner.ts +1 -1
- package/src/plugins/defaults/memory/context-search/sources/conversations.ts +124 -113
- package/src/plugins/defaults/memory/embeddings.ts +77 -0
- package/src/plugins/defaults/memory/find-most-recent-retrospective-for.ts +66 -0
- package/src/plugins/defaults/memory/frontmatter.ts +50 -0
- package/src/plugins/defaults/memory/graph/bootstrap.test.ts +36 -10
- package/src/plugins/defaults/memory/graph/bootstrap.ts +6 -5
- package/src/plugins/defaults/memory/graph/consolidation.ts +3 -5
- package/src/plugins/defaults/memory/graph/extraction.ts +3 -6
- package/src/plugins/defaults/memory/graph/graph-search.ts +12 -23
- package/src/plugins/defaults/memory/graph/narrative.ts +3 -5
- package/src/plugins/defaults/memory/graph/pattern-scan.ts +3 -5
- package/src/plugins/defaults/memory/graph/retriever.test.ts +1 -6
- package/src/plugins/defaults/memory/graph/retriever.ts +5 -10
- package/src/plugins/defaults/memory/graph/tools.ts +1 -1
- package/src/plugins/defaults/memory/hooks/init.ts +31 -5
- package/src/plugins/defaults/memory/indexer.ts +2 -3
- package/src/plugins/defaults/memory/injectors.ts +2 -2
- package/src/plugins/defaults/memory/job-handler-registration.ts +96 -0
- package/src/plugins/defaults/memory/job-handlers/backfill.ts +4 -26
- package/src/plugins/defaults/memory/job-handlers/embedding.test.ts +6 -19
- package/src/plugins/defaults/memory/job-handlers/embedding.ts +9 -22
- package/src/plugins/defaults/memory/job-handlers/index-maintenance.ts +2 -3
- package/src/plugins/defaults/memory/job-handlers.ts +13 -12
- package/src/plugins/defaults/memory/jobs/embed-concept-page.ts +1 -1
- package/src/plugins/defaults/memory/llm-helpers.ts +76 -0
- package/src/plugins/defaults/memory/memory-retrospective-job.ts +8 -5
- package/src/plugins/defaults/memory/memory-retrospective-startup-cleanup.ts +2 -2
- package/src/plugins/defaults/memory/memory-v2-concept-frequency.ts +2 -0
- package/src/plugins/defaults/memory/persistence-hooks.ts +46 -1
- package/src/plugins/defaults/memory/pkb/pkb-index.ts +1 -5
- package/src/plugins/defaults/memory/pkb/pkb-search.ts +2 -2
- package/src/plugins/defaults/memory/routes/__tests__/memory-v2-simulate-route.test.ts +4 -6
- package/src/plugins/defaults/memory/routes/memory-item-routes.ts +1 -1
- package/src/plugins/defaults/memory/search/semantic.ts +2 -2
- package/src/plugins/defaults/memory/startup.ts +244 -0
- package/src/plugins/defaults/memory/task-memory-cleanup.ts +8 -0
- package/src/{daemon → plugins/defaults/memory/v2}/__tests__/memory-v2-startup.test.ts +6 -6
- package/src/plugins/defaults/memory/v2/__tests__/migration.test.ts +2 -13
- package/src/plugins/defaults/memory/v2/__tests__/router.test.ts +4 -5
- package/src/plugins/defaults/memory/v2/__tests__/sweep-job.test.ts +1 -8
- package/src/plugins/defaults/memory/v2/activation.ts +2 -4
- package/src/plugins/defaults/memory/v2/cli-command-store.ts +2 -4
- package/src/plugins/defaults/memory/v2/frontmatter-sweep.ts +1 -1
- package/src/{daemon → plugins/defaults/memory/v2}/memory-v2-startup.test.ts +8 -8
- package/src/{daemon → plugins/defaults/memory/v2}/memory-v2-startup.ts +20 -22
- package/src/plugins/defaults/memory/v2/migration.ts +2 -5
- package/src/plugins/defaults/memory/v2/page-store.ts +1 -1
- package/src/plugins/defaults/memory/v2/qdrant.ts +2 -3
- package/src/plugins/defaults/memory/v2/router.ts +5 -5
- package/src/plugins/defaults/memory/v2/sim.ts +2 -4
- package/src/plugins/defaults/memory/v2/skill-store.ts +2 -4
- package/src/plugins/defaults/memory/v2/sweep-job.ts +6 -6
- package/src/plugins/defaults/memory/v3/__tests__/carry-integration.test.ts +11 -9
- package/src/plugins/defaults/memory/v3/__tests__/dense.test.ts +107 -2
- package/src/plugins/defaults/memory/v3/__tests__/gate-flag.test.ts +69 -0
- package/src/plugins/defaults/memory/v3/__tests__/gate.test.ts +181 -0
- package/src/plugins/defaults/memory/v3/__tests__/live-integration.test.ts +7 -3
- package/src/plugins/defaults/memory/v3/__tests__/orchestrate.test.ts +345 -8
- package/src/plugins/defaults/memory/v3/__tests__/pool-select.test.ts +1 -4
- package/src/plugins/defaults/memory/v3/__tests__/section-needle.test.ts +64 -0
- package/src/plugins/defaults/memory/v3/__tests__/shadow-integration.test.ts +18 -13
- package/src/plugins/defaults/memory/v3/__tests__/shadow-plugin.test.ts +62 -1
- package/src/plugins/defaults/memory/v3/card.ts +1 -4
- package/src/plugins/defaults/memory/v3/dense.ts +60 -25
- package/src/plugins/defaults/memory/v3/edge.ts +1 -1
- package/src/plugins/defaults/memory/v3/gate-flag.ts +20 -0
- package/src/plugins/defaults/memory/v3/gate.ts +158 -0
- package/src/plugins/defaults/memory/v3/maintain-job.ts +2 -4
- package/src/plugins/defaults/memory/v3/orchestrate.ts +186 -25
- package/src/plugins/defaults/memory/v3/pool-select.test.ts +7 -9
- package/src/plugins/defaults/memory/v3/pool-select.ts +6 -6
- package/src/plugins/defaults/memory/v3/prune.ts +2 -2
- package/src/plugins/defaults/memory/v3/section-dense-store.ts +8 -11
- package/src/plugins/defaults/memory/v3/section-needle.ts +27 -7
- package/src/plugins/defaults/memory/v3/shadow-plugin.ts +10 -0
- package/src/plugins/defaults/memory/v3-eval/eval-packets.ts +1 -4
- package/src/plugins/defaults/title-generate/hooks/user-prompt-submit.ts +5 -0
- package/src/plugins/defaults/turn-context/injectors.ts +1 -0
- package/src/plugins/defaults/turn-context/unified-turn-context.ts +12 -0
- package/src/plugins/injector-registry.ts +13 -2
- package/src/plugins/mtime-cache.ts +36 -47
- package/src/plugins/pipeline.ts +15 -1
- package/src/plugins/types.ts +14 -23
- package/src/prompts/__tests__/system-prompt.test.ts +170 -32
- package/src/prompts/persona-resolver.ts +13 -9
- package/src/prompts/system-prompt.ts +30 -9
- package/src/prompts/templates/BOOTSTRAP.md +16 -119
- package/src/prompts/templates/SOUL.md +43 -13
- package/src/prompts/templates/system-sections.ts +32 -27
- package/src/prompts/templates/users/default.md +19 -0
- package/src/providers/__tests__/placeholder-sentinels.test.ts +56 -0
- package/src/providers/inference/__tests__/base-url-route-validation.test.ts +96 -1
- package/src/providers/model-intents.ts +2 -2
- package/src/providers/openai/chat-completions-provider.ts +14 -1
- package/src/providers/openai/responses-provider.ts +18 -0
- package/src/providers/placeholder-sentinels.ts +18 -8
- package/src/providers/retry.ts +1 -0
- package/src/providers/speech-to-text/__tests__/provider-catalog.test.ts +0 -64
- package/src/providers/speech-to-text/__tests__/resolve.test.ts +92 -79
- package/src/providers/speech-to-text/deepgram-realtime.test.ts +98 -0
- package/src/providers/speech-to-text/deepgram-realtime.ts +62 -3
- package/src/providers/speech-to-text/provider-catalog.ts +0 -89
- package/src/providers/speech-to-text/resolve.ts +55 -0
- package/src/providers/tool-progress-events.test.ts +50 -0
- package/src/providers/tool-progress-events.ts +99 -0
- package/src/providers/types.ts +1 -1
- package/src/providers/vellum-model-routing.test.ts +51 -0
- package/src/providers/vellum-model-routing.ts +84 -0
- package/src/runtime/AGENTS.md +5 -4
- package/src/runtime/__tests__/agent-wake.test.ts +158 -1
- package/src/runtime/__tests__/channel-verification-service.test.ts +2 -2
- package/src/runtime/__tests__/trust-verdict-consumer.test.ts +37 -8
- package/src/runtime/access-request-helper.ts +154 -3
- package/src/runtime/actor-trust-resolver.ts +7 -21
- package/src/runtime/agent-wake.ts +41 -1
- package/src/runtime/assistant-event.ts +86 -12
- package/src/runtime/auth/__tests__/route-policy.test.ts +31 -0
- package/src/runtime/channel-approval-types.ts +52 -2
- package/src/runtime/channel-approvals.ts +23 -8
- package/src/runtime/channel-invite-transport.ts +2 -2
- package/src/runtime/channel-invite-transports/voice.ts +1 -1
- package/src/runtime/channel-readiness-service.ts +3 -5
- package/src/runtime/channel-retry-sweep.ts +18 -24
- package/src/runtime/channel-verification-service.ts +9 -11
- package/src/runtime/finalize-event-delivery.ts +30 -16
- package/src/runtime/guardian-action-service.ts +10 -11
- package/src/runtime/guardian-reply-router.ts +122 -21
- package/src/runtime/http-server.ts +44 -101
- package/src/runtime/introduction-policy.test.ts +214 -0
- package/src/runtime/introduction-policy.ts +284 -0
- package/src/runtime/invite-service.ts +104 -361
- package/src/runtime/local-actor-identity.test.ts +38 -0
- package/src/runtime/local-actor-identity.ts +14 -0
- package/src/runtime/middleware/__tests__/rate-limiter.test.ts +22 -0
- package/src/runtime/middleware/rate-limiter.ts +30 -0
- package/src/runtime/middleware/twilio-validation.ts +5 -7
- package/src/runtime/migrations/__tests__/gcs-signed-url.test.ts +28 -0
- package/src/runtime/migrations/origin-mode.ts +6 -6
- package/src/runtime/pre-first-message-gate.ts +1 -0
- package/src/runtime/routes/__tests__/channel-verification-revoke.test.ts +6 -35
- package/src/runtime/routes/__tests__/consolidation-routes.test.ts +24 -3
- package/src/runtime/routes/__tests__/contact-routes.test.ts +80 -15
- package/src/runtime/routes/__tests__/conversation-list-routes.test.ts +7 -1
- package/src/runtime/routes/__tests__/global-search-routes.test.ts +0 -3
- package/src/runtime/routes/__tests__/home-feed-routes.test.ts +142 -1
- package/src/runtime/routes/__tests__/invite-relay-routes.test.ts +119 -30
- package/src/runtime/routes/__tests__/migration-import-allowed-hosts-env.test.ts +70 -0
- package/src/runtime/routes/__tests__/monitoring-routes.test.ts +194 -0
- package/src/runtime/routes/__tests__/plugins-routes.test.ts +755 -29
- package/src/runtime/routes/__tests__/retrospective-routes.test.ts +4 -0
- package/src/runtime/routes/__tests__/schedule-routes-create.test.ts +70 -0
- package/src/runtime/routes/__tests__/schedule-worker-routes.test.ts +161 -0
- package/src/runtime/routes/__tests__/surface-action-routes.test.ts +1 -1
- package/src/runtime/routes/__tests__/surface-content-routes.test.ts +1 -1
- package/src/runtime/routes/acp-routes.ts +15 -3
- package/src/runtime/routes/app-management-routes.ts +4 -7
- package/src/runtime/routes/approval-routes.ts +4 -0
- package/src/runtime/routes/attachment-routes.ts +54 -3
- package/src/runtime/routes/avatar-routes.ts +0 -4
- package/src/runtime/routes/background-tool-routes.ts +34 -5
- package/src/runtime/routes/btw-routes.ts +32 -4
- package/src/runtime/routes/channel-route-shared.ts +18 -14
- package/src/runtime/routes/channel-verification-routes.ts +0 -3
- package/src/runtime/routes/contact-routes.ts +298 -117
- package/src/runtime/routes/conversation-list-routes.ts +6 -0
- package/src/runtime/routes/conversation-management-routes.ts +74 -37
- package/src/runtime/routes/conversation-query-routes.ts +5 -2
- package/src/runtime/routes/conversation-routes.ts +222 -82
- package/src/runtime/routes/conversations-import-routes.ts +8 -1
- package/src/runtime/routes/credential-prompt-routes.ts +20 -5
- package/src/runtime/routes/debug-routes.ts +1 -0
- package/src/runtime/routes/documents-routes.ts +5 -2
- package/src/runtime/routes/empty-state-greeting-cache.ts +37 -10
- package/src/runtime/routes/global-search-routes.ts +2 -1
- package/src/runtime/routes/guardian-approval-interception.ts +51 -0
- package/src/runtime/routes/home-feed-routes.ts +60 -1
- package/src/runtime/routes/identity-routes.ts +4 -87
- package/src/runtime/routes/inbound-message-handler.ts +82 -41
- package/src/runtime/routes/inbound-stages/acl-enforcement.test.ts +430 -57
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +302 -572
- package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +76 -270
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +21 -116
- package/src/runtime/routes/inbound-stages/edit-intercept.ts +9 -1
- package/src/runtime/routes/inbound-stages/escalation-intercept.test.ts +158 -0
- package/src/runtime/routes/inbound-stages/escalation-intercept.ts +22 -1
- package/src/runtime/routes/index.ts +6 -0
- package/src/runtime/routes/inference-provider-connection-routes.ts +22 -16
- package/src/runtime/routes/internal-twilio-routes.ts +0 -15
- package/src/runtime/routes/messages-lexical-routes.ts +75 -0
- package/src/runtime/routes/migration-routes.ts +69 -6
- package/src/runtime/routes/monitoring-routes.ts +237 -0
- package/src/runtime/routes/plugins-routes.ts +329 -8
- package/src/runtime/routes/schedule-routes.ts +49 -8
- package/src/runtime/routes/schedule-worker-routes.ts +210 -0
- package/src/runtime/routes/secret-routes.ts +1 -1
- package/src/runtime/routes/surface-conversation-resolver.ts +1 -0
- package/src/runtime/services/__tests__/analyze-conversation.test.ts +54 -9
- package/src/runtime/services/__tests__/auto-analysis-enqueue.test.ts +30 -6
- package/src/runtime/services/__tests__/conversation-analyze-job.test.ts +43 -8
- package/src/runtime/services/__tests__/conversation-serializer.test.ts +20 -0
- package/src/runtime/services/analyze-conversation.ts +14 -4
- package/src/runtime/services/conversation-serializer.ts +5 -0
- package/src/runtime/slack-no-response.ts +47 -0
- package/src/runtime/slack-reply-session.test.ts +633 -0
- package/src/runtime/slack-reply-session.ts +382 -0
- package/src/runtime/slack-task-progress.ts +95 -0
- package/src/runtime/sync/resource-sync-events.ts +25 -0
- package/src/runtime/tool-grant-request-helper.ts +17 -1
- package/src/runtime/trust-class.test.ts +141 -0
- package/src/runtime/trust-class.ts +121 -0
- package/src/runtime/trust-verdict-consumer.ts +7 -6
- package/src/schedule/__tests__/run-script.test.ts +21 -0
- package/src/schedule/__tests__/worker-control.test.ts +241 -0
- package/src/schedule/run-script.ts +13 -6
- package/src/schedule/schedule-usage-store.ts +1 -0
- package/src/schedule/scheduler.ts +178 -127
- package/src/schedule/worker-control.ts +118 -0
- package/src/schedule/worker.ts +131 -0
- package/src/skills/__tests__/categories-cache.test.ts +38 -0
- package/src/skills/categories-cache.ts +40 -5
- package/src/skills/managed-store.ts +41 -6
- package/src/skills/validate-input.ts +47 -0
- package/src/stt/types.ts +5 -9
- package/src/subagent/manager.ts +267 -39
- package/src/subagent/types.ts +6 -2
- package/src/subagent/validate-allowlists.ts +65 -0
- package/src/telemetry/watchdog-direct-emit.test.ts +109 -0
- package/src/telemetry/watchdog-direct-emit.ts +89 -0
- package/src/tools/acp/list-agents.test.ts +0 -6
- package/src/tools/background-tool-registry.ts +61 -0
- package/src/tools/document/document-comment-tool.test.ts +4 -0
- package/src/tools/host-terminal/host-shell.test.ts +397 -0
- package/src/tools/host-terminal/host-shell.ts +203 -14
- package/src/tools/skills/find-similar-skills.test.ts +152 -1
- package/src/tools/skills/find-similar-skills.ts +30 -4
- package/src/tools/skills/load.ts +36 -0
- package/src/tools/skills/scaffold-managed.ts +66 -34
- package/src/tools/skills/skill-script-runner.ts +17 -0
- package/src/tools/skills/skill-tool-factory.ts +5 -1
- package/src/tools/terminal/safe-env.ts +3 -0
- package/src/tools/terminal/shell.test.ts +177 -0
- package/src/tools/terminal/shell.ts +98 -4
- package/src/tools/tool-approval-handler.ts +106 -29
- package/{node_modules/@vellumai/skill-host-contracts/src → src/tools}/tool-types.ts +16 -17
- package/src/tools/types.ts +29 -17
- package/src/tools/ui-surface/definitions.ts +3 -1
- package/src/tts/__tests__/provider-adapters.test.ts +37 -0
- package/src/tts/__tests__/provider-catalog.test.ts +21 -0
- package/src/tts/provider-catalog.ts +40 -9
- package/src/tts/providers/fish-audio-provider.ts +19 -10
- package/src/tts/types.ts +3 -4
- package/src/util/__tests__/process-tree.test.ts +10 -2
- package/src/util/__tests__/text-spacing.test.ts +53 -0
- package/src/util/cgroup-memory.ts +142 -0
- package/src/util/image-conversion.ts +281 -0
- package/src/util/phone.ts +1 -8
- package/src/util/platform.ts +33 -0
- package/src/util/process-tree.ts +10 -2
- package/src/util/text-spacing.ts +53 -0
- package/src/util/worker-process.ts +271 -0
- package/src/workflows/journal-store.ts +16 -1
- package/src/workflows/library.test.ts +35 -20
- package/src/workflows/library.ts +105 -66
- package/src/workspace/git-service.ts +1 -0
- package/src/workspace/migrations/011-backfill-installation-id.ts +83 -31
- package/src/workspace/migrations/041-backfill-google-gmail-settings-scope.ts +41 -22
- package/src/workspace/migrations/070-memory-v2-summary-schema-rebuild.ts +1 -1
- package/src/workspace/migrations/118-seed-now-md.ts +64 -0
- package/src/workspace/migrations/119-strip-persisted-memory-v3-tuning-defaults.ts +169 -0
- package/src/workspace/migrations/120-revise-onboarding-threads.ts +47 -0
- package/src/workspace/migrations/121-seed-default-user-guardrails.ts +82 -0
- package/src/workspace/migrations/122-relocate-default-user-boundary.ts +111 -0
- package/src/workspace/migrations/123-swap-quality-profile-to-fable.ts +85 -0
- package/src/workspace/migrations/__tests__/119-strip-persisted-memory-v3-tuning-defaults.test.ts +181 -0
- package/src/workspace/migrations/registry.ts +12 -0
- package/drizzle/0000_dizzy_maggott.sql +0 -301
- package/drizzle/meta/0000_snapshot.json +0 -1933
- package/drizzle/meta/_journal.json +0 -13
- package/node_modules/@vellumai/skill-host-contracts/__tests__/client.test.ts +0 -887
- package/node_modules/@vellumai/skill-host-contracts/bun.lock +0 -24
- package/node_modules/@vellumai/skill-host-contracts/package.json +0 -18
- package/node_modules/@vellumai/skill-host-contracts/src/assistant-event.ts +0 -97
- package/node_modules/@vellumai/skill-host-contracts/src/client.ts +0 -1349
- package/node_modules/@vellumai/skill-host-contracts/src/index.ts +0 -6
- package/node_modules/@vellumai/skill-host-contracts/src/runtime-mode.ts +0 -11
- package/node_modules/@vellumai/skill-host-contracts/src/server-message.ts +0 -32
- package/node_modules/@vellumai/skill-host-contracts/src/skill-host.ts +0 -333
- package/node_modules/@vellumai/skill-host-contracts/tsconfig.json +0 -20
- package/node_modules/@vellumai/skill-host-contracts/tsconfig.test.json +0 -12
- package/src/__tests__/invite-redemption-service.test.ts +0 -1180
- package/src/__tests__/invite-service-ipc.test.ts +0 -350
- package/src/__tests__/job-handler-registry-guard.test.ts +0 -125
- package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +0 -203
- package/src/__tests__/relay-server.test.ts +0 -6153
- package/src/__tests__/telephony-stt-routing.test.ts +0 -329
- package/src/__tests__/voice-invite-redemption.test.ts +0 -702
- package/src/calls/relay-server.ts +0 -2463
- package/src/calls/telephony-stt-routing.ts +0 -145
- package/src/contacts/__tests__/contacts-write-revoke-relay.test.ts +0 -128
- package/src/daemon/__tests__/daemon-skill-host.test.ts +0 -273
- package/src/daemon/daemon-skill-host.ts +0 -262
- package/src/daemon/message-types/meet.ts +0 -143
- package/src/daemon/shutdown-registry.ts +0 -40
- package/src/ipc/__tests__/skill-server-bidirectional.test.ts +0 -253
- package/src/ipc/__tests__/skill-server.test.ts +0 -182
- package/src/ipc/skill-ipc-types.ts +0 -54
- package/src/ipc/skill-routes/__tests__/config.test.ts +0 -146
- package/src/ipc/skill-routes/__tests__/events-ipc.test.ts +0 -448
- package/src/ipc/skill-routes/__tests__/identity.test.ts +0 -62
- package/src/ipc/skill-routes/__tests__/log.test.ts +0 -133
- package/src/ipc/skill-routes/__tests__/memory.test.ts +0 -203
- package/src/ipc/skill-routes/__tests__/platform.test.ts +0 -111
- package/src/ipc/skill-routes/__tests__/providers.test.ts +0 -265
- package/src/ipc/skill-routes/__tests__/registries.test.ts +0 -400
- package/src/ipc/skill-routes/config.ts +0 -47
- package/src/ipc/skill-routes/events.ts +0 -147
- package/src/ipc/skill-routes/identity.ts +0 -21
- package/src/ipc/skill-routes/index.ts +0 -37
- package/src/ipc/skill-routes/log.ts +0 -40
- package/src/ipc/skill-routes/memory.ts +0 -92
- package/src/ipc/skill-routes/platform.ts +0 -39
- package/src/ipc/skill-routes/providers.ts +0 -162
- package/src/ipc/skill-routes/registries.ts +0 -338
- package/src/ipc/skill-server.ts +0 -831
- package/src/ipc/skill-socket-path.ts +0 -20
- package/src/jobs/register-job-handlers.ts +0 -74
- package/src/persistence/invite-store.ts +0 -481
- package/src/plugins/job-handler-registry.ts +0 -94
- package/src/providers/cache-control.ts +0 -26
- package/src/runtime/__tests__/runtime-mode.test.ts +0 -62
- package/src/runtime/invite-redemption-service.ts +0 -828
- package/src/runtime/invite-redemption-templates.ts +0 -46
- package/src/runtime/runtime-mode.ts +0 -40
- package/src/runtime/slack-dm-text-delivery.ts +0 -177
- package/src/util/voice-code.ts +0 -31
package/src/ipc/skill-server.ts
DELETED
|
@@ -1,831 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Skill IPC server — exposes daemon (host) capabilities to first-party skill
|
|
3
|
-
* processes over a Unix domain socket.
|
|
4
|
-
*
|
|
5
|
-
* Separate from the CLI IPC server so skill traffic (host.log, host.config.*,
|
|
6
|
-
* host.events.*, host.registries.*, etc.) stays off the CLI socket and can
|
|
7
|
-
* evolve its own long-lived subscribe streams.
|
|
8
|
-
*
|
|
9
|
-
* Protocol: newline-delimited JSON over a Unix domain socket.
|
|
10
|
-
*
|
|
11
|
-
* Bidirectional RPC: either side may initiate a request. Per-direction id
|
|
12
|
-
* namespacing prevents collisions:
|
|
13
|
-
* - Skill-initiated request ids start with `s:` (minted client-side).
|
|
14
|
-
* - Daemon-initiated request ids start with `d:` (minted server-side).
|
|
15
|
-
* Response frames echo the request id, so each side routes inbound responses
|
|
16
|
-
* to its own pending-request map by prefix.
|
|
17
|
-
*
|
|
18
|
-
* Skill→daemon one-shot RPC:
|
|
19
|
-
* - Request: { "id": "s:<n>", "method": string, "params"?: Record<string, unknown> }
|
|
20
|
-
* - Response: { "id": "s:<n>", "result"?: unknown, "error"?: string }
|
|
21
|
-
*
|
|
22
|
-
* Daemon→skill one-shot RPC:
|
|
23
|
-
* - Request: { "id": "d:<n>", "method": string, "params"?: unknown }
|
|
24
|
-
* - Response: { "id": "d:<n>", "result"?: unknown, "error"?: string }
|
|
25
|
-
*
|
|
26
|
-
* Streaming RPC (e.g. `host.events.subscribe`, skill-initiated only):
|
|
27
|
-
* - Request: { "id": "s:<n>", "method": string, "params"?: Record<string, unknown> }
|
|
28
|
-
* - Open ack: { "id": "s:<n>", "result": { "subscribed": true } }
|
|
29
|
-
* - Deliveries: { "id": "s:<n>", "event": "delivery", "payload": <data> } (0..N)
|
|
30
|
-
* - Error: { "id": "s:<n>", "error": string } (terminal)
|
|
31
|
-
* - Close req: { "id": "s:<n>", "method": "host.events.subscribe.close",
|
|
32
|
-
* "params": { "subscribeId": "<original-id>" } }
|
|
33
|
-
* - Close ack: { "id": "s:<n>", "result": { "closed": true } }
|
|
34
|
-
*
|
|
35
|
-
* The preferred socket path is `{workspaceDir}/assistant-skill.sock`. On
|
|
36
|
-
* platforms with strict AF_UNIX path limits (notably macOS), the server falls
|
|
37
|
-
* back to a shorter deterministic path via the shared socket-path resolver.
|
|
38
|
-
*/
|
|
39
|
-
|
|
40
|
-
import { existsSync, unlinkSync } from "node:fs";
|
|
41
|
-
import { createServer, type Server, type Socket } from "node:net";
|
|
42
|
-
|
|
43
|
-
import { ensureSocketDir, SocketWatchdog } from "@vellumai/ipc-server-utils";
|
|
44
|
-
|
|
45
|
-
import {
|
|
46
|
-
type SkillRouteHandle,
|
|
47
|
-
unregisterSkillRoute,
|
|
48
|
-
} from "../runtime/skill-route-registry.js";
|
|
49
|
-
import { unregisterSkillTools } from "../tools/registry.js";
|
|
50
|
-
import { getLogger } from "../util/logger.js";
|
|
51
|
-
import type { IpcRequest, IpcResponse } from "./assistant-server.js";
|
|
52
|
-
|
|
53
|
-
export type { SkillIpcRoute, SkillMethodHandler } from "./skill-ipc-types.js";
|
|
54
|
-
import type {
|
|
55
|
-
SkillIpcStream,
|
|
56
|
-
SkillIpcStreamingHandler,
|
|
57
|
-
SkillMethodHandler,
|
|
58
|
-
} from "./skill-ipc-types.js";
|
|
59
|
-
import {
|
|
60
|
-
skillIpcRoutes,
|
|
61
|
-
skillIpcStreamingRoutes,
|
|
62
|
-
} from "./skill-routes/index.js";
|
|
63
|
-
import { resolveSkillIpcSocketPath } from "./skill-socket-path.js";
|
|
64
|
-
import { ensureSocketPathFree } from "./socket-cleanup.js";
|
|
65
|
-
|
|
66
|
-
const log = getLogger("skill-ipc-server");
|
|
67
|
-
|
|
68
|
-
// ---------------------------------------------------------------------------
|
|
69
|
-
// Id namespacing
|
|
70
|
-
// ---------------------------------------------------------------------------
|
|
71
|
-
|
|
72
|
-
/** Prefix for ids minted by the daemon (server) side. */
|
|
73
|
-
export const SKILL_IPC_DAEMON_ID_PREFIX = "d:" as const;
|
|
74
|
-
|
|
75
|
-
/** Default per-call timeout for daemon-initiated requests. */
|
|
76
|
-
const DEFAULT_SEND_REQUEST_TIMEOUT_MS = 30_000;
|
|
77
|
-
|
|
78
|
-
// ---------------------------------------------------------------------------
|
|
79
|
-
// Streaming
|
|
80
|
-
// ---------------------------------------------------------------------------
|
|
81
|
-
|
|
82
|
-
/**
|
|
83
|
-
* Well-known control method the client sends to close an open stream. The
|
|
84
|
-
* server also tears down on socket close / daemon shutdown, so this is only
|
|
85
|
-
* needed when the client wants to keep the socket but end one subscription.
|
|
86
|
-
*/
|
|
87
|
-
const SKILL_IPC_SUBSCRIBE_CLOSE_METHOD = "host.events.subscribe.close" as const;
|
|
88
|
-
|
|
89
|
-
/** Stream handle passed to streaming-handler implementations. */
|
|
90
|
-
/**
|
|
91
|
-
* Maximum bytes Node may have queued in the socket's outbound buffer before
|
|
92
|
-
* the next streaming `send` will close the stream with a backpressure error.
|
|
93
|
-
* `socket.write()` returns `false` once the kernel buffer is full and Node
|
|
94
|
-
* starts queueing in user-space; without a cap, a slow or stalled subscriber
|
|
95
|
-
* would let that queue grow without bound and OOM the daemon. 1 MiB is large
|
|
96
|
-
* enough to absorb normal token-burst spikes but small enough to fail-fast
|
|
97
|
-
* on a genuinely stuck consumer.
|
|
98
|
-
*/
|
|
99
|
-
const STREAM_BACKPRESSURE_BYTES = 1024 * 1024;
|
|
100
|
-
|
|
101
|
-
// ---------------------------------------------------------------------------
|
|
102
|
-
// Per-connection context
|
|
103
|
-
// ---------------------------------------------------------------------------
|
|
104
|
-
|
|
105
|
-
/**
|
|
106
|
-
* Per-connection state threaded into skill-IPC method handlers as their
|
|
107
|
-
* second argument. Lets `host.registries.*` handlers attach route handles
|
|
108
|
-
* and skill-tool owner IDs to the live connection so the server can tear
|
|
109
|
-
* them down when the connection closes — without this, a skill process
|
|
110
|
-
* that disconnects (crash or reconnect) would leak its contributions into
|
|
111
|
-
* the daemon's in-memory registries.
|
|
112
|
-
*
|
|
113
|
-
* Mirrors the plugin-bootstrap pattern (`external-plugins-bootstrap.ts`),
|
|
114
|
-
* which retains the opaque {@link SkillRouteHandle} returned from
|
|
115
|
-
* `registerSkillRoute` and unregisters by identity during teardown.
|
|
116
|
-
*/
|
|
117
|
-
export interface SkillIpcConnection {
|
|
118
|
-
readonly connectionId: string;
|
|
119
|
-
/**
|
|
120
|
-
* Store a route handle under the given skill id so disconnect can
|
|
121
|
-
* revoke exactly the routes this connection contributed. Pattern-text
|
|
122
|
-
* is not a stable key — two owners may legitimately register the same
|
|
123
|
-
* regex.
|
|
124
|
-
*/
|
|
125
|
-
addRouteHandle(skillId: string, handle: SkillRouteHandle): void;
|
|
126
|
-
/**
|
|
127
|
-
* Record that this connection registered tools for `skillId`. The tool
|
|
128
|
-
* registry's `registerSkillTools` increments its internal refcount on
|
|
129
|
-
* every call, so each register_tools frame must be paired with exactly
|
|
130
|
-
* one `unregisterSkillTools` on disconnect — a deduplicated Set would
|
|
131
|
-
* leak the extra increments and pin stale proxies in the registry. On
|
|
132
|
-
* teardown the server calls `unregisterSkillTools(skillId)` once per
|
|
133
|
-
* recorded registration.
|
|
134
|
-
*/
|
|
135
|
-
addSkillToolsOwner(skillId: string): void;
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
/** Internal record for a daemon-initiated request awaiting a response. */
|
|
139
|
-
interface PendingDaemonRequest {
|
|
140
|
-
resolve: (value: unknown) => void;
|
|
141
|
-
reject: (err: Error) => void;
|
|
142
|
-
timer: ReturnType<typeof setTimeout>;
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
class SkillIpcConnectionState implements SkillIpcConnection {
|
|
146
|
-
readonly connectionId: string;
|
|
147
|
-
readonly socket: Socket;
|
|
148
|
-
private routeHandlesBySkill = new Map<string, SkillRouteHandle[]>();
|
|
149
|
-
/**
|
|
150
|
-
* Per-skill registration counts. `registerSkillTools` increments the
|
|
151
|
-
* tool-registry refcount on every call; storing a count (rather than a
|
|
152
|
-
* deduplicated Set) lets `dispose()` issue the matching number of
|
|
153
|
-
* `unregisterSkillTools` calls so a connection that registered tools in
|
|
154
|
-
* multiple batches doesn't leak refcount on disconnect.
|
|
155
|
-
*/
|
|
156
|
-
private skillToolOwnerCounts = new Map<string, number>();
|
|
157
|
-
/**
|
|
158
|
-
* Pending daemon-initiated requests keyed by `d:<n>` id. Cleared on
|
|
159
|
-
* connection teardown so callers never see a hung promise.
|
|
160
|
-
*/
|
|
161
|
-
readonly pendingDaemonRequests = new Map<string, PendingDaemonRequest>();
|
|
162
|
-
private nextRequestSeq = 1;
|
|
163
|
-
|
|
164
|
-
constructor(connectionId: string, socket: Socket) {
|
|
165
|
-
this.connectionId = connectionId;
|
|
166
|
-
this.socket = socket;
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
/** Allocate the next `d:<n>` id for a daemon-initiated request. */
|
|
170
|
-
nextDaemonRequestId(): string {
|
|
171
|
-
return `${SKILL_IPC_DAEMON_ID_PREFIX}${this.nextRequestSeq++}`;
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
addRouteHandle(skillId: string, handle: SkillRouteHandle): void {
|
|
175
|
-
const list = this.routeHandlesBySkill.get(skillId) ?? [];
|
|
176
|
-
list.push(handle);
|
|
177
|
-
this.routeHandlesBySkill.set(skillId, list);
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
addSkillToolsOwner(skillId: string): void {
|
|
181
|
-
this.skillToolOwnerCounts.set(
|
|
182
|
-
skillId,
|
|
183
|
-
(this.skillToolOwnerCounts.get(skillId) ?? 0) + 1,
|
|
184
|
-
);
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
dispose(): void {
|
|
188
|
-
for (const handles of this.routeHandlesBySkill.values()) {
|
|
189
|
-
for (const handle of handles) {
|
|
190
|
-
try {
|
|
191
|
-
unregisterSkillRoute(handle);
|
|
192
|
-
} catch (err) {
|
|
193
|
-
log.warn(
|
|
194
|
-
{ err, connectionId: this.connectionId },
|
|
195
|
-
"skill IPC disconnect: failed to unregister skill route",
|
|
196
|
-
);
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
this.routeHandlesBySkill.clear();
|
|
201
|
-
for (const [skillId, count] of this.skillToolOwnerCounts) {
|
|
202
|
-
for (let i = 0; i < count; i++) {
|
|
203
|
-
try {
|
|
204
|
-
unregisterSkillTools(skillId);
|
|
205
|
-
} catch (err) {
|
|
206
|
-
log.warn(
|
|
207
|
-
{ err, connectionId: this.connectionId, skillId },
|
|
208
|
-
"skill IPC disconnect: failed to unregister skill tools",
|
|
209
|
-
);
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
this.skillToolOwnerCounts.clear();
|
|
214
|
-
// Reject every in-flight daemon-initiated request so callers don't
|
|
215
|
-
// hang on a dropped peer. The socket's "close" listener fires before
|
|
216
|
-
// dispose() in the normal path, but defending here keeps behavior
|
|
217
|
-
// identical when teardown is invoked from the explicit `stop()` path.
|
|
218
|
-
if (this.pendingDaemonRequests.size > 0) {
|
|
219
|
-
const closeErr = new Error(
|
|
220
|
-
`SkillIpcServer: connection closed before response (connectionId=${this.connectionId})`,
|
|
221
|
-
);
|
|
222
|
-
for (const pending of this.pendingDaemonRequests.values()) {
|
|
223
|
-
clearTimeout(pending.timer);
|
|
224
|
-
pending.reject(closeErr);
|
|
225
|
-
}
|
|
226
|
-
this.pendingDaemonRequests.clear();
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
// ---------------------------------------------------------------------------
|
|
232
|
-
// Server
|
|
233
|
-
// ---------------------------------------------------------------------------
|
|
234
|
-
|
|
235
|
-
/** Optional configuration for {@link SkillIpcServer}. */
|
|
236
|
-
export interface SkillIpcServerOptions {
|
|
237
|
-
/**
|
|
238
|
-
* How often the socket-file watchdog stats the listening socket path.
|
|
239
|
-
* Set to `0` to disable. Defaults to {@link SocketWatchdog}'s 5000ms.
|
|
240
|
-
*/
|
|
241
|
-
watchdogIntervalMs?: number;
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
export class SkillIpcServer {
|
|
245
|
-
private server: Server | null = null;
|
|
246
|
-
private clients = new Set<Socket>();
|
|
247
|
-
private methods = new Map<string, SkillMethodHandler>();
|
|
248
|
-
private streamingMethods = new Map<string, SkillIpcStreamingHandler>();
|
|
249
|
-
/**
|
|
250
|
-
* Per-socket subscription registry. Keyed by the request id that opened
|
|
251
|
-
* the stream so the close-control message and socket-close teardown can
|
|
252
|
-
* locate the matching dispose callback.
|
|
253
|
-
*/
|
|
254
|
-
private subscriptions = new WeakMap<Socket, Map<string, () => void>>();
|
|
255
|
-
/**
|
|
256
|
-
* Per-socket connection state threaded into `host.registries.*` handlers.
|
|
257
|
-
* Holds route handles + skill-tool owner ids the connection contributed
|
|
258
|
-
* so `teardownConnection` can revoke them on disconnect.
|
|
259
|
-
*/
|
|
260
|
-
private connections = new WeakMap<Socket, SkillIpcConnectionState>();
|
|
261
|
-
private nextConnectionId = 1;
|
|
262
|
-
private socketPath: string;
|
|
263
|
-
private watchdog: SocketWatchdog;
|
|
264
|
-
/**
|
|
265
|
-
* Servers whose listener path has been replaced by a re-bind. Kept around
|
|
266
|
-
* so already-connected sockets continue to work; closed gracefully once
|
|
267
|
-
* their accept loops drain.
|
|
268
|
-
*/
|
|
269
|
-
private legacyServers = new Set<Server>();
|
|
270
|
-
|
|
271
|
-
constructor(options?: SkillIpcServerOptions) {
|
|
272
|
-
const resolution = resolveSkillIpcSocketPath();
|
|
273
|
-
this.socketPath = resolution.path;
|
|
274
|
-
log.info(
|
|
275
|
-
{ source: resolution.source, path: resolution.path },
|
|
276
|
-
"Skill IPC socket path resolved",
|
|
277
|
-
);
|
|
278
|
-
for (const route of skillIpcRoutes) {
|
|
279
|
-
this.methods.set(route.method, route.handler);
|
|
280
|
-
}
|
|
281
|
-
for (const route of skillIpcStreamingRoutes) {
|
|
282
|
-
this.streamingMethods.set(route.method, route.handler);
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
this.watchdog = new SocketWatchdog({
|
|
286
|
-
socketPath: this.socketPath,
|
|
287
|
-
intervalMs: options?.watchdogIntervalMs,
|
|
288
|
-
getServer: () => this.server,
|
|
289
|
-
createServer: () => this.createListeningServer(),
|
|
290
|
-
onRebind: (newServer, oldServer) => {
|
|
291
|
-
this.server = newServer;
|
|
292
|
-
this.legacyServers.add(oldServer);
|
|
293
|
-
oldServer.close(() => {
|
|
294
|
-
this.legacyServers.delete(oldServer);
|
|
295
|
-
});
|
|
296
|
-
},
|
|
297
|
-
log,
|
|
298
|
-
});
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
/** Register an additional method handler after construction. */
|
|
302
|
-
registerMethod(method: string, handler: SkillMethodHandler): void {
|
|
303
|
-
this.methods.set(method, handler);
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
/** Register an additional streaming handler after construction. */
|
|
307
|
-
registerStreamingMethod(
|
|
308
|
-
method: string,
|
|
309
|
-
handler: SkillIpcStreamingHandler,
|
|
310
|
-
): void {
|
|
311
|
-
this.streamingMethods.set(method, handler);
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
/**
|
|
315
|
-
* Send a request to the skill on the other side of `connection` and resolve
|
|
316
|
-
* with the matching response's `result` (or reject with its `error`).
|
|
317
|
-
*
|
|
318
|
-
* Daemon-initiated request ids are namespaced under the `d:` prefix so the
|
|
319
|
-
* skill can disambiguate them from its own `s:`-prefixed responses on the
|
|
320
|
-
* same socket. The pending entry is held on the per-connection state so a
|
|
321
|
-
* disconnect rejects every in-flight request without leaking timers.
|
|
322
|
-
*
|
|
323
|
-
* Throws synchronously if `connection` is unknown or its socket is already
|
|
324
|
-
* destroyed. Rejects asynchronously on:
|
|
325
|
-
* - skill-side error response (`{ id, error }`),
|
|
326
|
-
* - timeout (default 30s, override via `opts.timeoutMs`),
|
|
327
|
-
* - peer disconnect before a response arrives.
|
|
328
|
-
*/
|
|
329
|
-
sendRequest(
|
|
330
|
-
connection: SkillIpcConnection,
|
|
331
|
-
method: string,
|
|
332
|
-
params?: unknown,
|
|
333
|
-
opts?: { timeoutMs?: number },
|
|
334
|
-
): Promise<unknown> {
|
|
335
|
-
const state = connection as SkillIpcConnectionState;
|
|
336
|
-
if (!(state instanceof SkillIpcConnectionState)) {
|
|
337
|
-
return Promise.reject(
|
|
338
|
-
new Error(
|
|
339
|
-
"SkillIpcServer.sendRequest: connection must be a SkillIpcConnection produced by this server",
|
|
340
|
-
),
|
|
341
|
-
);
|
|
342
|
-
}
|
|
343
|
-
if (state.socket.destroyed) {
|
|
344
|
-
return Promise.reject(
|
|
345
|
-
new Error(
|
|
346
|
-
`SkillIpcServer.sendRequest: connection ${state.connectionId} socket is destroyed`,
|
|
347
|
-
),
|
|
348
|
-
);
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
const id = state.nextDaemonRequestId();
|
|
352
|
-
const timeoutMs = opts?.timeoutMs ?? DEFAULT_SEND_REQUEST_TIMEOUT_MS;
|
|
353
|
-
return new Promise<unknown>((resolve, reject) => {
|
|
354
|
-
const timer = setTimeout(() => {
|
|
355
|
-
if (state.pendingDaemonRequests.delete(id)) {
|
|
356
|
-
reject(
|
|
357
|
-
new Error(
|
|
358
|
-
`SkillIpcServer.sendRequest: '${method}' on ${state.connectionId} timed out after ${timeoutMs}ms`,
|
|
359
|
-
),
|
|
360
|
-
);
|
|
361
|
-
}
|
|
362
|
-
}, timeoutMs);
|
|
363
|
-
state.pendingDaemonRequests.set(id, { resolve, reject, timer });
|
|
364
|
-
try {
|
|
365
|
-
const frame: { id: string; method: string; params?: unknown } = {
|
|
366
|
-
id,
|
|
367
|
-
method,
|
|
368
|
-
};
|
|
369
|
-
if (params !== undefined) frame.params = params;
|
|
370
|
-
state.socket.write(JSON.stringify(frame) + "\n");
|
|
371
|
-
} catch (err) {
|
|
372
|
-
state.pendingDaemonRequests.delete(id);
|
|
373
|
-
clearTimeout(timer);
|
|
374
|
-
reject(err as Error);
|
|
375
|
-
}
|
|
376
|
-
});
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
/** Start listening on the Unix domain socket. */
|
|
380
|
-
async start(): Promise<void> {
|
|
381
|
-
// Ensure the parent directory exists before listening.
|
|
382
|
-
ensureSocketDir(this.socketPath);
|
|
383
|
-
|
|
384
|
-
// Probe before unlink so a second daemon can't silently orphan an active
|
|
385
|
-
// listener (Unix lets you unlink a still-bound socket file). See
|
|
386
|
-
// `ensureSocketPathFree` for the behavior matrix.
|
|
387
|
-
await ensureSocketPathFree(this.socketPath);
|
|
388
|
-
|
|
389
|
-
this.server = this.createListeningServer();
|
|
390
|
-
this.server.listen(this.socketPath, () => {
|
|
391
|
-
log.info({ path: this.socketPath }, "Skill IPC server listening");
|
|
392
|
-
});
|
|
393
|
-
|
|
394
|
-
this.watchdog.start();
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
/** Stop the server and disconnect all clients. */
|
|
398
|
-
stop(): void {
|
|
399
|
-
this.watchdog.stop();
|
|
400
|
-
|
|
401
|
-
for (const client of this.clients) {
|
|
402
|
-
this.teardownSubscriptions(client);
|
|
403
|
-
this.teardownConnection(client);
|
|
404
|
-
if (!client.destroyed) client.destroy();
|
|
405
|
-
}
|
|
406
|
-
this.clients.clear();
|
|
407
|
-
|
|
408
|
-
for (const legacy of this.legacyServers) {
|
|
409
|
-
legacy.close();
|
|
410
|
-
}
|
|
411
|
-
this.legacyServers.clear();
|
|
412
|
-
|
|
413
|
-
if (this.server) {
|
|
414
|
-
this.server.close();
|
|
415
|
-
this.server = null;
|
|
416
|
-
}
|
|
417
|
-
|
|
418
|
-
if (existsSync(this.socketPath)) {
|
|
419
|
-
try {
|
|
420
|
-
unlinkSync(this.socketPath);
|
|
421
|
-
} catch {
|
|
422
|
-
// Ignore
|
|
423
|
-
}
|
|
424
|
-
}
|
|
425
|
-
}
|
|
426
|
-
|
|
427
|
-
/** Get the socket path (for diagnostics). */
|
|
428
|
-
getSocketPath(): string {
|
|
429
|
-
return this.socketPath;
|
|
430
|
-
}
|
|
431
|
-
|
|
432
|
-
/**
|
|
433
|
-
* Re-bind the listening socket if its path entry is missing on disk.
|
|
434
|
-
*
|
|
435
|
-
* Public for tests so the watchdog can be exercised deterministically
|
|
436
|
-
* without waiting for the interval. Returns `true` when a re-bind was
|
|
437
|
-
* performed, `false` otherwise.
|
|
438
|
-
*/
|
|
439
|
-
async rebindIfMissing(): Promise<boolean> {
|
|
440
|
-
return this.watchdog.rebindIfMissing();
|
|
441
|
-
}
|
|
442
|
-
|
|
443
|
-
// ── Internal ──────────────────────────────────────────────────────────
|
|
444
|
-
|
|
445
|
-
private createListeningServer(): Server {
|
|
446
|
-
const server = createServer((socket) => {
|
|
447
|
-
this.clients.add(socket);
|
|
448
|
-
const connection = new SkillIpcConnectionState(
|
|
449
|
-
`skill-ipc-${this.nextConnectionId++}`,
|
|
450
|
-
socket,
|
|
451
|
-
);
|
|
452
|
-
this.connections.set(socket, connection);
|
|
453
|
-
log.debug(
|
|
454
|
-
{ connectionId: connection.connectionId },
|
|
455
|
-
"Skill IPC client connected",
|
|
456
|
-
);
|
|
457
|
-
|
|
458
|
-
let buffer = "";
|
|
459
|
-
|
|
460
|
-
socket.on("data", (chunk) => {
|
|
461
|
-
buffer += chunk.toString();
|
|
462
|
-
let newlineIdx: number;
|
|
463
|
-
while ((newlineIdx = buffer.indexOf("\n")) !== -1) {
|
|
464
|
-
const line = buffer.slice(0, newlineIdx).trim();
|
|
465
|
-
buffer = buffer.slice(newlineIdx + 1);
|
|
466
|
-
if (line) {
|
|
467
|
-
this.handleMessage(socket, line);
|
|
468
|
-
}
|
|
469
|
-
}
|
|
470
|
-
});
|
|
471
|
-
|
|
472
|
-
socket.on("close", () => {
|
|
473
|
-
this.clients.delete(socket);
|
|
474
|
-
this.teardownSubscriptions(socket);
|
|
475
|
-
this.teardownConnection(socket);
|
|
476
|
-
log.debug(
|
|
477
|
-
{ connectionId: connection.connectionId },
|
|
478
|
-
"Skill IPC client disconnected",
|
|
479
|
-
);
|
|
480
|
-
});
|
|
481
|
-
|
|
482
|
-
socket.on("error", (err) => {
|
|
483
|
-
log.warn(
|
|
484
|
-
{ err, connectionId: connection.connectionId },
|
|
485
|
-
"Skill IPC client socket error",
|
|
486
|
-
);
|
|
487
|
-
this.clients.delete(socket);
|
|
488
|
-
this.teardownSubscriptions(socket);
|
|
489
|
-
this.teardownConnection(socket);
|
|
490
|
-
});
|
|
491
|
-
});
|
|
492
|
-
|
|
493
|
-
server.on("error", (err) => {
|
|
494
|
-
log.error({ err }, "Skill IPC server error");
|
|
495
|
-
});
|
|
496
|
-
|
|
497
|
-
return server;
|
|
498
|
-
}
|
|
499
|
-
|
|
500
|
-
private handleMessage(socket: Socket, line: string): void {
|
|
501
|
-
let frame: IpcRequest & { result?: unknown; error?: string };
|
|
502
|
-
try {
|
|
503
|
-
frame = JSON.parse(line) as IpcRequest & {
|
|
504
|
-
result?: unknown;
|
|
505
|
-
error?: string;
|
|
506
|
-
};
|
|
507
|
-
} catch {
|
|
508
|
-
this.sendResponse(socket, {
|
|
509
|
-
id: "unknown",
|
|
510
|
-
error: "Invalid JSON",
|
|
511
|
-
});
|
|
512
|
-
return;
|
|
513
|
-
}
|
|
514
|
-
|
|
515
|
-
if (
|
|
516
|
-
!frame ||
|
|
517
|
-
typeof frame !== "object" ||
|
|
518
|
-
Array.isArray(frame) ||
|
|
519
|
-
typeof frame.id !== "string" ||
|
|
520
|
-
!frame.id
|
|
521
|
-
) {
|
|
522
|
-
const id =
|
|
523
|
-
frame &&
|
|
524
|
-
typeof frame === "object" &&
|
|
525
|
-
!Array.isArray(frame) &&
|
|
526
|
-
typeof frame.id === "string"
|
|
527
|
-
? frame.id
|
|
528
|
-
: "unknown";
|
|
529
|
-
this.sendResponse(socket, {
|
|
530
|
-
id,
|
|
531
|
-
error: "Missing 'id' or 'method' field",
|
|
532
|
-
});
|
|
533
|
-
return;
|
|
534
|
-
}
|
|
535
|
-
|
|
536
|
-
// Response frame for a daemon-initiated request — route to the
|
|
537
|
-
// pending-request map on the connection state instead of treating it
|
|
538
|
-
// as an inbound RPC. Identified by the `d:` id prefix and the
|
|
539
|
-
// absence of a `method` field.
|
|
540
|
-
if (
|
|
541
|
-
frame.method === undefined &&
|
|
542
|
-
frame.id.startsWith(SKILL_IPC_DAEMON_ID_PREFIX)
|
|
543
|
-
) {
|
|
544
|
-
this.handleDaemonResponse(socket, frame);
|
|
545
|
-
return;
|
|
546
|
-
}
|
|
547
|
-
|
|
548
|
-
if (!frame.method) {
|
|
549
|
-
this.sendResponse(socket, {
|
|
550
|
-
id: frame.id,
|
|
551
|
-
error: "Missing 'id' or 'method' field",
|
|
552
|
-
});
|
|
553
|
-
return;
|
|
554
|
-
}
|
|
555
|
-
|
|
556
|
-
const req = frame as IpcRequest;
|
|
557
|
-
|
|
558
|
-
// Reserve the daemon prefix for server-minted ids. A skill that sends
|
|
559
|
-
// a request whose id starts with `d:` would collide with daemon-side
|
|
560
|
-
// pending entries; reject it loudly so the bug surfaces early.
|
|
561
|
-
if (req.id.startsWith(SKILL_IPC_DAEMON_ID_PREFIX)) {
|
|
562
|
-
this.sendResponse(socket, {
|
|
563
|
-
id: req.id,
|
|
564
|
-
error: `Reserved id prefix '${SKILL_IPC_DAEMON_ID_PREFIX}': skill-initiated request ids must not collide with daemon-initiated ids`,
|
|
565
|
-
});
|
|
566
|
-
return;
|
|
567
|
-
}
|
|
568
|
-
|
|
569
|
-
// Subscribe-close is a built-in control message handled by the server.
|
|
570
|
-
if (req.method === SKILL_IPC_SUBSCRIBE_CLOSE_METHOD) {
|
|
571
|
-
this.handleSubscribeClose(socket, req);
|
|
572
|
-
return;
|
|
573
|
-
}
|
|
574
|
-
|
|
575
|
-
const streamingHandler = this.streamingMethods.get(req.method);
|
|
576
|
-
if (streamingHandler) {
|
|
577
|
-
this.handleStreamingRequest(socket, req, streamingHandler);
|
|
578
|
-
return;
|
|
579
|
-
}
|
|
580
|
-
|
|
581
|
-
const handler = this.methods.get(req.method);
|
|
582
|
-
if (!handler) {
|
|
583
|
-
this.sendResponse(socket, {
|
|
584
|
-
id: req.id,
|
|
585
|
-
error: `Unknown method: ${req.method}`,
|
|
586
|
-
});
|
|
587
|
-
return;
|
|
588
|
-
}
|
|
589
|
-
|
|
590
|
-
try {
|
|
591
|
-
const connection = this.connections.get(socket);
|
|
592
|
-
const result = handler(req.params, connection);
|
|
593
|
-
if (result instanceof Promise) {
|
|
594
|
-
result
|
|
595
|
-
.then((value) => {
|
|
596
|
-
this.sendResponse(socket, { id: req.id, result: value });
|
|
597
|
-
})
|
|
598
|
-
.catch((err) => {
|
|
599
|
-
log.warn({ err, method: req.method }, "Skill IPC handler error");
|
|
600
|
-
this.sendResponse(socket, {
|
|
601
|
-
id: req.id,
|
|
602
|
-
error: String(err),
|
|
603
|
-
});
|
|
604
|
-
});
|
|
605
|
-
} else {
|
|
606
|
-
this.sendResponse(socket, { id: req.id, result });
|
|
607
|
-
}
|
|
608
|
-
} catch (err) {
|
|
609
|
-
log.warn({ err, method: req.method }, "Skill IPC handler error");
|
|
610
|
-
this.sendResponse(socket, {
|
|
611
|
-
id: req.id,
|
|
612
|
-
error: String(err),
|
|
613
|
-
});
|
|
614
|
-
}
|
|
615
|
-
}
|
|
616
|
-
|
|
617
|
-
private handleStreamingRequest(
|
|
618
|
-
socket: Socket,
|
|
619
|
-
req: IpcRequest,
|
|
620
|
-
handler: SkillIpcStreamingHandler,
|
|
621
|
-
): void {
|
|
622
|
-
// Reject duplicate stream ids on the same socket so late deliveries
|
|
623
|
-
// on a zombie id never confuse the client's correlation table.
|
|
624
|
-
const existing = this.subscriptions.get(socket);
|
|
625
|
-
if (existing?.has(req.id)) {
|
|
626
|
-
this.sendResponse(socket, {
|
|
627
|
-
id: req.id,
|
|
628
|
-
error: `Stream id already active: ${req.id}`,
|
|
629
|
-
});
|
|
630
|
-
return;
|
|
631
|
-
}
|
|
632
|
-
|
|
633
|
-
let active = true;
|
|
634
|
-
let userDispose: (() => void) | null = null;
|
|
635
|
-
|
|
636
|
-
const close = (errorMessage?: string): void => {
|
|
637
|
-
if (!active) return;
|
|
638
|
-
active = false;
|
|
639
|
-
if (errorMessage && !socket.destroyed) {
|
|
640
|
-
try {
|
|
641
|
-
socket.write(
|
|
642
|
-
JSON.stringify({ id: req.id, error: errorMessage }) + "\n",
|
|
643
|
-
);
|
|
644
|
-
} catch (err) {
|
|
645
|
-
log.warn(
|
|
646
|
-
{ err, method: req.method },
|
|
647
|
-
"Skill IPC streaming close write error",
|
|
648
|
-
);
|
|
649
|
-
}
|
|
650
|
-
}
|
|
651
|
-
if (userDispose) {
|
|
652
|
-
try {
|
|
653
|
-
userDispose();
|
|
654
|
-
} catch (err) {
|
|
655
|
-
log.warn(
|
|
656
|
-
{ err, method: req.method },
|
|
657
|
-
"Skill IPC streaming dispose error",
|
|
658
|
-
);
|
|
659
|
-
}
|
|
660
|
-
}
|
|
661
|
-
this.subscriptions.get(socket)?.delete(req.id);
|
|
662
|
-
};
|
|
663
|
-
|
|
664
|
-
const stream: SkillIpcStream = {
|
|
665
|
-
id: req.id,
|
|
666
|
-
get active() {
|
|
667
|
-
return active;
|
|
668
|
-
},
|
|
669
|
-
send: (payload) => {
|
|
670
|
-
if (!active || socket.destroyed) return;
|
|
671
|
-
// Fail-fast on slow/stalled consumers: when Node has more than
|
|
672
|
-
// STREAM_BACKPRESSURE_BYTES queued in user-space, terminate the
|
|
673
|
-
// stream rather than letting the buffer grow unbounded. The
|
|
674
|
-
// client sees a terminal error frame and the hub subscription
|
|
675
|
-
// is disposed in the same call.
|
|
676
|
-
if (socket.writableLength > STREAM_BACKPRESSURE_BYTES) {
|
|
677
|
-
close(
|
|
678
|
-
`Stream ${req.id} closed: client not draining (socket buffer exceeded ${STREAM_BACKPRESSURE_BYTES} bytes)`,
|
|
679
|
-
);
|
|
680
|
-
return;
|
|
681
|
-
}
|
|
682
|
-
socket.write(
|
|
683
|
-
JSON.stringify({
|
|
684
|
-
id: req.id,
|
|
685
|
-
event: "delivery",
|
|
686
|
-
payload,
|
|
687
|
-
}) + "\n",
|
|
688
|
-
);
|
|
689
|
-
},
|
|
690
|
-
close,
|
|
691
|
-
};
|
|
692
|
-
|
|
693
|
-
try {
|
|
694
|
-
userDispose = handler(stream, req.params);
|
|
695
|
-
} catch (err) {
|
|
696
|
-
log.warn(
|
|
697
|
-
{ err, method: req.method },
|
|
698
|
-
"Skill IPC streaming handler error",
|
|
699
|
-
);
|
|
700
|
-
this.sendResponse(socket, { id: req.id, error: String(err) });
|
|
701
|
-
return;
|
|
702
|
-
}
|
|
703
|
-
|
|
704
|
-
const map = existing ?? new Map<string, () => void>();
|
|
705
|
-
if (!existing) this.subscriptions.set(socket, map);
|
|
706
|
-
map.set(req.id, () => close());
|
|
707
|
-
|
|
708
|
-
// Acknowledge the subscription open so the client can flip its
|
|
709
|
-
// correlation entry from "pending" to "streaming" before deliveries
|
|
710
|
-
// start arriving.
|
|
711
|
-
this.sendResponse(socket, {
|
|
712
|
-
id: req.id,
|
|
713
|
-
result: { subscribed: true },
|
|
714
|
-
});
|
|
715
|
-
}
|
|
716
|
-
|
|
717
|
-
private handleSubscribeClose(socket: Socket, req: IpcRequest): void {
|
|
718
|
-
const subscribeId =
|
|
719
|
-
req.params && typeof req.params.subscribeId === "string"
|
|
720
|
-
? req.params.subscribeId
|
|
721
|
-
: null;
|
|
722
|
-
if (!subscribeId) {
|
|
723
|
-
this.sendResponse(socket, {
|
|
724
|
-
id: req.id,
|
|
725
|
-
error: "Missing 'subscribeId' param",
|
|
726
|
-
});
|
|
727
|
-
return;
|
|
728
|
-
}
|
|
729
|
-
|
|
730
|
-
const map = this.subscriptions.get(socket);
|
|
731
|
-
const dispose = map?.get(subscribeId);
|
|
732
|
-
if (dispose) {
|
|
733
|
-
dispose();
|
|
734
|
-
map!.delete(subscribeId);
|
|
735
|
-
}
|
|
736
|
-
this.sendResponse(socket, {
|
|
737
|
-
id: req.id,
|
|
738
|
-
result: { closed: true },
|
|
739
|
-
});
|
|
740
|
-
}
|
|
741
|
-
|
|
742
|
-
private handleDaemonResponse(
|
|
743
|
-
socket: Socket,
|
|
744
|
-
frame: { id: string; result?: unknown; error?: string },
|
|
745
|
-
): void {
|
|
746
|
-
const connection = this.connections.get(socket);
|
|
747
|
-
if (!connection) return;
|
|
748
|
-
const pending = connection.pendingDaemonRequests.get(frame.id);
|
|
749
|
-
if (!pending) {
|
|
750
|
-
// Either a duplicate/late response or a frame for a request the
|
|
751
|
-
// server already timed out. Drop silently — it would have already
|
|
752
|
-
// settled the caller's promise.
|
|
753
|
-
return;
|
|
754
|
-
}
|
|
755
|
-
connection.pendingDaemonRequests.delete(frame.id);
|
|
756
|
-
clearTimeout(pending.timer);
|
|
757
|
-
if (frame.error !== undefined) {
|
|
758
|
-
pending.reject(new Error(String(frame.error)));
|
|
759
|
-
} else {
|
|
760
|
-
pending.resolve(frame.result);
|
|
761
|
-
}
|
|
762
|
-
}
|
|
763
|
-
|
|
764
|
-
private teardownConnection(socket: Socket): void {
|
|
765
|
-
const connection = this.connections.get(socket);
|
|
766
|
-
if (!connection) return;
|
|
767
|
-
connection.dispose();
|
|
768
|
-
this.connections.delete(socket);
|
|
769
|
-
}
|
|
770
|
-
|
|
771
|
-
private teardownSubscriptions(socket: Socket): void {
|
|
772
|
-
const map = this.subscriptions.get(socket);
|
|
773
|
-
if (!map) return;
|
|
774
|
-
for (const dispose of map.values()) {
|
|
775
|
-
try {
|
|
776
|
-
dispose();
|
|
777
|
-
} catch (err) {
|
|
778
|
-
log.warn({ err }, "Skill IPC teardown dispose error");
|
|
779
|
-
}
|
|
780
|
-
}
|
|
781
|
-
map.clear();
|
|
782
|
-
this.subscriptions.delete(socket);
|
|
783
|
-
}
|
|
784
|
-
|
|
785
|
-
private sendResponse(socket: Socket, response: IpcResponse): void {
|
|
786
|
-
if (!socket.destroyed) {
|
|
787
|
-
socket.write(JSON.stringify(response) + "\n");
|
|
788
|
-
}
|
|
789
|
-
}
|
|
790
|
-
}
|
|
791
|
-
|
|
792
|
-
// ── Process-level singleton ───────────────────────────────────────────────
|
|
793
|
-
|
|
794
|
-
let instance: SkillIpcServer | null = null;
|
|
795
|
-
|
|
796
|
-
/**
|
|
797
|
-
* Start the daemon's skill IPC server. First-party skill processes connect to
|
|
798
|
-
* this socket to access host capabilities (host.log, host.config.*,
|
|
799
|
-
* host.events.*, host.registries.*).
|
|
800
|
-
*
|
|
801
|
-
* Non-fatal: a failure to bind the socket is logged and startup continues with
|
|
802
|
-
* degraded skill-host connectivity. Returns the instance so callers can wire it
|
|
803
|
-
* into the meet-host supervisor's dispatch path.
|
|
804
|
-
*/
|
|
805
|
-
export async function startSkillIpcServer(): Promise<SkillIpcServer> {
|
|
806
|
-
instance = new SkillIpcServer();
|
|
807
|
-
try {
|
|
808
|
-
await instance.start();
|
|
809
|
-
} catch (err) {
|
|
810
|
-
log.warn(
|
|
811
|
-
{ err },
|
|
812
|
-
"Skill IPC server failed to start — continuing startup with degraded skill host connectivity",
|
|
813
|
-
);
|
|
814
|
-
}
|
|
815
|
-
return instance;
|
|
816
|
-
}
|
|
817
|
-
|
|
818
|
-
/**
|
|
819
|
-
* The live skill IPC server, or null before startup / after shutdown. Consumers
|
|
820
|
-
* that need to push frames to skill processes (e.g. the meet-host supervisor)
|
|
821
|
-
* read it here rather than receiving it via injection.
|
|
822
|
-
*/
|
|
823
|
-
export function getSkillIpcServer(): SkillIpcServer | null {
|
|
824
|
-
return instance;
|
|
825
|
-
}
|
|
826
|
-
|
|
827
|
-
/** Stop the skill IPC server during daemon shutdown. */
|
|
828
|
-
export function stopSkillIpcServer(): void {
|
|
829
|
-
instance?.stop();
|
|
830
|
-
instance = null;
|
|
831
|
-
}
|