@vellumai/assistant 0.8.8 → 0.8.9-dev.202606091926.ebb2d62

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 (490) 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 +273 -121
  12. package/package.json +2 -2
  13. package/scripts/sync-llm-catalog.ts +2 -0
  14. package/src/__tests__/activation-early-marking.test.ts +120 -0
  15. package/src/__tests__/agent-loop-callsite-precedence.test.ts +69 -14
  16. package/src/__tests__/agent-loop-exit-reason.test.ts +204 -144
  17. package/src/__tests__/agent-loop-mutable-latest-user-message.test.ts +50 -35
  18. package/src/__tests__/agent-loop-output-hooks.test.ts +357 -0
  19. package/src/__tests__/agent-loop-override-profile.test.ts +25 -6
  20. package/src/__tests__/agent-loop-provider-error-recording.test.ts +41 -21
  21. package/src/__tests__/agent-loop-thinking.test.ts +36 -20
  22. package/src/__tests__/agent-loop.test.ts +441 -96
  23. package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +14 -14
  24. package/src/__tests__/agent-wake-override-profile.test.ts +17 -21
  25. package/src/__tests__/anthropic-provider.test.ts +23 -8
  26. package/src/__tests__/app-builder-tool-scripts.test.ts +21 -0
  27. package/src/__tests__/app-control-flow.test.ts +1 -1
  28. package/src/__tests__/app-dir-path-guard.test.ts +1 -0
  29. package/src/__tests__/app-executors.test.ts +132 -0
  30. package/src/__tests__/approval-cascade.test.ts +6 -5
  31. package/src/__tests__/approval-routes-http.test.ts +4 -1
  32. package/src/__tests__/background-workers-disk-pressure.test.ts +1 -1
  33. package/src/__tests__/build-persisted-content.test.ts +75 -1
  34. package/src/__tests__/channel-approval-routes.test.ts +1 -1
  35. package/src/__tests__/channel-approvals.test.ts +1 -1
  36. package/src/__tests__/compaction-circuit.test.ts +258 -0
  37. package/src/__tests__/compaction-direct.test.ts +146 -0
  38. package/src/__tests__/compaction-events.test.ts +7 -7
  39. package/src/__tests__/compaction.benchmark.test.ts +1 -1
  40. package/src/__tests__/compactor-web-search-strip.test.ts +213 -0
  41. package/src/__tests__/config-managed-gemini-defaults.test.ts +2 -46
  42. package/src/__tests__/context-overflow-reducer.test.ts +265 -125
  43. package/src/__tests__/context-window-manager-compact-retry.test.ts +121 -15
  44. package/src/__tests__/conversation-abort-tool-results.test.ts +7 -5
  45. package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +7 -10
  46. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +78 -119
  47. package/src/__tests__/conversation-agent-loop-overflow.test.ts +158 -234
  48. package/src/__tests__/conversation-agent-loop.test.ts +342 -623
  49. package/src/__tests__/conversation-clean-command.test.ts +5 -2
  50. package/src/__tests__/conversation-confirmation-signals.test.ts +6 -5
  51. package/src/__tests__/conversation-crud-inference-profile.test.ts +7 -9
  52. package/src/__tests__/conversation-error.test.ts +15 -1
  53. package/src/__tests__/conversation-history-web-search.test.ts +6 -1
  54. package/src/__tests__/conversation-media-retry.test.ts +1 -1
  55. package/src/__tests__/conversation-process-app-control-preactivation.test.ts +44 -4
  56. package/src/__tests__/conversation-process-callsite.test.ts +15 -15
  57. package/src/__tests__/conversation-provider-retry-repair.test.ts +66 -65
  58. package/src/__tests__/conversation-queue.test.ts +10 -10
  59. package/src/__tests__/conversation-runtime-assembly.test.ts +1059 -231
  60. package/src/__tests__/conversation-runtime-workspace.test.ts +115 -20
  61. package/src/__tests__/conversation-slash-queue.test.ts +7 -5
  62. package/src/__tests__/conversation-slash-unknown.test.ts +7 -5
  63. package/src/__tests__/conversation-speed-override.test.ts +11 -10
  64. package/src/__tests__/conversation-starter-routes.test.ts +14 -6
  65. package/src/__tests__/conversation-surfaces-activation-emit.test.ts +395 -0
  66. package/src/__tests__/conversation-surfaces-app-control.test.ts +48 -1
  67. package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +73 -4
  68. package/src/__tests__/conversation-undo.test.ts +2 -2
  69. package/src/__tests__/conversation-workspace-cache-state.test.ts +24 -21
  70. package/src/__tests__/conversation-workspace-injection.test.ts +69 -7
  71. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +15 -12
  72. package/src/__tests__/conversations-import-system-filter.test.ts +101 -0
  73. package/src/__tests__/corrected-target.test.ts +93 -0
  74. package/src/__tests__/credential-execution-feature-gates.test.ts +5 -4
  75. package/src/__tests__/credential-security-invariants.test.ts +1 -0
  76. package/src/__tests__/cu-unified-flow.test.ts +36 -0
  77. package/src/__tests__/db-acp-history.test.ts +101 -0
  78. package/src/__tests__/dynamic-page-surface.test.ts +31 -0
  79. package/src/__tests__/embedding-managed-proxy-selection.test.ts +6 -40
  80. package/src/__tests__/empty-response-hook.test.ts +1 -1
  81. package/src/__tests__/file-write-tool.test.ts +63 -0
  82. package/src/__tests__/gateway-only-guard.test.ts +17 -2
  83. package/src/__tests__/guardian-grant-minting.test.ts +1 -1
  84. package/src/__tests__/guardian-routing-invariants.test.ts +93 -4
  85. package/src/__tests__/handlers-user-message-approval-consumption.test.ts +1 -1
  86. package/src/__tests__/heartbeat-disk-pressure.test.ts +1 -0
  87. package/src/__tests__/heartbeat-service.test.ts +1 -0
  88. package/src/__tests__/history-repair-hook.test.ts +5 -1
  89. package/src/__tests__/host-app-control-proxy.test.ts +45 -0
  90. package/src/__tests__/host-app-control-routes.test.ts +1 -1
  91. package/src/__tests__/host-cu-routes-targeted.test.ts +3 -3
  92. package/src/__tests__/inference-profile-reaper.test.ts +62 -0
  93. package/src/__tests__/inference-profile-session-handler.test.ts +86 -0
  94. package/src/__tests__/injector-background-turn.test.ts +13 -23
  95. package/src/__tests__/injector-chain.test.ts +268 -44
  96. package/src/__tests__/injector-disk-pressure.test.ts +210 -52
  97. package/src/__tests__/injector-document-comments.test.ts +97 -114
  98. package/src/__tests__/injector-pkb-v2-silenced.test.ts +2 -2
  99. package/src/__tests__/injector-v3-suppression.test.ts +4 -4
  100. package/src/__tests__/list-messages-client-message-id.test.ts +91 -0
  101. package/src/__tests__/list-messages-hidden-metadata.test.ts +38 -0
  102. package/src/__tests__/llm-catalog-parity.test.ts +4 -0
  103. package/src/__tests__/llm-resolver.test.ts +73 -0
  104. package/src/__tests__/memory-retrieval-hook.test.ts +156 -38
  105. package/src/__tests__/memory-v2-static-injector.test.ts +86 -8
  106. package/src/__tests__/notification-decision-strategy.test.ts +3 -3
  107. package/src/__tests__/parallel-tool.benchmark.test.ts +35 -8
  108. package/src/__tests__/persist-unsendable-image-downscale.test.ts +145 -0
  109. package/src/__tests__/persist-unsendable-image.test.ts +97 -1
  110. package/src/__tests__/persistence-secret-redaction.test.ts +78 -0
  111. package/src/__tests__/plugin-api-shim.test.ts +6 -9
  112. package/src/__tests__/plugin-bootstrap.test.ts +91 -81
  113. package/src/__tests__/plugin-registry.test.ts +3 -49
  114. package/src/__tests__/plugin-skill-contribution.test.ts +15 -14
  115. package/src/__tests__/plugin-tool-contribution.test.ts +7 -4
  116. package/src/__tests__/plugin-types.test.ts +0 -70
  117. package/src/__tests__/post-turn-tool-result-truncation.test.ts +69 -0
  118. package/src/__tests__/pre-model-call-sanitize.test.ts +109 -0
  119. package/src/__tests__/published-app-updater.test.ts +138 -0
  120. package/src/__tests__/reaction-persistence.test.ts +1 -1
  121. package/src/__tests__/retry-thinking-adaptive-only.test.ts +245 -0
  122. package/src/__tests__/send-endpoint-busy.test.ts +4 -1
  123. package/src/__tests__/server-history-render.test.ts +39 -0
  124. package/src/__tests__/skill-feature-flags-integration.test.ts +31 -0
  125. package/src/__tests__/steer-tool-repair.test.ts +1 -1
  126. package/src/__tests__/subagent-call-site-routing.test.ts +1 -1
  127. package/src/__tests__/subagent-detail.test.ts +25 -7
  128. package/src/__tests__/subagent-fork-notifications.test.ts +1 -3
  129. package/src/__tests__/subagent-fork-spawn.test.ts +1 -1
  130. package/src/__tests__/subagent-manager-notify.test.ts +1 -3
  131. package/src/__tests__/subagent-notify-parent.test.ts +1 -3
  132. package/src/__tests__/subagent-spawn-tool-fork.test.ts +1 -1
  133. package/src/__tests__/title-generate-hook.test.ts +5 -1
  134. package/src/__tests__/tool-error-hook.test.ts +1 -1
  135. package/src/__tests__/tool-result-truncate-hook.test.ts +1 -1
  136. package/src/__tests__/tool-start-timestamp.test.ts +218 -0
  137. package/src/__tests__/user-plugin-loader.test.ts +54 -286
  138. package/src/__tests__/web-fetch.test.ts +45 -0
  139. package/src/acp/__tests__/agent-process.test.ts +161 -0
  140. package/src/acp/__tests__/client-handler.test.ts +40 -0
  141. package/src/acp/__tests__/helpers/acp-config-stub.ts +0 -2
  142. package/src/acp/__tests__/helpers/acp-history-db.ts +82 -0
  143. package/src/acp/__tests__/helpers/exec-file-stub.ts +106 -0
  144. package/src/acp/__tests__/prepare-agent-env.test.ts +97 -0
  145. package/src/acp/__tests__/session-manager-persistence.test.ts +95 -28
  146. package/src/acp/__tests__/session-manager-resume.test.ts +888 -0
  147. package/src/acp/agent-process.ts +61 -1
  148. package/src/acp/auto-install.test.ts +280 -0
  149. package/src/acp/auto-install.ts +232 -0
  150. package/src/acp/client-handler.ts +31 -0
  151. package/src/acp/prepare-agent-env.ts +80 -27
  152. package/src/acp/resolve-agent.test.ts +188 -28
  153. package/src/acp/resolve-agent.ts +119 -42
  154. package/src/acp/resume-hint.ts +23 -0
  155. package/src/acp/session-manager.ts +507 -73
  156. package/src/agent/compaction-circuit.ts +60 -102
  157. package/src/agent/loop.ts +403 -251
  158. package/src/api/events/tool-result.ts +9 -0
  159. package/src/api/events/tool-use-start.ts +7 -0
  160. package/src/api/responses/conversation-message.ts +72 -13
  161. package/src/api/responses/memory-v3-selection-log.ts +19 -10
  162. package/src/approvals/guardian-request-resolvers.ts +27 -1
  163. package/src/background-wake/next-wake.ts +1 -0
  164. package/src/cli/commands/__tests__/memory-v3.test.ts +191 -210
  165. package/src/cli/commands/channel-verification-sessions.ts +6 -6
  166. package/src/cli/commands/db/__tests__/repair.test.ts +3 -1
  167. package/src/cli/commands/memory-v3.ts +57 -199
  168. package/src/cli/commands/plugins.ts +43 -37
  169. package/src/cli/lib/__tests__/install-from-github.test.ts +790 -111
  170. package/src/cli/lib/__tests__/plugin-catalog-cache.test.ts +196 -0
  171. package/src/cli/lib/__tests__/plugin-details.test.ts +381 -0
  172. package/src/cli/lib/__tests__/plugin-marketplace.test.ts +270 -0
  173. package/src/cli/lib/__tests__/search-plugins.test.ts +233 -32
  174. package/src/cli/lib/install-from-github.ts +797 -60
  175. package/src/cli/lib/plugin-catalog-cache.ts +84 -0
  176. package/src/cli/lib/plugin-details.ts +416 -0
  177. package/src/cli/lib/plugin-marketplace.ts +215 -0
  178. package/src/cli/lib/search-plugins.ts +201 -29
  179. package/src/config/__tests__/feature-flag-registry-guard.test.ts +2 -2
  180. package/src/config/acp-defaults.test.ts +10 -0
  181. package/src/config/acp-defaults.ts +9 -3
  182. package/src/config/acp-schema.ts +1 -7
  183. package/src/config/bundled-skills/acp/SKILL.md +80 -41
  184. package/src/config/bundled-skills/acp/TOOLS.json +4 -4
  185. package/src/config/bundled-skills/app-builder/SKILL.md +224 -381
  186. package/src/config/bundled-skills/app-builder/TOOLS.json +72 -2
  187. package/src/config/bundled-skills/app-builder/references/DESIGN_SYSTEM.md +48 -0
  188. package/src/config/bundled-skills/app-builder/references/RESPONSIVE.md +57 -0
  189. package/src/config/bundled-skills/app-builder/references/SLIDES.md +38 -0
  190. package/src/config/bundled-skills/app-builder/tools/app-list.ts +62 -0
  191. package/src/config/bundled-skills/app-builder/tools/app-update.ts +18 -0
  192. package/src/config/bundled-skills/document-editor/SKILL.md +28 -23
  193. package/src/config/bundled-skills/document-editor/TOOLS.json +1 -1
  194. package/src/config/bundled-tool-registry.ts +4 -0
  195. package/src/config/call-site-defaults.ts +0 -3
  196. package/src/config/feature-flag-registry.json +10 -56
  197. package/src/config/llm-resolver.ts +39 -7
  198. package/src/config/loader.ts +5 -22
  199. package/src/config/schemas/__tests__/memory-v3.test.ts +25 -9
  200. package/src/config/schemas/call-site-catalog.ts +0 -21
  201. package/src/config/schemas/heartbeat.ts +9 -0
  202. package/src/config/schemas/llm.ts +17 -3
  203. package/src/config/schemas/memory-v3.ts +58 -8
  204. package/src/config/seed-inference-profiles.ts +18 -0
  205. package/src/context/compactor.ts +22 -4
  206. package/src/context/post-turn-tool-result-truncation.ts +39 -1
  207. package/src/context/strip-injections.ts +8 -2
  208. package/src/daemon/conversation-agent-loop-handlers.ts +120 -42
  209. package/src/daemon/conversation-agent-loop.ts +308 -1297
  210. package/src/daemon/conversation-error.ts +31 -4
  211. package/src/daemon/conversation-history.ts +1 -1
  212. package/src/daemon/conversation-lifecycle.ts +11 -255
  213. package/src/daemon/conversation-media-retry.ts +19 -6
  214. package/src/daemon/conversation-messaging.ts +17 -0
  215. package/src/daemon/conversation-process.ts +22 -141
  216. package/src/daemon/conversation-queue-manager.ts +8 -0
  217. package/src/daemon/conversation-registry.ts +159 -0
  218. package/src/daemon/conversation-runtime-assembly.ts +361 -393
  219. package/src/daemon/conversation-store.ts +9 -90
  220. package/src/daemon/conversation-surfaces.ts +165 -11
  221. package/src/daemon/conversation-workspace.ts +17 -0
  222. package/src/daemon/conversation.ts +444 -62
  223. package/src/daemon/disk-pressure-policy.ts +0 -1
  224. package/src/daemon/external-plugins-bootstrap.ts +36 -46
  225. package/src/daemon/handlers/config-channels.ts +11 -2
  226. package/src/daemon/handlers/conversations.ts +3 -1
  227. package/src/daemon/handlers/shared.ts +9 -1
  228. package/src/daemon/handlers/skills.ts +4 -1
  229. package/src/daemon/host-app-control-proxy.ts +72 -57
  230. package/src/daemon/host-proxy-preactivation.ts +1 -3
  231. package/src/daemon/lifecycle.ts +21 -7
  232. package/src/daemon/persist-unsendable-image.ts +62 -25
  233. package/src/daemon/process-message.ts +1 -1
  234. package/src/daemon/server.ts +2 -0
  235. package/src/daemon/tool-side-effects.ts +15 -0
  236. package/src/daemon/wake-conversation-ops.ts +269 -0
  237. package/src/embedded/plugin-api.ts +2 -2
  238. package/src/export/__tests__/transcript-formatter.test.ts +5 -0
  239. package/src/heartbeat/__tests__/heartbeat-service.test.ts +3 -0
  240. package/src/heartbeat/heartbeat-run-store.ts +23 -1
  241. package/src/heartbeat/heartbeat-service.ts +26 -0
  242. package/src/ipc/__tests__/browser-ipc.test.ts +1 -1
  243. package/src/ipc/__tests__/ui-request-route.test.ts +3 -3
  244. package/src/ipc/skill-routes/__tests__/memory.test.ts +15 -0
  245. package/src/ipc/skill-routes/memory.ts +4 -2
  246. package/src/memory/__tests__/activation-session-store.test.ts +41 -0
  247. package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +87 -0
  248. package/src/memory/__tests__/onboarding-events-store.test.ts +80 -0
  249. package/src/memory/activation-session-store.ts +43 -0
  250. package/src/memory/conversation-crud.ts +29 -19
  251. package/src/memory/conversation-starter-checkpoints.ts +1 -0
  252. package/src/memory/db-init.ts +6 -0
  253. package/src/memory/embedding-backend.ts +5 -22
  254. package/src/memory/job-handlers/conversation-starters.ts +13 -2
  255. package/src/memory/jobs/__tests__/embed-concept-page.test.ts +5 -4
  256. package/src/memory/jobs-worker.ts +25 -1
  257. package/src/memory/migrations/272-acp-session-history-cwd.ts +36 -0
  258. package/src/memory/migrations/273-onboarding-events-funnel-columns.ts +46 -0
  259. package/src/memory/migrations/274-create-activation-sessions.ts +15 -0
  260. package/src/memory/migrations/index.ts +3 -0
  261. package/src/memory/onboarding-events-store.ts +66 -18
  262. package/src/memory/schema/acp.ts +4 -0
  263. package/src/memory/schema/infrastructure.ts +13 -0
  264. package/src/memory/v2/__tests__/consolidation-job.test.ts +4 -97
  265. package/src/memory/v2/__tests__/page-store.test.ts +22 -0
  266. package/src/memory/v2/consolidation-job.ts +2 -63
  267. package/src/memory/v2/types.ts +5 -0
  268. package/src/messaging/providers/telegram-bot/api.ts +14 -5
  269. package/src/notifications/__tests__/copy-composer.test.ts +244 -0
  270. package/src/notifications/access-request-copy.ts +298 -0
  271. package/src/notifications/adapters/slack.ts +3 -3
  272. package/src/notifications/adapters/telegram.ts +9 -2
  273. package/src/notifications/copy-composer.ts +49 -267
  274. package/src/notifications/decision-engine.ts +16 -35
  275. package/src/notifications/home-feed-side-effect.ts +1 -6
  276. package/src/plugin-api/constants.ts +4 -0
  277. package/src/plugin-api/index.ts +40 -11
  278. package/src/plugin-api/types.ts +108 -0
  279. package/src/plugins/defaults/compaction/compact.ts +106 -0
  280. package/src/{daemon → plugins/defaults/compaction}/context-overflow-reducer.ts +250 -42
  281. package/src/plugins/defaults/compaction/corrected-target.ts +53 -0
  282. package/src/plugins/defaults/compaction/manager-store.ts +57 -0
  283. package/src/plugins/defaults/compaction/package.json +1 -2
  284. package/src/{context → plugins/defaults/compaction}/window-manager.ts +95 -25
  285. package/src/plugins/defaults/empty-response/package.json +0 -1
  286. package/src/plugins/defaults/history-repair/package.json +0 -1
  287. package/src/plugins/defaults/index.ts +156 -26
  288. package/src/plugins/defaults/memory-retrieval/hooks/post-compact.ts +100 -52
  289. package/src/plugins/defaults/memory-retrieval/hooks/user-prompt-submit.ts +285 -0
  290. package/src/plugins/defaults/memory-retrieval/injector-chain.ts +2 -2
  291. package/src/plugins/defaults/{injectors/register.ts → memory-retrieval/injectors.ts} +148 -73
  292. package/src/plugins/defaults/memory-retrieval/package.json +14 -0
  293. package/src/plugins/defaults/memory-retrieval/unified-turn-context.ts +223 -0
  294. package/src/plugins/defaults/memory-v3-shadow/__tests__/capabilities.test.ts +71 -0
  295. package/src/plugins/defaults/memory-v3-shadow/__tests__/dense.test.ts +181 -0
  296. package/src/plugins/defaults/memory-v3-shadow/__tests__/edge.test.ts +247 -0
  297. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/live-integration.test.ts +147 -134
  298. package/src/plugins/defaults/memory-v3-shadow/__tests__/maintain-job.test.ts +456 -0
  299. package/src/plugins/defaults/memory-v3-shadow/__tests__/orchestrate.test.ts +662 -0
  300. package/src/plugins/defaults/memory-v3-shadow/__tests__/pool-select.test.ts +306 -0
  301. package/src/plugins/defaults/memory-v3-shadow/__tests__/render-injection.test.ts +91 -0
  302. package/src/plugins/defaults/memory-v3-shadow/__tests__/section-dense-store.test.ts +402 -0
  303. package/src/plugins/defaults/memory-v3-shadow/__tests__/section-needle.test.ts +135 -0
  304. package/src/plugins/defaults/memory-v3-shadow/__tests__/sections.test.ts +125 -0
  305. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/selection-log-store.test.ts +74 -19
  306. package/src/plugins/defaults/memory-v3-shadow/__tests__/shadow-integration.test.ts +446 -0
  307. package/src/plugins/defaults/memory-v3-shadow/__tests__/shadow-plugin.test.ts +592 -0
  308. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/types.test.ts +2 -24
  309. package/src/plugins/defaults/memory-v3-shadow/capabilities.ts +91 -0
  310. package/src/plugins/defaults/memory-v3-shadow/dense.ts +97 -0
  311. package/src/plugins/defaults/memory-v3-shadow/edge.ts +252 -0
  312. package/src/plugins/defaults/memory-v3-shadow/hooks/post-compact.ts +14 -0
  313. package/src/plugins/defaults/memory-v3-shadow/hooks/user-prompt-submit.ts +19 -0
  314. package/src/plugins/defaults/memory-v3-shadow/injector.ts +76 -0
  315. package/src/plugins/defaults/memory-v3-shadow/maintain-job.ts +555 -0
  316. package/src/plugins/defaults/memory-v3-shadow/orchestrate.ts +266 -0
  317. package/src/plugins/defaults/memory-v3-shadow/package.json +14 -0
  318. package/src/plugins/defaults/memory-v3-shadow/page-content.ts +71 -0
  319. package/src/plugins/defaults/memory-v3-shadow/pool-select.ts +204 -0
  320. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/render-injection.ts +16 -8
  321. package/src/plugins/defaults/memory-v3-shadow/section-dense-store.ts +236 -0
  322. package/src/plugins/defaults/memory-v3-shadow/section-needle.ts +200 -0
  323. package/src/plugins/defaults/memory-v3-shadow/sections.ts +115 -0
  324. package/src/plugins/defaults/memory-v3-shadow/selection-log-store.ts +156 -0
  325. package/src/plugins/defaults/memory-v3-shadow/shadow-plugin.ts +382 -0
  326. package/src/plugins/defaults/memory-v3-shadow/types.ts +92 -0
  327. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/working-set.ts +4 -1
  328. package/src/plugins/defaults/title-generate/package.json +0 -1
  329. package/src/plugins/defaults/tool-error/package.json +0 -1
  330. package/src/plugins/defaults/tool-result-truncate/package.json +0 -1
  331. package/src/plugins/external-api.ts +12 -2
  332. package/src/plugins/pipeline.ts +6 -293
  333. package/src/plugins/registry.ts +9 -37
  334. package/src/plugins/types.ts +76 -381
  335. package/src/plugins/user-loader.ts +30 -127
  336. package/src/prompts/__tests__/system-prompt.test.ts +6 -0
  337. package/src/prompts/system-prompt.ts +61 -10
  338. package/src/prompts/templates/BOOTSTRAP-ACTIVATION-RAIL.md +71 -4
  339. package/src/providers/anthropic/client.ts +9 -10
  340. package/src/providers/inference/kimi-cjk-token-ids.ts +493 -0
  341. package/src/providers/inference/logit-bias.ts +55 -0
  342. package/src/providers/model-catalog.ts +57 -0
  343. package/src/providers/openai/__tests__/vision-not-supported.test.ts +75 -0
  344. package/src/providers/openai/chat-completions-provider.ts +44 -1
  345. package/src/providers/retry.ts +57 -7
  346. package/src/providers/types.ts +6 -0
  347. package/src/runtime/__tests__/agent-wake.test.ts +555 -691
  348. package/src/runtime/__tests__/interactive-ui.test.ts +1 -1
  349. package/src/runtime/agent-wake.ts +108 -209
  350. package/src/runtime/assistant-event-hub.ts +1 -1
  351. package/src/runtime/channel-approvals.ts +1 -1
  352. package/src/runtime/interactive-ui.ts +1 -1
  353. package/src/runtime/routes/__tests__/acp-routes.test.ts +466 -55
  354. package/src/runtime/routes/__tests__/conversation-list-routes.test.ts +1 -1
  355. package/src/runtime/routes/__tests__/plugins-routes.test.ts +423 -73
  356. package/src/runtime/routes/__tests__/stt-routes.test.ts +112 -0
  357. package/src/runtime/routes/__tests__/surface-action-routes.test.ts +5 -4
  358. package/src/runtime/routes/__tests__/surface-content-routes.test.ts +4 -1
  359. package/src/runtime/routes/acp-routes.test.ts +185 -32
  360. package/src/runtime/routes/acp-routes.ts +328 -30
  361. package/src/runtime/routes/app-management-routes.ts +3 -0
  362. package/src/runtime/routes/approval-routes.ts +1 -1
  363. package/src/runtime/routes/browser-routes.ts +1 -1
  364. package/src/runtime/routes/browser-tabs-routes.ts +6 -10
  365. package/src/runtime/routes/channel-verification-routes.ts +14 -5
  366. package/src/runtime/routes/conversation-cli-routes.ts +1 -1
  367. package/src/runtime/routes/conversation-list-routes.ts +1 -1
  368. package/src/runtime/routes/conversation-query-routes.ts +1 -1
  369. package/src/runtime/routes/conversation-routes.ts +30 -2
  370. package/src/runtime/routes/conversation-starter-routes.ts +13 -7
  371. package/src/runtime/routes/conversations-import-routes.ts +24 -7
  372. package/src/runtime/routes/host-app-control-routes.ts +1 -1
  373. package/src/runtime/routes/host-cu-routes.ts +1 -1
  374. package/src/runtime/routes/identity-routes.ts +18 -3
  375. package/src/runtime/routes/inbound-message-handler.ts +1 -1
  376. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +33 -34
  377. package/src/runtime/routes/inference-profile-session-handler.ts +11 -0
  378. package/src/runtime/routes/inference-profile-session-reaper.ts +6 -0
  379. package/src/runtime/routes/memory-v3-routes.ts +65 -305
  380. package/src/runtime/routes/playground/__tests__/force-compact.test.ts +1 -1
  381. package/src/runtime/routes/playground/helpers.ts +1 -1
  382. package/src/runtime/routes/plugins-routes.ts +337 -35
  383. package/src/runtime/routes/stt-routes.ts +45 -12
  384. package/src/runtime/routes/surface-conversation-resolver.ts +4 -3
  385. package/src/runtime/routes/work-items-routes.ts +2 -4
  386. package/src/runtime/routes/workspace-routes.ts +50 -15
  387. package/src/runtime/services/conversation-serializer.ts +1 -1
  388. package/src/runtime/verification-outbound-actions.ts +147 -2
  389. package/src/runtime/verification-templates.ts +29 -3
  390. package/src/services/published-app-updater.ts +30 -8
  391. package/src/signals/cancel.ts +2 -4
  392. package/src/subagent/manager.ts +21 -5
  393. package/src/telemetry/__tests__/activation-funnel.test.ts +95 -0
  394. package/src/telemetry/activation-funnel.ts +167 -0
  395. package/src/telemetry/types.ts +13 -0
  396. package/src/telemetry/usage-telemetry-reporter.test.ts +154 -0
  397. package/src/telemetry/usage-telemetry-reporter.ts +26 -1
  398. package/src/tools/acp/context.ts +20 -0
  399. package/src/tools/acp/list-agents.test.ts +9 -19
  400. package/src/tools/acp/list-agents.ts +3 -15
  401. package/src/tools/acp/spawn.test.ts +173 -202
  402. package/src/tools/acp/spawn.ts +37 -172
  403. package/src/tools/acp/steer.test.ts +105 -8
  404. package/src/tools/acp/steer.ts +48 -17
  405. package/src/tools/apps/executors.ts +166 -50
  406. package/src/tools/browser/browser-execution.ts +12 -2
  407. package/src/tools/filesystem/write.ts +34 -0
  408. package/src/tools/network/web-fetch.ts +65 -24
  409. package/src/tools/skills/load.ts +1 -1
  410. package/src/tools/subagent/spawn.ts +2 -4
  411. package/src/tools/ui-surface/definitions.ts +32 -5
  412. package/src/workspace/migrations/051-seed-conversation-summarization-callsite.ts +4 -5
  413. package/src/workspace/migrations/097-enable-adaptive-thinking-managed-profiles.ts +69 -45
  414. package/docs/plugins.md +0 -832
  415. package/examples/plugins/echo/register.ts +0 -143
  416. package/src/__tests__/circuit-breaker-pipeline.test.ts +0 -405
  417. package/src/__tests__/compaction-pipeline.test.ts +0 -210
  418. package/src/__tests__/compaction-timeout-recovery.test.ts +0 -251
  419. package/src/__tests__/overflow-reduce-pipeline.test.ts +0 -667
  420. package/src/__tests__/pipeline-runner.test.ts +0 -554
  421. package/src/daemon/wake-target-adapter.ts +0 -253
  422. package/src/memory/v3/__tests__/assign.test.ts +0 -242
  423. package/src/memory/v3/__tests__/capabilities.test.ts +0 -118
  424. package/src/memory/v3/__tests__/core.test.ts +0 -39
  425. package/src/memory/v3/__tests__/health.test.ts +0 -219
  426. package/src/memory/v3/__tests__/maintain-job.test.ts +0 -288
  427. package/src/memory/v3/__tests__/needle.test.ts +0 -107
  428. package/src/memory/v3/__tests__/orchestrate.test.ts +0 -436
  429. package/src/memory/v3/__tests__/provider-blocks.test.ts +0 -13
  430. package/src/memory/v3/__tests__/reconcile.test.ts +0 -274
  431. package/src/memory/v3/__tests__/render-injection.test.ts +0 -61
  432. package/src/memory/v3/__tests__/router.test.ts +0 -332
  433. package/src/memory/v3/__tests__/selector.test.ts +0 -470
  434. package/src/memory/v3/__tests__/shadow-plugin.test.ts +0 -432
  435. package/src/memory/v3/__tests__/snapshot.test.ts +0 -168
  436. package/src/memory/v3/__tests__/tree.test.ts +0 -192
  437. package/src/memory/v3/assign.ts +0 -268
  438. package/src/memory/v3/capabilities.ts +0 -124
  439. package/src/memory/v3/core.ts +0 -26
  440. package/src/memory/v3/health.ts +0 -0
  441. package/src/memory/v3/maintain-job.ts +0 -314
  442. package/src/memory/v3/needle.ts +0 -115
  443. package/src/memory/v3/orchestrate.ts +0 -126
  444. package/src/memory/v3/page-content.ts +0 -34
  445. package/src/memory/v3/provider-blocks.ts +0 -26
  446. package/src/memory/v3/reconcile.ts +0 -523
  447. package/src/memory/v3/router.ts +0 -190
  448. package/src/memory/v3/selection-log-store.ts +0 -84
  449. package/src/memory/v3/selector.ts +0 -226
  450. package/src/memory/v3/shadow-plugin.ts +0 -411
  451. package/src/memory/v3/snapshot.ts +0 -209
  452. package/src/memory/v3/tree.ts +0 -174
  453. package/src/memory/v3/types.ts +0 -59
  454. package/src/notifications/__tests__/emit-signal-home-feed.test.ts +0 -187
  455. package/src/plugins/defaults/circuit-breaker/middlewares/circuitBreaker.ts +0 -93
  456. package/src/plugins/defaults/circuit-breaker/package.json +0 -15
  457. package/src/plugins/defaults/circuit-breaker/register.ts +0 -39
  458. package/src/plugins/defaults/compaction/middlewares/compaction.ts +0 -25
  459. package/src/plugins/defaults/compaction/register.ts +0 -35
  460. package/src/plugins/defaults/compaction/terminal.ts +0 -73
  461. package/src/plugins/defaults/empty-response/register.ts +0 -23
  462. package/src/plugins/defaults/history-repair/register.ts +0 -24
  463. package/src/plugins/defaults/memory-retrieval/hooks/user-prompt-submit-temp.ts +0 -216
  464. package/src/plugins/defaults/overflow-reduce/middlewares/overflowReduce.ts +0 -126
  465. package/src/plugins/defaults/overflow-reduce/package.json +0 -15
  466. package/src/plugins/defaults/overflow-reduce/register.ts +0 -42
  467. package/src/plugins/defaults/title-generate/register.ts +0 -35
  468. package/src/plugins/defaults/tool-error/register.ts +0 -23
  469. package/src/plugins/defaults/tool-result-truncate/register.ts +0 -24
  470. package/src/proactive-artifact/aux-message-injector.ts +0 -97
  471. package/src/proactive-artifact/decision.test.ts +0 -226
  472. package/src/proactive-artifact/decision.ts +0 -165
  473. package/src/proactive-artifact/index.ts +0 -7
  474. package/src/proactive-artifact/job.test.ts +0 -962
  475. package/src/proactive-artifact/job.ts +0 -372
  476. package/src/proactive-artifact/message-copy.ts +0 -58
  477. package/src/proactive-artifact/trigger-state.test.ts +0 -286
  478. package/src/proactive-artifact/trigger-state.ts +0 -123
  479. package/src/util/map-limit.ts +0 -27
  480. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/fixtures/eval-turns.json +0 -0
  481. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/fixtures/live-turns.json +0 -0
  482. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/working-set-eviction.test.ts +0 -0
  483. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/working-set-skeleton.test.ts +0 -0
  484. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/README.md +0 -0
  485. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/assignments.json +0 -0
  486. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/core.json +0 -0
  487. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/leaves/domain-a/topic-x.md +0 -0
  488. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/leaves/domain-a/topic-y.md +0 -0
  489. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/leaves/domain-b/topic-z.md +0 -0
  490. /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
  });