@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,161 @@
1
+ /**
2
+ * Channels that installed plugins bring.
3
+ *
4
+ * `getWorkspacePluginsDir` is mocked to a scratch directory so these read real
5
+ * files off disk without touching the machine's workspace.
6
+ */
7
+
8
+ import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
9
+ import { tmpdir } from "node:os";
10
+ import { join } from "node:path";
11
+ import { afterAll, beforeEach, describe, expect, mock, test } from "bun:test";
12
+
13
+ const workspacePluginsDir = mkdtempSync(join(tmpdir(), "plugin-channels-"));
14
+
15
+ const realPlatform = await import("../../util/platform.js");
16
+
17
+ mock.module("../../util/platform.js", () => ({
18
+ ...realPlatform,
19
+ getWorkspacePluginsDir: () => workspacePluginsDir,
20
+ }));
21
+
22
+ const { discoverPluginChannels } = await import(
23
+ "../plugin-channel-declarations.js"
24
+ );
25
+
26
+ interface PluginOptions {
27
+ /** Contents of `channels/ingress.json`; omit for a plugin with no ingress. */
28
+ ingress?: string;
29
+ manifest?: Record<string, unknown>;
30
+ }
31
+
32
+ const INGRESS = JSON.stringify({
33
+ routes: [{ path: "events", kind: "http", description: "inbound" }],
34
+ });
35
+
36
+ function writePlugin(name: string, options: PluginOptions = {}): string {
37
+ const dir = join(workspacePluginsDir, name);
38
+ mkdirSync(dir, { recursive: true });
39
+ writeFileSync(
40
+ join(dir, "package.json"),
41
+ JSON.stringify({ name, ...options.manifest }),
42
+ );
43
+ if (options.ingress !== undefined) {
44
+ mkdirSync(join(dir, "channels"), { recursive: true });
45
+ writeFileSync(join(dir, "channels", "ingress.json"), options.ingress);
46
+ }
47
+ return dir;
48
+ }
49
+
50
+ beforeEach(() => {
51
+ rmSync(workspacePluginsDir, { recursive: true, force: true });
52
+ mkdirSync(workspacePluginsDir, { recursive: true });
53
+ });
54
+
55
+ afterAll(() => {
56
+ rmSync(workspacePluginsDir, { recursive: true, force: true });
57
+ });
58
+
59
+ describe("discoverPluginChannels", () => {
60
+ test("a plugin is a channel because it declares ingress", async () => {
61
+ writePlugin("courier", {
62
+ ingress: INGRESS,
63
+ manifest: {
64
+ displayName: "Courier",
65
+ description: "Reach the assistant by carrier pigeon.",
66
+ icon: "send",
67
+ },
68
+ });
69
+
70
+ expect(await discoverPluginChannels()).toEqual([
71
+ {
72
+ id: "courier",
73
+ source: "plugin:courier",
74
+ label: "Courier",
75
+ subtitle: "Reach the assistant by carrier pigeon.",
76
+ icon: "send",
77
+ supportsVerification: false,
78
+ setupMessages: {
79
+ guardian: "I want to set up Courier. Can you help me?",
80
+ contact:
81
+ "I'd like to reach you on Courier. Can you help me get set up?",
82
+ },
83
+ },
84
+ ]);
85
+ });
86
+
87
+ test("ignores a plugin that declares no ingress", async () => {
88
+ // Presentation alone does not make a channel: reaching the assistant from
89
+ // outside is what one is, and ingress is where that is declared.
90
+ writePlugin("notes", { manifest: { displayName: "Notes", icon: "send" } });
91
+
92
+ expect(await discoverPluginChannels()).toEqual([]);
93
+ });
94
+
95
+ test("surfaces a channel whose ingress the gateway would reject", async () => {
96
+ // Validation belongs to the gateway, which owns the schema. A plugin with
97
+ // a broken declaration is a channel with broken ingress, and saying so
98
+ // beats dropping it off the page a guardian would look at.
99
+ writePlugin("courier", {
100
+ ingress: "{ not json",
101
+ manifest: { displayName: "Courier" },
102
+ });
103
+
104
+ expect((await discoverPluginChannels())[0]?.label).toBe("Courier");
105
+ });
106
+
107
+ test("skips a disabled plugin", async () => {
108
+ // Same source of truth the loader uses for hooks, tools and routes: a
109
+ // disabled plugin would otherwise offer a setup flow that cannot run.
110
+ const dir = writePlugin("courier", { ingress: INGRESS });
111
+ writeFileSync(join(dir, ".disabled"), "");
112
+
113
+ expect(await discoverPluginChannels()).toEqual([]);
114
+ });
115
+
116
+ test("refuses to let a plugin take a built-in channel's id", async () => {
117
+ // Two rows sharing an id would be ambiguous to any client keying on one,
118
+ // and letting the plugin win would let it impersonate a built-in.
119
+ writePlugin("slack", {
120
+ ingress: INGRESS,
121
+ manifest: { displayName: "Slack" },
122
+ });
123
+
124
+ expect(await discoverPluginChannels()).toEqual([]);
125
+ });
126
+
127
+ test("titles a plugin that names no display name", async () => {
128
+ // Presentation is best-effort, so a bare manifest costs a nicer title and
129
+ // never the row itself.
130
+ writePlugin("meeting-bot", { ingress: INGRESS });
131
+
132
+ expect(await discoverPluginChannels()).toMatchObject([
133
+ {
134
+ id: "meeting-bot",
135
+ source: "plugin:meeting-bot",
136
+ label: "Meeting Bot",
137
+ subtitle: "Provided by the Meeting Bot plugin",
138
+ icon: "message-square",
139
+ },
140
+ ]);
141
+ });
142
+
143
+ test("still lists a channel whose manifest cannot be read", async () => {
144
+ // The directory is the plugin's identity, so an unparseable manifest
145
+ // costs its presentation and not its existence.
146
+ const dir = writePlugin("courier", { ingress: INGRESS });
147
+ writeFileSync(join(dir, "package.json"), "{ not json");
148
+
149
+ expect((await discoverPluginChannels())[0]?.label).toBe("Courier");
150
+ });
151
+
152
+ test("never claims a plugin channel supports verification", async () => {
153
+ // There is no client-side verification flow for one, so clients render it
154
+ // display-only rather than pre-warming a status that cannot arrive.
155
+ writePlugin("courier", { ingress: INGRESS });
156
+
157
+ expect((await discoverPluginChannels())[0]?.supportsVerification).toBe(
158
+ false,
159
+ );
160
+ });
161
+ });
@@ -86,6 +86,19 @@ const CHANNEL_POLICIES = {
86
86
  conversationStrategy: "continue_existing_conversation",
87
87
  },
88
88
  },
89
+ plugin: {
90
+ notification: {
91
+ // Every plugin-brought channel shares this row, so the answer has to
92
+ // hold for all of them. A reply to an inbound plugin message routes by
93
+ // `replyCallbackUrl` and does not read this flag; proactive notification
94
+ // does, and it needs a guardian binding plus a destination resolver to
95
+ // reach. Neither exists per-plugin, and `NotificationChannel` is derived
96
+ // from this flag, so enabling it would let the decision engine pick a
97
+ // channel that resolves to nothing for whichever plugin it landed on.
98
+ deliveryEnabled: false,
99
+ conversationStrategy: "continue_existing_conversation",
100
+ },
101
+ },
89
102
  } as const satisfies Record<ChannelId, ChannelNotificationPolicy>;
90
103
 
91
104
  export type ChannelPolicies = typeof CHANNEL_POLICIES;
@@ -0,0 +1,108 @@
1
+ /**
2
+ * Channels that installed plugins bring.
3
+ *
4
+ * A plugin is a channel because it declares ingress: `channels/ingress.json`
5
+ * is the list of routes the outside world may reach it on, and reaching the
6
+ * assistant from outside is what being a channel means. There is no second
7
+ * file saying so, and nothing a plugin can set to claim the status without
8
+ * declaring the reach that constitutes it.
9
+ *
10
+ * What the gateway does with that file is a separate matter, and stays the
11
+ * gateway's: validating the routes, digesting them, holding them behind a
12
+ * guardian's approval. This reads its presence and nothing else, so a
13
+ * declaration the gateway rejects still surfaces here. That is the honest
14
+ * report, the plugin is a channel and its ingress is broken, and it keeps a
15
+ * schema this module does not own from deciding what a settings page lists.
16
+ *
17
+ * Presentation comes from the plugin's own manifest, where a plugin's title,
18
+ * description and icon already belong. All three are optional and none gate
19
+ * anything: a plugin with ingress and a bare `package.json` still appears,
20
+ * titled from its directory.
21
+ */
22
+
23
+ import { statSync } from "node:fs";
24
+ import { join } from "node:path";
25
+
26
+ import { isPluginDisabled } from "../plugins/disabled-state.js";
27
+ import { parsePluginPresentation } from "../plugins/external-plugin-loader.js";
28
+ import { listInstalledPluginDirs } from "../plugins/installed-plugin-dirs.js";
29
+ import { type AvailableChannel, isChannelId } from "./types.js";
30
+
31
+ /**
32
+ * The declaration that makes a plugin a channel. Owned by the gateway, which
33
+ * parses it; named here only to test for it.
34
+ */
35
+ export const PLUGIN_INGRESS_MANIFEST_RELPATH = "channels/ingress.json";
36
+
37
+ /** Icon for a plugin naming none. The generic "a message arrives here" glyph. */
38
+ const FALLBACK_ICON = "message-square";
39
+
40
+ /**
41
+ * Title for a plugin with no `displayName`.
42
+ *
43
+ * Derived rather than defaulted to the raw directory name so `meeting-bot`
44
+ * reads as "Meeting Bot" beside "Slack" and "Telegram". A plugin whose casing
45
+ * matters sets `displayName` and this never runs.
46
+ */
47
+ function titleFromDirectory(name: string): string {
48
+ return name
49
+ .split(/[-_]/)
50
+ .filter((part) => part.length > 0)
51
+ .map((part) => part.charAt(0).toUpperCase() + part.slice(1))
52
+ .join(" ");
53
+ }
54
+
55
+ /** True when the plugin declares ingress routes. */
56
+ function declaresIngress(pluginDir: string): boolean {
57
+ return (
58
+ statSync(join(pluginDir, PLUGIN_INGRESS_MANIFEST_RELPATH), {
59
+ throwIfNoEntry: false,
60
+ })?.isFile() === true
61
+ );
62
+ }
63
+
64
+ /**
65
+ * Every channel brought by an installed, enabled plugin.
66
+ *
67
+ * A plugin whose directory name is one of the assistant's own channels is
68
+ * skipped: two rows sharing an id would be ambiguous to any client keying on
69
+ * one, and the resolution that lets a plugin win would let it impersonate a
70
+ * built-in channel. The assistant's keep the name.
71
+ *
72
+ * Disabled plugins are skipped too, matching the source of truth the loader
73
+ * uses for hooks, tools and routes: a disabled plugin holds no ingress either,
74
+ * and one that reappeared here would offer a setup flow that cannot run.
75
+ *
76
+ * Order follows the plugins directory, and is stable for a stable install set.
77
+ */
78
+ export async function discoverPluginChannels(): Promise<AvailableChannel[]> {
79
+ const channels: AvailableChannel[] = [];
80
+
81
+ for (const { name, dir } of listInstalledPluginDirs()) {
82
+ if (isPluginDisabled(name) || isChannelId(name) || !declaresIngress(dir)) {
83
+ continue;
84
+ }
85
+ const presentation = await parsePluginPresentation(dir);
86
+ const label = presentation?.displayName ?? titleFromDirectory(name);
87
+ channels.push({
88
+ id: name,
89
+ source: `plugin:${name}`,
90
+ label,
91
+ subtitle: presentation?.description ?? `Provided by the ${label} plugin`,
92
+ icon: presentation?.icon ?? FALLBACK_ICON,
93
+ // No client-side verification flow exists for a plugin channel, so
94
+ // clients render it display-only and never pre-warm a status for it.
95
+ supportsVerification: false,
96
+ // Openers for a setup conversation, which is what this field is for.
97
+ // Deliberately not the verification copy the built-ins carry: there is
98
+ // no identity to verify here, and inventing that wording would send
99
+ // someone down a flow that does not exist.
100
+ setupMessages: {
101
+ guardian: `I want to set up ${label}. Can you help me?`,
102
+ contact: `I'd like to reach you on ${label}. Can you help me get set up?`,
103
+ },
104
+ });
105
+ }
106
+
107
+ return channels;
108
+ }
@@ -51,6 +51,32 @@ export interface ChannelInfo {
51
51
  };
52
52
  }
53
53
 
54
+ /**
55
+ * Source that contributes a channel, in the `<kind>[:<id>]` form the tool
56
+ * catalog and process tree already use: `default` for one the assistant ships,
57
+ * `plugin:<name>` for one an installed plugin brings.
58
+ *
59
+ * Composed from the plugin's install directory rather than from anything it
60
+ * declares, so a manifest cannot claim to be another source or pass itself off
61
+ * as built in.
62
+ */
63
+ export type ChannelSource = "default" | `plugin:${string}`;
64
+
65
+ /**
66
+ * A channel as `/v1/channels/available` reports it: the display metadata plus
67
+ * where it came from.
68
+ *
69
+ * `id` widens to a string here because a plugin channel's id is its plugin
70
+ * name, which is not a member of the closed {@link ChannelId} union. The union
71
+ * still governs everything the assistant routes, verifies and applies
72
+ * admission policy to; `source` is what tells a client which kind it is
73
+ * holding, so nothing has to infer it from the id.
74
+ */
75
+ export interface AvailableChannel extends Omit<ChannelInfo, "id"> {
76
+ id: string;
77
+ source: ChannelSource;
78
+ }
79
+
54
80
  /**
55
81
  * Per-channel display metadata for the channels the gateway can currently
56
82
  * surface to clients. Add an entry here when surfacing a new channel via
@@ -155,6 +181,10 @@ export const INTERFACE_IDS = [
155
181
  // device/service callbacks). Non-interactive — permission prompts route
156
182
  // through the guardian system, not an interactive client — and non-host-proxy.
157
183
  "route",
184
+ // Turns a plugin-brought channel delivered through the gateway. One id for
185
+ // every plugin, matching the `plugin` channel; which plugin it was is in
186
+ // `sourceMetadata.plugin`.
187
+ "plugin",
158
188
  ] as const;
159
189
 
160
190
  export type InterfaceId = (typeof INTERFACE_IDS)[number];
package/src/cli/AGENTS.md CHANGED
@@ -123,10 +123,13 @@ registerFooCommand(program);
123
123
  _synchronously_ at command registration (so it can't be a lazy
124
124
  `import()`) may stay hoisted behind a scoped
125
125
  `// eslint-disable-next-line cli/no-daemon-internals` with a comment
126
- explaining why. The only current case is `browser/operation-meta`, in
126
+ explaining why. The current cases are `browser/operation-meta`, in
127
127
  `commands/browser.ts` (it drives synchronous subcommand generation and
128
128
  deliberately pulls no Playwright graph) and `commands/browser.help.ts`
129
- (which derives the declarative help from the same contract).
129
+ (which derives the declarative help from the same contract); and
130
+ `providers/speech-to-text/provider-catalog`, in `commands/stt.help.ts`
131
+ (a literal map behind type-only imports, which the help text reads to
132
+ name the providers that serve the batch transcription boundary).
130
133
 
131
134
  2. **Lazy-import daemon functionality inside the action.** Running daemon
132
135
  logic in-process is encouraged where it avoids an IPC round-trip (which
@@ -0,0 +1,29 @@
1
+ export interface BundledCliModules {
2
+ configEnv: typeof import("../config/env.js");
3
+ providerSecretCatalog: typeof import("../providers/provider-secret-catalog.js");
4
+ pluginCatalogCache: typeof import("./lib/plugin-catalog-cache.js");
5
+ pluginCatalogLocal: typeof import("./lib/plugin-catalog-local.js");
6
+ pluginDiff: typeof import("./lib/diff-plugin.js");
7
+ pluginInspect: typeof import("./lib/inspect-plugin.js");
8
+ pluginInstallGitHub: typeof import("./lib/install-from-github.js");
9
+ pluginInstallPlatform: typeof import("./lib/install-from-platform.js");
10
+ pluginInstalled: typeof import("./lib/list-installed-plugins.js");
11
+ pluginPinHistory: typeof import("./lib/plugin-pin-history.js");
12
+ pluginSearch: typeof import("./lib/search-plugins.js");
13
+ pluginSurfaces: typeof import("./lib/plugin-surfaces.js");
14
+ pluginUninstall: typeof import("./lib/uninstall-plugin.js");
15
+ pluginUpgrade: typeof import("./lib/upgrade-plugin.js");
16
+ }
17
+
18
+ let bundledCliModules: BundledCliModules | undefined;
19
+
20
+ export function setBundledCliModules(modules: BundledCliModules): void {
21
+ bundledCliModules = modules;
22
+ }
23
+
24
+ export function resolveBundledCliModule<K extends keyof BundledCliModules>(
25
+ name: K,
26
+ fallback: () => BundledCliModules[K],
27
+ ): BundledCliModules[K] {
28
+ return bundledCliModules?.[name] ?? fallback();
29
+ }
@@ -293,8 +293,8 @@ encrypted vault with the specified metadata.
293
293
  Requires the assistant to be running with at least one connected client.
294
294
 
295
295
  This command BLOCKS until the user answers the prompt, so it returns only once
296
- the prompt has already closed. Tell the user what to paste BEFORE running it —
297
- anything said afterwards reaches them after the input is gone, and pointing
296
+ the prompt has already closed. Tell the user what to paste BEFORE running it.
297
+ Anything said afterwards reaches them after the input is gone, and pointing
298
298
  them at a closed prompt makes them re-submit a value that was already received.
299
299
  The --label and --description text renders inside the prompt itself, so put the
300
300
  instructions there rather than in a follow-up message.
@@ -15,7 +15,6 @@
15
15
  */
16
16
 
17
17
  import { existsSync } from "node:fs";
18
- import { createRequire } from "node:module";
19
18
 
20
19
  import type { Command } from "commander";
21
20
 
@@ -27,8 +26,6 @@ import { integrityCheckStep } from "./repair-step-integrity.js";
27
26
  import type { RepairReport, RepairStep, StepResult } from "./repair-steps.js";
28
27
  import { formatDurationMs, runRepairSteps } from "./repair-steps.js";
29
28
 
30
- const loadModule = createRequire(import.meta.url);
31
-
32
29
  // ---------------------------------------------------------------------------
33
30
  // Step sequence
34
31
  // ---------------------------------------------------------------------------
@@ -38,10 +35,9 @@ const loadModule = createRequire(import.meta.url);
38
35
  * structural damage surfaces early. Resolved lazily because the backfill
39
36
  * step pulls the DB graph.
40
37
  */
41
- function repairSteps(): RepairStep[] {
42
- const { conversationBackfillStep } = loadModule(
43
- "./repair-step-conversation-backfill.js",
44
- ) as typeof import("./repair-step-conversation-backfill.js");
38
+ async function repairSteps(): Promise<RepairStep[]> {
39
+ const { conversationBackfillStep } =
40
+ await import("./repair-step-conversation-backfill.js");
45
41
  return [integrityCheckStep, conversationBackfillStep];
46
42
  }
47
43
 
@@ -128,7 +124,7 @@ export function registerDbRepair(parent: Command): void {
128
124
 
129
125
  const report = await runRepairSteps(
130
126
  { dbPath },
131
- repairSteps(),
127
+ await repairSteps(),
132
128
  isJson
133
129
  ? {}
134
130
  : {
@@ -3,6 +3,7 @@ import { createRequire } from "node:module";
3
3
  import type { Command } from "commander";
4
4
 
5
5
  import { cliIpcCall, exitFromIpcResult } from "../../ipc/cli-client.js";
6
+ import { resolveBundledCliModule } from "../bundled-modules.js";
6
7
  import { applyCommandHelp, subcommand } from "../lib/cli-command-help.js";
7
8
  import { registerCommand } from "../lib/register-command.js";
8
9
  import { getCliLogger } from "../logger.js";
@@ -19,9 +20,11 @@ const log = getCliLogger("domain");
19
20
  * synchronously, so there is no place to await a module load.
20
21
  */
21
22
  function envDomains(): { apexDomain: string; baseDomain: string } {
22
- const { getApexDomain, getAssistantDomain } = loadModule(
23
- "../../config/env.js",
24
- ) as typeof import("../../config/env.js");
23
+ const { getApexDomain, getAssistantDomain } = resolveBundledCliModule(
24
+ "configEnv",
25
+ () =>
26
+ loadModule("../../config/env.js") as typeof import("../../config/env.js"),
27
+ );
25
28
  return { apexDomain: getApexDomain(), baseDomain: getAssistantDomain() };
26
29
  }
27
30
 
@@ -16,6 +16,7 @@ import {
16
16
  } from "../../ipc/cli-client.js";
17
17
  import { guessMimeType } from "../../util/mime-type.js";
18
18
  import { readStdinSync } from "../../util/read-stdin.js";
19
+ import { resolveBundledCliModule } from "../bundled-modules.js";
19
20
  import { applyCommandHelp, subcommand } from "../lib/cli-command-help.js";
20
21
  import { registerCommand } from "../lib/register-command.js";
21
22
  import { getCliLogger } from "../logger.js";
@@ -60,9 +61,11 @@ function handleEmailIpcError(
60
61
  * synchronously, so there is no place to await a module load.
61
62
  */
62
63
  function assistantDomain(): string {
63
- const { getAssistantDomain } = loadModule(
64
- "../../config/env.js",
65
- ) as typeof import("../../config/env.js");
64
+ const { getAssistantDomain } = resolveBundledCliModule(
65
+ "configEnv",
66
+ () =>
67
+ loadModule("../../config/env.js") as typeof import("../../config/env.js"),
68
+ );
66
69
  return getAssistantDomain();
67
70
  }
68
71
 
@@ -519,7 +519,7 @@ function attachLoginChatgptSubcommand(providers: Command): void {
519
519
  {
520
520
  body: {
521
521
  name: connectionName,
522
- provider: "openai",
522
+ provider: "chatgpt",
523
523
  auth: authInput,
524
524
  },
525
525
  },
@@ -2,6 +2,7 @@ import { createRequire } from "node:module";
2
2
 
3
3
  import type { Command } from "commander";
4
4
 
5
+ import { resolveBundledCliModule } from "../bundled-modules.js";
5
6
  import { applyCommandHelp, subcommand } from "../lib/cli-command-help.js";
6
7
  import { registerCommand } from "../lib/register-command.js";
7
8
  import { log } from "../logger.js";
@@ -16,9 +17,13 @@ const loadModule = createRequire(import.meta.url);
16
17
  * callbacks synchronously, so there is no place to await a module load.
17
18
  */
18
19
  function apiKeyProviders(): readonly string[] {
19
- const { API_KEY_PROVIDERS } = loadModule(
20
- "../../providers/provider-secret-catalog.js",
21
- ) as typeof import("../../providers/provider-secret-catalog.js");
20
+ const { API_KEY_PROVIDERS } = resolveBundledCliModule(
21
+ "providerSecretCatalog",
22
+ () =>
23
+ loadModule(
24
+ "../../providers/provider-secret-catalog.js",
25
+ ) as typeof import("../../providers/provider-secret-catalog.js"),
26
+ );
22
27
  return API_KEY_PROVIDERS;
23
28
  }
24
29
 
@@ -7,7 +7,8 @@ export const mcpHelp: CliCommandHelp = {
7
7
  description: "Manage MCP (Model Context Protocol) servers",
8
8
  helpText: `
9
9
  MCP servers extend the assistant's capabilities with external tools. Servers
10
- are configured in the assistant's config.json under the mcp.servers key. Each
10
+ are configured in the assistant's config.json under the mcp.servers key, or
11
+ declared by an installed plugin in its root mcp.json. Each
11
12
  server uses one of three transport types:
12
13
 
13
14
  stdio Local process communicating over stdin/stdout
@@ -28,13 +29,21 @@ Examples:
28
29
  description: "List configured MCP servers and their status",
29
30
  options: [{ flags: "--json", description: "Output as JSON" }],
30
31
  helpText: `
31
- Shows each configured MCP server with its current status and configuration:
32
+ Shows each MCP server with its current status and configuration. Servers come
33
+ from two places: the mcp.servers key in config.json, and the root mcp.json of
34
+ any installed plugin that declares one.
32
35
 
33
- Name The server identifier used in config.json
34
- Status Health check result:
36
+ Name The server identifier
37
+ Status Health check result for workspace servers:
35
38
  ✓ Connected and responding
36
39
  ✗ Error or disabled
37
40
  ! Needs authentication (OAuth required)
41
+ Plugin-declared servers report "declared" instead. They are
42
+ listed but not connected by the assistant, and they are not
43
+ health-checked, so no stored credential can reach a URL a
44
+ plugin chose.
45
+ Source Shown only for plugin-declared servers, naming the plugin.
46
+ Servers from config.json print no Source line.
38
47
  Transport stdio, sse, or streamable-http
39
48
  URL/Command The server URL (sse/streamable-http) or command (stdio)
40
49
  Risk Default risk level: low, medium, or high
@@ -24,6 +24,10 @@ interface McpServerEntry {
24
24
  defaultRiskLevel: string;
25
25
  allowedTools?: string[];
26
26
  blockedTools?: string[];
27
+ /** Workspace `config.json` or a plugin's `mcp.json`. */
28
+ source?: "workspace" | "plugin";
29
+ /** Plugin that declared the server, when `source` is `plugin`. */
30
+ pluginName?: string;
27
31
  }
28
32
 
29
33
  // ---------------------------------------------------------------------------
@@ -81,6 +85,11 @@ async function pollMcpAuthStatus(
81
85
  function printServerEntry(entry: McpServerEntry): void {
82
86
  log.info(` ${entry.id}`);
83
87
  log.info(` Status: ${entry.status}`);
88
+ // Only plugin-declared servers name a source. A workspace server is the
89
+ // default case and printing "workspace" on every one of them is noise.
90
+ if (entry.source === "plugin") {
91
+ log.info(` Source: plugin (${entry.pluginName ?? "unknown"})`);
92
+ }
84
93
  log.info(` Transport: ${entry.transport?.type ?? "unknown"}`);
85
94
  if (entry.transport?.type === "stdio") {
86
95
  log.info(