@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
@@ -0,0 +1,323 @@
1
+ /**
2
+ * Guard test: the event hub exposed to workspace plugins through
3
+ * `@vellumai/plugin-api` must not let an in-process plugin drive privileged
4
+ * host execution. It refuses to publish daemon-to-client host-proxy control
5
+ * events (`host_*`), withholds methods that hand out live subscriber callbacks
6
+ * (a direct delivery primitive), and snapshots published events so a mutating
7
+ * getter cannot slip a host event past the guard. Subscription and non-host
8
+ * publishing must still work and share state with the real hub.
9
+ */
10
+
11
+ import { describe, expect, test } from "bun:test";
12
+
13
+ import { assistantEventHub as pluginHub } from "../plugin-api/index.js";
14
+ import type { AssistantEvent } from "../runtime/assistant-event.js";
15
+ import { assistantEventHub as rawHub } from "../runtime/assistant-event-hub.js";
16
+
17
+ /** Minimal event envelope; the facade guard keys only off `message.type`. */
18
+ function envelope(type: string): AssistantEvent {
19
+ return { message: { type } } as unknown as AssistantEvent;
20
+ }
21
+
22
+ function eventType(event: unknown): unknown {
23
+ return (event as { message?: { type?: unknown } }).message?.type;
24
+ }
25
+
26
+ /** Register a host-capable desktop client subscriber on the raw hub. */
27
+ function subscribeHostClient(clientId: string, sink: AssistantEvent[]) {
28
+ return rawHub.subscribe({
29
+ type: "client",
30
+ clientId,
31
+ interfaceId: "macos",
32
+ capabilities: ["host_bash"],
33
+ callback: (event) => {
34
+ sink.push(event);
35
+ },
36
+ } as Parameters<typeof rawHub.subscribe>[0]);
37
+ }
38
+
39
+ describe("plugin-facing assistantEventHub facade", () => {
40
+ test("rejects publishing host-proxy control events", async () => {
41
+ for (const type of [
42
+ "host_bash_request",
43
+ "host_bash_cancel",
44
+ "host_file_request",
45
+ "host_transfer_request",
46
+ "host_browser_request",
47
+ "host_cu_request",
48
+ "host_app_control_request",
49
+ ]) {
50
+ let rejected: unknown;
51
+ try {
52
+ await pluginHub.publish(envelope(type));
53
+ } catch (err) {
54
+ rejected = err;
55
+ }
56
+ expect(rejected).toBeInstanceOf(Error);
57
+ expect((rejected as Error).message).toMatch(/host-proxy control events/);
58
+ }
59
+ });
60
+
61
+ test("does not expose the raw hub publish via the prototype chain (Codex P1)", async () => {
62
+ // A plain frozen object: its prototype is Object.prototype, which has no
63
+ // `publish`, so `Object.getPrototypeOf(...).publish` / `.constructor` cannot
64
+ // reach the unguarded `AssistantEventHub.prototype.publish`.
65
+ const proto = Object.getPrototypeOf(pluginHub) as { publish?: unknown };
66
+ expect(typeof proto?.publish).not.toBe("function");
67
+
68
+ const received: AssistantEvent[] = [];
69
+ const sub = subscribeHostClient("facade-proto-client", received);
70
+ try {
71
+ const p = Object.getPrototypeOf(pluginHub) as {
72
+ publish?: (event: AssistantEvent, options?: unknown) => Promise<void>;
73
+ } | null;
74
+ await p?.publish?.call(pluginHub, envelope("host_bash_request"), {
75
+ targetClientId: "facade-proto-client",
76
+ targetCapability: "host_bash",
77
+ });
78
+ expect(received).toHaveLength(0);
79
+ } finally {
80
+ sub.dispose();
81
+ }
82
+ });
83
+
84
+ test("withholds methods that leak subscriber callbacks (Codex P1)", () => {
85
+ const facade = pluginHub as unknown as Record<string, unknown>;
86
+ for (const method of [
87
+ "listClients",
88
+ "listClientsByCapability",
89
+ "listClientsByInterface",
90
+ "getClientById",
91
+ "getMostRecentClientByCapability",
92
+ "disposeClient",
93
+ "touchClient",
94
+ ]) {
95
+ expect(facade[method]).toBeUndefined();
96
+ }
97
+ });
98
+
99
+ test("snapshots the event so a mutating type getter cannot bypass the guard (Codex P1)", async () => {
100
+ const received: AssistantEvent[] = [];
101
+ const sub = subscribeHostClient("facade-toctou-client", received);
102
+ try {
103
+ // `message.type` reads benign first (what the guard would see) then turns
104
+ // into a host event — the classic time-of-check/time-of-use trick.
105
+ let reads = 0;
106
+ const message: Record<string, unknown> = {};
107
+ Object.defineProperty(message, "type", {
108
+ enumerable: true,
109
+ get() {
110
+ reads += 1;
111
+ return reads === 1 ? "sync_changed" : "host_bash_request";
112
+ },
113
+ });
114
+ const sneaky = { message } as unknown as AssistantEvent;
115
+
116
+ await pluginHub.publish(sneaky, {
117
+ targetClientId: "facade-toctou-client",
118
+ targetCapability: "host_bash",
119
+ });
120
+
121
+ // The client only ever sees the inert snapshot, never the host type.
122
+ expect(received).toHaveLength(1);
123
+ expect(eventType(received[0])).toBe("sync_changed");
124
+ } finally {
125
+ sub.dispose();
126
+ }
127
+ });
128
+
129
+ test("freezes the published snapshot so a subscriber cannot mutate it mid-fanout (Codex P1)", async () => {
130
+ const hostReceived: AssistantEvent[] = [];
131
+ // A malicious subscriber registered first tries to turn the in-flight event
132
+ // into a host request before the host-capable client (registered after)
133
+ // receives the same fanned-out object.
134
+ const attacker = rawHub.subscribe({
135
+ type: "process",
136
+ callback: (event) => {
137
+ try {
138
+ (event as { message: { type: string } }).message.type =
139
+ "host_bash_request";
140
+ } catch {
141
+ // Frozen snapshot — the mutation is rejected.
142
+ }
143
+ },
144
+ });
145
+ const hostSub = subscribeHostClient("facade-fanout-client", hostReceived);
146
+ try {
147
+ await pluginHub.publish(envelope("sync_changed"));
148
+ expect(hostReceived).toHaveLength(1);
149
+ expect(eventType(hostReceived[0])).toBe("sync_changed");
150
+ } finally {
151
+ attacker.dispose();
152
+ hostSub.dispose();
153
+ }
154
+ });
155
+
156
+ test("rejects host events disguised as boxed strings (Codex P1)", async () => {
157
+ const received: AssistantEvent[] = [];
158
+ const sub = subscribeHostClient("facade-boxed-client", received);
159
+ try {
160
+ // `new String(...)` is typeof "object" (slipping a naive string guard) but
161
+ // JSON-serializes to the primitive the client acts on. The canonical wire
162
+ // snapshot coerces it so the guard still blocks it.
163
+
164
+ const boxedType = new String("host_bash_request");
165
+ const boxed = {
166
+ message: { type: boxedType },
167
+ } as unknown as AssistantEvent;
168
+ let rejected: unknown;
169
+ try {
170
+ await pluginHub.publish(boxed, {
171
+ targetClientId: "facade-boxed-client",
172
+ targetCapability: "host_bash",
173
+ });
174
+ } catch (err) {
175
+ rejected = err;
176
+ }
177
+ expect(rejected).toBeInstanceOf(Error);
178
+ expect((rejected as Error).message).toMatch(/host-proxy control events/);
179
+ expect(received).toHaveLength(0);
180
+ } finally {
181
+ sub.dispose();
182
+ }
183
+ });
184
+
185
+ test("delegates non-host publish to the shared singleton", async () => {
186
+ const received: AssistantEvent[] = [];
187
+ // Subscribe on the RAW hub, publish through the FACADE: delivery proves the
188
+ // facade delegates to the same instance (shared subscriber state). The
189
+ // delivered event is a snapshot, so it is compared by value, not identity.
190
+ const sub = rawHub.subscribe({
191
+ type: "process",
192
+ callback: (event) => {
193
+ received.push(event);
194
+ },
195
+ });
196
+ try {
197
+ await pluginHub.publish(envelope("sync_changed"));
198
+ expect(received.some((e) => eventType(e) === "sync_changed")).toBe(true);
199
+ } finally {
200
+ sub.dispose();
201
+ }
202
+ });
203
+
204
+ test("delegates subscribe and hasSubscribersForEvent", () => {
205
+ const sub = pluginHub.subscribe({ type: "process", callback: () => {} });
206
+ try {
207
+ expect(typeof sub.dispose).toBe("function");
208
+ expect(
209
+ typeof pluginHub.hasSubscribersForEvent({ conversationId: undefined }),
210
+ ).toBe("boolean");
211
+ } finally {
212
+ sub.dispose();
213
+ }
214
+ });
215
+
216
+ test("downgrades plugin client subscriptions to in-process (no host-event interception) (Codex P1)", async () => {
217
+ const received: AssistantEvent[] = [];
218
+ // Ask for a host-capable client subscription; the facade must register a
219
+ // process subscriber, which never receives capability-targeted host events.
220
+ const sub = pluginHub.subscribe({
221
+ type: "client",
222
+ clientId: "plugin-fake-client",
223
+ interfaceId: "macos",
224
+ capabilities: ["host_bash"],
225
+ callback: (event) => {
226
+ received.push(event);
227
+ },
228
+ } as Parameters<typeof pluginHub.subscribe>[0]);
229
+ try {
230
+ await rawHub.publish(envelope("host_bash_request"), {
231
+ targetCapability: "host_bash",
232
+ });
233
+ expect(received).toHaveLength(0);
234
+ } finally {
235
+ sub.dispose();
236
+ }
237
+ });
238
+
239
+ test("isolates plugin callbacks so they cannot mutate the in-flight fanout event (Codex P1)", async () => {
240
+ const hostReceived: AssistantEvent[] = [];
241
+ // The plugin subscribes first and, from its callback, tries to rewrite the
242
+ // shared in-flight event into a host request. It must only see an isolated
243
+ // copy, leaving the real client's event untouched.
244
+ const pluginSub = pluginHub.subscribe({
245
+ type: "process",
246
+ callback: (event) => {
247
+ try {
248
+ (event as { message: { type: string } }).message.type =
249
+ "host_bash_request";
250
+ } catch {
251
+ // Isolated frozen copy — the mutation is rejected.
252
+ }
253
+ },
254
+ });
255
+ const hostSub = subscribeHostClient(
256
+ "facade-isolation-client",
257
+ hostReceived,
258
+ );
259
+ try {
260
+ // Daemon-published untargeted event (not via the facade): the plugin runs
261
+ // first in the fanout but only receives an isolated copy.
262
+ await rawHub.publish(envelope("sync_changed"));
263
+ expect(hostReceived).toHaveLength(1);
264
+ expect(eventType(hostReceived[0])).toBe("sync_changed");
265
+ } finally {
266
+ pluginSub.dispose();
267
+ hostSub.dispose();
268
+ }
269
+ });
270
+
271
+ test("snapshots plugin subscription filters so a filter getter never runs during fanout (Codex P1)", async () => {
272
+ let getterCalls = 0;
273
+ const filter = {};
274
+ Object.defineProperty(filter, "conversationId", {
275
+ enumerable: true,
276
+ get() {
277
+ getterCalls += 1;
278
+ return undefined;
279
+ },
280
+ });
281
+ const pluginSub = pluginHub.subscribe({
282
+ type: "process",
283
+ filter: filter as { conversationId?: string },
284
+ callback: () => {},
285
+ });
286
+ const hostSub = subscribeHostClient("facade-filter-client", []);
287
+ try {
288
+ const callsAfterSubscribe = getterCalls;
289
+ // A conversation-scoped event makes the hub read `entry.filter.conversationId`
290
+ // during fanout; with an inert snapshot the plugin's getter never fires.
291
+ await rawHub.publish(
292
+ {
293
+ message: { type: "host_bash_request" },
294
+ conversationId: "conv-1",
295
+ } as unknown as AssistantEvent,
296
+ { targetCapability: "host_bash" },
297
+ );
298
+ expect(getterCalls).toBe(callsAfterSubscribe);
299
+ } finally {
300
+ pluginSub.dispose();
301
+ hostSub.dispose();
302
+ }
303
+ });
304
+
305
+ test("guard survives String.prototype.startsWith being monkey-patched (Codex P1)", async () => {
306
+ const originalStartsWith = String.prototype.startsWith;
307
+ // Simulate a malicious plugin neutering the prototype method the guard reads.
308
+
309
+ String.prototype.startsWith = () => false;
310
+ try {
311
+ let rejected: unknown;
312
+ try {
313
+ await pluginHub.publish(envelope("host_bash_request"));
314
+ } catch (err) {
315
+ rejected = err;
316
+ }
317
+ expect(rejected).toBeInstanceOf(Error);
318
+ expect((rejected as Error).message).toMatch(/host-proxy control events/);
319
+ } finally {
320
+ String.prototype.startsWith = originalStartsWith;
321
+ }
322
+ });
323
+ });
@@ -40,7 +40,7 @@ const DEFAULTS_ABS = join(process.cwd(), DEFAULTS_REL);
40
40
  * specifiers it reaches for outside itself. These are host-internal couplings
41
41
  * with no `@vellumai/plugin-api` equivalent (memory/daemon/context/config
42
42
  * internals, runtime builtins, third-party packages). `providers/types.js`
43
- * appears only for `ToolDefinition` (a `@vellumai/skill-host-contracts` type
43
+ * appears only for `ToolDefinition` (a `tools/tool-types.js` type
44
44
  * distinct from plugin-api's), which the anti-backslide guard enforces.
45
45
  *
46
46
  * Regenerate after an intentional change with:
@@ -81,7 +81,9 @@ const BASELINE: Record<string, readonly string[]> = {
81
81
  "../../../../../config/types.js",
82
82
  "../../../../../messaging/providers/slack/message-metadata.js",
83
83
  "../../../../../persistence/auto-analysis-constants.js",
84
+ "../../../../../persistence/checkpoints.js",
84
85
  "../../../../../persistence/conversation-queries.js",
86
+ "../../../../../persistence/conversation-search-lexical.js",
85
87
  "../../../../../persistence/db-connection.js",
86
88
  "../../../../../persistence/embeddings/embed.js",
87
89
  "../../../../../persistence/embeddings/embedding-backend.js",
@@ -106,6 +108,7 @@ const BASELINE: Record<string, readonly string[]> = {
106
108
  "../../../../daemon/conversation-notices.js",
107
109
  "../../../../daemon/conversation-registry.js",
108
110
  "../../../../daemon/conversation-runtime-assembly.js",
111
+ "../../../../daemon/embedding-reconcile.js",
109
112
  "../../../../daemon/identity-helpers.js",
110
113
  "../../../../daemon/message-protocol.js",
111
114
  "../../../../daemon/message-types/memory.js",
@@ -131,10 +134,7 @@ const BASELINE: Record<string, readonly string[]> = {
131
134
  "../../../../persistence/schema/conversations.js",
132
135
  "../../../../persistence/schema/index.js",
133
136
  "../../../../prompts/system-prompt.js",
134
- "../../../../providers/cache-control.js",
135
- "../../../../providers/provider-send-message.js",
136
- "../../../../providers/types.js",
137
- "../../../../runtime/actor-trust-resolver.js",
137
+ "../../../../providers/platform-proxy/context.js",
138
138
  "../../../../runtime/assistant-event-hub.js",
139
139
  "../../../../runtime/auth/route-policy.js",
140
140
  "../../../../runtime/background-job-runner.js",
@@ -142,9 +142,9 @@ const BASELINE: Record<string, readonly string[]> = {
142
142
  "../../../../runtime/routes/types.js",
143
143
  "../../../../security/secret-scanner.js",
144
144
  "../../../../skills/catalog-cache.js",
145
- "../../../../skills/frontmatter.js",
146
145
  "../../../../skills/install-meta.js",
147
146
  "../../../../skills/skill-memory.js",
147
+ "../../../../telemetry/watchdog-events-store.js",
148
148
  "../../../../tools/skills/delete-managed.js",
149
149
  "../../../../util/abort-reasons.js",
150
150
  "../../../../util/errors.js",
@@ -159,18 +159,24 @@ const BASELINE: Record<string, readonly string[]> = {
159
159
  "../../../config/assistant-feature-flags.js",
160
160
  "../../../config/loader.js",
161
161
  "../../../config/memory-v3-gate.js",
162
+ "../../../config/schema.js",
162
163
  "../../../config/schemas/memory-v2.js",
163
164
  "../../../config/types.js",
164
165
  "../../../contacts/guardian-delivery-reader.js",
165
166
  "../../../context/compactor.js",
166
167
  "../../../context/strip-injections.js",
167
168
  "../../../context/token-estimator.js",
169
+ "../../../conversations/job-handlers/summarization.js",
168
170
  "../../../daemon/date-context.js",
169
171
  "../../../daemon/disk-pressure-background-gate.js",
172
+ "../../../daemon/embedding-reconcile.js",
170
173
  "../../../daemon/pkb-context-tracker.js",
171
174
  "../../../daemon/pkb-reminder-builder.js",
175
+ "../../../daemon/skill-memory-refresh.js",
172
176
  "../../../daemon/tool-setup-types.js",
173
177
  "../../../daemon/trust-context.js",
178
+ "../../../home/job-handlers/conversation-starters.js",
179
+ "../../../media/job-handlers/media-processing.js",
174
180
  "../../../permissions/types.js",
175
181
  "../../../persistence/checkpoints.js",
176
182
  "../../../persistence/conversation-crud.js",
@@ -178,7 +184,15 @@ const BASELINE: Record<string, readonly string[]> = {
178
184
  "../../../persistence/embeddings/embedding-backend.js",
179
185
  "../../../persistence/embeddings/embedding-runtime-manager.js",
180
186
  "../../../persistence/embeddings/embedding-types.js",
187
+ "../../../persistence/embeddings/messages-lexical-index.js",
188
+ "../../../persistence/embeddings/qdrant-client.js",
189
+ "../../../persistence/embeddings/qdrant-manager.js",
190
+ "../../../persistence/job-handlers/cleanup.js",
191
+ "../../../persistence/job-handlers/message-lexical-backfill.js",
192
+ "../../../persistence/job-handlers/message-lexical.js",
193
+ "../../../persistence/job-utils.js",
181
194
  "../../../persistence/jobs-store.js",
195
+ "../../../persistence/jobs-worker.js",
182
196
  "../../../persistence/memory-lifecycle-hooks.js",
183
197
  "../../../persistence/message-content.js",
184
198
  "../../../persistence/raw-query.js",
@@ -191,6 +205,7 @@ const BASELINE: Record<string, readonly string[]> = {
191
205
  "../../../runtime/capabilities.js",
192
206
  "../../../runtime/services/auto-analysis-enqueue.js",
193
207
  "../../../runtime/services/auto-analysis-guard.js",
208
+ "../../../runtime/services/conversation-analyze-job.js",
194
209
  "../../../tools/types.js",
195
210
  "../../../types.js",
196
211
  "../../../util/logger.js",
@@ -248,7 +263,7 @@ const BASELINE: Record<string, readonly string[]> = {
248
263
  * Symbols that `@vellumai/plugin-api` re-exports from `providers/types.js`. A
249
264
  * plugin must import these from the public API, not the host module. NOT
250
265
  * listed (and therefore allowed from `providers/types.js`): `ToolDefinition`,
251
- * which `providers/types.js` re-exports from `@vellumai/skill-host-contracts`
266
+ * which `providers/types.js` re-exports from `tools/tool-types.js`
252
267
  * — a different type than plugin-api's own `ToolDefinition`.
253
268
  */
254
269
  const PLUGIN_API_PROVIDER_TYPES: ReadonlySet<string> = new Set([
@@ -298,13 +313,19 @@ function collectPluginFiles(): PluginFile[] {
298
313
  cwd: process.cwd(),
299
314
  })) {
300
315
  const norm = rel.split("/").join(sep);
301
- if (norm.endsWith(".test.ts") || norm.endsWith(".test.tsx")) continue;
302
- if (norm.split(sep).includes("__tests__")) continue;
316
+ if (norm.endsWith(".test.ts") || norm.endsWith(".test.tsx")) {
317
+ continue;
318
+ }
319
+ if (norm.split(sep).includes("__tests__")) {
320
+ continue;
321
+ }
303
322
  const underDefaults = relative(DEFAULTS_REL, norm);
304
323
  const segments = underDefaults.split(sep);
305
324
  // A file directly under defaults/ (e.g. index.ts) is the registry, not a
306
325
  // plugin — it has no plugin directory segment.
307
- if (segments.length < 2) continue;
326
+ if (segments.length < 2) {
327
+ continue;
328
+ }
308
329
  const absPath = join(process.cwd(), norm);
309
330
  files.push({
310
331
  plugin: segments[0]!,
@@ -332,11 +353,15 @@ function collectEscapes(files: PluginFile[]): Escape[] {
332
353
  let match: RegExpExecArray | null;
333
354
  while ((match = regex.exec(file.source)) !== null) {
334
355
  const specifier = match[1] ?? match[2] ?? match[3];
335
- if (!specifier || specifier === "@vellumai/plugin-api") continue;
356
+ if (!specifier || specifier === "@vellumai/plugin-api") {
357
+ continue;
358
+ }
336
359
  if (specifier.startsWith(".")) {
337
360
  const resolved = resolve(dirname(file.absPath), specifier);
338
361
  // Stays inside the plugin's own directory → allowed.
339
- if (!relative(pluginRoot, resolved).startsWith("..")) continue;
362
+ if (!relative(pluginRoot, resolved).startsWith("..")) {
363
+ continue;
364
+ }
340
365
  }
341
366
  escapes.push({ plugin: file.plugin, specifier, relPath: file.relPath });
342
367
  }
@@ -349,7 +374,9 @@ function escapesByPlugin(escapes: Escape[]): Map<string, string[]> {
349
374
  const sets = new Map<string, Set<string>>();
350
375
  for (const e of escapes) {
351
376
  let set = sets.get(e.plugin);
352
- if (!set) sets.set(e.plugin, (set = new Set()));
377
+ if (!set) {
378
+ sets.set(e.plugin, (set = new Set()));
379
+ }
353
380
  set.add(e.specifier);
354
381
  }
355
382
  return new Map(
@@ -372,24 +399,61 @@ function parseNamedSymbols(clause: string): string[] {
372
399
  .filter((name) => name.length > 0);
373
400
  }
374
401
 
402
+ /** Sentinel returned by {@link symbolsImportedFrom} for a namespace import
403
+ * (`import * as NS from "X"` / `import type * as NS from "X"`): it binds the
404
+ * module's entire export surface, so it counts as importing every re-exported
405
+ * symbol. `*` cannot collide with a real named-import identifier. */
406
+ const NAMESPACE_IMPORT = "*";
407
+
375
408
  /** Symbols a plugin file imports from a host module whose specifier ends with
376
- * `hostPathSuffix` (e.g. `providers/types.js`), across multi-line clauses. */
409
+ * `hostPathSuffix` (e.g. `providers/types.js`), across multi-line clauses. A
410
+ * namespace import yields the {@link NAMESPACE_IMPORT} sentinel — it reaches
411
+ * the whole surface, so it must not slip past the anti-backslide check. */
377
412
  function symbolsImportedFrom(source: string, hostPathSuffix: string): string[] {
378
413
  const escaped = hostPathSuffix.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
379
- const regex = new RegExp(
380
- String.raw`import\s+(?:type\s+)?\{([^}]*)\}\s*from\s*['"]([^'"]*` +
381
- escaped +
382
- String.raw`)['"]`,
414
+ const from = String.raw`\s*from\s*['"]([^'"]*` + escaped + String.raw`)['"]`;
415
+ const namedRegex = new RegExp(
416
+ String.raw`import\s+(?:type\s+)?\{([^}]*)\}` + from,
417
+ "g",
418
+ );
419
+ const namespaceRegex = new RegExp(
420
+ String.raw`import\s+(?:type\s+)?\*\s+as\s+\w+` + from,
383
421
  "g",
384
422
  );
385
423
  const symbols: string[] = [];
386
424
  let match: RegExpExecArray | null;
387
- while ((match = regex.exec(source)) !== null) {
425
+ while ((match = namedRegex.exec(source)) !== null) {
388
426
  symbols.push(...parseNamedSymbols(match[1]!));
389
427
  }
428
+ while (namespaceRegex.exec(source) !== null) {
429
+ symbols.push(NAMESPACE_IMPORT);
430
+ }
390
431
  return symbols;
391
432
  }
392
433
 
434
+ /** Anti-backslide violations for one plugin file against one guarded host
435
+ * module: any re-exported symbol imported by name, plus any namespace import
436
+ * (which binds the whole surface, and thus every guarded symbol). */
437
+ function guardedImportViolations(
438
+ file: PluginFile,
439
+ hostPathSuffix: string,
440
+ guarded: ReadonlySet<string>,
441
+ ): string[] {
442
+ const violations: string[] = [];
443
+ for (const symbol of symbolsImportedFrom(file.source, hostPathSuffix)) {
444
+ if (symbol === NAMESPACE_IMPORT) {
445
+ violations.push(
446
+ ` - ${file.relPath}: "import * as … from ${hostPathSuffix}" reaches all re-exported symbols`,
447
+ );
448
+ } else if (guarded.has(symbol)) {
449
+ violations.push(
450
+ ` - ${file.relPath}: "${symbol}" from ${hostPathSuffix}`,
451
+ );
452
+ }
453
+ }
454
+ return violations;
455
+ }
456
+
393
457
  describe("plugin import boundary", () => {
394
458
  const files = collectPluginFiles();
395
459
  const escapes = collectEscapes(files);
@@ -426,7 +490,9 @@ describe("plugin import boundary", () => {
426
490
  }
427
491
  }
428
492
  for (const spec of [...allowed].sort()) {
429
- if (!found.has(spec)) stale.push(` - ${plugin}: "${spec}"`);
493
+ if (!found.has(spec)) {
494
+ stale.push(` - ${plugin}: "${spec}"`);
495
+ }
430
496
  }
431
497
  }
432
498
 
@@ -444,7 +510,9 @@ describe("plugin import boundary", () => {
444
510
  );
445
511
  }
446
512
  if (stale.length > 0) {
447
- if (problems.length > 0) problems.push("");
513
+ if (problems.length > 0) {
514
+ problems.push("");
515
+ }
448
516
  problems.push(
449
517
  "Stale baseline entries (no longer imported — tighten the baseline):",
450
518
  ...stale,
@@ -459,26 +527,18 @@ describe("plugin import boundary", () => {
459
527
  test("plugins import plugin-api-provided types from @vellumai/plugin-api, not host modules", () => {
460
528
  const violations: string[] = [];
461
529
  for (const file of files) {
462
- for (const symbol of symbolsImportedFrom(
463
- file.source,
464
- "providers/types.js",
465
- )) {
466
- if (PLUGIN_API_PROVIDER_TYPES.has(symbol)) {
467
- violations.push(
468
- ` - ${file.relPath}: "${symbol}" from providers/types.js`,
469
- );
470
- }
471
- }
472
- for (const symbol of symbolsImportedFrom(
473
- file.source,
474
- "config/schemas/llm.js",
475
- )) {
476
- if (PLUGIN_API_LLM_TYPES.has(symbol)) {
477
- violations.push(
478
- ` - ${file.relPath}: "${symbol}" from config/schemas/llm.js`,
479
- );
480
- }
481
- }
530
+ violations.push(
531
+ ...guardedImportViolations(
532
+ file,
533
+ "providers/types.js",
534
+ PLUGIN_API_PROVIDER_TYPES,
535
+ ),
536
+ ...guardedImportViolations(
537
+ file,
538
+ "config/schemas/llm.js",
539
+ PLUGIN_API_LLM_TYPES,
540
+ ),
541
+ );
482
542
  }
483
543
 
484
544
  const message = [
@@ -487,9 +547,63 @@ describe("plugin import boundary", () => {
487
547
  ...violations,
488
548
  "",
489
549
  "(ToolDefinition from providers/types.js is allowed — it is a distinct",
490
- "@vellumai/skill-host-contracts type, not plugin-api's ToolDefinition.)",
550
+ "tools/tool-types.js type, not plugin-api's ToolDefinition.)",
491
551
  ].join("\n");
492
552
 
493
553
  expect(violations, message).toEqual([]);
494
554
  });
495
555
  });
556
+
557
+ describe("anti-backslide symbol extraction", () => {
558
+ const fileWith = (source: string): PluginFile => ({
559
+ plugin: "compaction",
560
+ relPath: "src/plugins/defaults/compaction/example.ts",
561
+ absPath: "/example.ts",
562
+ source,
563
+ });
564
+
565
+ test("a re-exported type imported by name is flagged", () => {
566
+ const file = fileWith(
567
+ `import type { Message } from "../../../providers/types.js";`,
568
+ );
569
+ expect(
570
+ guardedImportViolations(
571
+ file,
572
+ "providers/types.js",
573
+ PLUGIN_API_PROVIDER_TYPES,
574
+ ),
575
+ ).not.toEqual([]);
576
+ });
577
+
578
+ test("the allowed ToolDefinition named import stays clean", () => {
579
+ const file = fileWith(
580
+ `import type { ToolDefinition } from "../../../providers/types.js";`,
581
+ );
582
+ expect(
583
+ guardedImportViolations(
584
+ file,
585
+ "providers/types.js",
586
+ PLUGIN_API_PROVIDER_TYPES,
587
+ ),
588
+ ).toEqual([]);
589
+ });
590
+
591
+ // A namespace import binds the whole surface (`NS.Message`), so it must be
592
+ // caught even though the anti-backslide check extracts no named symbols and
593
+ // the specifier is already in the ratchet baseline.
594
+ test("a namespace import of a guarded module is flagged", () => {
595
+ for (const source of [
596
+ `import * as ProviderTypes from "../../../providers/types.js";`,
597
+ `import type * as ProviderTypes from "../../../providers/types.js";`,
598
+ ]) {
599
+ expect(
600
+ guardedImportViolations(
601
+ fileWith(source),
602
+ "providers/types.js",
603
+ PLUGIN_API_PROVIDER_TYPES,
604
+ ),
605
+ source,
606
+ ).not.toEqual([]);
607
+ }
608
+ });
609
+ });