@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.
Files changed (866) hide show
  1. package/ARCHITECTURE.md +94 -91
  2. package/Dockerfile +5 -16
  3. package/README.md +7 -10
  4. package/bun.lock +0 -4
  5. package/docs/architecture/security.md +20 -20
  6. package/docs/stt-provider-onboarding.md +4 -5
  7. package/docs/trusted-contact-access.md +7 -7
  8. package/eslint-rules/cli-no-daemon-internals.js +4 -0
  9. package/eslint.config.mjs +7 -1
  10. package/knip.json +0 -1
  11. package/node_modules/@vellumai/gateway-client/src/__tests__/contact-read-contracts.test.ts +36 -0
  12. package/node_modules/@vellumai/gateway-client/src/__tests__/invite-contract.test.ts +233 -0
  13. package/node_modules/@vellumai/gateway-client/src/__tests__/trust-verdict-contract.test.ts +40 -0
  14. package/node_modules/@vellumai/gateway-client/src/gateway-ipc-contracts.ts +20 -8
  15. package/node_modules/@vellumai/gateway-client/src/inbound-contract.ts +10 -0
  16. package/node_modules/@vellumai/gateway-client/src/index.ts +33 -0
  17. package/node_modules/@vellumai/gateway-client/src/invite-contract.ts +216 -0
  18. package/node_modules/@vellumai/gateway-client/src/outbound-contract.ts +91 -0
  19. package/node_modules/@vellumai/gateway-client/src/trust-verdict-contract.ts +39 -3
  20. package/node_modules/@vellumai/service-contracts/src/__tests__/ingress.test.ts +0 -8
  21. package/node_modules/@vellumai/service-contracts/src/__tests__/package-boundary.test.ts +1 -5
  22. package/node_modules/@vellumai/service-contracts/src/twilio-ingress.ts +3 -14
  23. package/openapi.yaml +1073 -225
  24. package/package.json +1 -4
  25. package/scripts/test.sh +35 -13
  26. package/src/__tests__/access-request-seed-content-blocks.test.ts +60 -4
  27. package/src/__tests__/acp-session.test.ts +4 -1
  28. package/src/__tests__/actor-trust-resolver-address-fallback.test.ts +0 -6
  29. package/src/__tests__/add-message-preassigned-id.test.ts +56 -0
  30. package/src/__tests__/agent-loop-set-system-prompt.test.ts +139 -0
  31. package/src/__tests__/app-conversation-ids-backfill.test.ts +3 -0
  32. package/src/__tests__/app-source-watcher.test.ts +11 -0
  33. package/src/__tests__/approval-interception-trust-gates.test.ts +148 -3
  34. package/src/__tests__/assistant-attachments.test.ts +62 -4
  35. package/src/__tests__/assistant-id-boundary-guard.test.ts +0 -1
  36. package/src/__tests__/attachments-store-heic-normalize.test.ts +230 -0
  37. package/src/__tests__/attachments-store.test.ts +3 -0
  38. package/src/__tests__/background-shell-bash.test.ts +34 -0
  39. package/src/__tests__/background-shell-host-bash.test.ts +12 -0
  40. package/src/__tests__/background-tool-registry.test.ts +97 -0
  41. package/src/__tests__/background-tool-routes.test.ts +72 -1
  42. package/src/__tests__/background-workers-disk-pressure.test.ts +2 -1
  43. package/src/__tests__/btw-routes.test.ts +57 -3
  44. package/src/__tests__/call-controller.test.ts +474 -84
  45. package/src/__tests__/call-domain.test.ts +48 -1
  46. package/src/__tests__/call-pointer-messages.test.ts +57 -19
  47. package/src/__tests__/call-pointer-no-hardcoded-copy.guard.test.ts +2 -6
  48. package/src/__tests__/call-routes-http.test.ts +15 -14
  49. package/src/__tests__/call-setup-flow-invite.test.ts +568 -0
  50. package/src/__tests__/call-setup-flow-midcall-trust.test.ts +231 -0
  51. package/src/__tests__/call-setup-flow-name-capture.test.ts +754 -0
  52. package/src/__tests__/call-setup-flow-verification.test.ts +925 -0
  53. package/src/__tests__/call-setup-flow.test.ts +311 -0
  54. package/src/__tests__/cancel-resolves-conversation-key.test.ts +0 -1
  55. package/src/__tests__/channel-guardian.test.ts +4 -7
  56. package/src/__tests__/channel-readiness-service.test.ts +0 -6
  57. package/src/__tests__/channel-readiness-slack-remote.test.ts +0 -4
  58. package/src/__tests__/channel-retry-sweep.test.ts +76 -64
  59. package/src/__tests__/channel-setup-panel-ack.test.ts +184 -0
  60. package/src/__tests__/clear-all-lexical.test.ts +90 -0
  61. package/src/__tests__/compactor-media-strip.test.ts +177 -0
  62. package/src/__tests__/config-loader-backfill.test.ts +5 -5
  63. package/src/__tests__/config-schema.test.ts +17 -0
  64. package/src/__tests__/contact-store-interaction-info.test.ts +27 -70
  65. package/src/__tests__/contacts-relay-reads.test.ts +188 -23
  66. package/src/__tests__/contacts-tools.test.ts +42 -1
  67. package/src/__tests__/contacts-write.test.ts +181 -0
  68. package/src/__tests__/context-search-conversations-source.test.ts +220 -81
  69. package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +1 -0
  70. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +1 -0
  71. package/src/__tests__/conversation-agent-loop-overflow.test.ts +1 -0
  72. package/src/__tests__/conversation-agent-loop.test.ts +39 -0
  73. package/src/__tests__/conversation-analysis-routes.test.ts +1 -1
  74. package/src/__tests__/conversation-app-control-instantiation.test.ts +2 -0
  75. package/src/__tests__/conversation-clear-safety.test.ts +0 -1
  76. package/src/__tests__/conversation-crud-enabled-plugins.test.ts +60 -0
  77. package/src/__tests__/conversation-delete-schedule-cleanup.test.ts +0 -1
  78. package/src/__tests__/conversation-disk-view.test.ts +1 -0
  79. package/src/__tests__/conversation-enabledplugins-route.test.ts +184 -0
  80. package/src/__tests__/conversation-error.test.ts +0 -18
  81. package/src/__tests__/conversation-fork-crud.test.ts +67 -0
  82. package/src/__tests__/conversation-history-web-search.test.ts +7 -137
  83. package/src/__tests__/conversation-initial-prompt.test.ts +110 -0
  84. package/src/__tests__/conversation-loop-db-lock-resilience.test.ts +191 -0
  85. package/src/__tests__/conversation-process-callsite.test.ts +37 -0
  86. package/src/__tests__/conversation-queue.test.ts +149 -0
  87. package/src/__tests__/conversation-routes-enabled-plugins.test.ts +392 -0
  88. package/src/__tests__/conversation-routes-guardian-reply.test.ts +84 -0
  89. package/src/__tests__/conversation-routes-hidden-queue.test.ts +407 -0
  90. package/src/__tests__/conversation-runtime-assembly.test.ts +36 -16
  91. package/src/__tests__/conversation-skill-tools.test.ts +73 -0
  92. package/src/__tests__/conversation-wipe.test.ts +20 -5
  93. package/src/__tests__/credential-prompt-route.test.ts +69 -0
  94. package/src/__tests__/credential-security-invariants.test.ts +1 -3
  95. package/src/__tests__/db-drop-messages-fts.test.ts +115 -0
  96. package/src/__tests__/deterministic-verification-control-plane.test.ts +1 -62
  97. package/src/__tests__/edit-propagation.test.ts +56 -2
  98. package/src/__tests__/empty-state-greeting-cache.test.ts +9 -0
  99. package/src/__tests__/gateway-only-enforcement.test.ts +15 -110
  100. package/src/__tests__/guardian-expiry-notifier.test.ts +1 -0
  101. package/src/__tests__/guardian-question-mode.test.ts +57 -0
  102. package/src/__tests__/guardian-verification-voice-binding.test.ts +1 -1
  103. package/src/__tests__/guardian-wait-controller.test.ts +619 -0
  104. package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +33 -2
  105. package/src/__tests__/heic-fixture.ts +55 -0
  106. package/src/__tests__/helpers/seed-contact-channel.ts +0 -2
  107. package/src/__tests__/http-conversation-lineage.test.ts +6 -1
  108. package/src/__tests__/image-conversion.test.ts +170 -0
  109. package/src/__tests__/inbound-invite-redemption.test.ts +72 -341
  110. package/src/__tests__/introduction-card-resolver.test.ts +354 -0
  111. package/src/__tests__/invite-redeemed-ipc.test.ts +97 -0
  112. package/src/__tests__/invite-routes-http.test.ts +246 -420
  113. package/src/__tests__/job-handler-registration-guard.test.ts +104 -0
  114. package/src/__tests__/lexical-index-dual-write.test.ts +426 -0
  115. package/src/__tests__/lifecycle-memory-v2-seed.test.ts +2 -2
  116. package/src/__tests__/list-messages-attachments.test.ts +159 -0
  117. package/src/__tests__/list-messages-background-tool-completion.test.ts +141 -0
  118. package/src/__tests__/list-messages-queued.test.ts +25 -0
  119. package/src/__tests__/managed-store.test.ts +129 -1
  120. package/src/__tests__/media-stream-audio-transcode.test.ts +113 -0
  121. package/src/__tests__/media-stream-output.test.ts +350 -19
  122. package/src/__tests__/media-stream-server-integration.test.ts +943 -169
  123. package/src/__tests__/media-stream-stt-session.test.ts +498 -1
  124. package/src/__tests__/memory-jobs-worker-lanes.test.ts +2 -2
  125. package/src/__tests__/model-intents.test.ts +1 -1
  126. package/src/__tests__/mtime-cache.test.ts +19 -0
  127. package/src/__tests__/non-member-access-request.test.ts +349 -3
  128. package/src/__tests__/notification-decision-fallback.test.ts +104 -8
  129. package/src/__tests__/notification-decision-strategy.test.ts +57 -8
  130. package/src/__tests__/onboarding-template-contract.test.ts +27 -43
  131. package/src/__tests__/openai-provider.test.ts +33 -0
  132. package/src/__tests__/openai-responses-provider.test.ts +40 -0
  133. package/src/__tests__/persistence-layering-guard.test.ts +29 -20
  134. package/src/__tests__/persona-resolver.test.ts +56 -2
  135. package/src/__tests__/personal-memory-auth-bypass.test.ts +62 -0
  136. package/src/__tests__/phone.test.ts +1 -15
  137. package/src/__tests__/plugin-bootstrap.test.ts +25 -196
  138. package/src/__tests__/plugin-disabled-state.test.ts +33 -0
  139. package/src/__tests__/plugin-effective-enabled-set.test.ts +227 -0
  140. package/src/__tests__/plugin-event-hub-facade.test.ts +323 -0
  141. package/src/__tests__/plugin-import-boundary-guard.test.ts +156 -42
  142. package/src/__tests__/plugin-injector-contribution.test.ts +4 -20
  143. package/src/__tests__/plugin-pipeline.test.ts +63 -1
  144. package/src/__tests__/plugin-route-contribution.test.ts +62 -115
  145. package/src/__tests__/plugin-tool-contribution.test.ts +0 -22
  146. package/src/__tests__/plugin-types.test.ts +0 -1
  147. package/src/__tests__/pointer-conversation-trust.test.ts +38 -6
  148. package/src/__tests__/pre-model-call-sanitize.test.ts +1 -1
  149. package/src/__tests__/prune-old-tool-invocations-job.test.ts +97 -0
  150. package/src/__tests__/public-ingress-urls.test.ts +0 -48
  151. package/src/__tests__/qdrant-collection-migration.test.ts +145 -2
  152. package/src/__tests__/reaction-intercept-member-verdict-warm.test.ts +0 -1
  153. package/src/__tests__/resolve-trust-class.test.ts +28 -10
  154. package/src/__tests__/scaffold-managed-skill-tool.test.ts +137 -0
  155. package/src/__tests__/schedule-retry.test.ts +38 -14
  156. package/src/__tests__/schedule-routes-workflow-validation.test.ts +3 -3
  157. package/src/__tests__/schedule-routes.test.ts +14 -6
  158. package/src/__tests__/schedule-store.test.ts +3 -1
  159. package/src/__tests__/scheduler-disk-pressure.test.ts +17 -6
  160. package/src/__tests__/scheduler-recurrence.test.ts +57 -107
  161. package/src/__tests__/scheduler-reuse-conversation.test.ts +51 -46
  162. package/src/__tests__/scheduler-wake.test.ts +13 -23
  163. package/src/__tests__/scheduler-worker-standdown.test.ts +220 -0
  164. package/src/__tests__/secret-routes-platform-proxy.test.ts +1 -1
  165. package/src/__tests__/shell-observability.test.ts +1 -0
  166. package/src/__tests__/skill-boundary-guard.test.ts +3 -4
  167. package/src/__tests__/skill-load-plugin-scope.test.ts +238 -0
  168. package/src/__tests__/skill-projection-feature-flag.test.ts +2 -0
  169. package/src/__tests__/skill-script-runner-host.test.ts +53 -0
  170. package/src/__tests__/skill-script-runner-sandbox.test.ts +5 -2
  171. package/src/__tests__/skill-tool-factory.test.ts +73 -1
  172. package/src/__tests__/slack-app-setup-skill-regression.test.ts +37 -14
  173. package/src/__tests__/slack-inbound-verification.test.ts +36 -0
  174. package/src/__tests__/slack-notification-approval-card.test.ts +89 -2
  175. package/src/__tests__/slack-reaction-canonical-approval.test.ts +51 -1
  176. package/src/__tests__/stt-hints.test.ts +2 -256
  177. package/src/__tests__/subagent-allowlist-validation.test.ts +47 -0
  178. package/src/__tests__/subagent-call-site-routing.test.ts +72 -0
  179. package/src/__tests__/subagent-fork-notifications.test.ts +14 -2
  180. package/src/__tests__/subagent-persistence.test.ts +122 -0
  181. package/src/__tests__/subagent-spawn-and-await.test.ts +1 -0
  182. package/src/__tests__/subagent-terminal-message.test.ts +99 -0
  183. package/src/__tests__/subagent-tool-gate-mode.test.ts +78 -1
  184. package/src/__tests__/system-prompt.test.ts +17 -118
  185. package/src/__tests__/task-scheduler.test.ts +68 -89
  186. package/src/__tests__/telephony-credential-preflight.test.ts +312 -0
  187. package/src/__tests__/telephony-tts-guard.test.ts +538 -0
  188. package/src/__tests__/title-generate-hook.test.ts +16 -0
  189. package/src/__tests__/tool-approval-handler.test.ts +87 -1
  190. package/src/__tests__/tool-approval-seed-content-blocks.test.ts +45 -20
  191. package/src/__tests__/tool-grant-request-escalation.test.ts +39 -0
  192. package/src/__tests__/trust-context-guards.test.ts +21 -10
  193. package/src/__tests__/trusted-contact-multichannel.test.ts +4 -0
  194. package/src/__tests__/twilio-provider.test.ts +17 -17
  195. package/src/__tests__/twilio-routes-twiml.test.ts +6 -543
  196. package/src/__tests__/twilio-routes.test.ts +257 -387
  197. package/src/__tests__/twilio-validation.test.ts +1 -1
  198. package/src/__tests__/unified-turn-context-client-os.test.ts +45 -0
  199. package/src/__tests__/usage-cache-backfill-migration.test.ts +5 -0
  200. package/src/__tests__/voice-approval-resolver-relay.test.ts +150 -0
  201. package/src/__tests__/voice-ingress-preflight.test.ts +61 -0
  202. package/src/__tests__/voice-quality.test.ts +2 -2
  203. package/src/__tests__/voice-scoped-grant-consumer.test.ts +1 -7
  204. package/src/__tests__/voice-session-bridge-processing-wait.test.ts +27 -0
  205. package/src/__tests__/voice-session-bridge.test.ts +1 -10
  206. package/src/__tests__/workspace-git-service.test.ts +1 -1
  207. package/src/__tests__/workspace-migration-013-repair-conversation-disk-view.test.ts +1 -0
  208. package/src/__tests__/workspace-migration-118-seed-now-md.test.ts +120 -0
  209. package/src/__tests__/workspace-migration-120-revise-onboarding-threads.test.ts +175 -0
  210. package/src/__tests__/workspace-migration-121-seed-default-user-guardrails.test.ts +118 -0
  211. package/src/__tests__/workspace-migration-122-relocate-default-user-boundary.test.ts +119 -0
  212. package/src/__tests__/workspace-migration-123-swap-quality-profile-to-fable.test.ts +191 -0
  213. package/src/__tests__/workspace-migration-backfill-installation-id.test.ts +235 -241
  214. package/src/acp/__tests__/prepare-agent-env.test.ts +0 -97
  215. package/src/acp/__tests__/session-manager-persistence.test.ts +2 -0
  216. package/src/acp/__tests__/session-manager-resume.test.ts +8 -0
  217. package/src/acp/__tests__/session-manager-usage.test.ts +6 -0
  218. package/src/acp/__tests__/session-manager.test.ts +6 -0
  219. package/src/acp/agent-process.test.ts +116 -0
  220. package/src/acp/agent-process.ts +71 -0
  221. package/src/acp/auto-install.ts +12 -8
  222. package/src/acp/failure-error.test.ts +109 -0
  223. package/src/acp/failure-error.ts +111 -0
  224. package/src/acp/prepare-agent-env.ts +0 -12
  225. package/src/acp/resolve-agent.test.ts +6 -45
  226. package/src/acp/resolve-agent.ts +2 -4
  227. package/src/acp/session-manager.test.ts +312 -0
  228. package/src/acp/session-manager.ts +102 -46
  229. package/src/agent/ax-tree-compaction.test.ts +4 -1
  230. package/src/agent/image-optimize.ts +17 -127
  231. package/src/agent/loop.ts +45 -192
  232. package/src/api/events/background-tool-completed.test.ts +51 -0
  233. package/src/api/events/background-tool-completed.ts +29 -0
  234. package/src/api/events/background-tool-started.test.ts +36 -0
  235. package/src/api/events/background-tool-started.ts +28 -0
  236. package/src/api/events/conversation-error.ts +0 -1
  237. package/src/api/events/open-panel.ts +33 -0
  238. package/src/api/events/subagent-status-changed.ts +4 -1
  239. package/src/api/index.ts +19 -0
  240. package/src/api/responses/conversation-message.ts +34 -0
  241. package/src/approvals/guardian-decision-primitive.ts +74 -24
  242. package/src/approvals/guardian-request-resolvers.ts +450 -122
  243. package/src/apps/app-store.ts +1 -0
  244. package/src/apps/shared-app-links-store.ts +1 -0
  245. package/src/avatar/identity-avatar.ts +3 -7
  246. package/src/background-wake/wake-intent-hooks.test.ts +1 -1
  247. package/src/calls/__tests__/fish-audio-client.test.ts +73 -0
  248. package/src/calls/__tests__/gateway-invite-reader.test.ts +170 -0
  249. package/src/calls/__tests__/relay-setup-router.test.ts +126 -102
  250. package/src/calls/call-controller.ts +134 -48
  251. package/src/calls/call-domain.ts +18 -42
  252. package/src/calls/call-pointer-messages.ts +51 -67
  253. package/src/calls/call-setup-flow-types.ts +76 -0
  254. package/src/calls/call-setup-flow.ts +1743 -0
  255. package/src/calls/call-speech-output.ts +87 -23
  256. package/src/calls/call-store.ts +4 -0
  257. package/src/calls/call-transport.ts +22 -36
  258. package/src/calls/fish-audio-client.ts +3 -0
  259. package/src/calls/gateway-invite-reader.ts +98 -0
  260. package/src/calls/guardian-wait-controller.ts +451 -0
  261. package/src/calls/media-stream-audio-transcode.ts +82 -2
  262. package/src/calls/media-stream-output.ts +142 -36
  263. package/src/calls/media-stream-server.ts +297 -178
  264. package/src/calls/media-stream-stt-session.ts +393 -50
  265. package/src/calls/media-turn-detector.ts +4 -6
  266. package/src/calls/relay-access-wait.ts +3 -4
  267. package/src/calls/relay-setup-router.ts +22 -43
  268. package/src/calls/relay-verification.ts +17 -24
  269. package/src/calls/resolve-call-tts-provider.ts +96 -29
  270. package/src/calls/stt-hints.ts +24 -87
  271. package/src/calls/telephony-credential-preflight.ts +159 -0
  272. package/src/calls/telephony-tts-capability.ts +183 -0
  273. package/src/calls/tts-call-strategy.ts +18 -20
  274. package/src/calls/twilio-provider.ts +3 -2
  275. package/src/calls/twilio-routes.ts +47 -351
  276. package/src/calls/types.ts +5 -3
  277. package/src/calls/voice-ingress-preflight.ts +9 -0
  278. package/src/calls/voice-quality.ts +13 -18
  279. package/src/calls/voice-session-bridge.ts +25 -35
  280. package/src/channels/__tests__/types.test.ts +28 -0
  281. package/src/channels/channel-verification-sessions.ts +7 -2
  282. package/src/channels/config.ts +0 -42
  283. package/src/channels/slack-thread-store.ts +12 -0
  284. package/src/channels/types.ts +23 -0
  285. package/src/cli/commands/__tests__/conversations-slack.test.ts +1 -1
  286. package/src/cli/commands/__tests__/schedules.test.ts +83 -34
  287. package/src/cli/commands/__tests__/status.test.ts +42 -2
  288. package/src/cli/commands/contacts.ts +2 -2
  289. package/src/cli/commands/credentials.ts +17 -0
  290. package/src/cli/commands/monitoring.ts +191 -0
  291. package/src/cli/commands/schedules-worker.ts +175 -0
  292. package/src/cli/commands/schedules.ts +169 -43
  293. package/src/cli/commands/status.ts +12 -1
  294. package/src/cli/commands/tools.ts +5 -1
  295. package/src/cli/lib/__tests__/plugin-catalog-cache.test.ts +1 -0
  296. package/src/cli/lib/__tests__/search-plugins.test.ts +29 -1
  297. package/src/cli/lib/__tests__/toggle-plugin.test.ts +7 -0
  298. package/src/cli/lib/search-plugins.ts +6 -0
  299. package/src/cli/lib/toggle-plugin.ts +21 -2
  300. package/src/cli/program.ts +3 -1
  301. package/src/config/__tests__/deployment-context-defaults.test.ts +23 -0
  302. package/src/config/acp-defaults.test.ts +0 -10
  303. package/src/config/acp-defaults.ts +0 -6
  304. package/src/config/bundled-skills/acp/SKILL.md +13 -45
  305. package/src/config/bundled-skills/acp/TOOLS.json +3 -3
  306. package/src/config/bundled-skills/app-builder/SKILL.md +3 -3
  307. package/src/config/bundled-skills/app-builder/references/RESPONSIVE.md +9 -9
  308. package/src/config/bundled-skills/contacts/tools/contact-merge.ts +1 -1
  309. package/src/config/bundled-skills/contacts/tools/contact-search.ts +1 -1
  310. package/src/config/bundled-skills/phone-calls/SKILL.md +1 -1
  311. package/src/config/bundled-skills/phone-calls/references/CONFIG.md +9 -9
  312. package/src/config/bundled-skills/phone-calls/references/TROUBLESHOOTING.md +10 -7
  313. package/src/config/bundled-skills/skill-management/TOOLS.json +10 -0
  314. package/src/config/call-site-defaults.ts +0 -2
  315. package/src/config/feature-flag-registry.json +16 -8
  316. package/src/config/loader.ts +11 -0
  317. package/src/config/schema.ts +9 -1
  318. package/src/config/schemas/__tests__/memory-v2.test.ts +2 -2
  319. package/src/config/schemas/__tests__/memory-v3.test.ts +64 -0
  320. package/src/config/schemas/call-site-catalog.ts +0 -12
  321. package/src/config/schemas/calls.ts +8 -0
  322. package/src/config/schemas/elevenlabs.ts +1 -1
  323. package/src/config/schemas/llm.ts +0 -2
  324. package/src/config/schemas/memory-v2.ts +1 -1
  325. package/src/config/schemas/memory-v3.ts +82 -0
  326. package/src/config/schemas/monitoring.ts +61 -0
  327. package/src/config/schemas/schedules.ts +35 -0
  328. package/src/config/seed-inference-profiles.ts +2 -2
  329. package/src/config/skills-plugin-filter.test.ts +96 -0
  330. package/src/config/skills.ts +26 -0
  331. package/src/contacts/__tests__/member-write-relay.test.ts +156 -4
  332. package/src/contacts/canonical-guardian-store.ts +5 -0
  333. package/src/contacts/contact-store.ts +81 -35
  334. package/src/contacts/contacts-write.ts +50 -25
  335. package/src/contacts/member-write-relay.ts +115 -31
  336. package/src/contacts/types.ts +0 -8
  337. package/src/context/compactor.ts +29 -15
  338. package/src/context/outbound-sanitize.ts +202 -0
  339. package/src/daemon/__tests__/abort-null-controller.test.ts +167 -0
  340. package/src/daemon/__tests__/conversation-tool-setup-plugin-scope.test.ts +122 -0
  341. package/src/daemon/__tests__/embedding-reconcile.test.ts +99 -16
  342. package/src/daemon/__tests__/wake-conversation-ops-completion.test.ts +107 -0
  343. package/src/daemon/abort-watchdog.ts +7 -0
  344. package/src/daemon/app-source-watcher.ts +9 -0
  345. package/src/daemon/assistant-attachments.ts +42 -0
  346. package/src/daemon/conversation-agent-loop-handlers.ts +256 -147
  347. package/src/daemon/conversation-agent-loop.ts +61 -68
  348. package/src/daemon/conversation-error.ts +1 -15
  349. package/src/daemon/conversation-history.ts +32 -236
  350. package/src/daemon/conversation-initial-prompt.ts +77 -0
  351. package/src/daemon/conversation-lifecycle.ts +25 -1
  352. package/src/daemon/conversation-messaging.ts +2 -2
  353. package/src/daemon/conversation-plugin-scope.ts +38 -0
  354. package/src/daemon/conversation-process.ts +50 -14
  355. package/src/daemon/conversation-runtime-assembly.ts +36 -6
  356. package/src/daemon/conversation-skill-tools.ts +19 -3
  357. package/src/daemon/conversation-store.ts +3 -3
  358. package/src/daemon/conversation-surfaces.ts +171 -0
  359. package/src/daemon/conversation-tool-setup.test.ts +95 -0
  360. package/src/daemon/conversation-tool-setup.ts +116 -1
  361. package/src/daemon/conversation-turn-finalize.ts +211 -0
  362. package/src/daemon/conversation.ts +92 -1
  363. package/src/daemon/disk-pressure-policy.ts +2 -1
  364. package/src/daemon/event-loop-watchdog.ts +22 -6
  365. package/src/daemon/external-plugins-bootstrap.ts +47 -134
  366. package/src/daemon/handlers/__tests__/config-a2a-accept.test.ts +1 -1
  367. package/src/daemon/handlers/__tests__/config-a2a-complete.test.ts +26 -14
  368. package/src/daemon/handlers/__tests__/config-a2a-invite.test.ts +27 -14
  369. package/src/daemon/handlers/__tests__/config-channels.test.ts +0 -5
  370. package/src/daemon/handlers/config-a2a.ts +7 -14
  371. package/src/daemon/handlers/config-channels.ts +2 -10
  372. package/src/daemon/handlers/conversation-history.ts +3 -1
  373. package/src/daemon/handlers/conversations.ts +0 -52
  374. package/src/daemon/handlers/shared.ts +4 -24
  375. package/src/daemon/handlers/skills.ts +4 -1
  376. package/src/daemon/host-cu-proxy.ts +1 -1
  377. package/src/daemon/lifecycle.ts +59 -472
  378. package/src/daemon/message-protocol.ts +3 -3
  379. package/src/daemon/message-provenance.ts +12 -14
  380. package/src/daemon/message-types/background-tools.ts +28 -0
  381. package/src/daemon/message-types/contacts.ts +2 -10
  382. package/src/daemon/message-types/conversations.ts +10 -0
  383. package/src/daemon/message-types/integrations.ts +2 -0
  384. package/src/daemon/message-types/surfaces.ts +1 -0
  385. package/src/daemon/message-types/sync.ts +1 -0
  386. package/src/daemon/pointer-conversation-trust.ts +23 -9
  387. package/src/daemon/pointer-turn-runner.ts +174 -0
  388. package/src/daemon/providers-setup.ts +16 -0
  389. package/src/daemon/shutdown-handlers.ts +139 -47
  390. package/src/daemon/skill-memory-refresh.ts +2 -2
  391. package/src/daemon/sqlite-corruption-watchdog.test.ts +217 -0
  392. package/src/daemon/sqlite-corruption-watchdog.ts +155 -0
  393. package/src/daemon/tool-setup-types.ts +8 -0
  394. package/src/daemon/trust-context.ts +21 -6
  395. package/src/daemon/turn-latency-tracker.test.ts +93 -0
  396. package/src/daemon/turn-latency-tracker.ts +38 -0
  397. package/src/daemon/wake-conversation-ops.ts +10 -8
  398. package/src/documents/document-comments-store.test.ts +7 -1
  399. package/src/documents/document-comments-store.ts +8 -0
  400. package/src/documents/document-store.ts +15 -0
  401. package/src/export/__tests__/transcript-formatter.test.ts +11 -0
  402. package/src/export/transcript-formatter.ts +49 -67
  403. package/src/home/__tests__/feed-writer.test.ts +247 -1
  404. package/src/home/conversation-starter-checkpoints.ts +1 -0
  405. package/src/home/feed-writer.ts +61 -0
  406. package/src/home/job-handlers/conversation-starters.ts +1 -0
  407. package/src/hooks/hook-loader.ts +12 -0
  408. package/src/hooks/registry.ts +32 -4
  409. package/src/inbound/public-ingress-urls.ts +0 -17
  410. package/src/ipc/__tests__/contacts-info-ipc.test.ts +285 -0
  411. package/src/ipc/assistant-server.ts +28 -7
  412. package/src/ipc/routes/__tests__/contacts-mirror-apply-atomicity.test.ts +62 -0
  413. package/src/ipc/routes/__tests__/contacts-mirror-apply.test.ts +272 -0
  414. package/src/ipc/routes/__tests__/contacts-mirror-ipc-routes.test.ts +322 -0
  415. package/src/ipc/routes/__tests__/invite-ipc-routes.test.ts +60 -4
  416. package/src/ipc/routes/contacts-info-ipc-routes.ts +239 -0
  417. package/src/ipc/routes/contacts-mirror-ipc-routes.ts +202 -0
  418. package/src/ipc/routes/db-proxy.ts +5 -2
  419. package/src/ipc/routes/invite-ipc-routes.ts +53 -39
  420. package/src/jobs/worker.ts +9 -2
  421. package/src/live-voice/__tests__/live-voice-archive.test.ts +10 -1
  422. package/src/live-voice/live-voice-archive.ts +5 -0
  423. package/src/messaging/providers/__tests__/transport-dispatch.test.ts +22 -6
  424. package/src/messaging/providers/channel-transport.ts +6 -0
  425. package/src/messaging/providers/index.ts +3 -0
  426. package/src/messaging/providers/slack/api.test.ts +49 -1
  427. package/src/messaging/providers/slack/api.ts +110 -0
  428. package/src/messaging/providers/slack/send.test.ts +85 -0
  429. package/src/messaging/providers/slack/send.ts +100 -28
  430. package/src/messaging/providers/slack/transport.ts +7 -13
  431. package/src/messaging/providers/whatsapp/send.ts +29 -9
  432. package/src/monitoring/__tests__/control.test.ts +235 -0
  433. package/src/monitoring/__tests__/sample-ring-buffer.test.ts +96 -0
  434. package/src/monitoring/control.ts +105 -0
  435. package/src/monitoring/resource-sampler.ts +258 -0
  436. package/src/monitoring/sample-ring-buffer.ts +108 -0
  437. package/src/monitoring/worker.ts +94 -0
  438. package/src/notifications/README.md +1 -1
  439. package/src/notifications/access-request-copy.ts +94 -23
  440. package/src/notifications/adapters/slack.ts +89 -21
  441. package/src/notifications/approval-card-builder.ts +33 -18
  442. package/src/notifications/approval-card-data.ts +48 -15
  443. package/src/notifications/broadcaster.ts +25 -16
  444. package/src/notifications/decision-engine.ts +131 -32
  445. package/src/notifications/guardian-question-mode.ts +58 -10
  446. package/src/permissions/approval-policy.ts +8 -1
  447. package/src/permissions/checker.ts +2 -0
  448. package/src/permissions/gateway-threshold-reader.ts +7 -6
  449. package/src/permissions/ipc-risk-types.ts +1 -0
  450. package/src/permissions/secret-prompter.ts +11 -3
  451. package/src/permissions/types.ts +2 -2
  452. package/src/persistence/__tests__/conversation-queries-search.test.ts +397 -0
  453. package/src/persistence/__tests__/conversation-search-lexical.test.ts +103 -0
  454. package/src/persistence/__tests__/jobs-worker-memory-disabled.test.ts +95 -0
  455. package/src/persistence/__tests__/slow-query-log.test.ts +266 -0
  456. package/src/persistence/__tests__/slow-sync-log.test.ts +155 -0
  457. package/src/persistence/a2a-invite-store.ts +205 -0
  458. package/src/persistence/attachments-store.ts +94 -10
  459. package/src/persistence/checkpoints.ts +45 -0
  460. package/src/persistence/conversation-crud.ts +453 -260
  461. package/src/persistence/conversation-display-order-migration.ts +8 -2
  462. package/src/persistence/conversation-group-migration.test.ts +8 -0
  463. package/src/persistence/conversation-group-migration.ts +9 -0
  464. package/src/persistence/conversation-queries.ts +244 -125
  465. package/src/persistence/conversation-row-batch-delete.ts +9 -5
  466. package/src/persistence/conversation-search-lexical.ts +49 -0
  467. package/src/persistence/db-async-query.ts +42 -0
  468. package/src/persistence/db-connection.ts +13 -0
  469. package/src/persistence/delivery-channels.ts +0 -82
  470. package/src/persistence/delivery-crud.ts +27 -6
  471. package/src/persistence/embeddings/__tests__/embedding-identity.test.ts +18 -5
  472. package/src/persistence/embeddings/__tests__/messages-lexical-index.test.ts +334 -0
  473. package/src/persistence/embeddings/embedding-identity.ts +17 -5
  474. package/src/persistence/embeddings/embedding-runtime-manager.ts +31 -0
  475. package/src/persistence/embeddings/messages-lexical-index.ts +396 -0
  476. package/src/persistence/embeddings/qdrant-client.ts +81 -5
  477. package/src/persistence/group-crud.ts +13 -1
  478. package/src/persistence/job-handlers/__tests__/message-lexical-backfill.test.ts +506 -0
  479. package/src/persistence/job-handlers/__tests__/message-lexical-enqueue.test.ts +164 -0
  480. package/src/persistence/job-handlers/__tests__/message-lexical.test.ts +259 -0
  481. package/src/persistence/job-handlers/cleanup.ts +57 -9
  482. package/src/persistence/job-handlers/message-lexical-backfill.ts +187 -0
  483. package/src/persistence/job-handlers/message-lexical.ts +251 -0
  484. package/src/persistence/jobs-store.ts +102 -8
  485. package/src/persistence/jobs-worker.ts +68 -28
  486. package/src/persistence/llm-request-log-store.ts +35 -19
  487. package/src/persistence/llm-usage-store.ts +11 -0
  488. package/src/persistence/memory-lifecycle-hooks.test.ts +65 -0
  489. package/src/persistence/memory-lifecycle-hooks.ts +55 -1
  490. package/src/persistence/migrations/028-call-session-mode.ts +1 -1
  491. package/src/persistence/migrations/116-messages-fts.ts +8 -1
  492. package/src/persistence/migrations/311-create-subagents-table.ts +50 -0
  493. package/src/persistence/migrations/312-drop-inbox-conversation-state-table.ts +15 -0
  494. package/src/persistence/migrations/313-drop-messages-fts.ts +17 -0
  495. package/src/persistence/migrations/314-add-conversation-enabled-plugins.ts +25 -0
  496. package/src/persistence/migrations/315-create-a2a-invites.ts +58 -0
  497. package/src/persistence/migrations/316-drop-contact-channels-invite-id.ts +28 -0
  498. package/src/persistence/migrations/317-canonical-guardian-requester-signals.ts +24 -0
  499. package/src/persistence/migrations/318-drop-contact-channel-telemetry.ts +32 -0
  500. package/src/persistence/migrations/__tests__/315-create-a2a-invites.test.ts +161 -0
  501. package/src/persistence/migrations/__tests__/316-drop-contact-channels-invite-id.test.ts +156 -0
  502. package/src/persistence/migrations/__tests__/318-drop-contact-channel-telemetry.test.ts +134 -0
  503. package/src/persistence/migrations/__tests__/migration-prefix-guard.test.ts +99 -0
  504. package/src/persistence/raw-query.ts +50 -11
  505. package/src/persistence/schema/a2a.ts +14 -0
  506. package/src/persistence/schema/contacts.ts +0 -62
  507. package/src/persistence/schema/conversation-groups.ts +12 -0
  508. package/src/persistence/schema/conversations.ts +2 -0
  509. package/src/persistence/schema/documents.ts +65 -0
  510. package/src/persistence/schema/guardian.ts +4 -0
  511. package/src/persistence/schema/index.ts +4 -0
  512. package/src/persistence/schema/memory-injection.ts +62 -0
  513. package/src/persistence/schema/workflows.ts +55 -0
  514. package/src/persistence/slow-query-log.ts +437 -0
  515. package/src/persistence/slow-sync-log.ts +204 -0
  516. package/src/persistence/steps.ts +16 -0
  517. package/src/persistence/subagent-store.ts +125 -0
  518. package/src/persistence/worker-control.ts +45 -238
  519. package/src/plugin-api/event-hub-facade.ts +172 -0
  520. package/src/plugin-api/index.ts +9 -1
  521. package/src/plugin-api/types.ts +40 -9
  522. package/src/plugins/defaults/default-plugin-names.ts +60 -0
  523. package/src/plugins/defaults/index.ts +19 -29
  524. package/src/plugins/defaults/memory/__tests__/conversation-queries.test.ts +46 -67
  525. package/src/plugins/defaults/memory/__tests__/db-async-query.test.ts +36 -1
  526. package/src/plugins/defaults/memory/__tests__/find-most-recent-retrospective-for.test.ts +2 -4
  527. package/src/plugins/defaults/memory/__tests__/jobs-worker-v2-graph-trigger-embed.test.ts +2 -2
  528. package/src/plugins/defaults/memory/__tests__/jobs-worker-v2-schedule.test.ts +9 -0
  529. package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +7 -4
  530. package/src/plugins/defaults/memory/config.ts +11 -0
  531. package/src/plugins/defaults/memory/context-search/agent-runner.ts +1 -1
  532. package/src/plugins/defaults/memory/context-search/sources/conversations.ts +124 -113
  533. package/src/plugins/defaults/memory/embeddings.ts +77 -0
  534. package/src/plugins/defaults/memory/find-most-recent-retrospective-for.ts +66 -0
  535. package/src/plugins/defaults/memory/frontmatter.ts +50 -0
  536. package/src/plugins/defaults/memory/graph/bootstrap.test.ts +36 -10
  537. package/src/plugins/defaults/memory/graph/bootstrap.ts +6 -5
  538. package/src/plugins/defaults/memory/graph/consolidation.ts +3 -5
  539. package/src/plugins/defaults/memory/graph/extraction.ts +3 -6
  540. package/src/plugins/defaults/memory/graph/graph-search.ts +12 -23
  541. package/src/plugins/defaults/memory/graph/narrative.ts +3 -5
  542. package/src/plugins/defaults/memory/graph/pattern-scan.ts +3 -5
  543. package/src/plugins/defaults/memory/graph/retriever.test.ts +1 -6
  544. package/src/plugins/defaults/memory/graph/retriever.ts +5 -10
  545. package/src/plugins/defaults/memory/graph/tools.ts +1 -1
  546. package/src/plugins/defaults/memory/hooks/init.ts +31 -5
  547. package/src/plugins/defaults/memory/indexer.ts +2 -3
  548. package/src/plugins/defaults/memory/injectors.ts +2 -2
  549. package/src/plugins/defaults/memory/job-handler-registration.ts +96 -0
  550. package/src/plugins/defaults/memory/job-handlers/backfill.ts +4 -26
  551. package/src/plugins/defaults/memory/job-handlers/embedding.test.ts +6 -19
  552. package/src/plugins/defaults/memory/job-handlers/embedding.ts +9 -22
  553. package/src/plugins/defaults/memory/job-handlers/index-maintenance.ts +2 -3
  554. package/src/plugins/defaults/memory/job-handlers.ts +13 -12
  555. package/src/plugins/defaults/memory/jobs/embed-concept-page.ts +1 -1
  556. package/src/plugins/defaults/memory/llm-helpers.ts +76 -0
  557. package/src/plugins/defaults/memory/memory-retrospective-job.ts +8 -5
  558. package/src/plugins/defaults/memory/memory-retrospective-startup-cleanup.ts +2 -2
  559. package/src/plugins/defaults/memory/memory-v2-concept-frequency.ts +2 -0
  560. package/src/plugins/defaults/memory/persistence-hooks.ts +46 -1
  561. package/src/plugins/defaults/memory/pkb/pkb-index.ts +1 -5
  562. package/src/plugins/defaults/memory/pkb/pkb-search.ts +2 -2
  563. package/src/plugins/defaults/memory/routes/__tests__/memory-v2-simulate-route.test.ts +4 -6
  564. package/src/plugins/defaults/memory/routes/memory-item-routes.ts +1 -1
  565. package/src/plugins/defaults/memory/search/semantic.ts +2 -2
  566. package/src/plugins/defaults/memory/startup.ts +244 -0
  567. package/src/plugins/defaults/memory/task-memory-cleanup.ts +8 -0
  568. package/src/{daemon → plugins/defaults/memory/v2}/__tests__/memory-v2-startup.test.ts +6 -6
  569. package/src/plugins/defaults/memory/v2/__tests__/migration.test.ts +2 -13
  570. package/src/plugins/defaults/memory/v2/__tests__/router.test.ts +4 -5
  571. package/src/plugins/defaults/memory/v2/__tests__/sweep-job.test.ts +1 -8
  572. package/src/plugins/defaults/memory/v2/activation.ts +2 -4
  573. package/src/plugins/defaults/memory/v2/cli-command-store.ts +2 -4
  574. package/src/plugins/defaults/memory/v2/frontmatter-sweep.ts +1 -1
  575. package/src/{daemon → plugins/defaults/memory/v2}/memory-v2-startup.test.ts +8 -8
  576. package/src/{daemon → plugins/defaults/memory/v2}/memory-v2-startup.ts +20 -22
  577. package/src/plugins/defaults/memory/v2/migration.ts +2 -5
  578. package/src/plugins/defaults/memory/v2/page-store.ts +1 -1
  579. package/src/plugins/defaults/memory/v2/qdrant.ts +2 -3
  580. package/src/plugins/defaults/memory/v2/router.ts +5 -5
  581. package/src/plugins/defaults/memory/v2/sim.ts +2 -4
  582. package/src/plugins/defaults/memory/v2/skill-store.ts +2 -4
  583. package/src/plugins/defaults/memory/v2/sweep-job.ts +6 -6
  584. package/src/plugins/defaults/memory/v3/__tests__/carry-integration.test.ts +11 -9
  585. package/src/plugins/defaults/memory/v3/__tests__/dense.test.ts +107 -2
  586. package/src/plugins/defaults/memory/v3/__tests__/gate-flag.test.ts +69 -0
  587. package/src/plugins/defaults/memory/v3/__tests__/gate.test.ts +181 -0
  588. package/src/plugins/defaults/memory/v3/__tests__/live-integration.test.ts +7 -3
  589. package/src/plugins/defaults/memory/v3/__tests__/orchestrate.test.ts +345 -8
  590. package/src/plugins/defaults/memory/v3/__tests__/pool-select.test.ts +1 -4
  591. package/src/plugins/defaults/memory/v3/__tests__/section-needle.test.ts +64 -0
  592. package/src/plugins/defaults/memory/v3/__tests__/shadow-integration.test.ts +18 -13
  593. package/src/plugins/defaults/memory/v3/__tests__/shadow-plugin.test.ts +62 -1
  594. package/src/plugins/defaults/memory/v3/card.ts +1 -4
  595. package/src/plugins/defaults/memory/v3/dense.ts +60 -25
  596. package/src/plugins/defaults/memory/v3/edge.ts +1 -1
  597. package/src/plugins/defaults/memory/v3/gate-flag.ts +20 -0
  598. package/src/plugins/defaults/memory/v3/gate.ts +158 -0
  599. package/src/plugins/defaults/memory/v3/maintain-job.ts +2 -4
  600. package/src/plugins/defaults/memory/v3/orchestrate.ts +186 -25
  601. package/src/plugins/defaults/memory/v3/pool-select.test.ts +7 -9
  602. package/src/plugins/defaults/memory/v3/pool-select.ts +6 -6
  603. package/src/plugins/defaults/memory/v3/prune.ts +2 -2
  604. package/src/plugins/defaults/memory/v3/section-dense-store.ts +8 -11
  605. package/src/plugins/defaults/memory/v3/section-needle.ts +27 -7
  606. package/src/plugins/defaults/memory/v3/shadow-plugin.ts +10 -0
  607. package/src/plugins/defaults/memory/v3-eval/eval-packets.ts +1 -4
  608. package/src/plugins/defaults/title-generate/hooks/user-prompt-submit.ts +5 -0
  609. package/src/plugins/defaults/turn-context/injectors.ts +1 -0
  610. package/src/plugins/defaults/turn-context/unified-turn-context.ts +12 -0
  611. package/src/plugins/injector-registry.ts +13 -2
  612. package/src/plugins/mtime-cache.ts +36 -47
  613. package/src/plugins/pipeline.ts +15 -1
  614. package/src/plugins/types.ts +14 -23
  615. package/src/prompts/__tests__/system-prompt.test.ts +170 -32
  616. package/src/prompts/persona-resolver.ts +13 -9
  617. package/src/prompts/system-prompt.ts +30 -9
  618. package/src/prompts/templates/BOOTSTRAP.md +16 -119
  619. package/src/prompts/templates/SOUL.md +43 -13
  620. package/src/prompts/templates/system-sections.ts +32 -27
  621. package/src/prompts/templates/users/default.md +19 -0
  622. package/src/providers/__tests__/placeholder-sentinels.test.ts +56 -0
  623. package/src/providers/inference/__tests__/base-url-route-validation.test.ts +96 -1
  624. package/src/providers/model-intents.ts +2 -2
  625. package/src/providers/openai/chat-completions-provider.ts +14 -1
  626. package/src/providers/openai/responses-provider.ts +18 -0
  627. package/src/providers/placeholder-sentinels.ts +18 -8
  628. package/src/providers/retry.ts +1 -0
  629. package/src/providers/speech-to-text/__tests__/provider-catalog.test.ts +0 -64
  630. package/src/providers/speech-to-text/__tests__/resolve.test.ts +92 -79
  631. package/src/providers/speech-to-text/deepgram-realtime.test.ts +98 -0
  632. package/src/providers/speech-to-text/deepgram-realtime.ts +62 -3
  633. package/src/providers/speech-to-text/provider-catalog.ts +0 -89
  634. package/src/providers/speech-to-text/resolve.ts +55 -0
  635. package/src/providers/tool-progress-events.test.ts +50 -0
  636. package/src/providers/tool-progress-events.ts +99 -0
  637. package/src/providers/types.ts +1 -1
  638. package/src/providers/vellum-model-routing.test.ts +51 -0
  639. package/src/providers/vellum-model-routing.ts +84 -0
  640. package/src/runtime/AGENTS.md +5 -4
  641. package/src/runtime/__tests__/agent-wake.test.ts +158 -1
  642. package/src/runtime/__tests__/channel-verification-service.test.ts +2 -2
  643. package/src/runtime/__tests__/trust-verdict-consumer.test.ts +37 -8
  644. package/src/runtime/access-request-helper.ts +154 -3
  645. package/src/runtime/actor-trust-resolver.ts +7 -21
  646. package/src/runtime/agent-wake.ts +41 -1
  647. package/src/runtime/assistant-event.ts +86 -12
  648. package/src/runtime/auth/__tests__/route-policy.test.ts +31 -0
  649. package/src/runtime/channel-approval-types.ts +52 -2
  650. package/src/runtime/channel-approvals.ts +23 -8
  651. package/src/runtime/channel-invite-transport.ts +2 -2
  652. package/src/runtime/channel-invite-transports/voice.ts +1 -1
  653. package/src/runtime/channel-readiness-service.ts +3 -5
  654. package/src/runtime/channel-retry-sweep.ts +18 -24
  655. package/src/runtime/channel-verification-service.ts +9 -11
  656. package/src/runtime/finalize-event-delivery.ts +30 -16
  657. package/src/runtime/guardian-action-service.ts +10 -11
  658. package/src/runtime/guardian-reply-router.ts +122 -21
  659. package/src/runtime/http-server.ts +44 -101
  660. package/src/runtime/introduction-policy.test.ts +214 -0
  661. package/src/runtime/introduction-policy.ts +284 -0
  662. package/src/runtime/invite-service.ts +104 -361
  663. package/src/runtime/local-actor-identity.test.ts +38 -0
  664. package/src/runtime/local-actor-identity.ts +14 -0
  665. package/src/runtime/middleware/__tests__/rate-limiter.test.ts +22 -0
  666. package/src/runtime/middleware/rate-limiter.ts +30 -0
  667. package/src/runtime/middleware/twilio-validation.ts +5 -7
  668. package/src/runtime/migrations/__tests__/gcs-signed-url.test.ts +28 -0
  669. package/src/runtime/migrations/origin-mode.ts +6 -6
  670. package/src/runtime/pre-first-message-gate.ts +1 -0
  671. package/src/runtime/routes/__tests__/channel-verification-revoke.test.ts +6 -35
  672. package/src/runtime/routes/__tests__/consolidation-routes.test.ts +24 -3
  673. package/src/runtime/routes/__tests__/contact-routes.test.ts +80 -15
  674. package/src/runtime/routes/__tests__/conversation-list-routes.test.ts +7 -1
  675. package/src/runtime/routes/__tests__/global-search-routes.test.ts +0 -3
  676. package/src/runtime/routes/__tests__/home-feed-routes.test.ts +142 -1
  677. package/src/runtime/routes/__tests__/invite-relay-routes.test.ts +119 -30
  678. package/src/runtime/routes/__tests__/migration-import-allowed-hosts-env.test.ts +70 -0
  679. package/src/runtime/routes/__tests__/monitoring-routes.test.ts +194 -0
  680. package/src/runtime/routes/__tests__/plugins-routes.test.ts +755 -29
  681. package/src/runtime/routes/__tests__/retrospective-routes.test.ts +4 -0
  682. package/src/runtime/routes/__tests__/schedule-routes-create.test.ts +70 -0
  683. package/src/runtime/routes/__tests__/schedule-worker-routes.test.ts +161 -0
  684. package/src/runtime/routes/__tests__/surface-action-routes.test.ts +1 -1
  685. package/src/runtime/routes/__tests__/surface-content-routes.test.ts +1 -1
  686. package/src/runtime/routes/acp-routes.ts +15 -3
  687. package/src/runtime/routes/app-management-routes.ts +4 -7
  688. package/src/runtime/routes/approval-routes.ts +4 -0
  689. package/src/runtime/routes/attachment-routes.ts +54 -3
  690. package/src/runtime/routes/avatar-routes.ts +0 -4
  691. package/src/runtime/routes/background-tool-routes.ts +34 -5
  692. package/src/runtime/routes/btw-routes.ts +32 -4
  693. package/src/runtime/routes/channel-route-shared.ts +18 -14
  694. package/src/runtime/routes/channel-verification-routes.ts +0 -3
  695. package/src/runtime/routes/contact-routes.ts +298 -117
  696. package/src/runtime/routes/conversation-list-routes.ts +6 -0
  697. package/src/runtime/routes/conversation-management-routes.ts +74 -37
  698. package/src/runtime/routes/conversation-query-routes.ts +5 -2
  699. package/src/runtime/routes/conversation-routes.ts +222 -82
  700. package/src/runtime/routes/conversations-import-routes.ts +8 -1
  701. package/src/runtime/routes/credential-prompt-routes.ts +20 -5
  702. package/src/runtime/routes/debug-routes.ts +1 -0
  703. package/src/runtime/routes/documents-routes.ts +5 -2
  704. package/src/runtime/routes/empty-state-greeting-cache.ts +37 -10
  705. package/src/runtime/routes/global-search-routes.ts +2 -1
  706. package/src/runtime/routes/guardian-approval-interception.ts +51 -0
  707. package/src/runtime/routes/home-feed-routes.ts +60 -1
  708. package/src/runtime/routes/identity-routes.ts +4 -87
  709. package/src/runtime/routes/inbound-message-handler.ts +82 -41
  710. package/src/runtime/routes/inbound-stages/acl-enforcement.test.ts +430 -57
  711. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +302 -572
  712. package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +76 -270
  713. package/src/runtime/routes/inbound-stages/background-dispatch.ts +21 -116
  714. package/src/runtime/routes/inbound-stages/edit-intercept.ts +9 -1
  715. package/src/runtime/routes/inbound-stages/escalation-intercept.test.ts +158 -0
  716. package/src/runtime/routes/inbound-stages/escalation-intercept.ts +22 -1
  717. package/src/runtime/routes/index.ts +6 -0
  718. package/src/runtime/routes/inference-provider-connection-routes.ts +22 -16
  719. package/src/runtime/routes/internal-twilio-routes.ts +0 -15
  720. package/src/runtime/routes/messages-lexical-routes.ts +75 -0
  721. package/src/runtime/routes/migration-routes.ts +69 -6
  722. package/src/runtime/routes/monitoring-routes.ts +237 -0
  723. package/src/runtime/routes/plugins-routes.ts +329 -8
  724. package/src/runtime/routes/schedule-routes.ts +49 -8
  725. package/src/runtime/routes/schedule-worker-routes.ts +210 -0
  726. package/src/runtime/routes/secret-routes.ts +1 -1
  727. package/src/runtime/routes/surface-conversation-resolver.ts +1 -0
  728. package/src/runtime/services/__tests__/analyze-conversation.test.ts +54 -9
  729. package/src/runtime/services/__tests__/auto-analysis-enqueue.test.ts +30 -6
  730. package/src/runtime/services/__tests__/conversation-analyze-job.test.ts +43 -8
  731. package/src/runtime/services/__tests__/conversation-serializer.test.ts +20 -0
  732. package/src/runtime/services/analyze-conversation.ts +14 -4
  733. package/src/runtime/services/conversation-serializer.ts +5 -0
  734. package/src/runtime/slack-no-response.ts +47 -0
  735. package/src/runtime/slack-reply-session.test.ts +633 -0
  736. package/src/runtime/slack-reply-session.ts +382 -0
  737. package/src/runtime/slack-task-progress.ts +95 -0
  738. package/src/runtime/sync/resource-sync-events.ts +25 -0
  739. package/src/runtime/tool-grant-request-helper.ts +17 -1
  740. package/src/runtime/trust-class.test.ts +141 -0
  741. package/src/runtime/trust-class.ts +121 -0
  742. package/src/runtime/trust-verdict-consumer.ts +7 -6
  743. package/src/schedule/__tests__/run-script.test.ts +21 -0
  744. package/src/schedule/__tests__/worker-control.test.ts +241 -0
  745. package/src/schedule/run-script.ts +13 -6
  746. package/src/schedule/schedule-usage-store.ts +1 -0
  747. package/src/schedule/scheduler.ts +178 -127
  748. package/src/schedule/worker-control.ts +118 -0
  749. package/src/schedule/worker.ts +131 -0
  750. package/src/skills/__tests__/categories-cache.test.ts +38 -0
  751. package/src/skills/categories-cache.ts +40 -5
  752. package/src/skills/managed-store.ts +41 -6
  753. package/src/skills/validate-input.ts +47 -0
  754. package/src/stt/types.ts +5 -9
  755. package/src/subagent/manager.ts +267 -39
  756. package/src/subagent/types.ts +6 -2
  757. package/src/subagent/validate-allowlists.ts +65 -0
  758. package/src/telemetry/watchdog-direct-emit.test.ts +109 -0
  759. package/src/telemetry/watchdog-direct-emit.ts +89 -0
  760. package/src/tools/acp/list-agents.test.ts +0 -6
  761. package/src/tools/background-tool-registry.ts +61 -0
  762. package/src/tools/document/document-comment-tool.test.ts +4 -0
  763. package/src/tools/host-terminal/host-shell.test.ts +397 -0
  764. package/src/tools/host-terminal/host-shell.ts +203 -14
  765. package/src/tools/skills/find-similar-skills.test.ts +152 -1
  766. package/src/tools/skills/find-similar-skills.ts +30 -4
  767. package/src/tools/skills/load.ts +36 -0
  768. package/src/tools/skills/scaffold-managed.ts +66 -34
  769. package/src/tools/skills/skill-script-runner.ts +17 -0
  770. package/src/tools/skills/skill-tool-factory.ts +5 -1
  771. package/src/tools/terminal/safe-env.ts +3 -0
  772. package/src/tools/terminal/shell.test.ts +177 -0
  773. package/src/tools/terminal/shell.ts +98 -4
  774. package/src/tools/tool-approval-handler.ts +106 -29
  775. package/{node_modules/@vellumai/skill-host-contracts/src → src/tools}/tool-types.ts +16 -17
  776. package/src/tools/types.ts +29 -17
  777. package/src/tools/ui-surface/definitions.ts +3 -1
  778. package/src/tts/__tests__/provider-adapters.test.ts +37 -0
  779. package/src/tts/__tests__/provider-catalog.test.ts +21 -0
  780. package/src/tts/provider-catalog.ts +40 -9
  781. package/src/tts/providers/fish-audio-provider.ts +19 -10
  782. package/src/tts/types.ts +3 -4
  783. package/src/util/__tests__/process-tree.test.ts +10 -2
  784. package/src/util/__tests__/text-spacing.test.ts +53 -0
  785. package/src/util/cgroup-memory.ts +142 -0
  786. package/src/util/image-conversion.ts +281 -0
  787. package/src/util/phone.ts +1 -8
  788. package/src/util/platform.ts +33 -0
  789. package/src/util/process-tree.ts +10 -2
  790. package/src/util/text-spacing.ts +53 -0
  791. package/src/util/worker-process.ts +271 -0
  792. package/src/workflows/journal-store.ts +16 -1
  793. package/src/workflows/library.test.ts +35 -20
  794. package/src/workflows/library.ts +105 -66
  795. package/src/workspace/git-service.ts +1 -0
  796. package/src/workspace/migrations/011-backfill-installation-id.ts +83 -31
  797. package/src/workspace/migrations/041-backfill-google-gmail-settings-scope.ts +41 -22
  798. package/src/workspace/migrations/070-memory-v2-summary-schema-rebuild.ts +1 -1
  799. package/src/workspace/migrations/118-seed-now-md.ts +64 -0
  800. package/src/workspace/migrations/119-strip-persisted-memory-v3-tuning-defaults.ts +169 -0
  801. package/src/workspace/migrations/120-revise-onboarding-threads.ts +47 -0
  802. package/src/workspace/migrations/121-seed-default-user-guardrails.ts +82 -0
  803. package/src/workspace/migrations/122-relocate-default-user-boundary.ts +111 -0
  804. package/src/workspace/migrations/123-swap-quality-profile-to-fable.ts +85 -0
  805. package/src/workspace/migrations/__tests__/119-strip-persisted-memory-v3-tuning-defaults.test.ts +181 -0
  806. package/src/workspace/migrations/registry.ts +12 -0
  807. package/drizzle/0000_dizzy_maggott.sql +0 -301
  808. package/drizzle/meta/0000_snapshot.json +0 -1933
  809. package/drizzle/meta/_journal.json +0 -13
  810. package/node_modules/@vellumai/skill-host-contracts/__tests__/client.test.ts +0 -887
  811. package/node_modules/@vellumai/skill-host-contracts/bun.lock +0 -24
  812. package/node_modules/@vellumai/skill-host-contracts/package.json +0 -18
  813. package/node_modules/@vellumai/skill-host-contracts/src/assistant-event.ts +0 -97
  814. package/node_modules/@vellumai/skill-host-contracts/src/client.ts +0 -1349
  815. package/node_modules/@vellumai/skill-host-contracts/src/index.ts +0 -6
  816. package/node_modules/@vellumai/skill-host-contracts/src/runtime-mode.ts +0 -11
  817. package/node_modules/@vellumai/skill-host-contracts/src/server-message.ts +0 -32
  818. package/node_modules/@vellumai/skill-host-contracts/src/skill-host.ts +0 -333
  819. package/node_modules/@vellumai/skill-host-contracts/tsconfig.json +0 -20
  820. package/node_modules/@vellumai/skill-host-contracts/tsconfig.test.json +0 -12
  821. package/src/__tests__/invite-redemption-service.test.ts +0 -1180
  822. package/src/__tests__/invite-service-ipc.test.ts +0 -350
  823. package/src/__tests__/job-handler-registry-guard.test.ts +0 -125
  824. package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +0 -203
  825. package/src/__tests__/relay-server.test.ts +0 -6153
  826. package/src/__tests__/telephony-stt-routing.test.ts +0 -329
  827. package/src/__tests__/voice-invite-redemption.test.ts +0 -702
  828. package/src/calls/relay-server.ts +0 -2463
  829. package/src/calls/telephony-stt-routing.ts +0 -145
  830. package/src/contacts/__tests__/contacts-write-revoke-relay.test.ts +0 -128
  831. package/src/daemon/__tests__/daemon-skill-host.test.ts +0 -273
  832. package/src/daemon/daemon-skill-host.ts +0 -262
  833. package/src/daemon/message-types/meet.ts +0 -143
  834. package/src/daemon/shutdown-registry.ts +0 -40
  835. package/src/ipc/__tests__/skill-server-bidirectional.test.ts +0 -253
  836. package/src/ipc/__tests__/skill-server.test.ts +0 -182
  837. package/src/ipc/skill-ipc-types.ts +0 -54
  838. package/src/ipc/skill-routes/__tests__/config.test.ts +0 -146
  839. package/src/ipc/skill-routes/__tests__/events-ipc.test.ts +0 -448
  840. package/src/ipc/skill-routes/__tests__/identity.test.ts +0 -62
  841. package/src/ipc/skill-routes/__tests__/log.test.ts +0 -133
  842. package/src/ipc/skill-routes/__tests__/memory.test.ts +0 -203
  843. package/src/ipc/skill-routes/__tests__/platform.test.ts +0 -111
  844. package/src/ipc/skill-routes/__tests__/providers.test.ts +0 -265
  845. package/src/ipc/skill-routes/__tests__/registries.test.ts +0 -400
  846. package/src/ipc/skill-routes/config.ts +0 -47
  847. package/src/ipc/skill-routes/events.ts +0 -147
  848. package/src/ipc/skill-routes/identity.ts +0 -21
  849. package/src/ipc/skill-routes/index.ts +0 -37
  850. package/src/ipc/skill-routes/log.ts +0 -40
  851. package/src/ipc/skill-routes/memory.ts +0 -92
  852. package/src/ipc/skill-routes/platform.ts +0 -39
  853. package/src/ipc/skill-routes/providers.ts +0 -162
  854. package/src/ipc/skill-routes/registries.ts +0 -338
  855. package/src/ipc/skill-server.ts +0 -831
  856. package/src/ipc/skill-socket-path.ts +0 -20
  857. package/src/jobs/register-job-handlers.ts +0 -74
  858. package/src/persistence/invite-store.ts +0 -481
  859. package/src/plugins/job-handler-registry.ts +0 -94
  860. package/src/providers/cache-control.ts +0 -26
  861. package/src/runtime/__tests__/runtime-mode.test.ts +0 -62
  862. package/src/runtime/invite-redemption-service.ts +0 -828
  863. package/src/runtime/invite-redemption-templates.ts +0 -46
  864. package/src/runtime/runtime-mode.ts +0 -40
  865. package/src/runtime/slack-dm-text-delivery.ts +0 -177
  866. package/src/util/voice-code.ts +0 -31
@@ -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
- }