@vellumai/assistant 0.11.3 → 0.11.4-dev.202608190019.b94dbf2

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 (596) hide show
  1. package/AGENTS.md +9 -3
  2. package/ARCHITECTURE.md +32 -10
  3. package/docs/architecture/memory.md +43 -5
  4. package/docs/architecture/security.md +96 -152
  5. package/docs/architecture/turn-actor.md +70 -0
  6. package/docs/browser-use-architecture-phase2.md +128 -56
  7. package/docs/flux-turn-detection-spike.md +248 -0
  8. package/docs/guardian-request-flow.md +35 -0
  9. package/docs/stt-provider-onboarding.md +3 -1
  10. package/knip.json +3 -0
  11. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/package.json +1 -0
  12. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/__tests__/url-normalization.test.ts +135 -0
  13. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/channels.ts +11 -0
  14. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
  15. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/remote-web-pairing.ts +60 -0
  16. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/url-normalization.ts +107 -0
  17. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/package.json +1 -0
  18. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/__tests__/url-normalization.test.ts +135 -0
  19. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/channels.ts +11 -0
  20. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
  21. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/remote-web-pairing.ts +60 -0
  22. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/url-normalization.ts +107 -0
  23. package/node_modules/@vellumai/gateway-client/src/admission-policy-contract.ts +34 -0
  24. package/node_modules/@vellumai/gateway-client/src/gateway-ipc-contracts.ts +166 -1
  25. package/node_modules/@vellumai/gateway-client/src/index.ts +2 -0
  26. package/node_modules/@vellumai/service-contracts/package.json +1 -0
  27. package/node_modules/@vellumai/service-contracts/src/__tests__/url-normalization.test.ts +135 -0
  28. package/node_modules/@vellumai/service-contracts/src/channels.ts +11 -0
  29. package/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
  30. package/node_modules/@vellumai/service-contracts/src/remote-web-pairing.ts +60 -0
  31. package/node_modules/@vellumai/service-contracts/src/url-normalization.ts +107 -0
  32. package/openapi.yaml +289 -113
  33. package/package.json +1 -1
  34. package/scripts/voice-ttft-spike.ts +3 -3
  35. package/scripts/write-plugin-api-shim.ts +10 -0
  36. package/src/__tests__/app-compiler.test.ts +38 -3
  37. package/src/__tests__/app-control-flow.test.ts +1 -0
  38. package/src/__tests__/approval-routes-http.test.ts +2 -2
  39. package/src/__tests__/assistant-feature-flag-guard.test.ts +25 -3
  40. package/src/__tests__/attachments-store.test.ts +21 -12
  41. package/src/__tests__/byok-default-profile-ensure.test.ts +17 -0
  42. package/src/__tests__/call-setup-flow-name-capture.test.ts +0 -1
  43. package/src/__tests__/call-site-routing-provider.test.ts +1 -1
  44. package/src/__tests__/channel-availability-routes.test.ts +14 -1
  45. package/src/__tests__/channel-capabilities-dedupe.test.ts +214 -0
  46. package/src/__tests__/channel-delivery-store.test.ts +14 -14
  47. package/src/__tests__/channel-inbound-disk-pressure.test.ts +4 -4
  48. package/src/__tests__/channel-setup-panel-ack.test.ts +1 -1
  49. package/src/__tests__/checker.test.ts +20 -314
  50. package/src/__tests__/cli-memory-v2-reembed-skills.test.ts +6 -2
  51. package/src/__tests__/compaction-events.test.ts +8 -10
  52. package/src/__tests__/config-loader-backfill.test.ts +3 -3
  53. package/src/__tests__/config-schema.test.ts +25 -10
  54. package/src/__tests__/context-search-memory-v2-source.test.ts +0 -1
  55. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +8 -11
  56. package/src/__tests__/conversation-agent-loop-overflow.test.ts +8 -11
  57. package/src/__tests__/conversation-agent-loop.test.ts +32 -21
  58. package/src/__tests__/conversation-attachments.test.ts +0 -1
  59. package/src/__tests__/conversation-attention-store.test.ts +63 -0
  60. package/src/__tests__/conversation-confirmation-signals.test.ts +112 -0
  61. package/src/__tests__/conversation-delete-schedule-cleanup.test.ts +0 -4
  62. package/src/__tests__/conversation-fork-crud.test.ts +69 -0
  63. package/src/__tests__/conversation-fork-referential.test.ts +67 -0
  64. package/src/__tests__/conversation-fork-retrospective.test.ts +24 -0
  65. package/src/__tests__/conversation-load-history-repair.test.ts +209 -0
  66. package/src/__tests__/conversation-notifiers-provenance.test.ts +59 -0
  67. package/src/__tests__/conversation-queue.test.ts +154 -4
  68. package/src/__tests__/conversation-routes-disk-view.test.ts +1 -1
  69. package/src/__tests__/conversation-routes-enabled-plugins.test.ts +1 -1
  70. package/src/__tests__/conversation-routes-guardian-reply.test.ts +9 -9
  71. package/src/__tests__/conversation-routes-hidden-queue.test.ts +1 -1
  72. package/src/__tests__/conversation-routes-slash-commands.test.ts +1 -1
  73. package/src/__tests__/conversation-runtime-assembly.test.ts +187 -102
  74. package/src/__tests__/conversation-runtime-workspace.test.ts +14 -10
  75. package/src/__tests__/conversation-slash-queue.test.ts +3 -0
  76. package/src/__tests__/conversation-surfaces-action-delivery.test.ts +1 -0
  77. package/src/__tests__/conversation-surfaces-activation-emit.test.ts +1 -0
  78. package/src/__tests__/conversation-surfaces-app-control.test.ts +1 -0
  79. package/src/__tests__/conversation-surfaces-app-open.test.ts +1 -1
  80. package/src/__tests__/conversation-surfaces-data-persist.test.ts +1 -1
  81. package/src/__tests__/conversation-surfaces-history-restored-completion.test.ts +21 -14
  82. package/src/__tests__/conversation-surfaces-queued-emit.test.ts +1 -0
  83. package/src/__tests__/conversation-surfaces-standalone-payloads.test.ts +1 -0
  84. package/src/__tests__/conversation-surfaces-standalone.test.ts +1 -0
  85. package/src/__tests__/conversation-surfaces-state-update.test.ts +1 -1
  86. package/src/__tests__/conversation-surfaces-table-action.test.ts +1 -1
  87. package/src/__tests__/conversation-surfaces-task-progress.test.ts +1 -1
  88. package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +1 -1
  89. package/src/__tests__/conversation-tool-setup-attribution.test.ts +1 -1
  90. package/src/__tests__/credential-prompt-route.test.ts +7 -10
  91. package/src/__tests__/credential-security-invariants.test.ts +1 -0
  92. package/src/__tests__/cu-unified-flow.test.ts +1 -0
  93. package/src/__tests__/custom-profile-ensure.test.ts +5 -1
  94. package/src/__tests__/default-plugin-names-guard.test.ts +12 -1
  95. package/src/__tests__/discord-access-request-privacy.test.ts +5 -1
  96. package/src/__tests__/discord-requester-notice-privacy.test.ts +3 -3
  97. package/src/__tests__/document-append-idempotency.test.ts +233 -0
  98. package/src/__tests__/document-sync-tags.test.ts +0 -75
  99. package/src/__tests__/dynamic-skill-background-guard.test.ts +0 -2
  100. package/src/__tests__/edit-propagation.test.ts +107 -11
  101. package/src/__tests__/file-ops-service.test.ts +163 -30
  102. package/src/__tests__/filesystem-tools.test.ts +23 -24
  103. package/src/__tests__/gateway-only-guard.test.ts +2 -5
  104. package/src/__tests__/helpers/gateway-classify-mock.ts +27 -6
  105. package/src/__tests__/helpers/mock-actor-context.ts +49 -0
  106. package/src/__tests__/helpers/mock-conversation.ts +13 -1
  107. package/src/__tests__/host-file-read-tool.test.ts +16 -19
  108. package/src/__tests__/http-user-message-parity.test.ts +1 -1
  109. package/src/__tests__/init-feature-flag-overrides.test.ts +49 -0
  110. package/src/__tests__/injector-chain.test.ts +63 -41
  111. package/src/__tests__/injector-disk-pressure.test.ts +11 -23
  112. package/src/__tests__/inline-skill-load-permissions.test.ts +47 -36
  113. package/src/__tests__/llm-context-resolution.test.ts +73 -1
  114. package/src/__tests__/llm-schema.test.ts +5 -2
  115. package/src/__tests__/managed-skill-lifecycle.test.ts +7 -0
  116. package/src/__tests__/mcp-list-plugin-servers.test.ts +250 -0
  117. package/src/__tests__/media-generate-image.test.ts +131 -21
  118. package/src/__tests__/memory-retrieval-hook.test.ts +100 -7
  119. package/src/__tests__/messages-read-boundary-guard.test.ts +134 -0
  120. package/src/__tests__/mtime-cache.test.ts +3 -1
  121. package/src/__tests__/non-member-access-request.test.ts +0 -20
  122. package/src/__tests__/outbound-slack-persistence.test.ts +40 -1
  123. package/src/__tests__/platform-bash-auto-approve.test.ts +0 -4
  124. package/src/__tests__/plugin-api-store-credential.test.ts +261 -0
  125. package/src/__tests__/plugin-api-webhook-url.test.ts +10 -7
  126. package/src/__tests__/plugin-disabled-state.test.ts +2 -0
  127. package/src/__tests__/plugin-effective-enabled-set.test.ts +55 -3
  128. package/src/__tests__/plugin-execution-context.test.ts +73 -0
  129. package/src/__tests__/plugin-import-boundary-guard.test.ts +5 -1
  130. package/src/__tests__/plugin-import-boundary-reverse-guard.test.ts +7 -4
  131. package/src/__tests__/plugin-secret-pattern-contribution.test.ts +1 -1
  132. package/src/__tests__/post-compaction-reinjection-idempotency.test.ts +14 -7
  133. package/src/__tests__/provider-commit-message-generator.test.ts +20 -0
  134. package/src/__tests__/proxy-approval-callback.test.ts +1 -0
  135. package/src/__tests__/qdrant-manager.test.ts +14 -1
  136. package/src/__tests__/reaction-persistence.test.ts +200 -7
  137. package/src/__tests__/require-fresh-approval.test.ts +0 -4
  138. package/src/__tests__/risk-classification-boundary-guard.test.ts +115 -0
  139. package/src/__tests__/run-conversation-turn-persistence.test.ts +460 -105
  140. package/src/__tests__/run-due-schedules.test.ts +21 -0
  141. package/src/__tests__/scaffold-managed-skill-tool.test.ts +187 -18
  142. package/src/__tests__/schedule-routes.test.ts +23 -0
  143. package/src/__tests__/schedule-store.test.ts +17 -0
  144. package/src/__tests__/scoped-approval-grants.test.ts +11 -6
  145. package/src/__tests__/secret-ingress-channel.test.ts +0 -1
  146. package/src/__tests__/secret-ingress-http.test.ts +1 -1
  147. package/src/__tests__/send-endpoint-busy.test.ts +3 -3
  148. package/src/__tests__/skills.test.ts +32 -0
  149. package/src/__tests__/slack-edit-ordering-characterization.test.ts +0 -1
  150. package/src/__tests__/starter-task-flow.test.ts +5 -4
  151. package/src/__tests__/subagent-call-site-routing.test.ts +31 -19
  152. package/src/__tests__/subagent-fork-prompt-role.test.ts +1 -1
  153. package/src/__tests__/subagent-spawn-and-await.test.ts +18 -17
  154. package/src/__tests__/subagent-tool-gate-mode.test.ts +1 -1
  155. package/src/__tests__/subagent-tools.test.ts +81 -101
  156. package/src/__tests__/surface-completion-in-flight-snapshot.test.ts +1 -0
  157. package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +1 -1
  158. package/src/__tests__/tool-executor-lifecycle-events.test.ts +132 -5
  159. package/src/__tests__/tool-executor.test.ts +68 -39
  160. package/src/__tests__/turn-events-store.test.ts +43 -0
  161. package/src/__tests__/ui-choice-copy-surfaces.test.ts +1 -1
  162. package/src/__tests__/ui-shape-teaching.test.ts +33 -0
  163. package/src/__tests__/ui-visual-surface.test.ts +1 -1
  164. package/src/__tests__/ui-voice-picker-surface.test.ts +128 -0
  165. package/src/__tests__/ui-work-result-surface.test.ts +1 -1
  166. package/src/__tests__/user-plugin-loader.test.ts +3 -1
  167. package/src/__tests__/verification-control-plane-policy.test.ts +0 -2
  168. package/src/__tests__/visible-app-context.test.ts +16 -9
  169. package/src/__tests__/voice-config-update.test.ts +40 -0
  170. package/src/__tests__/voice-scoped-grant-consumer.test.ts +5 -3
  171. package/src/__tests__/voice-session-bridge.test.ts +85 -29
  172. package/src/__tests__/worker-entrypoint-guards.test.ts +54 -0
  173. package/src/__tests__/worker-plugin-surface.test.ts +77 -0
  174. package/src/__tests__/workspace-migration-142-consolidate-voice-front-door.test.ts +158 -0
  175. package/src/__tests__/workspace-migration-143-repair-deprecated-codex-model-id.test.ts +133 -0
  176. package/src/__tests__/workspace-migration-144-convert-stranded-subscription-openai-profiles.test.ts +316 -0
  177. package/src/__tests__/workspace-migration-145-collapse-profile-bindings-to-entries.test.ts +325 -0
  178. package/src/__tests__/workspace-migration-146-repair-retired-fireworks-deepseek-flash-model-id.test.ts +235 -0
  179. package/src/acp/__tests__/acp-claude-oauth.test.ts +10 -2
  180. package/src/acp/__tests__/auth-required.test.ts +161 -0
  181. package/src/acp/acp-claude-oauth.ts +19 -2
  182. package/src/acp/agent-process.test.ts +100 -0
  183. package/src/acp/agent-process.ts +29 -26
  184. package/src/acp/auth-required.ts +102 -0
  185. package/src/acp/session-manager.test.ts +119 -0
  186. package/src/acp/session-manager.ts +76 -3
  187. package/src/api/events/acp-auth-required.ts +55 -0
  188. package/src/api/events/host-file.ts +2 -2
  189. package/src/api/index.ts +7 -0
  190. package/src/api/surfaces.ts +12 -3
  191. package/src/apps/app-store.ts +3 -0
  192. package/src/bundler/package-resolver.ts +2 -30
  193. package/src/calls/__tests__/voice-session-bridge.test.ts +194 -11
  194. package/src/calls/__tests__/voice-triage-escalate.test.ts +102 -0
  195. package/src/calls/call-controller.ts +19 -3
  196. package/src/calls/call-setup-flow.ts +0 -1
  197. package/src/calls/media-stream-stt-session.ts +15 -0
  198. package/src/calls/voice-session-bridge.ts +115 -41
  199. package/src/calls/voice-triage-escalate.ts +105 -2
  200. package/src/channels/__tests__/plugin-channel-declarations.test.ts +161 -0
  201. package/src/channels/config.ts +13 -0
  202. package/src/channels/plugin-channel-declarations.ts +108 -0
  203. package/src/channels/types.ts +30 -0
  204. package/src/cli/AGENTS.md +5 -2
  205. package/src/cli/bundled-modules.ts +29 -0
  206. package/src/cli/commands/credentials.help.ts +2 -2
  207. package/src/cli/commands/db/repair.ts +4 -8
  208. package/src/cli/commands/domain.ts +6 -3
  209. package/src/cli/commands/email.ts +6 -3
  210. package/src/cli/commands/inference-providers.ts +1 -1
  211. package/src/cli/commands/keys.ts +8 -3
  212. package/src/cli/commands/mcp.help.ts +13 -4
  213. package/src/cli/commands/mcp.ts +9 -0
  214. package/src/cli/commands/memory/__tests__/memory-v2.test.ts +57 -7
  215. package/src/cli/commands/memory/__tests__/memory-v3.test.ts +128 -5
  216. package/src/cli/commands/memory/index.help.ts +84 -28
  217. package/src/cli/commands/memory/index.ts +2 -0
  218. package/src/cli/commands/memory/memory-v2.ts +58 -54
  219. package/src/cli/commands/memory/memory-v3.ts +64 -0
  220. package/src/cli/commands/memory/memory-validate.ts +18 -0
  221. package/src/cli/commands/plugins.ts +85 -36
  222. package/src/cli/commands/schedules.ts +35 -1
  223. package/src/cli/commands/stt.help.ts +27 -2
  224. package/src/cli/commands/trust.ts +3 -14
  225. package/src/cli/lib/__tests__/upgrade-plugin.test.ts +39 -0
  226. package/src/cli/lib/bundled-marketplace.json +14 -1
  227. package/src/cli/lib/upgrade-plugin.ts +42 -0
  228. package/src/config/__tests__/balanced-model-experiment.test.ts +278 -0
  229. package/src/config/__tests__/default-profile-catalog.test.ts +34 -2
  230. package/src/config/__tests__/default-provider.test.ts +6 -1
  231. package/src/config/__tests__/profile-materialization.test.ts +75 -19
  232. package/src/config/assistant-feature-flags.ts +36 -15
  233. package/src/config/balanced-model-experiment.ts +35 -0
  234. package/src/config/bundled-skills/acp/SKILL.md +6 -7
  235. package/src/config/bundled-skills/document-editor/SKILL.md +2 -2
  236. package/src/config/bundled-skills/document-editor/TOOLS.json +2 -2
  237. package/src/config/bundled-skills/image-studio/SKILL.md +5 -4
  238. package/src/config/bundled-skills/image-studio/TOOLS.json +1 -1
  239. package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +101 -0
  240. package/src/config/bundled-skills/media-processing/services/preprocess.ts +14 -4
  241. package/src/config/bundled-skills/settings/TOOLS.json +3 -3
  242. package/src/config/bundled-skills/settings/tools/navigate-settings-tab.test.ts +65 -0
  243. package/src/config/bundled-skills/settings/tools/navigate-settings-tab.ts +7 -1
  244. package/src/config/bundled-skills/settings/tools/shared.ts +16 -0
  245. package/src/config/bundled-skills/settings/tools/voice-config-update.ts +19 -1
  246. package/src/config/bundled-skills/skill-management/TOOLS.json +9 -3
  247. package/src/config/bundled-skills/subagent/SKILL.md +17 -12
  248. package/src/config/bundled-skills/subagent/TOOLS.json +4 -4
  249. package/src/config/bundled-skills/transcribe/tools/transcribe-media.test.ts +22 -1
  250. package/src/config/bundled-skills/transcribe/tools/transcribe-media.ts +9 -2
  251. package/src/config/call-site-defaults.ts +11 -5
  252. package/src/config/default-profile-catalog.ts +179 -16
  253. package/src/config/default-profile-names.ts +4 -1
  254. package/src/config/default-provider-resolution.ts +4 -0
  255. package/src/config/feature-flag-registry.json +12 -12
  256. package/src/config/llm-context-resolution.ts +11 -3
  257. package/src/config/llm-resolver.ts +28 -1
  258. package/src/config/profile-materialization.ts +70 -22
  259. package/src/config/schemas/__tests__/live-voice.test.ts +107 -4
  260. package/src/config/schemas/call-site-catalog.ts +4 -4
  261. package/src/config/schemas/live-voice.ts +57 -23
  262. package/src/config/schemas/llm.ts +59 -32
  263. package/src/config/schemas/mcp.ts +23 -0
  264. package/src/config/schemas/plugin-updates.ts +6 -2
  265. package/src/config/schemas/stt.ts +1 -0
  266. package/src/config/skills.ts +9 -2
  267. package/src/context/outbound-sanitize.ts +96 -1
  268. package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +1 -1
  269. package/src/daemon/__tests__/plugin-mcp-reconcile.test.ts +82 -0
  270. package/src/daemon/conversation-agent-loop-handlers.ts +15 -10
  271. package/src/daemon/conversation-agent-loop.ts +31 -19
  272. package/src/daemon/conversation-messaging.ts +5 -1
  273. package/src/daemon/conversation-notifiers.ts +20 -10
  274. package/src/daemon/conversation-process.ts +20 -6
  275. package/src/daemon/conversation-runtime-assembly.ts +12 -6
  276. package/src/daemon/conversation-store.ts +14 -4
  277. package/src/daemon/conversation-surfaces.ts +75 -26
  278. package/src/daemon/conversation-tool-setup.ts +3 -6
  279. package/src/daemon/conversation.ts +154 -51
  280. package/src/daemon/doordash-steps.ts +2 -2
  281. package/src/daemon/lifecycle.ts +14 -1
  282. package/src/daemon/mcp-reload-service.ts +36 -6
  283. package/src/daemon/process-message.ts +13 -26
  284. package/src/daemon/providers-setup.ts +6 -3
  285. package/src/daemon/trust-context-types.ts +29 -0
  286. package/src/daemon/trust-context.ts +12 -7
  287. package/src/daemon/wake-conversation-ops.ts +3 -2
  288. package/src/daemon/windows-compiled-entry.ts +4 -0
  289. package/src/documents/document-store.ts +143 -240
  290. package/src/hooks/hook-loader.ts +3 -3
  291. package/src/hooks/registry.ts +103 -45
  292. package/src/hooks/types.ts +5 -0
  293. package/src/inbound/__tests__/oauth-callback-url.test.ts +83 -0
  294. package/src/inbound/oauth-callback-url.ts +61 -0
  295. package/src/ipc/gateway-client.test.ts +1 -1
  296. package/src/ipc/gateway-client.ts +14 -21
  297. package/src/ipc/gateway-flag-listener.ts +17 -3
  298. package/src/live-voice/__tests__/live-voice-agent-turn.test.ts +1 -104
  299. package/src/live-voice/__tests__/live-voice-events.test.ts +7 -8
  300. package/src/live-voice/__tests__/live-voice-flux-turn-end.test.ts +1050 -0
  301. package/src/live-voice/__tests__/live-voice-metrics.test.ts +115 -8
  302. package/src/live-voice/__tests__/live-voice-photo.test.ts +100 -0
  303. package/src/live-voice/__tests__/live-voice-progress.test.ts +60 -194
  304. package/src/live-voice/__tests__/live-voice-stt.test.ts +14 -0
  305. package/src/live-voice/__tests__/live-voice-triage-escalate.test.ts +29 -0
  306. package/src/live-voice/__tests__/live-voice-tts-session.test.ts +0 -483
  307. package/src/live-voice/__tests__/live-voice-vad.test.ts +0 -16
  308. package/src/live-voice/__tests__/progress-narration.test.ts +214 -0
  309. package/src/live-voice/live-voice-archive.ts +2 -0
  310. package/src/live-voice/live-voice-manager.ts +16 -3
  311. package/src/live-voice/live-voice-metrics.ts +57 -32
  312. package/src/live-voice/live-voice-photo.ts +1 -2
  313. package/src/live-voice/live-voice-session.ts +598 -323
  314. package/src/live-voice/progress-narration.ts +277 -0
  315. package/src/live-voice/protocol.ts +21 -1
  316. package/src/live-voice/windows-compiled-live-voice.ts +4 -0
  317. package/src/mcp/__tests__/effective-config.test.ts +238 -0
  318. package/src/mcp/__tests__/mcp-auth-orchestrator.test.ts +0 -1
  319. package/src/mcp/__tests__/mcp-oauth-client-registration.test.ts +200 -0
  320. package/src/mcp/__tests__/mcp-oauth-provider.test.ts +9 -9
  321. package/src/mcp/__tests__/plugin-server-credential-isolation.test.ts +95 -0
  322. package/src/mcp/client.ts +16 -11
  323. package/src/mcp/effective-config.ts +113 -0
  324. package/src/mcp/manager.ts +11 -6
  325. package/src/mcp/mcp-auth-orchestrator.ts +13 -22
  326. package/src/mcp/mcp-oauth-provider.ts +205 -240
  327. package/src/monitoring/__tests__/plugin-auto-update.test.ts +166 -3
  328. package/src/monitoring/control.ts +1 -0
  329. package/src/monitoring/db-integrity-sample.ts +4 -5
  330. package/src/monitoring/plugin-auto-update.ts +128 -24
  331. package/src/notifications/AGENTS.md +2 -0
  332. package/src/notifications/approval-card-data.ts +33 -0
  333. package/src/notifications/signal.ts +1 -0
  334. package/src/permissions/AGENTS.md +16 -0
  335. package/src/permissions/checker.test.ts +75 -122
  336. package/src/permissions/checker.ts +44 -560
  337. package/src/permissions/confirmation-guardian-request.test.ts +15 -11
  338. package/src/permissions/confirmation-guardian-request.ts +2 -2
  339. package/src/permissions/prompter.ts +1 -5
  340. package/src/permissions/question-guardian-request.test.ts +14 -6
  341. package/src/permissions/question-guardian-request.ts +1 -2
  342. package/src/persistence/attachments-store.ts +8 -1
  343. package/src/persistence/bookmark-crud.ts +3 -7
  344. package/src/persistence/conversation-attention-store.ts +16 -45
  345. package/src/persistence/conversation-crud.ts +33 -4
  346. package/src/persistence/conversation-lineage.ts +9 -0
  347. package/src/persistence/conversation-queries.ts +182 -52
  348. package/src/persistence/delivery-crud.ts +150 -36
  349. package/src/persistence/embeddings/qdrant-manager.ts +84 -49
  350. package/src/persistence/external-conversation-store.ts +32 -4
  351. package/src/persistence/llm-request-log-store.ts +4 -10
  352. package/src/persistence/llm-usage-store.ts +8 -3
  353. package/src/persistence/message-reads.test.ts +197 -0
  354. package/src/persistence/message-reads.ts +211 -0
  355. package/src/persistence/migrations/360-add-document-workspace-path.ts +5 -14
  356. package/src/persistence/migrations/366-chatgpt-subscription-row-identity.test.ts +120 -0
  357. package/src/persistence/migrations/366-chatgpt-subscription-row-identity.ts +62 -0
  358. package/src/persistence/real-user-turn-filter.ts +27 -3
  359. package/src/persistence/schema/documents.ts +4 -4
  360. package/src/persistence/steps.ts +9 -0
  361. package/src/plugin-api/__tests__/oauth-callback-url-export.test.ts +29 -0
  362. package/src/plugin-api/constants.ts +8 -0
  363. package/src/plugin-api/conversation-turn.ts +195 -5
  364. package/src/plugin-api/index.ts +38 -6
  365. package/src/plugin-api/resolve-credential.ts +3 -2
  366. package/src/plugin-api/store-credential.ts +146 -0
  367. package/src/plugin-api/vision-support.test.ts +1 -1
  368. package/src/plugin-api/webhook-url.ts +13 -11
  369. package/src/plugins/__tests__/mcp-servers.test.ts +371 -0
  370. package/src/plugins/defaults/main.ts +21 -7
  371. package/src/plugins/defaults/memory/AGENTS.md +15 -3
  372. package/src/plugins/defaults/memory/__tests__/buffer-format.test.ts +204 -0
  373. package/src/plugins/defaults/memory/__tests__/memory-retrospective-accounting.test.ts +72 -0
  374. package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +4 -1
  375. package/src/plugins/defaults/memory/__tests__/memory-retrospective-provider-path.test.ts +4 -1
  376. package/src/plugins/defaults/memory/__tests__/memory-tier-boundary-guard.test.ts +0 -1
  377. package/src/plugins/defaults/memory/buffer-format.ts +165 -0
  378. package/src/plugins/defaults/memory/context-search/sources/conversations.ts +6 -0
  379. package/src/plugins/defaults/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +77 -0
  380. package/src/plugins/defaults/memory/graph/conversation-graph-memory.ts +24 -6
  381. package/src/plugins/defaults/memory/graph/image-ref-utils.ts +3 -0
  382. package/src/plugins/defaults/memory/graph/tool-handlers.ts +1 -30
  383. package/src/plugins/defaults/memory/graph-topology/pending-buffer.test.ts +34 -0
  384. package/src/plugins/defaults/memory/graph-topology/pending-buffer.ts +17 -24
  385. package/src/plugins/defaults/memory/hooks/post-compact.ts +1 -4
  386. package/src/plugins/defaults/memory/hooks/user-prompt-submit.ts +53 -5
  387. package/src/plugins/defaults/memory/indexer.ts +3 -1
  388. package/src/plugins/defaults/memory/memory-retrospective-accounting.ts +19 -7
  389. package/src/plugins/defaults/memory/memory-retrospective-job.ts +4 -4
  390. package/src/plugins/defaults/memory/src/__tests__/memory-v3-gate-stats.test.ts +281 -0
  391. package/src/plugins/defaults/memory/src/memory-v2-routes.ts +12 -10
  392. package/src/plugins/defaults/memory/src/memory-v3-routes.ts +207 -0
  393. package/src/plugins/defaults/memory/substrate/__tests__/consolidation-job.test.ts +147 -0
  394. package/src/plugins/defaults/memory/substrate/__tests__/consolidation-prompt-flag-gating-guard.test.ts +8 -0
  395. package/src/plugins/defaults/memory/substrate/__tests__/edge-index.test.ts +0 -30
  396. package/src/plugins/defaults/memory/substrate/__tests__/ingest.test.ts +73 -1
  397. package/src/plugins/defaults/memory/substrate/__tests__/page-index.test.ts +37 -0
  398. package/src/plugins/defaults/memory/substrate/__tests__/page-links.test.ts +208 -0
  399. package/src/plugins/defaults/memory/substrate/__tests__/prompts-consolidation.test.ts +158 -1
  400. package/src/plugins/defaults/memory/substrate/__tests__/static-context.test.ts +195 -58
  401. package/src/plugins/defaults/memory/substrate/consolidation-job.ts +93 -24
  402. package/src/plugins/defaults/memory/substrate/edge-index.ts +0 -31
  403. package/src/plugins/defaults/memory/substrate/ingest.ts +59 -0
  404. package/src/plugins/defaults/memory/substrate/page-index.ts +35 -8
  405. package/src/plugins/defaults/memory/substrate/page-links.ts +133 -0
  406. package/src/plugins/defaults/memory/substrate/page-store.ts +10 -0
  407. package/src/plugins/defaults/memory/substrate/prompts/consolidation.ts +124 -34
  408. package/src/plugins/defaults/memory/substrate/skill-content.ts +8 -1
  409. package/src/plugins/defaults/memory/substrate/static-context.ts +160 -33
  410. package/src/plugins/defaults/memory/substrate/sweep-job.ts +2 -4
  411. package/src/plugins/defaults/memory/v1/graph/extraction.ts +3 -1
  412. package/src/plugins/defaults/memory/v3/__tests__/injection.test.ts +18 -0
  413. package/src/plugins/defaults/memory/v3/__tests__/shadow-plugin.test.ts +66 -1
  414. package/src/plugins/defaults/memory/v3/card.ts +9 -9
  415. package/src/plugins/defaults/memory/v3/core-set.test.ts +7 -0
  416. package/src/plugins/defaults/memory/v3/core-set.ts +5 -1
  417. package/src/plugins/defaults/memory/v3/edge.ts +13 -57
  418. package/src/plugins/defaults/memory/v3/injector.ts +8 -0
  419. package/src/plugins/defaults/memory/v3/prune.ts +2 -0
  420. package/src/plugins/defaults/memory/v3/selection-log-store.ts +2 -0
  421. package/src/plugins/defaults/memory/v3/shadow-plugin.ts +23 -9
  422. package/src/plugins/defaults/memory/worker-control.ts +1 -0
  423. package/src/plugins/defaults/memory/worker.ts +6 -3
  424. package/src/plugins/defaults/worker-entrypoints.ts +3 -0
  425. package/src/plugins/external-plugin-loader.ts +47 -0
  426. package/src/plugins/mcp-servers.ts +361 -0
  427. package/src/plugins/mtime-cache.ts +37 -46
  428. package/src/plugins/pipeline.ts +14 -7
  429. package/src/plugins/plugin-execution-context.ts +35 -11
  430. package/src/plugins/worker-plugin-surface.ts +33 -0
  431. package/src/prompts/templates/system-sections.ts +0 -7
  432. package/src/providers/__tests__/connection-model-compat.test.ts +1 -1
  433. package/src/providers/__tests__/context-overflow-error.test.ts +24 -0
  434. package/src/providers/__tests__/dispatch-connection-routing.test.ts +214 -2
  435. package/src/providers/__tests__/preflight-resolved-config.test.ts +57 -0
  436. package/src/providers/__tests__/retry-callsite.test.ts +25 -2
  437. package/src/providers/anthropic/__tests__/pause-turn-continuation.test.ts +170 -0
  438. package/src/providers/anthropic/client.ts +332 -241
  439. package/src/providers/call-site-routing.ts +30 -3
  440. package/src/providers/connection-resolution.ts +194 -11
  441. package/src/providers/inference/__tests__/adapter-factory-openai-compatible.test.ts +4 -0
  442. package/src/providers/inference/adapter-factory.ts +3 -0
  443. package/src/providers/inference/auth.ts +6 -0
  444. package/src/providers/inference/connection-availability.ts +24 -2
  445. package/src/providers/inference/connections.ts +2 -0
  446. package/src/providers/model-catalog.ts +3 -3
  447. package/src/providers/model-intents.ts +28 -8
  448. package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +163 -40
  449. package/src/providers/openai/__tests__/tool-choice-mapping.test.ts +125 -2
  450. package/src/providers/openai/chat-completions-provider.ts +133 -36
  451. package/src/providers/openai/codex-models.ts +2 -1
  452. package/src/providers/provider-send-message.ts +32 -3
  453. package/src/providers/speech-to-text/__tests__/deepgram-flux-frames.test.ts +433 -0
  454. package/src/providers/speech-to-text/__tests__/deepgram-flux-realtime.test.ts +625 -0
  455. package/src/providers/speech-to-text/__tests__/provider-catalog.test.ts +34 -0
  456. package/src/providers/speech-to-text/__tests__/resolve.test.ts +285 -6
  457. package/src/providers/speech-to-text/deepgram-flux-frames.ts +395 -0
  458. package/src/providers/speech-to-text/deepgram-flux-realtime.ts +679 -0
  459. package/src/providers/speech-to-text/provider-catalog.ts +99 -8
  460. package/src/providers/speech-to-text/resolve.ts +25 -2
  461. package/src/routes/control.ts +1 -0
  462. package/src/routes/route-host-client.ts +1 -0
  463. package/src/routes/route-host-protocol.ts +7 -0
  464. package/src/routes/worker.ts +48 -15
  465. package/src/runtime/AGENTS.md +16 -17
  466. package/src/runtime/access-request-helper.ts +9 -12
  467. package/src/runtime/agent-wake.ts +18 -15
  468. package/src/runtime/effective-capabilities.test.ts +43 -0
  469. package/src/runtime/effective-capabilities.ts +27 -0
  470. package/src/runtime/guardian-reply-router.ts +6 -2
  471. package/src/runtime/pre-first-message-gate.ts +4 -0
  472. package/src/runtime/routes/__tests__/acp-claude-auth-routes.test.ts +12 -4
  473. package/src/runtime/routes/__tests__/conversation-list-routes.test.ts +522 -2
  474. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +52 -0
  475. package/src/runtime/routes/__tests__/default-provider-routes.test.ts +61 -0
  476. package/src/runtime/routes/__tests__/inference-profiles-routes.test.ts +44 -0
  477. package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +102 -1
  478. package/src/runtime/routes/__tests__/plugins-routes.test.ts +132 -35
  479. package/src/runtime/routes/__tests__/schedule-routes-disarm-reason.test.ts +215 -0
  480. package/src/runtime/routes/__tests__/stt-routes.test.ts +25 -0
  481. package/src/runtime/routes/__tests__/surface-action-routes.test.ts +55 -6
  482. package/src/runtime/routes/__tests__/user-route-dispatcher-host.test.ts +52 -1
  483. package/src/runtime/routes/__tests__/user-route-dispatcher.test.ts +133 -1
  484. package/src/runtime/routes/channel-availability-routes.ts +32 -14
  485. package/src/runtime/routes/channel-route-shared.ts +0 -6
  486. package/src/runtime/routes/chatgpt-subscription-auth-routes.ts +6 -6
  487. package/src/runtime/routes/conversation-list-routes.ts +181 -23
  488. package/src/runtime/routes/conversation-management-routes.ts +17 -12
  489. package/src/runtime/routes/conversation-query-routes.ts +40 -27
  490. package/src/runtime/routes/conversation-routes.ts +43 -29
  491. package/src/runtime/routes/credential-prompt-routes.ts +4 -7
  492. package/src/runtime/routes/credential-routes.ts +26 -82
  493. package/src/runtime/routes/default-provider-routes.ts +15 -0
  494. package/src/runtime/routes/documents-routes.ts +3 -222
  495. package/src/runtime/routes/inbound-message-handler.ts +21 -45
  496. package/src/runtime/routes/inbound-stages/acl-enforcement.test.ts +0 -1
  497. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +0 -9
  498. package/src/runtime/routes/inbound-stages/admission-policy.ts +1 -17
  499. package/src/runtime/routes/inbound-stages/bootstrap-intercept.test.ts +0 -1
  500. package/src/runtime/routes/inbound-stages/bootstrap-intercept.ts +2 -3
  501. package/src/runtime/routes/inbound-stages/edit-intercept.ts +101 -79
  502. package/src/runtime/routes/inbound-stages/guardian-reply-intercept.test.ts +0 -1
  503. package/src/runtime/routes/inbound-stages/guardian-reply-intercept.ts +12 -7
  504. package/src/runtime/routes/inbound-stages/reaction-intercept.test.ts +91 -8
  505. package/src/runtime/routes/inbound-stages/reaction-intercept.ts +72 -79
  506. package/src/runtime/routes/inbound-stages/secret-ingress-check.ts +2 -3
  507. package/src/runtime/routes/inference-profiles-routes.ts +20 -11
  508. package/src/runtime/routes/inference-provider-connection-routes.ts +77 -15
  509. package/src/runtime/routes/log-export-routes.ts +3 -0
  510. package/src/runtime/routes/mcp-auth-routes.ts +148 -57
  511. package/src/runtime/routes/playground/__tests__/inject-failures.test.ts +2 -0
  512. package/src/runtime/routes/playground/__tests__/reset-circuit.test.ts +3 -0
  513. package/src/runtime/routes/playground/inject-failures.ts +2 -2
  514. package/src/runtime/routes/playground/reset-circuit.ts +1 -1
  515. package/src/runtime/routes/plugins-routes.ts +38 -8
  516. package/src/runtime/routes/schedule-routes.ts +94 -7
  517. package/src/runtime/routes/settings-routes.ts +6 -6
  518. package/src/runtime/routes/stt-routes.ts +31 -25
  519. package/src/runtime/routes/surface-action-routes.ts +20 -19
  520. package/src/runtime/routes/surface-conversation-resolver.ts +3 -0
  521. package/src/runtime/routes/user-route-dispatcher.ts +69 -15
  522. package/src/runtime/routes/user-route-import.ts +108 -0
  523. package/src/runtime/routes/user-route-resolution.ts +18 -1
  524. package/src/runtime/routes/workspace-routes.ts +0 -9
  525. package/src/runtime/routes/workspace-utils.ts +3 -13
  526. package/src/runtime/services/conversation-serializer.ts +7 -2
  527. package/src/schedule/__tests__/plugin-schedule-declarations.test.ts +68 -5
  528. package/src/schedule/__tests__/plugin-schedule-reconciler.test.ts +81 -0
  529. package/src/schedule/plugin-schedule-availability.ts +58 -0
  530. package/src/schedule/plugin-schedule-declarations.ts +23 -27
  531. package/src/schedule/plugin-schedule-reconciler.ts +12 -3
  532. package/src/schedule/schedule-store.ts +5 -1
  533. package/src/schedule/scheduler.ts +9 -4
  534. package/src/schedule/worker-control.ts +1 -0
  535. package/src/schedule/worker.ts +6 -0
  536. package/src/security/oauth2.ts +6 -22
  537. package/src/stt/__tests__/daemon-batch-transcriber.test.ts +22 -0
  538. package/src/stt/__tests__/types.test.ts +94 -0
  539. package/src/stt/daemon-batch-transcriber.ts +10 -0
  540. package/src/stt/stt-stream-session.ts +8 -4
  541. package/src/stt/types.ts +103 -0
  542. package/src/subagent/__tests__/consult-prompt.test.ts +26 -15
  543. package/src/subagent/consult-context.ts +11 -11
  544. package/src/subagent/consult-prompt.ts +26 -35
  545. package/src/subagent/manager.ts +21 -40
  546. package/src/subagent/notify.ts +7 -1
  547. package/src/subagent/types.ts +15 -12
  548. package/src/tools/__tests__/tool-input-schemas.test.ts +7 -7
  549. package/src/tools/acp/spawn.test.ts +97 -0
  550. package/src/tools/acp/spawn.ts +38 -4
  551. package/src/tools/credentials/ref-parse.ts +35 -0
  552. package/src/tools/credentials/resolve.ts +4 -10
  553. package/src/tools/credentials/store.ts +168 -0
  554. package/src/tools/document/document-tool.ts +12 -3
  555. package/src/tools/executor.ts +53 -15
  556. package/src/tools/filesystem/read.ts +27 -10
  557. package/src/tools/host-filesystem/read.ts +27 -15
  558. package/src/tools/network/url-safety.ts +9 -16
  559. package/src/tools/permission-checker.ts +43 -52
  560. package/src/tools/registry.ts +2 -1
  561. package/src/tools/shared/filesystem/file-ops-service.ts +63 -35
  562. package/src/tools/shared/filesystem/legacy-read-args.ts +22 -0
  563. package/src/tools/shared/filesystem/types.ts +5 -5
  564. package/src/tools/skills/scaffold-managed.ts +25 -7
  565. package/src/tools/subagent/spawn.ts +28 -88
  566. package/src/tools/tool-types.ts +26 -13
  567. package/src/tools/types.ts +6 -6
  568. package/src/tools/ui-surface/surface-shape-docs.ts +12 -1
  569. package/src/tools/workflows/run-workflow.ts +1 -2
  570. package/src/tts/__tests__/reasoning-tag-filter.test.ts +78 -0
  571. package/src/tts/reasoning-tag-filter.ts +89 -0
  572. package/src/util/__tests__/worker-process-command.test.ts +37 -0
  573. package/src/util/logger.ts +16 -0
  574. package/src/util/think-tag-stream.ts +95 -0
  575. package/src/util/worker-process.ts +37 -4
  576. package/src/windows-compiled-cli.ts +32 -0
  577. package/src/windows-compiled-entry.ts +4 -0
  578. package/src/windows-compiled-logger.ts +6 -0
  579. package/src/windows-compiled-worker-entry.ts +29 -0
  580. package/src/workspace/byok-default-profile-ensure.ts +76 -24
  581. package/src/workspace/custom-profile-ensure.ts +4 -24
  582. package/src/workspace/migrations/142-consolidate-voice-front-door.ts +70 -0
  583. package/src/workspace/migrations/143-repair-deprecated-codex-model-id.ts +134 -0
  584. package/src/workspace/migrations/144-convert-stranded-subscription-openai-profiles.ts +265 -0
  585. package/src/workspace/migrations/145-collapse-profile-bindings-to-entries.ts +328 -0
  586. package/src/workspace/migrations/146-repair-retired-fireworks-deepseek-flash-model-id.ts +195 -0
  587. package/src/workspace/migrations/__tests__/141-stt-english-default-to-multilingual.test.ts +0 -10
  588. package/src/workspace/migrations/registry.ts +10 -0
  589. package/src/workspace/provider-commit-message-generator.ts +7 -5
  590. package/src/__tests__/document-workspace-file.test.ts +0 -467
  591. package/src/live-voice/__tests__/front-decision.test.ts +0 -645
  592. package/src/live-voice/front-decision.ts +0 -476
  593. package/src/permissions/ipc-risk-types.ts +0 -143
  594. package/src/permissions/risk-types.ts +0 -76
  595. package/src/subagent/__tests__/consult-transcript.test.ts +0 -184
  596. package/src/subagent/consult-transcript.ts +0 -90
@@ -0,0 +1,361 @@
1
+ /**
2
+ * Plugin-contributed MCP servers.
3
+ *
4
+ * A plugin declares MCP servers in a root `mcp.json`, per the Agent
5
+ * Plugins 1.0.0 specification:
6
+ *
7
+ * {
8
+ * "$schema": "https://agent-plugins.org/schemas/1.0.0/mcp.schema.json",
9
+ * "mcpServers": {
10
+ * "unabyss": { "type": "streamable-http", "url": "https://mcp.unabyss.com" }
11
+ * }
12
+ * }
13
+ *
14
+ * This module reads those files and projects each entry onto the
15
+ * assistant's own `McpServerConfig` shape, so a plugin-declared server can
16
+ * flow through the same surfaces as one configured in the workspace
17
+ * `config.json`.
18
+ *
19
+ * Failure isolation follows the spec: an invalid top-level `mcp.json`
20
+ * disables MCP for that plugin only, and an invalid individual server
21
+ * disables only that entry. Neither ever throws, because a malformed file
22
+ * in one plugin must not remove another plugin's servers from a listing.
23
+ *
24
+ * Authentication is deliberately absent. Agent Plugins 1.0.0 defines no
25
+ * portable OAuth or credential-reference fields; authentication is
26
+ * client-managed, and any `headers` in the file are literal package data.
27
+ * A plugin therefore cannot ship a credential, and the assistant's own
28
+ * credential store stays the only place secrets live.
29
+ *
30
+ * Consumers must not resolve a plugin server's id against the
31
+ * `mcp:<serverId>:*` credential namespace. Those keys belong to
32
+ * workspace-configured servers, and a plugin controls both its server key
33
+ * and its URL, so honoring them for a plugin-declared server would send a
34
+ * workspace credential to an endpoint the plugin chose. Every config built
35
+ * here carries `source: "plugin"`, which is what `McpClient` reads to
36
+ * decide, so the rule travels with the server rather than with the caller.
37
+ */
38
+
39
+ import { existsSync, readFileSync } from "node:fs";
40
+ import { join } from "node:path";
41
+
42
+ import { z } from "zod";
43
+
44
+ import {
45
+ type AllPluginInfo,
46
+ listAllPlugins,
47
+ type ListInstalledPluginsOptions,
48
+ } from "../cli/lib/list-installed-plugins.js";
49
+ import type {
50
+ McpTransport,
51
+ ResolvedMcpServerConfig,
52
+ } from "../config/schemas/mcp.js";
53
+ import { getLogger } from "../util/logger.js";
54
+
55
+ const log = getLogger("plugin-mcp-servers");
56
+
57
+ /** Filename a plugin declares its MCP servers in, at the plugin root. */
58
+ export const PLUGIN_MCP_MANIFEST = "mcp.json";
59
+
60
+ /**
61
+ * Risk level assigned to a plugin-declared server. `mcp.json` has no risk
62
+ * field, since the spec defines none, so a host default applies.
63
+ *
64
+ * `low` — so a plugin's tools run without prompting under the default
65
+ * auto-approve threshold — because the review happens earlier: the
66
+ * marketplace catalog (`plugins/marketplace.json`) is a curated whitelist
67
+ * of SHA-pinned entries, and installing a plugin is itself the user's
68
+ * decision to run the code it ships. Gating every call afterwards prompts
69
+ * on the tools the user installed the plugin to get.
70
+ *
71
+ * The gap this leaves is deliberate and known: a plugin installed
72
+ * off-marketplace straight from a GitHub URL gets the same default, and
73
+ * nothing recorded at install time distinguishes the two afterwards. A
74
+ * provenance signal is what would let this default be curation-gated
75
+ * rather than blanket. The user can still override per server — see the
76
+ * `defaultRiskLevel` field on a workspace `config.json` entry, which
77
+ * outranks a plugin's declaration of the same id.
78
+ */
79
+ const PLUGIN_SERVER_DEFAULT_RISK = "low" as const;
80
+
81
+ /** Matches the `maxTools` default in `McpServerConfigSchema`. */
82
+ const PLUGIN_SERVER_DEFAULT_MAX_TOOLS = 20;
83
+
84
+ // ---------------------------------------------------------------------------
85
+ // Wire schema (Agent Plugins 1.0.0)
86
+ // ---------------------------------------------------------------------------
87
+
88
+ const PluginStdioServerSchema = z.object({
89
+ type: z.literal("stdio"),
90
+ command: z.string().min(1),
91
+ args: z.array(z.string()).optional(),
92
+ env: z.record(z.string(), z.string()).optional(),
93
+ cwd: z.string().optional(),
94
+ });
95
+
96
+ const PluginHttpServerSchema = z.object({
97
+ type: z.enum(["streamable-http", "sse"]),
98
+ url: z.string().min(1),
99
+ headers: z.record(z.string(), z.string()).optional(),
100
+ });
101
+
102
+ const PluginMcpServerSchema = z.discriminatedUnion("type", [
103
+ PluginStdioServerSchema,
104
+ PluginHttpServerSchema,
105
+ ]);
106
+
107
+ const PluginMcpManifestSchema = z.object({
108
+ mcpServers: z.record(z.string(), z.unknown()),
109
+ });
110
+
111
+ // ---------------------------------------------------------------------------
112
+ // Public shape
113
+ // ---------------------------------------------------------------------------
114
+
115
+ /** One MCP server declared by one plugin. */
116
+ export interface PluginMcpServer {
117
+ /** Server id in the assistant's namespace. See {@link buildServerId}. */
118
+ readonly id: string;
119
+ /** Directory name of the plugin that declared it. */
120
+ readonly pluginName: string;
121
+ /** Key this server appears under in the plugin's `mcp.json`. */
122
+ readonly serverKey: string;
123
+ /** Projected onto the assistant's own server-config shape. */
124
+ readonly config: ResolvedMcpServerConfig;
125
+ }
126
+
127
+ /** A plugin's `mcp.json` that could not be used, in whole or in part. */
128
+ export interface PluginMcpIssue {
129
+ readonly pluginName: string;
130
+ /** Absent when the whole manifest is unusable rather than one entry. */
131
+ readonly serverKey?: string;
132
+ readonly message: string;
133
+ }
134
+
135
+ export interface PluginMcpServersResult {
136
+ readonly servers: readonly PluginMcpServer[];
137
+ readonly issues: readonly PluginMcpIssue[];
138
+ }
139
+
140
+ /**
141
+ * Server id for a plugin-declared server.
142
+ *
143
+ * Plugin servers share one namespace with workspace servers and with each
144
+ * other, so the plugin name is the qualifier. The redundant case is
145
+ * collapsed: a plugin named `unabyss` whose server key is also `unabyss`
146
+ * yields `unabyss`, not `unabyss__unabyss`, which matters because the id
147
+ * is embedded in every tool name the server contributes
148
+ * (`mcp__<id>__<tool>`).
149
+ */
150
+ export function buildServerId(pluginName: string, serverKey: string): string {
151
+ return pluginName === serverKey ? pluginName : `${pluginName}__${serverKey}`;
152
+ }
153
+
154
+ /**
155
+ * Expand the two path variables the Agent Plugins spec defines for stdio
156
+ * servers. They interpolate textually in `args`, `env` values, and `cwd`
157
+ * only, never in `command`, a URL, or a header, so a manifest cannot use
158
+ * them to build the executable path itself.
159
+ */
160
+ export function interpolatePluginPaths(
161
+ value: string,
162
+ pluginRoot: string,
163
+ pluginData: string,
164
+ ): string {
165
+ return value
166
+ .replaceAll("${PLUGIN_ROOT}", pluginRoot)
167
+ .replaceAll("${PLUGIN_DATA}", pluginData);
168
+ }
169
+
170
+ /**
171
+ * Whether a directory is a plugin the runtime would actually load.
172
+ *
173
+ * `listAllPlugins` is an inventory of directories and reports a malformed
174
+ * entry rather than dropping it, so it happily returns a directory with no
175
+ * usable `package.json`. The runtime loader rejects those in
176
+ * `parsePluginManifest`: the manifest must parse and carry a non-empty
177
+ * `name`. Applying the same gate here keeps `mcp.json` from being honored
178
+ * for a directory that will never load as a plugin.
179
+ */
180
+ export function hasLoadableManifest(plugin: AllPluginInfo): boolean {
181
+ const name = plugin.packageJson?.name;
182
+ return typeof name === "string" && name.length > 0;
183
+ }
184
+
185
+ // ---------------------------------------------------------------------------
186
+ // Reading
187
+ // ---------------------------------------------------------------------------
188
+
189
+ /**
190
+ * Read every installed plugin's `mcp.json` and return the servers they
191
+ * declare, plus anything that could not be read.
192
+ *
193
+ * A disabled plugin is skipped entirely: `.disabled` means the plugin
194
+ * contributes no hooks and no tools, and an MCP server it declares is no
195
+ * different.
196
+ */
197
+ export function readPluginMcpServers(
198
+ opts: ListInstalledPluginsOptions = {},
199
+ ): PluginMcpServersResult {
200
+ const servers: PluginMcpServer[] = [];
201
+ const issues: PluginMcpIssue[] = [];
202
+ const seen = new Map<string, string>();
203
+
204
+ let plugins: readonly AllPluginInfo[];
205
+ try {
206
+ plugins = listAllPlugins(opts);
207
+ } catch (err) {
208
+ // The plugins directory being unreadable is not a reason to fail a
209
+ // listing that also has workspace-configured servers in it.
210
+ log.warn({ err }, "Could not enumerate plugins for MCP declarations");
211
+ return { servers: [], issues: [] };
212
+ }
213
+
214
+ for (const plugin of plugins) {
215
+ if (plugin.disabled) {
216
+ continue;
217
+ }
218
+ const manifestPath = join(plugin.target, PLUGIN_MCP_MANIFEST);
219
+ if (!existsSync(manifestPath)) {
220
+ continue;
221
+ }
222
+
223
+ if (!hasLoadableManifest(plugin)) {
224
+ issues.push({
225
+ pluginName: plugin.name,
226
+ message: `${PLUGIN_MCP_MANIFEST} ignored: package.json is missing, unparseable, or has no name, so the runtime will not load this directory as a plugin`,
227
+ });
228
+ continue;
229
+ }
230
+
231
+ const parsed = parseManifest(manifestPath);
232
+ if ("error" in parsed) {
233
+ issues.push({ pluginName: plugin.name, message: parsed.error });
234
+ continue;
235
+ }
236
+
237
+ for (const [serverKey, raw] of Object.entries(parsed.mcpServers)) {
238
+ if (serverKey.trim().length === 0) {
239
+ issues.push({
240
+ pluginName: plugin.name,
241
+ message: "server key must be a non-empty string; skipping",
242
+ });
243
+ continue;
244
+ }
245
+
246
+ const entry = PluginMcpServerSchema.safeParse(raw);
247
+ if (!entry.success) {
248
+ issues.push({
249
+ pluginName: plugin.name,
250
+ serverKey,
251
+ message: `invalid server entry: ${entry.error.issues
252
+ .map((i) => `${i.path.join(".") || "<root>"}: ${i.message}`)
253
+ .join("; ")}`,
254
+ });
255
+ continue;
256
+ }
257
+
258
+ const id = buildServerId(plugin.name, serverKey);
259
+ const previous = seen.get(id);
260
+ if (previous) {
261
+ // Two plugins claiming one id would silently shadow each other, and
262
+ // the loser's tools would just be missing. Report both instead.
263
+ issues.push({
264
+ pluginName: plugin.name,
265
+ serverKey,
266
+ message: `server id "${id}" is already declared by plugin "${previous}"; skipping`,
267
+ });
268
+ continue;
269
+ }
270
+ seen.set(id, plugin.name);
271
+
272
+ // The spec allows `cwd` on a stdio server; the assistant's transport
273
+ // has no such field. Dropping it silently would leave a server that
274
+ // resolves its relative paths against the wrong directory and fails
275
+ // for no visible reason, so say so.
276
+ if (entry.data.type === "stdio" && entry.data.cwd) {
277
+ issues.push({
278
+ pluginName: plugin.name,
279
+ serverKey,
280
+ message: `"cwd" is not supported by this host and was ignored; the server runs in the daemon's working directory`,
281
+ });
282
+ }
283
+
284
+ servers.push({
285
+ id,
286
+ pluginName: plugin.name,
287
+ serverKey,
288
+ config: {
289
+ transport: projectTransport(entry.data, plugin.target),
290
+ enabled: true,
291
+ defaultRiskLevel: PLUGIN_SERVER_DEFAULT_RISK,
292
+ maxTools: PLUGIN_SERVER_DEFAULT_MAX_TOOLS,
293
+ source: "plugin",
294
+ },
295
+ });
296
+ }
297
+ }
298
+
299
+ return { servers, issues };
300
+ }
301
+
302
+ function parseManifest(
303
+ path: string,
304
+ ): { mcpServers: Record<string, unknown> } | { error: string } {
305
+ let raw: string;
306
+ try {
307
+ raw = readFileSync(path, "utf8");
308
+ } catch (err) {
309
+ return {
310
+ error: `${PLUGIN_MCP_MANIFEST} unreadable: ${err instanceof Error ? err.message : String(err)}`,
311
+ };
312
+ }
313
+
314
+ let json: unknown;
315
+ try {
316
+ json = JSON.parse(raw);
317
+ } catch (err) {
318
+ return {
319
+ error: `${PLUGIN_MCP_MANIFEST} invalid JSON: ${err instanceof Error ? err.message : String(err)}`,
320
+ };
321
+ }
322
+
323
+ const manifest = PluginMcpManifestSchema.safeParse(json);
324
+ if (!manifest.success) {
325
+ return {
326
+ error: `${PLUGIN_MCP_MANIFEST} is missing a valid "mcpServers" object`,
327
+ };
328
+ }
329
+ return { mcpServers: manifest.data.mcpServers };
330
+ }
331
+
332
+ /**
333
+ * Project one spec-shaped entry onto the assistant's transport union. The
334
+ * two vocabularies already agree on type names and required fields, so this
335
+ * is a field copy plus path interpolation for the stdio case.
336
+ */
337
+ function projectTransport(
338
+ entry: z.infer<typeof PluginMcpServerSchema>,
339
+ pluginRoot: string,
340
+ ): McpTransport {
341
+ if (entry.type === "stdio") {
342
+ const pluginData = join(pluginRoot, "data");
343
+ const expand = (v: string): string =>
344
+ interpolatePluginPaths(v, pluginRoot, pluginData);
345
+ return {
346
+ type: "stdio",
347
+ command: entry.command,
348
+ args: (entry.args ?? []).map(expand),
349
+ ...(entry.env && {
350
+ env: Object.fromEntries(
351
+ Object.entries(entry.env).map(([k, v]) => [k, expand(v)]),
352
+ ),
353
+ }),
354
+ };
355
+ }
356
+ return {
357
+ type: entry.type,
358
+ url: entry.url,
359
+ ...(entry.headers && { headers: entry.headers }),
360
+ };
361
+ }
@@ -26,9 +26,9 @@
26
26
  * - Plugins are never "registered" as a unit — we register their tools into
27
27
  * the global tool registry.
28
28
  *
29
- * Tools are populated at boot by `loadUserPlugins()`; `getHooksFor` reads
30
- * hooks on every dispatch via {@link getUserHookEntriesFor}, which resolves
31
- * each hook through the hook loader on demand.
29
+ * Tools are populated at boot by `loadUserPlugins()`; hook dispatch reads
30
+ * discovered plugin names from this cache via {@link getDiscoveredUserPluginNames}
31
+ * and resolves each hook through the hook loader on demand.
32
32
  */
33
33
 
34
34
  import { existsSync, readdirSync, readFileSync, statSync } from "node:fs";
@@ -38,7 +38,6 @@ import type { Logger } from "pino";
38
38
 
39
39
  import {
40
40
  clearPluginHooks,
41
- collectUserHookEntries,
42
41
  evictHooksForOwner,
43
42
  hasWorkspaceHooks,
44
43
  type HookOwnerKind,
@@ -47,7 +46,7 @@ import {
47
46
  runShutdownHook,
48
47
  WORKSPACE_HOOKS_OWNER,
49
48
  } from "../hooks/hook-loader.js";
50
- import type { HookFunction, ShutdownReason } from "../plugin-api/types.js";
49
+ import type { ShutdownReason } from "../plugin-api/types.js";
51
50
  import {
52
51
  registerPluginSecretPatterns,
53
52
  resetPluginSecretPatternsForTests,
@@ -76,11 +75,7 @@ import {
76
75
  importWithTimeout,
77
76
  setSurfaceImportTimeout,
78
77
  } from "./surface-import.js";
79
- import type { HookEntry, PluginCredentialKeyPattern } from "./types.js";
80
-
81
- // Re-export for type compat — consumers that import HookFunction from
82
- // the mtime cache module still resolve.
83
- export type { HookFunction } from "./types.js";
78
+ import type { PluginCredentialKeyPattern } from "./types.js";
84
79
 
85
80
  const log = getLogger("plugin-mtime-cache");
86
81
 
@@ -206,48 +201,32 @@ let lastVersions: Record<string, PluginSourceVersion> = {};
206
201
  /** In-flight reconcile — concurrent imperative pokes await it rather than racing. */
207
202
  let reconcileInFlight: Promise<void> | null = null;
208
203
 
209
- // ─── Hook reads ──────────────────────────────────────────────────────────────
204
+ // ─── Discovery reads ─────────────────────────────────────────────────────────
210
205
 
211
206
  /**
212
- * Get all hooks for a given event name from user plugins and standalone
213
- * workspace hooks, from the hook loader's in-memory cache. Plugin hooks run
214
- * in install-date order, the workspace hook runs last.
215
- *
216
- * This is a pure cache read: it never scans disk, activates a plugin, or
217
- * runs `init`. Activation happens only at boot ({@link populateCacheAtBoot})
218
- * and through the imperative install/uninstall poke
219
- * ({@link reconcilePluginSourcesNow}) — both main-daemon paths — so a
220
- * sidecar process that dispatches hooks (a worker running conversation
221
- * turns) can never bring a plugin up in its own process.
222
- *
223
- * `effectiveEnabledPlugins` carries the per-chat plugin scope: when non-null,
224
- * user plugins outside the set are skipped (standalone workspace hooks always
225
- * run). `null`/omitted means no per-chat restriction.
207
+ * Plugin names currently in the discovery cache, in install-date order.
208
+ * Hook lookup in `hooks/registry.ts` walks this set; the cache itself does
209
+ * not resolve hooks.
226
210
  */
227
- export async function getUserHookEntriesFor<TCtx = unknown>(
228
- hookName: string,
229
- effectiveEnabledPlugins?: Set<string> | null,
230
- ): Promise<HookEntry<TCtx>[]> {
231
- return collectUserHookEntries<TCtx>(
232
- hookName,
233
- discoveredPluginDirs.values(),
234
- effectiveEnabledPlugins,
235
- );
211
+ export function getDiscoveredUserPluginNames(): Iterable<string> {
212
+ return discoveredPluginDirs.values();
236
213
  }
237
214
 
238
215
  /**
239
- * {@link getUserHookEntriesFor} without owner attribution — returns just the
240
- * hook functions in the same order.
216
+ * True when this daemon process brought the plugin directory `dir` up:
217
+ * {@link bringUpPlugin} ran for it and its `init` was attempted. An `init` that
218
+ * threw still counts, because activation never aborts on init failure (see
219
+ * {@link activatePlugin}), and that is deliberate: an init-failed plugin's
220
+ * hooks and tools stay live, so its schedules must too. What membership
221
+ * excludes is a directory dropped in out-of-band that no boot scan and no
222
+ * reconcile pass has activated yet.
223
+ *
224
+ * The backing map is per-process, so a process that runs no plugin loader (the
225
+ * schedule worker, sidecar turn workers) reads `false` for every directory.
226
+ * Only code that provably runs in the main daemon may treat this as an answer.
241
227
  */
242
- export async function getUserHooksFor<TCtx = unknown>(
243
- hookName: string,
244
- effectiveEnabledPlugins?: Set<string> | null,
245
- ): Promise<HookFunction<TCtx>[]> {
246
- const entries = await getUserHookEntriesFor<TCtx>(
247
- hookName,
248
- effectiveEnabledPlugins,
249
- );
250
- return entries.map((e) => e.fn);
228
+ export function isPluginDirActivated(dir: string): boolean {
229
+ return discoveredPluginDirs.has(dir);
251
230
  }
252
231
 
253
232
  // ─── Source-versions reconcile ───────────────────────────────────────────────
@@ -300,6 +279,18 @@ export async function reconcilePluginSourcesNow(): Promise<void> {
300
279
  } catch (err) {
301
280
  log.error({ err }, "plugin schedule reconcile failed");
302
281
  }
282
+ // Converge plugin-declared MCP servers the same way, so an install
283
+ // brings its `mcp.json` servers up and an uninstall/disable takes their
284
+ // connected clients and registered tools back down. Reloads only when
285
+ // the declared set actually moved. Lazily imported for the same reason
286
+ // as the schedule reconciler, and equally self-contained.
287
+ try {
288
+ const { reconcilePluginMcpServers } =
289
+ await import("../daemon/mcp-reload-service.js");
290
+ await reconcilePluginMcpServers();
291
+ } catch (err) {
292
+ log.error({ err }, "plugin MCP reconcile failed");
293
+ }
303
294
  })().finally(() => {
304
295
  reconcileInFlight = null;
305
296
  });
@@ -1080,7 +1071,7 @@ async function deactivatePlugin(
1080
1071
  * Called by `loadUserPlugins()` during daemon startup. After boot, the same
1081
1072
  * `activatePlugin`/`deactivatePlugin` reconciliation runs only through the
1082
1073
  * imperative poke ({@link reconcilePluginSourcesNow}) the install/uninstall/
1083
- * enable/disable routes call, so plugin lifecycle stays confined to the main
1074
+ * upgrade/enable routes call, so plugin lifecycle stays confined to the main
1084
1075
  * daemon — dispatch-time hook and tool reads never activate anything.
1085
1076
  */
1086
1077
  export async function populateCacheAtBoot(
@@ -25,7 +25,10 @@ import { getHookEntriesFor } from "../hooks/registry.js";
25
25
  import type { BaseHookContext } from "../hooks/types.js";
26
26
  import { type HookName, HOOKS } from "../plugin-api/constants.js";
27
27
  import { getLogger } from "../util/logger.js";
28
- import { runInPluginContext } from "./plugin-execution-context.js";
28
+ import {
29
+ runInPluginContext,
30
+ runOutsidePluginContext,
31
+ } from "./plugin-execution-context.js";
29
32
  import type { HookEntry } from "./types.js";
30
33
 
31
34
  // ─── Hook runner ────────────────────────────────────────────────────────────
@@ -303,9 +306,10 @@ export async function callWithTimeout<T>(
303
306
  *
304
307
  * When `initialCtx` carries a `conversationId`, it is passed to
305
308
  * {@link getHookEntriesFor}, which resolves the conversation's per-chat plugin
306
- * scope (memory, then DB) and skips a hook whose contributing plugin is outside
307
- * the effective set. Contexts without a `conversationId` impose no restriction —
308
- * every globally-enabled plugin's hook runs.
309
+ * scope (memory, then DB) and skips a user-plugin hook whose owner is
310
+ * outside the effective set. First-party default plugins always run (unless
311
+ * workspace-disabled). Contexts without a `conversationId` impose no
312
+ * restriction: every globally-enabled plugin's hook runs.
309
313
  *
310
314
  * Before each hook runs, the pipeline stamps the {@link BaseHookContext}
311
315
  * capabilities onto its (freshly-cloned) draft, both bound to that hook's
@@ -354,12 +358,15 @@ export async function runHook<TInput extends object>(
354
358
  };
355
359
  try {
356
360
  // Mark the contributing plugin as in context so host APIs the hook
357
- // reaches (e.g. resolveCredential) can scope to it. Standalone workspace
358
- // hooks are not plugins and establish no context.
361
+ // reaches (e.g. resolveCredential) can scope to it. A standalone
362
+ // workspace hook is not a plugin, and runs with the context explicitly
363
+ // cleared rather than merely unset: the turn may have been started by a
364
+ // plugin (a route handler calling `runConversationTurn`), and this hook
365
+ // must not inherit that plugin's identity.
359
366
  const invokeHook =
360
367
  owner.kind === "plugin"
361
368
  ? () => runInPluginContext(owner.id, () => fn(draft))
362
- : () => fn(draft);
369
+ : () => runOutsidePluginContext(() => fn(draft));
363
370
  const result = await callWithTimeout(
364
371
  invokeHook,
365
372
  HOOK_TIMEOUT_MS,
@@ -1,25 +1,35 @@
1
1
  /**
2
- * Plugin execution context — tracks which plugin's code is currently running.
2
+ * Plugin execution context. Tracks which plugin's code is currently running.
3
3
  *
4
4
  * Host APIs exposed to plugins through `@vellumai/plugin-api` sometimes need to
5
5
  * know *which* plugin is calling them so they can scope their behavior to that
6
6
  * plugin (e.g. {@link ../plugin-api/resolve-credential.resolveCredential} limits
7
7
  * a plugin to its own credentials). A plugin's manifest name is not threaded
8
- * through every host call, so the pipeline that invokes a plugin's hook — and
9
- * the tool executor that runs a plugin's tool — mark the plugin as "in context"
10
- * for the duration of that invocation via an {@link AsyncLocalStorage}. Host
11
- * APIs read {@link getCurrentPluginName} to recover it.
8
+ * through every host call, so every seam that enters a plugin's code marks the
9
+ * plugin as "in context" for the duration of that invocation via an
10
+ * {@link AsyncLocalStorage}: the pipeline that invokes its hook, the executor
11
+ * that runs its tool, and the dispatcher that serves its
12
+ * `/x/plugins/<name>/` routes. Host APIs read {@link getCurrentPluginName} to
13
+ * recover it.
12
14
  *
13
15
  * The store propagates across `await` boundaries, so a plugin that awaits a
14
- * host API deep inside its hook/tool body is still seen as in context. When no
15
- * plugin is in context (host-internal callers, the CLI, tests), the store is
16
- * empty and scoped APIs fall back to their unscoped behavior.
16
+ * host API deep inside its hook/tool/route body is still seen as in context.
17
+ * That propagation is why the same seams clear the context on the way back out
18
+ * to host code ({@link runOutsidePluginContext}): a plugin route can start a
19
+ * whole conversation turn, and the host tools and workspace hooks that turn
20
+ * runs are not the plugin's code, so they must not inherit its identity.
21
+ *
22
+ * When no plugin is in context (host-internal callers, the CLI, tests), the
23
+ * store is empty and scoped APIs fall back to their unscoped behavior.
17
24
  */
18
25
 
19
26
  import { AsyncLocalStorage } from "node:async_hooks";
20
27
 
21
28
  export interface PluginExecutionContext {
22
- /** Manifest name of the plugin whose hook or tool is currently executing. */
29
+ /**
30
+ * Manifest name of the plugin whose hook, tool, or route is currently
31
+ * executing.
32
+ */
23
33
  pluginName: string;
24
34
  }
25
35
 
@@ -36,8 +46,22 @@ export function runInPluginContext<T>(pluginName: string, fn: () => T): T {
36
46
  }
37
47
 
38
48
  /**
39
- * Name of the plugin whose hook or tool is currently executing, or `undefined`
40
- * when no plugin is in context.
49
+ * Run `fn` with no plugin in context, whatever the caller is running inside.
50
+ *
51
+ * Host code reached *from* a plugin (a default tool executed during a turn a
52
+ * plugin route started, a workspace hook fired inside a plugin's hook) is not
53
+ * the plugin's code and must not borrow its identity: scoped APIs would
54
+ * attribute the host's work to that plugin, or refuse it for being out of the
55
+ * plugin's scope. The seams that dispatch non-plugin code call this so the
56
+ * store reflects who is really running rather than who started the chain.
57
+ */
58
+ export function runOutsidePluginContext<T>(fn: () => T): T {
59
+ return storage.exit(fn);
60
+ }
61
+
62
+ /**
63
+ * Name of the plugin whose hook, tool, or route is currently executing, or
64
+ * `undefined` when no plugin is in context.
41
65
  */
42
66
  export function getCurrentPluginName(): string | undefined {
43
67
  return storage.getStore()?.pluginName;
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Default-plugin surface for sidecar worker processes.
3
+ *
4
+ * Worker processes that run real agent conversations (the memory jobs worker,
5
+ * the schedule worker) register the first-party default plugins' hooks and
6
+ * runtime injectors so those conversations get the same hook-driven behavior as
7
+ * conversations in the daemon: image captioning and vision-rejection recovery,
8
+ * tool-result truncation, history repair, and the per-turn runtime injections.
9
+ * Hook and injector dispatch is process-global, so one call at worker startup
10
+ * covers every conversation that process runs.
11
+ *
12
+ * Plugin `init` hooks are deliberately not run here. Registration is pure
13
+ * hook-table and injector-table population, and the default plugins degrade
14
+ * gracefully without their init-owned state (the image-fallback caption cache
15
+ * falls back to in-memory caching when its SQLite handle is absent). The memory
16
+ * plugin's init must never run in a worker: it starts the memory jobs worker
17
+ * process itself.
18
+ */
19
+
20
+ import {
21
+ registerDefaultPluginInjectors,
22
+ registerDefaultPlugins,
23
+ } from "./defaults/index.js";
24
+
25
+ /**
26
+ * Register the first-party default plugins' hooks and runtime injectors in the
27
+ * current process. Both registration functions are idempotent, so repeat calls
28
+ * are safe.
29
+ */
30
+ export function registerWorkerPluginSurface(): void {
31
+ registerDefaultPlugins();
32
+ registerDefaultPluginInjectors();
33
+ }
@@ -267,13 +267,6 @@ export const BUNDLED_SYSTEM_SECTIONS: readonly BundledSection[] = [
267
267
  body: "",
268
268
  enabled: "!excludeCustomPrefix",
269
269
  },
270
- {
271
- id: "01-delegate-subagents",
272
- body: `## Delegate independent work
273
-
274
- When part of a task can run on its own — a research sweep, a multi-file investigation, a build-and-test loop — hand it off instead of grinding through it inline: load the \`subagent\` skill, then \`subagent_spawn\` early and in parallel. Make delegating that kind of work your default, not a last resort; an unnecessary subagent is cheaper than serialized work, and a long inline dig floods your own context.
275
- `,
276
- },
277
270
  {
278
271
  id: "01-parallel-tool-calls",
279
272
  body: `<use_parallel_tool_calls>