@vellumai/assistant 0.8.8 → 0.8.9-dev.202606091853.fbaa2ae

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 (475) hide show
  1. package/ARCHITECTURE.md +6 -6
  2. package/bun.lock +2 -2
  3. package/docs/activation-funnel-telemetry.md +310 -0
  4. package/examples/plugins/echo/README.md +61 -60
  5. package/examples/plugins/echo/hooks/post-tool-use.ts +18 -0
  6. package/examples/plugins/echo/hooks/stop.ts +16 -0
  7. package/examples/plugins/echo/hooks/user-prompt-submit.ts +18 -0
  8. package/examples/plugins/echo/package.json +1 -2
  9. package/examples/plugins/echo/src/emit.ts +19 -0
  10. package/node_modules/@vellumai/skill-host-contracts/src/skill-host.ts +7 -6
  11. package/openapi.yaml +263 -121
  12. package/package.json +2 -2
  13. package/src/__tests__/activation-early-marking.test.ts +120 -0
  14. package/src/__tests__/agent-loop-callsite-precedence.test.ts +69 -14
  15. package/src/__tests__/agent-loop-exit-reason.test.ts +204 -144
  16. package/src/__tests__/agent-loop-mutable-latest-user-message.test.ts +50 -35
  17. package/src/__tests__/agent-loop-output-hooks.test.ts +357 -0
  18. package/src/__tests__/agent-loop-override-profile.test.ts +25 -6
  19. package/src/__tests__/agent-loop-provider-error-recording.test.ts +41 -21
  20. package/src/__tests__/agent-loop-thinking.test.ts +36 -20
  21. package/src/__tests__/agent-loop.test.ts +441 -96
  22. package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +14 -14
  23. package/src/__tests__/agent-wake-override-profile.test.ts +17 -21
  24. package/src/__tests__/anthropic-provider.test.ts +23 -8
  25. package/src/__tests__/app-builder-tool-scripts.test.ts +21 -0
  26. package/src/__tests__/app-control-flow.test.ts +1 -1
  27. package/src/__tests__/app-dir-path-guard.test.ts +1 -0
  28. package/src/__tests__/app-executors.test.ts +132 -0
  29. package/src/__tests__/approval-cascade.test.ts +6 -5
  30. package/src/__tests__/approval-routes-http.test.ts +4 -1
  31. package/src/__tests__/background-workers-disk-pressure.test.ts +1 -1
  32. package/src/__tests__/channel-approval-routes.test.ts +1 -1
  33. package/src/__tests__/channel-approvals.test.ts +1 -1
  34. package/src/__tests__/compaction-circuit.test.ts +258 -0
  35. package/src/__tests__/compaction-direct.test.ts +146 -0
  36. package/src/__tests__/compaction-events.test.ts +7 -7
  37. package/src/__tests__/compaction.benchmark.test.ts +1 -1
  38. package/src/__tests__/compactor-web-search-strip.test.ts +213 -0
  39. package/src/__tests__/context-overflow-reducer.test.ts +265 -125
  40. package/src/__tests__/context-window-manager-compact-retry.test.ts +121 -15
  41. package/src/__tests__/conversation-abort-tool-results.test.ts +7 -5
  42. package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +7 -10
  43. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +78 -119
  44. package/src/__tests__/conversation-agent-loop-overflow.test.ts +158 -234
  45. package/src/__tests__/conversation-agent-loop.test.ts +342 -623
  46. package/src/__tests__/conversation-clean-command.test.ts +5 -2
  47. package/src/__tests__/conversation-confirmation-signals.test.ts +6 -5
  48. package/src/__tests__/conversation-crud-inference-profile.test.ts +7 -9
  49. package/src/__tests__/conversation-error.test.ts +15 -1
  50. package/src/__tests__/conversation-history-web-search.test.ts +6 -1
  51. package/src/__tests__/conversation-media-retry.test.ts +1 -1
  52. package/src/__tests__/conversation-process-app-control-preactivation.test.ts +44 -4
  53. package/src/__tests__/conversation-process-callsite.test.ts +15 -15
  54. package/src/__tests__/conversation-provider-retry-repair.test.ts +66 -65
  55. package/src/__tests__/conversation-queue.test.ts +10 -10
  56. package/src/__tests__/conversation-runtime-assembly.test.ts +1059 -231
  57. package/src/__tests__/conversation-runtime-workspace.test.ts +115 -20
  58. package/src/__tests__/conversation-slash-queue.test.ts +7 -5
  59. package/src/__tests__/conversation-slash-unknown.test.ts +7 -5
  60. package/src/__tests__/conversation-speed-override.test.ts +11 -10
  61. package/src/__tests__/conversation-starter-routes.test.ts +14 -6
  62. package/src/__tests__/conversation-surfaces-activation-emit.test.ts +395 -0
  63. package/src/__tests__/conversation-surfaces-app-control.test.ts +48 -1
  64. package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +73 -4
  65. package/src/__tests__/conversation-undo.test.ts +2 -2
  66. package/src/__tests__/conversation-workspace-cache-state.test.ts +24 -21
  67. package/src/__tests__/conversation-workspace-injection.test.ts +69 -7
  68. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +15 -12
  69. package/src/__tests__/conversations-import-system-filter.test.ts +101 -0
  70. package/src/__tests__/corrected-target.test.ts +93 -0
  71. package/src/__tests__/credential-security-invariants.test.ts +1 -0
  72. package/src/__tests__/cu-unified-flow.test.ts +36 -0
  73. package/src/__tests__/db-acp-history.test.ts +101 -0
  74. package/src/__tests__/dynamic-page-surface.test.ts +31 -0
  75. package/src/__tests__/empty-response-hook.test.ts +1 -1
  76. package/src/__tests__/file-write-tool.test.ts +63 -0
  77. package/src/__tests__/gateway-only-guard.test.ts +17 -2
  78. package/src/__tests__/guardian-grant-minting.test.ts +1 -1
  79. package/src/__tests__/guardian-routing-invariants.test.ts +93 -4
  80. package/src/__tests__/handlers-user-message-approval-consumption.test.ts +1 -1
  81. package/src/__tests__/heartbeat-disk-pressure.test.ts +1 -0
  82. package/src/__tests__/heartbeat-service.test.ts +1 -0
  83. package/src/__tests__/history-repair-hook.test.ts +5 -1
  84. package/src/__tests__/host-app-control-proxy.test.ts +45 -0
  85. package/src/__tests__/host-app-control-routes.test.ts +1 -1
  86. package/src/__tests__/host-cu-routes-targeted.test.ts +3 -3
  87. package/src/__tests__/inference-profile-reaper.test.ts +62 -0
  88. package/src/__tests__/inference-profile-session-handler.test.ts +86 -0
  89. package/src/__tests__/injector-background-turn.test.ts +13 -23
  90. package/src/__tests__/injector-chain.test.ts +268 -44
  91. package/src/__tests__/injector-disk-pressure.test.ts +210 -52
  92. package/src/__tests__/injector-document-comments.test.ts +97 -114
  93. package/src/__tests__/injector-pkb-v2-silenced.test.ts +2 -2
  94. package/src/__tests__/injector-v3-suppression.test.ts +4 -4
  95. package/src/__tests__/list-messages-client-message-id.test.ts +91 -0
  96. package/src/__tests__/list-messages-hidden-metadata.test.ts +38 -0
  97. package/src/__tests__/llm-resolver.test.ts +73 -0
  98. package/src/__tests__/memory-retrieval-hook.test.ts +156 -38
  99. package/src/__tests__/memory-v2-static-injector.test.ts +86 -8
  100. package/src/__tests__/notification-decision-strategy.test.ts +3 -3
  101. package/src/__tests__/parallel-tool.benchmark.test.ts +35 -8
  102. package/src/__tests__/persist-unsendable-image-downscale.test.ts +145 -0
  103. package/src/__tests__/persist-unsendable-image.test.ts +97 -1
  104. package/src/__tests__/plugin-api-shim.test.ts +6 -9
  105. package/src/__tests__/plugin-bootstrap.test.ts +91 -81
  106. package/src/__tests__/plugin-registry.test.ts +3 -49
  107. package/src/__tests__/plugin-skill-contribution.test.ts +15 -14
  108. package/src/__tests__/plugin-tool-contribution.test.ts +7 -4
  109. package/src/__tests__/plugin-types.test.ts +0 -70
  110. package/src/__tests__/post-turn-tool-result-truncation.test.ts +69 -0
  111. package/src/__tests__/pre-model-call-sanitize.test.ts +109 -0
  112. package/src/__tests__/published-app-updater.test.ts +138 -0
  113. package/src/__tests__/reaction-persistence.test.ts +1 -1
  114. package/src/__tests__/send-endpoint-busy.test.ts +4 -1
  115. package/src/__tests__/skill-feature-flags-integration.test.ts +31 -0
  116. package/src/__tests__/steer-tool-repair.test.ts +1 -1
  117. package/src/__tests__/subagent-call-site-routing.test.ts +1 -1
  118. package/src/__tests__/subagent-detail.test.ts +25 -7
  119. package/src/__tests__/subagent-fork-notifications.test.ts +1 -3
  120. package/src/__tests__/subagent-fork-spawn.test.ts +1 -1
  121. package/src/__tests__/subagent-manager-notify.test.ts +1 -3
  122. package/src/__tests__/subagent-notify-parent.test.ts +1 -3
  123. package/src/__tests__/subagent-spawn-tool-fork.test.ts +1 -1
  124. package/src/__tests__/title-generate-hook.test.ts +5 -1
  125. package/src/__tests__/tool-error-hook.test.ts +1 -1
  126. package/src/__tests__/tool-result-truncate-hook.test.ts +1 -1
  127. package/src/__tests__/user-plugin-loader.test.ts +54 -286
  128. package/src/__tests__/web-fetch.test.ts +45 -0
  129. package/src/acp/__tests__/agent-process.test.ts +161 -0
  130. package/src/acp/__tests__/client-handler.test.ts +40 -0
  131. package/src/acp/__tests__/helpers/acp-config-stub.ts +0 -2
  132. package/src/acp/__tests__/helpers/acp-history-db.ts +82 -0
  133. package/src/acp/__tests__/helpers/exec-file-stub.ts +106 -0
  134. package/src/acp/__tests__/prepare-agent-env.test.ts +97 -0
  135. package/src/acp/__tests__/session-manager-persistence.test.ts +95 -28
  136. package/src/acp/__tests__/session-manager-resume.test.ts +888 -0
  137. package/src/acp/agent-process.ts +61 -1
  138. package/src/acp/auto-install.test.ts +280 -0
  139. package/src/acp/auto-install.ts +232 -0
  140. package/src/acp/client-handler.ts +31 -0
  141. package/src/acp/prepare-agent-env.ts +80 -27
  142. package/src/acp/resolve-agent.test.ts +188 -28
  143. package/src/acp/resolve-agent.ts +119 -42
  144. package/src/acp/resume-hint.ts +23 -0
  145. package/src/acp/session-manager.ts +507 -73
  146. package/src/agent/compaction-circuit.ts +60 -102
  147. package/src/agent/loop.ts +403 -251
  148. package/src/api/responses/conversation-message.ts +22 -2
  149. package/src/api/responses/memory-v3-selection-log.ts +19 -10
  150. package/src/approvals/guardian-request-resolvers.ts +27 -1
  151. package/src/background-wake/next-wake.ts +1 -0
  152. package/src/cli/commands/__tests__/memory-v3.test.ts +191 -210
  153. package/src/cli/commands/channel-verification-sessions.ts +6 -6
  154. package/src/cli/commands/db/__tests__/repair.test.ts +3 -1
  155. package/src/cli/commands/memory-v3.ts +57 -199
  156. package/src/cli/commands/plugins.ts +43 -37
  157. package/src/cli/lib/__tests__/install-from-github.test.ts +790 -111
  158. package/src/cli/lib/__tests__/plugin-catalog-cache.test.ts +196 -0
  159. package/src/cli/lib/__tests__/plugin-details.test.ts +381 -0
  160. package/src/cli/lib/__tests__/plugin-marketplace.test.ts +270 -0
  161. package/src/cli/lib/__tests__/search-plugins.test.ts +233 -32
  162. package/src/cli/lib/install-from-github.ts +797 -60
  163. package/src/cli/lib/plugin-catalog-cache.ts +84 -0
  164. package/src/cli/lib/plugin-details.ts +416 -0
  165. package/src/cli/lib/plugin-marketplace.ts +215 -0
  166. package/src/cli/lib/search-plugins.ts +201 -29
  167. package/src/config/__tests__/feature-flag-registry-guard.test.ts +2 -2
  168. package/src/config/acp-defaults.test.ts +10 -0
  169. package/src/config/acp-defaults.ts +9 -3
  170. package/src/config/acp-schema.ts +1 -7
  171. package/src/config/bundled-skills/acp/SKILL.md +80 -41
  172. package/src/config/bundled-skills/acp/TOOLS.json +4 -4
  173. package/src/config/bundled-skills/app-builder/SKILL.md +224 -381
  174. package/src/config/bundled-skills/app-builder/TOOLS.json +72 -2
  175. package/src/config/bundled-skills/app-builder/references/DESIGN_SYSTEM.md +48 -0
  176. package/src/config/bundled-skills/app-builder/references/RESPONSIVE.md +57 -0
  177. package/src/config/bundled-skills/app-builder/references/SLIDES.md +38 -0
  178. package/src/config/bundled-skills/app-builder/tools/app-list.ts +62 -0
  179. package/src/config/bundled-skills/app-builder/tools/app-update.ts +18 -0
  180. package/src/config/bundled-skills/document-editor/SKILL.md +28 -23
  181. package/src/config/bundled-skills/document-editor/TOOLS.json +1 -1
  182. package/src/config/bundled-tool-registry.ts +4 -0
  183. package/src/config/call-site-defaults.ts +0 -3
  184. package/src/config/feature-flag-registry.json +10 -16
  185. package/src/config/llm-resolver.ts +39 -7
  186. package/src/config/schemas/__tests__/memory-v3.test.ts +25 -9
  187. package/src/config/schemas/call-site-catalog.ts +0 -21
  188. package/src/config/schemas/heartbeat.ts +9 -0
  189. package/src/config/schemas/llm.ts +17 -3
  190. package/src/config/schemas/memory-v3.ts +58 -8
  191. package/src/config/seed-inference-profiles.ts +18 -0
  192. package/src/context/compactor.ts +22 -4
  193. package/src/context/post-turn-tool-result-truncation.ts +39 -1
  194. package/src/context/strip-injections.ts +8 -2
  195. package/src/daemon/conversation-agent-loop-handlers.ts +18 -36
  196. package/src/daemon/conversation-agent-loop.ts +308 -1297
  197. package/src/daemon/conversation-error.ts +31 -4
  198. package/src/daemon/conversation-history.ts +1 -1
  199. package/src/daemon/conversation-lifecycle.ts +11 -255
  200. package/src/daemon/conversation-media-retry.ts +19 -6
  201. package/src/daemon/conversation-messaging.ts +17 -0
  202. package/src/daemon/conversation-process.ts +22 -141
  203. package/src/daemon/conversation-queue-manager.ts +8 -0
  204. package/src/daemon/conversation-registry.ts +159 -0
  205. package/src/daemon/conversation-runtime-assembly.ts +361 -393
  206. package/src/daemon/conversation-store.ts +9 -90
  207. package/src/daemon/conversation-surfaces.ts +165 -11
  208. package/src/daemon/conversation-workspace.ts +17 -0
  209. package/src/daemon/conversation.ts +444 -62
  210. package/src/daemon/disk-pressure-policy.ts +0 -1
  211. package/src/daemon/external-plugins-bootstrap.ts +36 -46
  212. package/src/daemon/handlers/config-channels.ts +11 -2
  213. package/src/daemon/handlers/conversations.ts +3 -1
  214. package/src/daemon/handlers/skills.ts +4 -1
  215. package/src/daemon/host-app-control-proxy.ts +72 -57
  216. package/src/daemon/host-proxy-preactivation.ts +1 -3
  217. package/src/daemon/lifecycle.ts +21 -7
  218. package/src/daemon/persist-unsendable-image.ts +62 -25
  219. package/src/daemon/process-message.ts +1 -1
  220. package/src/daemon/server.ts +2 -0
  221. package/src/daemon/tool-side-effects.ts +15 -0
  222. package/src/daemon/wake-conversation-ops.ts +269 -0
  223. package/src/embedded/plugin-api.ts +2 -2
  224. package/src/export/__tests__/transcript-formatter.test.ts +5 -0
  225. package/src/heartbeat/__tests__/heartbeat-service.test.ts +3 -0
  226. package/src/heartbeat/heartbeat-run-store.ts +23 -1
  227. package/src/heartbeat/heartbeat-service.ts +26 -0
  228. package/src/ipc/__tests__/browser-ipc.test.ts +1 -1
  229. package/src/ipc/__tests__/ui-request-route.test.ts +3 -3
  230. package/src/ipc/skill-routes/__tests__/memory.test.ts +15 -0
  231. package/src/ipc/skill-routes/memory.ts +4 -2
  232. package/src/memory/__tests__/activation-session-store.test.ts +41 -0
  233. package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +87 -0
  234. package/src/memory/__tests__/onboarding-events-store.test.ts +80 -0
  235. package/src/memory/activation-session-store.ts +43 -0
  236. package/src/memory/conversation-crud.ts +29 -19
  237. package/src/memory/conversation-starter-checkpoints.ts +1 -0
  238. package/src/memory/db-init.ts +6 -0
  239. package/src/memory/job-handlers/conversation-starters.ts +13 -2
  240. package/src/memory/jobs/__tests__/embed-concept-page.test.ts +5 -4
  241. package/src/memory/jobs-worker.ts +25 -1
  242. package/src/memory/migrations/272-acp-session-history-cwd.ts +36 -0
  243. package/src/memory/migrations/273-onboarding-events-funnel-columns.ts +46 -0
  244. package/src/memory/migrations/274-create-activation-sessions.ts +15 -0
  245. package/src/memory/migrations/index.ts +3 -0
  246. package/src/memory/onboarding-events-store.ts +66 -18
  247. package/src/memory/schema/acp.ts +4 -0
  248. package/src/memory/schema/infrastructure.ts +13 -0
  249. package/src/memory/v2/__tests__/consolidation-job.test.ts +4 -97
  250. package/src/memory/v2/__tests__/page-store.test.ts +22 -0
  251. package/src/memory/v2/consolidation-job.ts +2 -63
  252. package/src/memory/v2/types.ts +5 -0
  253. package/src/messaging/providers/telegram-bot/api.ts +14 -5
  254. package/src/notifications/__tests__/copy-composer.test.ts +244 -0
  255. package/src/notifications/access-request-copy.ts +298 -0
  256. package/src/notifications/adapters/slack.ts +3 -3
  257. package/src/notifications/adapters/telegram.ts +9 -2
  258. package/src/notifications/copy-composer.ts +49 -267
  259. package/src/notifications/decision-engine.ts +16 -35
  260. package/src/notifications/home-feed-side-effect.ts +1 -6
  261. package/src/plugin-api/constants.ts +4 -0
  262. package/src/plugin-api/index.ts +40 -11
  263. package/src/plugin-api/types.ts +108 -0
  264. package/src/plugins/defaults/compaction/compact.ts +106 -0
  265. package/src/{daemon → plugins/defaults/compaction}/context-overflow-reducer.ts +250 -42
  266. package/src/plugins/defaults/compaction/corrected-target.ts +53 -0
  267. package/src/plugins/defaults/compaction/manager-store.ts +57 -0
  268. package/src/plugins/defaults/compaction/package.json +1 -2
  269. package/src/{context → plugins/defaults/compaction}/window-manager.ts +95 -25
  270. package/src/plugins/defaults/empty-response/package.json +0 -1
  271. package/src/plugins/defaults/history-repair/package.json +0 -1
  272. package/src/plugins/defaults/index.ts +156 -26
  273. package/src/plugins/defaults/memory-retrieval/hooks/post-compact.ts +100 -52
  274. package/src/plugins/defaults/memory-retrieval/hooks/user-prompt-submit.ts +285 -0
  275. package/src/plugins/defaults/memory-retrieval/injector-chain.ts +2 -2
  276. package/src/plugins/defaults/{injectors/register.ts → memory-retrieval/injectors.ts} +148 -73
  277. package/src/plugins/defaults/memory-retrieval/package.json +14 -0
  278. package/src/plugins/defaults/memory-retrieval/unified-turn-context.ts +223 -0
  279. package/src/plugins/defaults/memory-v3-shadow/__tests__/capabilities.test.ts +71 -0
  280. package/src/plugins/defaults/memory-v3-shadow/__tests__/dense.test.ts +181 -0
  281. package/src/plugins/defaults/memory-v3-shadow/__tests__/edge.test.ts +247 -0
  282. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/live-integration.test.ts +147 -134
  283. package/src/plugins/defaults/memory-v3-shadow/__tests__/maintain-job.test.ts +456 -0
  284. package/src/plugins/defaults/memory-v3-shadow/__tests__/orchestrate.test.ts +662 -0
  285. package/src/plugins/defaults/memory-v3-shadow/__tests__/pool-select.test.ts +306 -0
  286. package/src/plugins/defaults/memory-v3-shadow/__tests__/render-injection.test.ts +91 -0
  287. package/src/plugins/defaults/memory-v3-shadow/__tests__/section-dense-store.test.ts +402 -0
  288. package/src/plugins/defaults/memory-v3-shadow/__tests__/section-needle.test.ts +135 -0
  289. package/src/plugins/defaults/memory-v3-shadow/__tests__/sections.test.ts +125 -0
  290. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/selection-log-store.test.ts +74 -19
  291. package/src/plugins/defaults/memory-v3-shadow/__tests__/shadow-integration.test.ts +446 -0
  292. package/src/plugins/defaults/memory-v3-shadow/__tests__/shadow-plugin.test.ts +592 -0
  293. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/types.test.ts +2 -24
  294. package/src/plugins/defaults/memory-v3-shadow/capabilities.ts +91 -0
  295. package/src/plugins/defaults/memory-v3-shadow/dense.ts +97 -0
  296. package/src/plugins/defaults/memory-v3-shadow/edge.ts +252 -0
  297. package/src/plugins/defaults/memory-v3-shadow/hooks/post-compact.ts +14 -0
  298. package/src/plugins/defaults/memory-v3-shadow/hooks/user-prompt-submit.ts +19 -0
  299. package/src/plugins/defaults/memory-v3-shadow/injector.ts +76 -0
  300. package/src/plugins/defaults/memory-v3-shadow/maintain-job.ts +555 -0
  301. package/src/plugins/defaults/memory-v3-shadow/orchestrate.ts +266 -0
  302. package/src/plugins/defaults/memory-v3-shadow/package.json +14 -0
  303. package/src/plugins/defaults/memory-v3-shadow/page-content.ts +71 -0
  304. package/src/plugins/defaults/memory-v3-shadow/pool-select.ts +204 -0
  305. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/render-injection.ts +16 -8
  306. package/src/plugins/defaults/memory-v3-shadow/section-dense-store.ts +236 -0
  307. package/src/plugins/defaults/memory-v3-shadow/section-needle.ts +200 -0
  308. package/src/plugins/defaults/memory-v3-shadow/sections.ts +115 -0
  309. package/src/plugins/defaults/memory-v3-shadow/selection-log-store.ts +156 -0
  310. package/src/plugins/defaults/memory-v3-shadow/shadow-plugin.ts +382 -0
  311. package/src/plugins/defaults/memory-v3-shadow/types.ts +92 -0
  312. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/working-set.ts +4 -1
  313. package/src/plugins/defaults/title-generate/package.json +0 -1
  314. package/src/plugins/defaults/tool-error/package.json +0 -1
  315. package/src/plugins/defaults/tool-result-truncate/package.json +0 -1
  316. package/src/plugins/external-api.ts +12 -2
  317. package/src/plugins/pipeline.ts +6 -293
  318. package/src/plugins/registry.ts +9 -37
  319. package/src/plugins/types.ts +76 -381
  320. package/src/plugins/user-loader.ts +30 -127
  321. package/src/prompts/__tests__/system-prompt.test.ts +6 -0
  322. package/src/prompts/system-prompt.ts +61 -10
  323. package/src/prompts/templates/BOOTSTRAP-ACTIVATION-RAIL.md +71 -4
  324. package/src/providers/anthropic/client.ts +9 -10
  325. package/src/providers/inference/kimi-cjk-token-ids.ts +493 -0
  326. package/src/providers/inference/logit-bias.ts +55 -0
  327. package/src/providers/model-catalog.ts +34 -0
  328. package/src/providers/openai/__tests__/vision-not-supported.test.ts +75 -0
  329. package/src/providers/openai/chat-completions-provider.ts +44 -1
  330. package/src/providers/retry.ts +22 -0
  331. package/src/providers/types.ts +6 -0
  332. package/src/runtime/__tests__/agent-wake.test.ts +555 -691
  333. package/src/runtime/__tests__/interactive-ui.test.ts +1 -1
  334. package/src/runtime/agent-wake.ts +108 -209
  335. package/src/runtime/assistant-event-hub.ts +1 -1
  336. package/src/runtime/channel-approvals.ts +1 -1
  337. package/src/runtime/interactive-ui.ts +1 -1
  338. package/src/runtime/routes/__tests__/acp-routes.test.ts +466 -55
  339. package/src/runtime/routes/__tests__/conversation-list-routes.test.ts +1 -1
  340. package/src/runtime/routes/__tests__/plugins-routes.test.ts +423 -73
  341. package/src/runtime/routes/__tests__/stt-routes.test.ts +112 -0
  342. package/src/runtime/routes/__tests__/surface-action-routes.test.ts +5 -4
  343. package/src/runtime/routes/__tests__/surface-content-routes.test.ts +4 -1
  344. package/src/runtime/routes/acp-routes.test.ts +185 -32
  345. package/src/runtime/routes/acp-routes.ts +328 -30
  346. package/src/runtime/routes/app-management-routes.ts +3 -0
  347. package/src/runtime/routes/approval-routes.ts +1 -1
  348. package/src/runtime/routes/browser-routes.ts +1 -1
  349. package/src/runtime/routes/browser-tabs-routes.ts +6 -10
  350. package/src/runtime/routes/channel-verification-routes.ts +14 -5
  351. package/src/runtime/routes/conversation-cli-routes.ts +1 -1
  352. package/src/runtime/routes/conversation-list-routes.ts +1 -1
  353. package/src/runtime/routes/conversation-query-routes.ts +1 -1
  354. package/src/runtime/routes/conversation-routes.ts +30 -2
  355. package/src/runtime/routes/conversation-starter-routes.ts +13 -7
  356. package/src/runtime/routes/conversations-import-routes.ts +24 -7
  357. package/src/runtime/routes/host-app-control-routes.ts +1 -1
  358. package/src/runtime/routes/host-cu-routes.ts +1 -1
  359. package/src/runtime/routes/identity-routes.ts +18 -3
  360. package/src/runtime/routes/inbound-message-handler.ts +1 -1
  361. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +33 -34
  362. package/src/runtime/routes/inference-profile-session-handler.ts +11 -0
  363. package/src/runtime/routes/inference-profile-session-reaper.ts +6 -0
  364. package/src/runtime/routes/memory-v3-routes.ts +65 -305
  365. package/src/runtime/routes/playground/__tests__/force-compact.test.ts +1 -1
  366. package/src/runtime/routes/playground/helpers.ts +1 -1
  367. package/src/runtime/routes/plugins-routes.ts +337 -35
  368. package/src/runtime/routes/stt-routes.ts +45 -12
  369. package/src/runtime/routes/surface-conversation-resolver.ts +4 -3
  370. package/src/runtime/routes/work-items-routes.ts +2 -4
  371. package/src/runtime/routes/workspace-routes.ts +50 -15
  372. package/src/runtime/services/conversation-serializer.ts +1 -1
  373. package/src/runtime/verification-outbound-actions.ts +147 -2
  374. package/src/runtime/verification-templates.ts +29 -3
  375. package/src/services/published-app-updater.ts +30 -8
  376. package/src/signals/cancel.ts +2 -4
  377. package/src/subagent/manager.ts +21 -5
  378. package/src/telemetry/__tests__/activation-funnel.test.ts +95 -0
  379. package/src/telemetry/activation-funnel.ts +167 -0
  380. package/src/telemetry/types.ts +13 -0
  381. package/src/telemetry/usage-telemetry-reporter.test.ts +154 -0
  382. package/src/telemetry/usage-telemetry-reporter.ts +26 -1
  383. package/src/tools/acp/context.ts +20 -0
  384. package/src/tools/acp/list-agents.test.ts +9 -19
  385. package/src/tools/acp/list-agents.ts +3 -15
  386. package/src/tools/acp/spawn.test.ts +173 -202
  387. package/src/tools/acp/spawn.ts +37 -172
  388. package/src/tools/acp/steer.test.ts +105 -8
  389. package/src/tools/acp/steer.ts +48 -17
  390. package/src/tools/apps/executors.ts +166 -50
  391. package/src/tools/browser/browser-execution.ts +12 -2
  392. package/src/tools/filesystem/write.ts +34 -0
  393. package/src/tools/network/web-fetch.ts +65 -24
  394. package/src/tools/skills/load.ts +1 -1
  395. package/src/tools/subagent/spawn.ts +2 -4
  396. package/src/tools/ui-surface/definitions.ts +32 -5
  397. package/src/workspace/migrations/051-seed-conversation-summarization-callsite.ts +4 -5
  398. package/src/workspace/migrations/097-enable-adaptive-thinking-managed-profiles.ts +69 -45
  399. package/docs/plugins.md +0 -832
  400. package/examples/plugins/echo/register.ts +0 -143
  401. package/src/__tests__/circuit-breaker-pipeline.test.ts +0 -405
  402. package/src/__tests__/compaction-pipeline.test.ts +0 -210
  403. package/src/__tests__/compaction-timeout-recovery.test.ts +0 -251
  404. package/src/__tests__/overflow-reduce-pipeline.test.ts +0 -667
  405. package/src/__tests__/pipeline-runner.test.ts +0 -554
  406. package/src/daemon/wake-target-adapter.ts +0 -253
  407. package/src/memory/v3/__tests__/assign.test.ts +0 -242
  408. package/src/memory/v3/__tests__/capabilities.test.ts +0 -118
  409. package/src/memory/v3/__tests__/core.test.ts +0 -39
  410. package/src/memory/v3/__tests__/health.test.ts +0 -219
  411. package/src/memory/v3/__tests__/maintain-job.test.ts +0 -288
  412. package/src/memory/v3/__tests__/needle.test.ts +0 -107
  413. package/src/memory/v3/__tests__/orchestrate.test.ts +0 -436
  414. package/src/memory/v3/__tests__/provider-blocks.test.ts +0 -13
  415. package/src/memory/v3/__tests__/reconcile.test.ts +0 -274
  416. package/src/memory/v3/__tests__/render-injection.test.ts +0 -61
  417. package/src/memory/v3/__tests__/router.test.ts +0 -332
  418. package/src/memory/v3/__tests__/selector.test.ts +0 -470
  419. package/src/memory/v3/__tests__/shadow-plugin.test.ts +0 -432
  420. package/src/memory/v3/__tests__/snapshot.test.ts +0 -168
  421. package/src/memory/v3/__tests__/tree.test.ts +0 -192
  422. package/src/memory/v3/assign.ts +0 -268
  423. package/src/memory/v3/capabilities.ts +0 -124
  424. package/src/memory/v3/core.ts +0 -26
  425. package/src/memory/v3/health.ts +0 -0
  426. package/src/memory/v3/maintain-job.ts +0 -314
  427. package/src/memory/v3/needle.ts +0 -115
  428. package/src/memory/v3/orchestrate.ts +0 -126
  429. package/src/memory/v3/page-content.ts +0 -34
  430. package/src/memory/v3/provider-blocks.ts +0 -26
  431. package/src/memory/v3/reconcile.ts +0 -523
  432. package/src/memory/v3/router.ts +0 -190
  433. package/src/memory/v3/selection-log-store.ts +0 -84
  434. package/src/memory/v3/selector.ts +0 -226
  435. package/src/memory/v3/shadow-plugin.ts +0 -411
  436. package/src/memory/v3/snapshot.ts +0 -209
  437. package/src/memory/v3/tree.ts +0 -174
  438. package/src/memory/v3/types.ts +0 -59
  439. package/src/notifications/__tests__/emit-signal-home-feed.test.ts +0 -187
  440. package/src/plugins/defaults/circuit-breaker/middlewares/circuitBreaker.ts +0 -93
  441. package/src/plugins/defaults/circuit-breaker/package.json +0 -15
  442. package/src/plugins/defaults/circuit-breaker/register.ts +0 -39
  443. package/src/plugins/defaults/compaction/middlewares/compaction.ts +0 -25
  444. package/src/plugins/defaults/compaction/register.ts +0 -35
  445. package/src/plugins/defaults/compaction/terminal.ts +0 -73
  446. package/src/plugins/defaults/empty-response/register.ts +0 -23
  447. package/src/plugins/defaults/history-repair/register.ts +0 -24
  448. package/src/plugins/defaults/memory-retrieval/hooks/user-prompt-submit-temp.ts +0 -216
  449. package/src/plugins/defaults/overflow-reduce/middlewares/overflowReduce.ts +0 -126
  450. package/src/plugins/defaults/overflow-reduce/package.json +0 -15
  451. package/src/plugins/defaults/overflow-reduce/register.ts +0 -42
  452. package/src/plugins/defaults/title-generate/register.ts +0 -35
  453. package/src/plugins/defaults/tool-error/register.ts +0 -23
  454. package/src/plugins/defaults/tool-result-truncate/register.ts +0 -24
  455. package/src/proactive-artifact/aux-message-injector.ts +0 -97
  456. package/src/proactive-artifact/decision.test.ts +0 -226
  457. package/src/proactive-artifact/decision.ts +0 -165
  458. package/src/proactive-artifact/index.ts +0 -7
  459. package/src/proactive-artifact/job.test.ts +0 -962
  460. package/src/proactive-artifact/job.ts +0 -372
  461. package/src/proactive-artifact/message-copy.ts +0 -58
  462. package/src/proactive-artifact/trigger-state.test.ts +0 -286
  463. package/src/proactive-artifact/trigger-state.ts +0 -123
  464. package/src/util/map-limit.ts +0 -27
  465. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/fixtures/eval-turns.json +0 -0
  466. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/fixtures/live-turns.json +0 -0
  467. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/working-set-eviction.test.ts +0 -0
  468. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/working-set-skeleton.test.ts +0 -0
  469. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/README.md +0 -0
  470. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/assignments.json +0 -0
  471. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/core.json +0 -0
  472. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/leaves/domain-a/topic-x.md +0 -0
  473. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/leaves/domain-a/topic-y.md +0 -0
  474. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/leaves/domain-b/topic-z.md +0 -0
  475. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/llm-retry.ts +0 -0
@@ -28,48 +28,82 @@ import {
28
28
  getCredentialMetadata,
29
29
  upsertCredentialMetadata,
30
30
  } from "../tools/credentials/metadata-store.js";
31
+ import { getLogger } from "../util/logger.js";
31
32
  import type { AcpAgentConfig } from "./types.js";
32
33
 
34
+ const log = getLogger("acp:prepare-agent-env");
35
+
33
36
  const ACP_SPAWN_TOOL = "acp_spawn";
37
+ const ACP_SERVICE = "acp";
34
38
 
35
39
  /**
36
- * Ensure the `acp/claude_oauth_token` credential has metadata that allows
37
- * the `acp_spawn` tool to read it, but only for legacy/unmanaged cases:
40
+ * Ensure an `acp/<field>` credential has metadata that allows the
41
+ * `acp_spawn` tool to read it, but only for legacy/unmanaged cases:
38
42
  *
39
- * - No metadata at all → create with `allowedTools: ["acp_spawn"]`.
40
- * - Metadata exists with an empty `allowedTools` → default provisioning
43
+ * - No metadata at all: create with `allowedTools: ["acp_spawn"]`.
44
+ * - Metadata exists with an empty `allowedTools`: default provisioning
41
45
  * path (user ran `credentials set` without `--allowed-tools`), add it.
42
- * - Metadata exists with a non-empty `allowedTools` → explicit policy set
43
- * by the user/admin. Respect it even if `acp_spawn` is absent — the
44
- * broker will deny the read and the preflight will throw.
46
+ * - Metadata exists with a non-empty `allowedTools`: explicit policy set
47
+ * by the user/admin. Respect it even if `acp_spawn` is absent; the
48
+ * broker will deny the read and the caller decides whether that's fatal.
45
49
  */
46
- function ensureAcpTokenPolicy(): void {
47
- const meta = getCredentialMetadata("acp", "claude_oauth_token");
50
+ function ensureAcpCredentialPolicy(
51
+ field: string,
52
+ usageDescription: string,
53
+ ): void {
54
+ const meta = getCredentialMetadata(ACP_SERVICE, field);
48
55
  if (!meta) {
49
- upsertCredentialMetadata("acp", "claude_oauth_token", {
56
+ upsertCredentialMetadata(ACP_SERVICE, field, {
50
57
  allowedTools: [ACP_SPAWN_TOOL],
51
- usageDescription:
52
- "Claude OAuth token for ACP agent authentication",
58
+ usageDescription,
53
59
  });
54
60
  return;
55
61
  }
56
62
  const tools = meta.allowedTools ?? [];
57
63
  if (tools.length === 0) {
58
- upsertCredentialMetadata("acp", "claude_oauth_token", {
64
+ upsertCredentialMetadata(ACP_SERVICE, field, {
59
65
  allowedTools: [ACP_SPAWN_TOOL],
60
66
  });
61
67
  }
62
68
  }
63
69
 
70
+ /**
71
+ * Read an `acp/<field>` credential through the broker and inject it into
72
+ * `env` under `envVar`. Returns the broker's failure reason when the value
73
+ * was not injected (missing credential, denied policy, no stored value),
74
+ * or undefined on success. Never throws: `serverUse` signals every failure
75
+ * mode, including a simply-absent credential, as `{ success: false,
76
+ * reason }`, so callers choose whether a miss is fatal.
77
+ */
78
+ async function injectCredential(
79
+ env: Record<string, string>,
80
+ field: string,
81
+ envVar: string,
82
+ usageDescription: string,
83
+ ): Promise<string | undefined> {
84
+ ensureAcpCredentialPolicy(field, usageDescription);
85
+ const result = await credentialBroker.serverUse<void>({
86
+ service: ACP_SERVICE,
87
+ field,
88
+ toolName: ACP_SPAWN_TOOL,
89
+ execute: async (value) => {
90
+ env[envVar] = value;
91
+ },
92
+ });
93
+ return result.success ? undefined : result.reason;
94
+ }
95
+
64
96
  /**
65
97
  * Returns a NEW config with any required credentials merged into `env`.
66
98
  * Does NOT mutate the input. Throws `FailedDependencyError` if a required
67
99
  * credential is missing from both the user-supplied env override and the
68
100
  * secure store.
69
101
  *
70
- * Gating is keyed off the resolved agent COMMAND (basename), not the
71
- * user-facing agent id, so a custom `acp.agents.my-claude = { command:
72
- * "claude-agent-acp", ... }` alias still gets the env it needs.
102
+ * Gating is keyed off the resolved command basename, not the user-facing
103
+ * agent id. A custom `acp.agents.my-claude = { command: "claude-agent-acp",
104
+ * ... }` alias (or a full path like `/opt/bin/claude-agent-acp`) still gets
105
+ * the env it needs. Because resolution always yields the real adapter binary
106
+ * (never a `bun x` wrapper), the basename is the canonical adapter identity.
73
107
  *
74
108
  * For `claude-agent-acp` the only required env var is
75
109
  * `CLAUDE_CODE_OAUTH_TOKEN`. Two provisioning routes converge on it, with
@@ -84,6 +118,11 @@ function ensureAcpTokenPolicy(): void {
84
118
  * before spawning. The "fail-fast" throw is symmetric with the existing
85
119
  * `binary_not_found` preflight in `resolveAcpAgent` and strictly better
86
120
  * than a `warn` + zombie subprocess 10 seconds later.
121
+ *
122
+ * For `gemini` the env var is `GEMINI_API_KEY`, provisioned the same two
123
+ * ways (config.json override wins, vault field `gemini_api_key` second),
124
+ * but it is OPTIONAL: the Gemini CLI supports its own OAuth login, so a
125
+ * vault miss proceeds without the key instead of failing the spawn.
87
126
  */
88
127
  export async function prepareAgentEnv(
89
128
  agentConfig: AcpAgentConfig,
@@ -92,19 +131,16 @@ export async function prepareAgentEnv(
92
131
  // agent reference. The local `env` binding sidesteps TS narrowing
93
132
  // limitations on the optional `AcpAgentConfig.env` field.
94
133
  const env: Record<string, string> = { ...(agentConfig.env ?? {}) };
95
- const commandBasename = basename(agentConfig.command);
134
+ const adapterCommand = basename(agentConfig.command);
96
135
 
97
- if (commandBasename === "claude-agent-acp") {
136
+ if (adapterCommand === "claude-agent-acp") {
98
137
  if (!env.CLAUDE_CODE_OAUTH_TOKEN) {
99
- ensureAcpTokenPolicy();
100
- await credentialBroker.serverUse<void>({
101
- service: "acp",
102
- field: "claude_oauth_token",
103
- toolName: ACP_SPAWN_TOOL,
104
- execute: async (token) => {
105
- env.CLAUDE_CODE_OAUTH_TOKEN = token;
106
- },
107
- });
138
+ await injectCredential(
139
+ env,
140
+ "claude_oauth_token",
141
+ "CLAUDE_CODE_OAUTH_TOKEN",
142
+ "Claude OAuth token for ACP agent authentication",
143
+ );
108
144
  }
109
145
  if (!env.CLAUDE_CODE_OAUTH_TOKEN) {
110
146
  throw new FailedDependencyError(
@@ -113,6 +149,23 @@ export async function prepareAgentEnv(
113
149
  "(or set it under acp.agents.<id>.env in config.json).",
114
150
  );
115
151
  }
152
+ } else if (adapterCommand === "gemini") {
153
+ if (!env.GEMINI_API_KEY) {
154
+ const missReason = await injectCredential(
155
+ env,
156
+ "gemini_api_key",
157
+ "GEMINI_API_KEY",
158
+ "Gemini API key for ACP agent authentication",
159
+ );
160
+ if (missReason !== undefined) {
161
+ // Optional credential: Gemini CLI can authenticate via its own
162
+ // OAuth login, so a vault miss must not fail the spawn.
163
+ log.debug(
164
+ { reason: missReason },
165
+ "Gemini API key unavailable from the vault; spawning without GEMINI_API_KEY",
166
+ );
167
+ }
168
+ }
116
169
  }
117
170
 
118
171
  return { ...agentConfig, env };
@@ -24,19 +24,6 @@ beforeEach(() => {
24
24
  // ---------------------------------------------------------------------------
25
25
 
26
26
  describe("resolveAcpAgent", () => {
27
- test("returns acp_disabled when config.acp.enabled is false", () => {
28
- config.setConfig({ enabled: false });
29
-
30
- const result = resolveAcpAgent("claude");
31
-
32
- expect(result.ok).toBe(false);
33
- if (result.ok) return;
34
- expect(result.reason).toBe("acp_disabled");
35
- if (result.reason !== "acp_disabled") return;
36
- expect(result.hint).toContain("acp.enabled");
37
- expect(result.hint).toContain("config.json");
38
- });
39
-
40
27
  test("user config wins over default profile", () => {
41
28
  config.setConfig({
42
29
  agents: {
@@ -78,6 +65,79 @@ describe("resolveAcpAgent", () => {
78
65
  expect(result.agent.command).toBe("claude-agent-acp");
79
66
  });
80
67
 
68
+ test("falls back to the gemini default profile when no user entry", () => {
69
+ config.setConfig({ agents: {} });
70
+
71
+ const result = resolveAcpAgent("gemini");
72
+
73
+ expect(result.ok).toBe(true);
74
+ if (!result.ok) return;
75
+ expect(result.agent.command).toBe("gemini");
76
+ expect(result.agent.args).toEqual(["--acp"]);
77
+ });
78
+
79
+ test.each([
80
+ ["claude code", "claude-agent-acp"],
81
+ ["Claude Code", "claude-agent-acp"],
82
+ ["claude-code", "claude-agent-acp"],
83
+ ["claude_code", "claude-agent-acp"],
84
+ ["codex cli", "codex-acp"],
85
+ ["OpenAI Codex", "codex-acp"],
86
+ ["gemini cli", "gemini"],
87
+ ["Gemini CLI", "gemini"],
88
+ ["google gemini", "gemini"],
89
+ ])("alias %p resolves to the %p profile", (alias, command) => {
90
+ config.setConfig({ agents: {} });
91
+
92
+ const result = resolveAcpAgent(alias);
93
+
94
+ expect(result.ok).toBe(true);
95
+ if (!result.ok) return;
96
+ expect(result.agent.command).toBe(command);
97
+ });
98
+
99
+ test("user config entry literally keyed 'claude code' beats the alias", () => {
100
+ config.setConfig({
101
+ agents: {
102
+ "claude code": {
103
+ command: "my-claude-fork",
104
+ args: [],
105
+ description: "user-defined agent that happens to share an alias",
106
+ },
107
+ },
108
+ });
109
+
110
+ const result = resolveAcpAgent("claude code");
111
+
112
+ expect(result.ok).toBe(true);
113
+ if (!result.ok) return;
114
+ expect(result.agent.command).toBe("my-claude-fork");
115
+ });
116
+
117
+ test("alias re-runs the normal lookup, so a user override of the canonical id wins", () => {
118
+ config.setConfig({
119
+ agents: {
120
+ claude: { command: "my-custom-claude", args: [] },
121
+ },
122
+ });
123
+
124
+ const result = resolveAcpAgent("claude code");
125
+
126
+ expect(result.ok).toBe(true);
127
+ if (!result.ok) return;
128
+ expect(result.agent.command).toBe("my-custom-claude");
129
+ });
130
+
131
+ test("non-alias unknown id still returns unknown_agent", () => {
132
+ config.setConfig({ agents: {} });
133
+
134
+ const result = resolveAcpAgent("cursor cli");
135
+
136
+ expect(result.ok).toBe(false);
137
+ if (result.ok) return;
138
+ expect(result.reason).toBe("unknown_agent");
139
+ });
140
+
81
141
  test("returns unknown_agent with merged available list when id not found", () => {
82
142
  config.setConfig({
83
143
  agents: {
@@ -92,7 +152,12 @@ describe("resolveAcpAgent", () => {
92
152
  expect(result.reason).toBe("unknown_agent");
93
153
  if (result.reason !== "unknown_agent") return;
94
154
  // Defaults plus user-only ids, deduped, in stable order (defaults first).
95
- expect(result.available).toEqual(["claude", "codex", "user-only"]);
155
+ expect(result.available).toEqual([
156
+ "claude",
157
+ "codex",
158
+ "gemini",
159
+ "user-only",
160
+ ]);
96
161
  });
97
162
 
98
163
  test("unknown_agent available list contains both defaults when user config is empty", () => {
@@ -106,6 +171,7 @@ describe("resolveAcpAgent", () => {
106
171
  if (result.reason !== "unknown_agent") return;
107
172
  expect(result.available).toContain("claude");
108
173
  expect(result.available).toContain("codex");
174
+ expect(result.available).toContain("gemini");
109
175
  });
110
176
 
111
177
  test("returns binary_not_found with the registered install hint", () => {
@@ -118,7 +184,7 @@ describe("resolveAcpAgent", () => {
118
184
  if (result.ok) return;
119
185
  expect(result.reason).toBe("binary_not_found");
120
186
  if (result.reason !== "binary_not_found") return;
121
- expect(result.hint).toBe("npm i -g @agentclientprotocol/claude-agent-acp");
187
+ expect(result.hint).toBe("bun add -g @agentclientprotocol/claude-agent-acp");
122
188
  expect(result.command).toBe("claude-agent-acp");
123
189
  });
124
190
 
@@ -158,7 +224,7 @@ describe("resolveAcpAgent", () => {
158
224
  if (result.ok) return;
159
225
  expect(result.reason).toBe("binary_not_found");
160
226
  if (result.reason !== "binary_not_found") return;
161
- expect(result.hint).toBe("npm i -g @zed-industries/codex-acp");
227
+ expect(result.hint).toBe("bun add -g @zed-industries/codex-acp");
162
228
  });
163
229
 
164
230
  test("binary preflight honors agent.env.PATH override (matches spawn env)", () => {
@@ -200,30 +266,74 @@ describe("resolveAcpAgent", () => {
200
266
  if (!result.ok) return;
201
267
  expect(result.agent.args).toEqual(["--verbose"]);
202
268
  });
269
+
270
+ test("resolves a full-path command directly without rewriting it", () => {
271
+ config.setConfig({
272
+ agents: {
273
+ custom: { command: "/opt/bin/claude-agent-acp", args: [] },
274
+ },
275
+ });
276
+
277
+ const direct = resolveAcpAgent("claude");
278
+ expect(direct.ok).toBe(true);
279
+ if (!direct.ok) return;
280
+ expect(direct.agent.command).toBe("claude-agent-acp");
281
+
282
+ const fullPath = resolveAcpAgent("custom");
283
+ expect(fullPath.ok).toBe(true);
284
+ if (!fullPath.ok) return;
285
+ expect(fullPath.agent.command).toBe("/opt/bin/claude-agent-acp");
286
+ });
203
287
  });
204
288
 
205
289
  // ---------------------------------------------------------------------------
206
- // listAcpAgents
290
+ // resolveAcpAgent - missing binaries are never run from the task cwd
207
291
  // ---------------------------------------------------------------------------
208
292
 
209
- describe("listAcpAgents", () => {
210
- test("returns enabled: false with empty agents when ACP is disabled", () => {
211
- config.setConfig({ enabled: false });
293
+ describe("resolveAcpAgent - missing binary", () => {
294
+ test("binary missing + bun present: still binary_not_found (no bunx rewrite)", () => {
295
+ // bun on PATH no longer makes a missing adapter "runnable" at resolve
296
+ // time: the sandboxed install happens separately, never as a `bun x`
297
+ // rewrite in the untrusted cwd.
298
+ config.setConfig({ agents: {} });
299
+ which.setWhich({ bun: "/usr/local/bin/bun" });
212
300
 
213
- const result = listAcpAgents();
301
+ const result = resolveAcpAgent("claude");
302
+
303
+ expect(result.ok).toBe(false);
304
+ if (result.ok) return;
305
+ expect(result.reason).toBe("binary_not_found");
306
+ if (result.reason !== "binary_not_found") return;
307
+ expect(result.command).toBe("claude-agent-acp");
308
+ expect(result.hint).toBe("bun add -g @agentclientprotocol/claude-agent-acp");
309
+ });
310
+
311
+ test("binary missing + bun missing: binary_not_found with the bun hint", () => {
312
+ config.setConfig({ agents: {} });
313
+ which.setWhich({});
214
314
 
215
- expect(result.enabled).toBe(false);
216
- expect(result.agents).toEqual([]);
315
+ const result = resolveAcpAgent("claude");
316
+
317
+ expect(result.ok).toBe(false);
318
+ if (result.ok) return;
319
+ expect(result.reason).toBe("binary_not_found");
320
+ if (result.reason !== "binary_not_found") return;
321
+ expect(result.hint).toBe("bun add -g @agentclientprotocol/claude-agent-acp");
217
322
  });
323
+ });
218
324
 
219
- test("includes both bundled defaults when user config is empty", () => {
325
+ // ---------------------------------------------------------------------------
326
+ // listAcpAgents
327
+ // ---------------------------------------------------------------------------
328
+
329
+ describe("listAcpAgents", () => {
330
+ test("includes all bundled defaults when user config is empty", () => {
220
331
  config.setConfig({ agents: {} });
221
332
 
222
333
  const result = listAcpAgents();
223
334
 
224
- expect(result.enabled).toBe(true);
225
335
  const ids = result.agents.map((a) => a.id);
226
- expect(ids).toEqual(["claude", "codex"]);
336
+ expect(ids).toEqual(["claude", "codex", "gemini"]);
227
337
  for (const entry of result.agents) {
228
338
  expect(entry.source).toBe("default");
229
339
  expect(entry.available).toBe(true);
@@ -245,6 +355,7 @@ describe("listAcpAgents", () => {
245
355
  which.setWhich({
246
356
  "my-claude": "/usr/bin/my-claude",
247
357
  "codex-acp": "/usr/bin/codex-acp",
358
+ gemini: "/usr/bin/gemini",
248
359
  });
249
360
 
250
361
  const result = listAcpAgents();
@@ -257,6 +368,27 @@ describe("listAcpAgents", () => {
257
368
  expect(codex?.source).toBe("default");
258
369
  });
259
370
 
371
+ test("missing binaries are listed unavailable even when bun is present", () => {
372
+ // bun presence no longer makes a missing adapter available: it is
373
+ // installed on demand at spawn time, not run via `bun x` from the cwd.
374
+ config.setConfig({ agents: {} });
375
+ which.setWhich({ bun: "/usr/local/bin/bun" });
376
+
377
+ const result = listAcpAgents();
378
+
379
+ for (const entry of result.agents) {
380
+ expect(entry.available).toBe(false);
381
+ expect(entry.unavailableReason).toBeDefined();
382
+ expect(entry.setupHint).toContain("bun add -g");
383
+ }
384
+ // The catalog keeps the canonical adapter commands.
385
+ expect(result.agents.map((a) => a.command)).toEqual([
386
+ "claude-agent-acp",
387
+ "codex-acp",
388
+ "gemini",
389
+ ]);
390
+ });
391
+
260
392
  test("unavailable agent surfaces install hint derived from DEFAULT_AGENT_NPM_PACKAGES", () => {
261
393
  config.setConfig({ agents: {} });
262
394
  which.setWhich({ "claude-agent-acp": "/usr/bin/claude-agent-acp" });
@@ -266,7 +398,33 @@ describe("listAcpAgents", () => {
266
398
  const codex = result.agents.find((a) => a.id === "codex");
267
399
  expect(codex?.available).toBe(false);
268
400
  expect(codex?.unavailableReason).toBe("'codex-acp' is not on PATH");
269
- expect(codex?.setupHint).toBe("npm i -g @zed-industries/codex-acp");
401
+ expect(codex?.setupHint).toBe("bun add -g @zed-industries/codex-acp");
402
+ });
403
+
404
+ test("unavailable gemini surfaces the @google/gemini-cli install hint", () => {
405
+ config.setConfig({ agents: {} });
406
+ which.setWhich({
407
+ "claude-agent-acp": "/usr/bin/claude-agent-acp",
408
+ "codex-acp": "/usr/bin/codex-acp",
409
+ });
410
+
411
+ const result = listAcpAgents();
412
+
413
+ const gemini = result.agents.find((a) => a.id === "gemini");
414
+ expect(gemini?.available).toBe(false);
415
+ expect(gemini?.unavailableReason).toBe("'gemini' is not on PATH");
416
+ expect(gemini?.setupHint).toBe("bun add -g @google/gemini-cli");
417
+ });
418
+
419
+ test("aliases are resolution sugar, not catalog entries", () => {
420
+ config.setConfig({ agents: {} });
421
+
422
+ // "gemini cli" resolves via the alias...
423
+ expect(resolveAcpAgent("gemini cli").ok).toBe(true);
424
+
425
+ // ...but the catalog lists only canonical ids.
426
+ const ids = listAcpAgents().agents.map((a) => a.id);
427
+ expect(ids).toEqual(["claude", "codex", "gemini"]);
270
428
  });
271
429
 
272
430
  test("user-only agent appended after defaults in stable order", () => {
@@ -282,6 +440,7 @@ describe("listAcpAgents", () => {
282
440
  which.setWhich({
283
441
  "claude-agent-acp": "/x",
284
442
  "codex-acp": "/x",
443
+ gemini: "/x",
285
444
  "my-binary": "/x",
286
445
  });
287
446
 
@@ -290,9 +449,10 @@ describe("listAcpAgents", () => {
290
449
  expect(result.agents.map((a) => a.id)).toEqual([
291
450
  "claude",
292
451
  "codex",
452
+ "gemini",
293
453
  "my-agent",
294
454
  ]);
295
- const userOnly = result.agents[2];
455
+ const userOnly = result.agents[3];
296
456
  expect(userOnly.source).toBe("config");
297
457
  expect(userOnly.description).toBe("user-only");
298
458
  });