@vellumai/assistant 0.8.3 → 0.8.5

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 (665) hide show
  1. package/ARCHITECTURE.md +2 -2
  2. package/docker-entrypoint.sh +0 -1
  3. package/docs/browser-use-architecture-phase2.md +1 -1
  4. package/knip.json +2 -1
  5. package/node_modules/@vellumai/gateway-client/src/types.ts +2 -0
  6. package/openapi.yaml +1492 -100
  7. package/package.json +1 -1
  8. package/src/__tests__/agent-loop-exit-reason.test.ts +4 -5
  9. package/src/__tests__/agent-loop-override-profile.test.ts +1 -1
  10. package/src/__tests__/agent-loop.test.ts +88 -3
  11. package/src/__tests__/anthropic-provider.test.ts +302 -33
  12. package/src/__tests__/approval-cascade.test.ts +1 -1
  13. package/src/__tests__/assistant-event-hub-self-exclusion.test.ts +293 -0
  14. package/src/__tests__/assistant-feature-flags-integration.test.ts +3 -3
  15. package/src/__tests__/audit-log-rotation.test.ts +70 -16
  16. package/src/__tests__/background-workers-disk-pressure.test.ts +4 -3
  17. package/src/__tests__/btw-routes.test.ts +2 -3
  18. package/src/__tests__/call-controller.test.ts +0 -1
  19. package/src/__tests__/cancel-resolves-conversation-key.test.ts +1 -1
  20. package/src/__tests__/channel-delivery-store.test.ts +193 -0
  21. package/src/__tests__/channel-guardian.test.ts +3 -3
  22. package/src/__tests__/channel-reply-delivery.test.ts +284 -5
  23. package/src/__tests__/channel-retry-sweep.test.ts +274 -1
  24. package/src/__tests__/checker.test.ts +6 -15
  25. package/src/__tests__/compaction-events.test.ts +2 -1
  26. package/src/__tests__/compactor-call-site-logging.test.ts +214 -0
  27. package/src/__tests__/compactor-preserved-tail-count.test.ts +110 -0
  28. package/src/__tests__/computer-use-skill-manifest-regression.test.ts +5 -11
  29. package/src/__tests__/computer-use-tools.test.ts +2 -4
  30. package/src/__tests__/config-watcher.test.ts +1 -1
  31. package/src/__tests__/confirmation-request-guardian-bridge.test.ts +0 -1
  32. package/src/__tests__/context-token-estimator.test.ts +91 -1
  33. package/src/__tests__/conversation-abort-tool-results.test.ts +1 -1
  34. package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +1 -1
  35. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +55 -4
  36. package/src/__tests__/conversation-agent-loop-overflow.test.ts +228 -8
  37. package/src/__tests__/conversation-agent-loop.test.ts +188 -129
  38. package/src/__tests__/conversation-app-control-instantiation.test.ts +2 -5
  39. package/src/__tests__/conversation-app-control-lifecycle.test.ts +1 -1
  40. package/src/__tests__/conversation-clean-command.test.ts +137 -0
  41. package/src/__tests__/conversation-clear-safety.test.ts +25 -25
  42. package/src/__tests__/conversation-confirmation-signals.test.ts +1 -1
  43. package/src/__tests__/conversation-delete-schedule-cleanup.test.ts +1 -1
  44. package/src/__tests__/conversation-disk-view-integration.test.ts +2 -2
  45. package/src/__tests__/conversation-error.test.ts +31 -0
  46. package/src/__tests__/conversation-fork-crud.test.ts +324 -0
  47. package/src/__tests__/conversation-lifecycle.test.ts +53 -12
  48. package/src/__tests__/conversation-load-history-repair.test.ts +1 -1
  49. package/src/__tests__/conversation-load-history-stripped.test.ts +279 -0
  50. package/src/__tests__/conversation-pairing.test.ts +2 -2
  51. package/src/__tests__/conversation-process-callsite.test.ts +1 -1
  52. package/src/__tests__/conversation-provider-retry-repair.test.ts +2 -1
  53. package/src/__tests__/conversation-queue.test.ts +1 -1
  54. package/src/__tests__/conversation-routes-disk-view.test.ts +109 -0
  55. package/src/__tests__/conversation-routes-slash-commands.test.ts +35 -0
  56. package/src/__tests__/conversation-runtime-assembly.test.ts +264 -81
  57. package/src/__tests__/conversation-seed-composer.test.ts +66 -4
  58. package/src/__tests__/conversation-skill-tools.test.ts +2 -5
  59. package/src/__tests__/conversation-slash-commands.test.ts +36 -8
  60. package/src/__tests__/conversation-slash-queue.test.ts +1 -1
  61. package/src/__tests__/conversation-slash-unknown.test.ts +1 -1
  62. package/src/__tests__/conversation-speed-override.test.ts +1 -1
  63. package/src/__tests__/conversation-store.test.ts +1 -1
  64. package/src/__tests__/conversation-surfaces-task-progress.test.ts +220 -0
  65. package/src/__tests__/conversation-sync-tags.test.ts +99 -32
  66. package/src/__tests__/conversation-workspace-cache-state.test.ts +2 -1
  67. package/src/__tests__/conversation-workspace-injection.test.ts +5 -1
  68. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +5 -1
  69. package/src/__tests__/credential-execution-feature-gates.test.ts +9 -7
  70. package/src/__tests__/credential-execution-tools.test.ts +6 -6
  71. package/src/__tests__/credential-security-invariants.test.ts +7 -0
  72. package/src/__tests__/credential-vault-unit.test.ts +2 -2
  73. package/src/__tests__/cu-unified-flow.test.ts +10 -1
  74. package/src/__tests__/dm-backfill.test.ts +64 -0
  75. package/src/__tests__/dm-persistence.test.ts +33 -0
  76. package/src/__tests__/document-find-replace.test.ts +501 -0
  77. package/src/__tests__/dynamic-page-surface.test.ts +2 -2
  78. package/src/__tests__/email-html-renderer.test.ts +12 -0
  79. package/src/__tests__/first-greeting.test.ts +23 -2
  80. package/src/__tests__/gateway-flag-listener.test.ts +237 -0
  81. package/src/__tests__/gemini-provider.test.ts +78 -0
  82. package/src/__tests__/guardian-dispatch.test.ts +0 -1
  83. package/src/__tests__/guardian-outbound-http.test.ts +7 -5
  84. package/src/__tests__/handlers-user-message-approval-consumption.test.ts +1 -1
  85. package/src/__tests__/headless-browser-navigate.test.ts +172 -0
  86. package/src/__tests__/heartbeat-disk-pressure.test.ts +4 -0
  87. package/src/__tests__/heartbeat-service.test.ts +4 -0
  88. package/src/__tests__/host-bash-proxy.test.ts +6 -0
  89. package/src/__tests__/host-browser-proxy.test.ts +10 -0
  90. package/src/__tests__/host-cu-proxy.test.ts +8 -1
  91. package/src/__tests__/host-file-proxy.test.ts +8 -1
  92. package/src/__tests__/host-shell-tool.test.ts +1 -1
  93. package/src/__tests__/host-transfer-proxy.test.ts +8 -1
  94. package/src/__tests__/identity-routes.test.ts +57 -0
  95. package/src/__tests__/inbound-slack-persistence.test.ts +3 -0
  96. package/src/__tests__/init-feature-flag-overrides.test.ts +5 -6
  97. package/src/__tests__/injector-chain.test.ts +2 -0
  98. package/src/__tests__/injector-document-comments.test.ts +378 -0
  99. package/src/__tests__/injector-pkb-v2-silenced.test.ts +4 -25
  100. package/src/__tests__/list-messages-attachments.test.ts +21 -17
  101. package/src/__tests__/list-messages-hidden-metadata.test.ts +217 -0
  102. package/src/__tests__/list-messages-page-latest.test.ts +130 -14
  103. package/src/__tests__/list-messages-tool-merge.test.ts +77 -17
  104. package/src/__tests__/llm-context-normalization.test.ts +0 -2
  105. package/src/__tests__/llm-request-log-call-site.test.ts +136 -0
  106. package/src/__tests__/llm-request-log-source-clickhouse.test.ts +26 -0
  107. package/src/__tests__/llm-resolver.test.ts +161 -9
  108. package/src/__tests__/llm-usage-store.test.ts +66 -0
  109. package/src/__tests__/log-export-routes.test.ts +99 -2
  110. package/src/__tests__/logger.test.ts +89 -0
  111. package/src/__tests__/mcp-abort-signal.test.ts +2 -2
  112. package/src/__tests__/media-generate-image.test.ts +31 -0
  113. package/src/__tests__/memory-v2-static-injector.test.ts +7 -7
  114. package/src/__tests__/message-queue-steer.test.ts +114 -0
  115. package/src/__tests__/model-intents.test.ts +2 -4
  116. package/src/__tests__/notification-guardian-path.test.ts +0 -1
  117. package/src/__tests__/onboarding-template-contract.test.ts +1 -1
  118. package/src/__tests__/openai-provider.test.ts +151 -0
  119. package/src/__tests__/openai-responses-provider.test.ts +118 -16
  120. package/src/__tests__/outbound-slack-persistence.test.ts +187 -20
  121. package/src/__tests__/pending-interactions-resolved-event.test.ts +189 -0
  122. package/src/__tests__/platform-bash-auto-approve.test.ts +2 -2
  123. package/src/__tests__/platform.test.ts +2 -5
  124. package/src/__tests__/plugin-api-tool-definition.test.ts +92 -0
  125. package/src/__tests__/plugin-bootstrap.test.ts +2 -2
  126. package/src/__tests__/plugin-source-watcher.test.ts +302 -0
  127. package/src/__tests__/plugin-tool-contribution.test.ts +13 -6
  128. package/src/__tests__/plugin-types.test.ts +3 -2
  129. package/src/__tests__/prechat-onboarding-contract.test.ts +131 -98
  130. package/src/__tests__/pricing.test.ts +12 -0
  131. package/src/__tests__/process-message-background-slack.test.ts +1 -51
  132. package/src/__tests__/process-message-display-content.test.ts +21 -16
  133. package/src/__tests__/prune-jobs-changes-parser.test.ts +61 -0
  134. package/src/__tests__/registry.test.ts +2 -8
  135. package/src/__tests__/require-fresh-approval.test.ts +2 -2
  136. package/src/__tests__/runtime-events-sse-bilingual.test.ts +154 -0
  137. package/src/__tests__/server-history-render.test.ts +83 -4
  138. package/src/__tests__/shell-tool-proxy-mode.test.ts +1 -1
  139. package/src/__tests__/skill-feature-flags.test.ts +2 -2
  140. package/src/__tests__/skill-projection-feature-flag.test.ts +4 -7
  141. package/src/__tests__/skill-projection.benchmark.test.ts +2 -6
  142. package/src/__tests__/skill-tool-factory.test.ts +1 -1
  143. package/src/__tests__/steer-tool-repair.test.ts +249 -0
  144. package/src/__tests__/subagent-notify-parent.test.ts +1 -1
  145. package/src/__tests__/suggestion-routes.test.ts +1 -0
  146. package/src/__tests__/sync-message-contract.test.ts +59 -0
  147. package/src/__tests__/system-prompt.test.ts +161 -124
  148. package/src/__tests__/terminal-tools.test.ts +12 -2
  149. package/src/__tests__/thinking-block-replay.test.ts +113 -0
  150. package/src/__tests__/thread-backfill.test.ts +370 -22
  151. package/src/__tests__/tool-approval-handler.test.ts +1 -5
  152. package/src/__tests__/tool-execute-pipeline.test.ts +2 -2
  153. package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +2 -5
  154. package/src/__tests__/tool-executor-lifecycle-events.test.ts +15 -5
  155. package/src/__tests__/tool-executor.test.ts +89 -53
  156. package/src/__tests__/tool-grant-request-escalation.test.ts +1 -6
  157. package/src/__tests__/tool-result-metadata-plumbing.test.ts +167 -0
  158. package/src/__tests__/trusted-contact-approval-notifier.test.ts +0 -1
  159. package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +1 -6
  160. package/src/__tests__/trusted-contact-multichannel.test.ts +0 -1
  161. package/src/__tests__/twilio-routes.test.ts +1 -1
  162. package/src/__tests__/ui-file-upload-surface.test.ts +2 -2
  163. package/src/__tests__/usage-routes.test.ts +3 -0
  164. package/src/__tests__/verification-control-plane-policy.test.ts +2 -2
  165. package/src/__tests__/web-fetch.test.ts +2 -2
  166. package/src/__tests__/workspace-git-service.test.ts +94 -10
  167. package/src/__tests__/workspace-migration-088-deprecate-background-conversation-override.test.ts +158 -0
  168. package/src/__tests__/workspace-migration-089-move-memory-tree-out-of-v3.test.ts +86 -0
  169. package/src/acp/__tests__/prepare-agent-env.test.ts +146 -0
  170. package/src/acp/prepare-agent-env.ts +78 -0
  171. package/src/acp/session-manager.ts +1 -1
  172. package/src/agent/attachments.ts +1 -0
  173. package/src/agent/loop.ts +65 -20
  174. package/src/api/README.md +5 -0
  175. package/src/api/index.ts +4 -0
  176. package/src/api/package.json +10 -0
  177. package/src/background-wake/background-wake-routes.test.ts +233 -0
  178. package/src/background-wake/next-wake.test.ts +289 -0
  179. package/src/background-wake/next-wake.ts +172 -0
  180. package/src/background-wake/runtime-registry.ts +24 -0
  181. package/src/browser/operations.ts +15 -0
  182. package/src/cli/commands/__tests__/browser.test.ts +23 -5
  183. package/src/cli/commands/__tests__/conversations-slack.test.ts +572 -0
  184. package/src/cli/commands/__tests__/domain-register.test.ts +110 -0
  185. package/src/cli/commands/__tests__/domain-status.test.ts +33 -33
  186. package/src/cli/commands/__tests__/inference-send.test.ts +108 -5
  187. package/src/cli/commands/__tests__/memory-v2-compare-render.test.ts +98 -0
  188. package/src/cli/commands/__tests__/memory-v2.test.ts +10 -12
  189. package/src/cli/commands/__tests__/memory-v3-render.test.ts +340 -0
  190. package/src/cli/commands/browser.ts +247 -0
  191. package/src/cli/commands/conversations.ts +128 -1
  192. package/src/cli/commands/domain.ts +91 -41
  193. package/src/cli/commands/inference-providers.ts +147 -1
  194. package/src/cli/commands/inference.ts +93 -40
  195. package/src/cli/commands/memory-v2-compare-render.ts +115 -0
  196. package/src/cli/commands/memory-v2.ts +483 -0
  197. package/src/cli/commands/memory-v3-render.ts +344 -0
  198. package/src/cli/commands/memory-v3.ts +316 -0
  199. package/src/cli/commands/notifications.ts +24 -2
  200. package/src/cli/program.ts +2 -0
  201. package/src/cli/utils/conversation-id.ts +17 -5
  202. package/src/config/assistant-feature-flags.ts +21 -9
  203. package/src/config/bundled-skills/app-builder/SKILL.md +2 -2
  204. package/src/config/bundled-skills/document-editor/SKILL.md +124 -0
  205. package/src/config/bundled-skills/document-editor/TOOLS.json +258 -0
  206. package/src/config/bundled-skills/document-editor/tools/comment-list.ts +12 -0
  207. package/src/config/bundled-skills/document-editor/tools/comment-reply.ts +12 -0
  208. package/src/config/bundled-skills/document-editor/tools/comment-resolve.ts +12 -0
  209. package/src/config/bundled-skills/document-editor/tools/document-find.ts +12 -0
  210. package/src/config/bundled-skills/document-editor/tools/document-open.ts +12 -0
  211. package/src/config/bundled-skills/document-editor/tools/document-replace-text.ts +12 -0
  212. package/src/config/bundled-skills/image-studio/SKILL.md +4 -0
  213. package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +2 -2
  214. package/src/config/bundled-skills/media-processing/SKILL.md +8 -0
  215. package/src/config/bundled-skills/media-processing/tools/ingest-media.ts +13 -8
  216. package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +10 -3
  217. package/src/config/bundled-skills/phone-calls/references/TRANSCRIPTS.md +16 -14
  218. package/src/config/bundled-skills/playbooks/tools/playbook-create.ts +7 -2
  219. package/src/config/bundled-skills/playbooks/tools/playbook-update.ts +7 -2
  220. package/src/config/bundled-skills/schedule/SKILL.md +8 -0
  221. package/src/config/bundled-tool-registry.ts +24 -12
  222. package/src/config/call-site-defaults.ts +20 -0
  223. package/src/config/feature-flag-registry.json +115 -3
  224. package/src/config/llm-resolver.ts +16 -2
  225. package/src/config/schemas/__tests__/memory-v2.test.ts +217 -1
  226. package/src/config/schemas/call-site-catalog.ts +35 -0
  227. package/src/config/schemas/llm.ts +14 -0
  228. package/src/config/schemas/memory-v2.ts +294 -1
  229. package/src/config/schemas/memory.ts +2 -1
  230. package/src/context/compactor.ts +60 -1
  231. package/src/context/token-estimator.ts +47 -4
  232. package/src/context/window-manager.ts +25 -0
  233. package/src/conversations/__tests__/message-consolidation.test.ts +350 -0
  234. package/src/conversations/message-consolidation.ts +404 -0
  235. package/src/credential-health/credential-health-service.ts +34 -19
  236. package/src/daemon/__tests__/conversation-tool-setup-exclude.test.ts +1 -1
  237. package/src/daemon/__tests__/conversation-tool-setup.test.ts +66 -6
  238. package/src/daemon/__tests__/meet-manifest-loader.test.ts +1 -1
  239. package/src/daemon/__tests__/native-web-search-metadata.test.ts +357 -0
  240. package/src/daemon/__tests__/web-search-status-text.test.ts +287 -0
  241. package/src/daemon/conversation-agent-loop-handlers.ts +155 -36
  242. package/src/daemon/conversation-agent-loop.ts +307 -88
  243. package/src/daemon/conversation-error.ts +31 -1
  244. package/src/daemon/conversation-lifecycle.ts +149 -118
  245. package/src/daemon/conversation-messaging.ts +3 -0
  246. package/src/daemon/conversation-process.ts +273 -0
  247. package/src/daemon/conversation-queue-manager.ts +14 -0
  248. package/src/daemon/conversation-runtime-assembly.ts +145 -84
  249. package/src/daemon/conversation-slash.ts +37 -5
  250. package/src/daemon/conversation-surfaces.ts +45 -2
  251. package/src/daemon/conversation-tool-setup.ts +70 -3
  252. package/src/daemon/conversation-usage.ts +2 -0
  253. package/src/daemon/conversation.ts +54 -32
  254. package/src/daemon/disk-pressure-guard.ts +14 -2
  255. package/src/daemon/first-greeting.ts +10 -0
  256. package/src/daemon/handlers/__tests__/config-a2a-accept.test.ts +498 -0
  257. package/src/daemon/handlers/config-a2a.ts +160 -0
  258. package/src/daemon/handlers/config-model.test.ts +2 -0
  259. package/src/daemon/handlers/conversations.ts +90 -3
  260. package/src/daemon/handlers/shared.ts +92 -29
  261. package/src/daemon/host-bash-proxy.ts +1 -1
  262. package/src/daemon/host-browser-proxy.ts +5 -5
  263. package/src/daemon/host-cu-proxy.ts +5 -5
  264. package/src/daemon/host-file-proxy.ts +5 -5
  265. package/src/daemon/host-proxy-base.ts +4 -4
  266. package/src/daemon/host-transfer-proxy.ts +11 -11
  267. package/src/daemon/lifecycle.ts +40 -23
  268. package/src/daemon/meet-manifest-loader.ts +1 -7
  269. package/src/daemon/message-protocol.ts +4 -0
  270. package/src/daemon/message-types/conversations.ts +14 -9
  271. package/src/daemon/message-types/document-comments.ts +50 -0
  272. package/src/daemon/message-types/home.ts +1 -13
  273. package/src/daemon/message-types/messages.ts +66 -7
  274. package/src/daemon/message-types/surfaces.ts +3 -1
  275. package/src/daemon/message-types/sync.ts +14 -0
  276. package/src/daemon/message-types/web-activity.ts +57 -0
  277. package/src/daemon/plugin-source-watcher.ts +135 -3
  278. package/src/daemon/process-message.ts +69 -12
  279. package/src/daemon/shutdown-handlers.ts +24 -5
  280. package/src/daemon/switch-inference-profile-tool.ts +52 -0
  281. package/src/daemon/tool-setup-types.ts +13 -0
  282. package/src/daemon/trust-context.ts +6 -0
  283. package/src/documents/document-comments-store.test.ts +338 -0
  284. package/src/documents/document-comments-store.ts +237 -0
  285. package/src/documents/document-store.ts +202 -0
  286. package/src/events/relationship-state-updated.ts +25 -0
  287. package/src/heartbeat/__tests__/heartbeat-service.test.ts +1 -2
  288. package/src/heartbeat/heartbeat-service.ts +1 -0
  289. package/src/home/__tests__/suggested-prompts.test.ts +33 -2
  290. package/src/home/feed-types.ts +6 -1
  291. package/src/home/home-content-refresh.ts +52 -0
  292. package/src/home/home-greeting-cache.ts +69 -0
  293. package/src/home/home-greeting.ts +85 -0
  294. package/src/home/suggested-prompts.ts +168 -9
  295. package/src/ipc/gateway-flag-listener.ts +123 -0
  296. package/src/ipc/skill-routes/registries.ts +8 -12
  297. package/src/memory/__tests__/db-async-query.test.ts +165 -0
  298. package/src/memory/__tests__/db-maintenance.test.ts +115 -0
  299. package/src/memory/__tests__/jobs-store-enqueue-gate.test.ts +241 -0
  300. package/src/memory/__tests__/jobs-store-job-classes.test.ts +28 -1
  301. package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +135 -2
  302. package/src/memory/__tests__/memory-retrospective-job.test.ts +327 -6
  303. package/src/memory/auto-analysis-enqueue.ts +5 -1
  304. package/src/memory/conversation-crud.ts +191 -100
  305. package/src/memory/conversation-starters-cadence.ts +3 -1
  306. package/src/memory/conversation-title-service.ts +19 -3
  307. package/src/memory/db-async-query.ts +214 -0
  308. package/src/memory/db-init.ts +26 -0
  309. package/src/memory/db-maintenance.ts +30 -21
  310. package/src/memory/delivery-crud.ts +41 -0
  311. package/src/memory/delivery-status.ts +141 -15
  312. package/src/memory/external-conversation-store.ts +32 -1
  313. package/src/memory/graph/bootstrap.ts +8 -1
  314. package/src/memory/graph/capability-seed.ts +7 -3
  315. package/src/memory/graph/conversation-graph-memory.ts +100 -17
  316. package/src/memory/graph/extraction.ts +1 -5
  317. package/src/memory/graph/graph-search.ts +7 -1
  318. package/src/memory/indexer.ts +28 -18
  319. package/src/memory/job-handlers/cleanup.ts +76 -18
  320. package/src/memory/job-handlers/conversation-starters.ts +1 -4
  321. package/src/memory/jobs/embed-pkb-file.ts +6 -1
  322. package/src/memory/jobs-store.ts +14 -0
  323. package/src/memory/jobs-worker.ts +68 -15
  324. package/src/memory/llm-request-log-source-clickhouse.ts +42 -2
  325. package/src/memory/llm-request-log-source-local.ts +7 -0
  326. package/src/memory/llm-request-log-source.ts +9 -2
  327. package/src/memory/llm-request-log-store.ts +43 -1
  328. package/src/memory/llm-usage-store.ts +24 -0
  329. package/src/memory/memory-retrospective-constants.ts +28 -0
  330. package/src/memory/memory-retrospective-enqueue.ts +11 -3
  331. package/src/memory/memory-retrospective-job.ts +413 -18
  332. package/src/memory/memory-retrospective-startup-cleanup.ts +3 -3
  333. package/src/memory/memory-v2-activation-log-store.ts +41 -14
  334. package/src/memory/migrations/100-core-tables.ts +1 -0
  335. package/src/memory/migrations/109-external-conversation-bindings.ts +1 -0
  336. package/src/memory/migrations/253-conversation-last-notified-profile.ts +15 -0
  337. package/src/memory/migrations/253-document-comments.ts +47 -0
  338. package/src/memory/migrations/254-external-conversation-binding-chat-name.ts +43 -0
  339. package/src/memory/migrations/255-channel-inbound-delivery-attempts.ts +24 -0
  340. package/src/memory/migrations/256-memory-v2-injection-events.ts +113 -0
  341. package/src/memory/migrations/257-strip-base-url-non-openai-compatible.ts +22 -0
  342. package/src/memory/migrations/258-onboarding-events-prior-assistants.ts +13 -0
  343. package/src/memory/migrations/259-conversation-cleaned-at.ts +33 -0
  344. package/src/memory/migrations/260-rename-cleaned-at.ts +44 -0
  345. package/src/memory/migrations/261-llm-usage-add-raw-usage.ts +36 -0
  346. package/src/memory/migrations/262-memory-v3-coactivation.ts +57 -0
  347. package/src/memory/migrations/263-memory-v3-auto-edges.ts +50 -0
  348. package/src/memory/migrations/264-llm-request-log-call-site.ts +29 -0
  349. package/src/memory/migrations/index.ts +34 -0
  350. package/src/memory/migrations/registry.ts +58 -0
  351. package/src/memory/onboarding-events-store.ts +7 -0
  352. package/src/memory/schema/calls.ts +1 -0
  353. package/src/memory/schema/conversations.ts +3 -0
  354. package/src/memory/schema/infrastructure.ts +22 -0
  355. package/src/memory/tool-usage-store.ts +36 -8
  356. package/src/memory/v2/__tests__/consolidation-job.test.ts +1 -0
  357. package/src/memory/v2/__tests__/harness-compare.test.ts +186 -0
  358. package/src/memory/v2/__tests__/harness-metrics.test.ts +74 -0
  359. package/src/memory/v2/__tests__/harness-oracle.test.ts +257 -0
  360. package/src/memory/v2/__tests__/harness-replay-input.test.ts +225 -0
  361. package/src/memory/v2/__tests__/harness-runner.test.ts +109 -0
  362. package/src/memory/v2/__tests__/injection-events.test.ts +318 -0
  363. package/src/memory/v2/__tests__/injection.test.ts +158 -112
  364. package/src/memory/v2/__tests__/page-index.test.ts +365 -1
  365. package/src/memory/v2/__tests__/qdrant.test.ts +36 -0
  366. package/src/memory/v2/__tests__/router.test.ts +660 -4
  367. package/src/memory/v2/consolidation-job.ts +14 -0
  368. package/src/memory/v2/harness/compare.ts +57 -0
  369. package/src/memory/v2/harness/metrics.ts +124 -0
  370. package/src/memory/v2/harness/oracle.ts +145 -0
  371. package/src/memory/v2/harness/replay-input.ts +224 -0
  372. package/src/memory/v2/harness/retriever.ts +74 -0
  373. package/src/memory/v2/harness/router-retriever.ts +43 -0
  374. package/src/memory/v2/harness/runner.ts +106 -0
  375. package/src/memory/v2/harness/trace.ts +58 -0
  376. package/src/memory/v2/injection-events.ts +101 -0
  377. package/src/memory/v2/injection.ts +42 -25
  378. package/src/memory/v2/page-index.ts +209 -7
  379. package/src/memory/v2/page-store.ts +18 -0
  380. package/src/memory/v2/prompts/router.ts +26 -1
  381. package/src/memory/v2/qdrant.ts +14 -2
  382. package/src/memory/v2/router.ts +369 -62
  383. package/src/memory/v3/__tests__/coactivation-store.test.ts +422 -0
  384. package/src/memory/v3/__tests__/consolidation-job.test.ts +468 -0
  385. package/src/memory/v3/__tests__/edge-learning-job.test.ts +324 -0
  386. package/src/memory/v3/__tests__/edges.test.ts +563 -0
  387. package/src/memory/v3/__tests__/filter.test.ts +512 -0
  388. package/src/memory/v3/__tests__/gate.test.ts +574 -0
  389. package/src/memory/v3/__tests__/index-composition.test.ts +233 -0
  390. package/src/memory/v3/__tests__/loop.test.ts +530 -0
  391. package/src/memory/v3/__tests__/retriever.test.ts +226 -0
  392. package/src/memory/v3/__tests__/scouts.test.ts +440 -0
  393. package/src/memory/v3/__tests__/shadow-middleware.test.ts +312 -0
  394. package/src/memory/v3/__tests__/system-prompts.test.ts +154 -0
  395. package/src/memory/v3/__tests__/traversal.test.ts +469 -0
  396. package/src/memory/v3/__tests__/tree-index.test.ts +280 -0
  397. package/src/memory/v3/__tests__/tree-store.test.ts +529 -0
  398. package/src/memory/v3/__tests__/tree-walk.test.ts +707 -0
  399. package/src/memory/v3/__tests__/validate.test.ts +245 -0
  400. package/src/memory/v3/auto-edges.ts +223 -0
  401. package/src/memory/v3/coactivation-store.ts +124 -0
  402. package/src/memory/v3/consolidation-job.ts +323 -0
  403. package/src/memory/v3/edge-learning-job.ts +160 -0
  404. package/src/memory/v3/edges.ts +249 -0
  405. package/src/memory/v3/filter.ts +281 -0
  406. package/src/memory/v3/gate.ts +334 -0
  407. package/src/memory/v3/index-composition.ts +113 -0
  408. package/src/memory/v3/llm-capture.ts +46 -0
  409. package/src/memory/v3/loop.ts +382 -0
  410. package/src/memory/v3/maintenance.ts +144 -0
  411. package/src/memory/v3/prompt-context.ts +33 -0
  412. package/src/memory/v3/prompts/consolidation.ts +458 -0
  413. package/src/memory/v3/prompts/system-prompts.ts +196 -0
  414. package/src/memory/v3/retriever.ts +33 -0
  415. package/src/memory/v3/scouts.ts +420 -0
  416. package/src/memory/v3/shadow-middleware.ts +305 -0
  417. package/src/memory/v3/traversal.ts +206 -0
  418. package/src/memory/v3/tree-index.ts +237 -0
  419. package/src/memory/v3/tree-store.ts +394 -0
  420. package/src/memory/v3/tree-walk.ts +351 -0
  421. package/src/memory/v3/types.ts +65 -0
  422. package/src/memory/v3/validate.ts +300 -0
  423. package/src/messaging/providers/index.ts +7 -1
  424. package/src/messaging/providers/slack/__tests__/adapter-mention-rendering.test.ts +329 -3
  425. package/src/messaging/providers/slack/__tests__/adapter-token-routing.test.ts +34 -1
  426. package/src/messaging/providers/slack/adapter.ts +178 -25
  427. package/src/messaging/providers/slack/api.test.ts +54 -0
  428. package/src/messaging/providers/slack/api.ts +119 -3
  429. package/src/messaging/providers/slack/client.ts +12 -0
  430. package/src/messaging/providers/slack/deep-link.ts +20 -1
  431. package/src/messaging/providers/slack/message-metadata.test.ts +48 -0
  432. package/src/messaging/providers/slack/message-metadata.ts +156 -0
  433. package/src/messaging/providers/slack/render-transcript.test.ts +107 -75
  434. package/src/messaging/providers/slack/render-transcript.ts +176 -49
  435. package/src/messaging/providers/slack/send.test.ts +77 -0
  436. package/src/messaging/providers/slack/send.ts +8 -2
  437. package/src/messaging/providers/slack/types.ts +14 -0
  438. package/src/notifications/__tests__/emit-signal-home-feed.test.ts +4 -1
  439. package/src/notifications/__tests__/home-feed-side-effect.test.ts +116 -54
  440. package/src/notifications/adapters/macos.ts +18 -1
  441. package/src/notifications/adapters/platform.ts +1 -1
  442. package/src/notifications/conversation-seed-composer.ts +14 -2
  443. package/src/notifications/decision-engine.ts +1 -4
  444. package/src/notifications/deferred-emit.ts +135 -0
  445. package/src/notifications/emit-signal.ts +38 -50
  446. package/src/notifications/home-feed-side-effect.ts +60 -30
  447. package/src/oauth/connect-orchestrator.ts +3 -0
  448. package/src/oauth/credential-token-resolver.ts +2 -0
  449. package/src/oauth/manual-token-connection.ts +19 -0
  450. package/src/oauth/oauth-store.ts +12 -0
  451. package/src/oauth/seed-providers.ts +22 -0
  452. package/src/permissions/prompter.ts +8 -5
  453. package/src/permissions/question-prompter.ts +5 -2
  454. package/src/permissions/secret-prompter.ts +6 -3
  455. package/src/plugin-api/index.ts +4 -0
  456. package/src/plugin-api/types.ts +7 -33
  457. package/src/plugins/defaults/index.ts +6 -0
  458. package/src/plugins/defaults/injectors.ts +100 -20
  459. package/src/plugins/external-plugin-loader.ts +5 -68
  460. package/src/plugins/types.ts +11 -16
  461. package/src/proactive-artifact/aux-message-injector.ts +17 -4
  462. package/src/prompts/__tests__/system-prompt.test.ts +46 -2
  463. package/src/prompts/__tests__/task-progress-hint-section.test.ts +3 -9
  464. package/src/prompts/normalize-onboarding.ts +40 -0
  465. package/src/prompts/persona-resolver.ts +36 -21
  466. package/src/prompts/sections.ts +69 -19
  467. package/src/prompts/system-prompt.ts +118 -216
  468. package/src/prompts/template-detection.ts +37 -0
  469. package/src/prompts/templates/BOOTSTRAP-CONTENT-AUTOMATION.md +141 -0
  470. package/src/prompts/templates/BOOTSTRAP.md +10 -2
  471. package/src/prompts/templates/VOICE.md +3 -0
  472. package/src/prompts/templates/system-sections.ts +281 -9
  473. package/src/providers/__tests__/connection-model-compat.test.ts +234 -0
  474. package/src/providers/__tests__/retry-callsite.test.ts +85 -5
  475. package/src/providers/anthropic/client.ts +159 -66
  476. package/src/providers/call-site-routing.ts +14 -2
  477. package/src/providers/connection-model-compat.ts +38 -0
  478. package/src/providers/connection-resolution.ts +16 -2
  479. package/src/providers/fireworks/client.ts +20 -2
  480. package/src/providers/gemini/client.ts +49 -6
  481. package/src/providers/inference/__tests__/base-url-route-validation.test.ts +342 -0
  482. package/src/providers/inference/__tests__/base-url-security.test.ts +189 -0
  483. package/src/providers/inference/__tests__/codex-token-refresh.test.ts +254 -0
  484. package/src/providers/inference/adapter-factory.ts +18 -1
  485. package/src/providers/inference/auth.ts +3 -3
  486. package/src/providers/inference/codex-token-refresh.ts +128 -0
  487. package/src/providers/inference/resolve-auth.ts +49 -6
  488. package/src/providers/minimax/client.ts +106 -0
  489. package/src/providers/model-catalog.ts +91 -1
  490. package/src/providers/model-intents.ts +1 -1
  491. package/src/providers/openai/chat-completions-provider.ts +63 -23
  492. package/src/providers/openai/codex-models.ts +18 -0
  493. package/src/providers/openai/responses-provider.ts +86 -23
  494. package/src/providers/openrouter/client.ts +5 -1
  495. package/src/providers/provider-send-message.ts +7 -1
  496. package/src/providers/retry.ts +34 -3
  497. package/src/providers/thinking-config.ts +26 -1
  498. package/src/providers/types.ts +25 -0
  499. package/src/providers/usage-tracking.ts +2 -0
  500. package/src/runtime/AGENTS.md +2 -2
  501. package/src/runtime/__tests__/agent-wake.test.ts +214 -0
  502. package/src/runtime/__tests__/background-job-runner.test.ts +128 -0
  503. package/src/runtime/agent-wake.ts +152 -56
  504. package/src/runtime/assistant-event-hub.ts +76 -6
  505. package/src/runtime/auth/route-policy.ts +43 -3
  506. package/src/runtime/background-job-runner.ts +26 -0
  507. package/src/runtime/btw-sidechain.ts +0 -6
  508. package/src/runtime/channel-reply-delivery.ts +182 -47
  509. package/src/runtime/channel-retry-sweep.ts +141 -16
  510. package/src/runtime/http-types.ts +7 -6
  511. package/src/runtime/migrations/vbundle-builder.ts +10 -3
  512. package/src/runtime/pending-interactions.ts +50 -8
  513. package/src/runtime/routes/__tests__/content-source-routes.test.ts +162 -0
  514. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +161 -1
  515. package/src/runtime/routes/__tests__/memory-v2-routes.test.ts +14 -0
  516. package/src/runtime/routes/__tests__/memory-v2-simulate-route.test.ts +290 -0
  517. package/src/runtime/routes/__tests__/plugins-routes.test.ts +512 -0
  518. package/src/runtime/routes/__tests__/sanity-routes.test.ts +280 -0
  519. package/src/runtime/routes/__tests__/slack-channel-routes.test.ts +266 -0
  520. package/src/runtime/routes/acp-routes.test.ts +255 -6
  521. package/src/runtime/routes/acp-routes.ts +8 -1
  522. package/src/runtime/routes/approval-routes.ts +4 -1
  523. package/src/runtime/routes/avatar-routes.ts +10 -10
  524. package/src/runtime/routes/background-wake-routes.ts +188 -0
  525. package/src/runtime/routes/browser-tabs-routes.ts +200 -0
  526. package/src/runtime/routes/btw-routes.ts +0 -6
  527. package/src/runtime/routes/chatgpt-subscription-auth-routes.ts +246 -0
  528. package/src/runtime/routes/content-source-routes.ts +78 -0
  529. package/src/runtime/routes/conversation-cli-routes.ts +147 -2
  530. package/src/runtime/routes/conversation-list-routes.ts +12 -4
  531. package/src/runtime/routes/conversation-management-routes.ts +77 -20
  532. package/src/runtime/routes/conversation-query-routes.ts +196 -31
  533. package/src/runtime/routes/conversation-routes.ts +472 -425
  534. package/src/runtime/routes/conversation-starter-routes.ts +6 -3
  535. package/src/runtime/routes/disk-pressure-routes.ts +1 -1
  536. package/src/runtime/routes/document-comments-routes.ts +287 -0
  537. package/src/runtime/routes/documents-routes.ts +33 -0
  538. package/src/runtime/routes/domain-routes.ts +60 -10
  539. package/src/runtime/routes/email-routes.ts +5 -2
  540. package/src/runtime/routes/events-routes.ts +54 -10
  541. package/src/runtime/routes/group-routes.ts +24 -8
  542. package/src/runtime/routes/home-feed-routes.ts +6 -3
  543. package/src/runtime/routes/host-app-control-routes.ts +1 -1
  544. package/src/runtime/routes/host-browser-routes.ts +17 -2
  545. package/src/runtime/routes/host-cu-routes.ts +2 -2
  546. package/src/runtime/routes/identity-routes.ts +21 -0
  547. package/src/runtime/routes/inbound-message-handler.ts +288 -58
  548. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +96 -3
  549. package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +365 -6
  550. package/src/runtime/routes/inbound-stages/background-dispatch.ts +283 -82
  551. package/src/runtime/routes/index.ts +20 -4
  552. package/src/runtime/routes/inference-profile-session-handler.ts +22 -12
  553. package/src/runtime/routes/inference-profile-session-routes.ts +7 -1
  554. package/src/runtime/routes/inference-provider-connection-routes.ts +63 -7
  555. package/src/runtime/routes/integrations/a2a.ts +60 -1
  556. package/src/runtime/routes/llm-call-sites-routes.ts +32 -5
  557. package/src/runtime/routes/log-export-routes.ts +39 -0
  558. package/src/runtime/routes/memory-item-routes.ts +8 -3
  559. package/src/runtime/routes/memory-v2-routes.ts +427 -0
  560. package/src/runtime/routes/memory-v3-routes.ts +316 -0
  561. package/src/runtime/routes/migration-routes.ts +21 -24
  562. package/src/runtime/routes/notification-routes.ts +19 -2
  563. package/src/runtime/routes/plugins-routes.ts +337 -0
  564. package/src/runtime/routes/question-routes.ts +4 -1
  565. package/src/runtime/routes/rename-conversation-routes.ts +6 -2
  566. package/src/runtime/routes/sanity-routes.ts +159 -0
  567. package/src/runtime/routes/secret-routes.ts +25 -5
  568. package/src/runtime/routes/settings-routes.ts +12 -11
  569. package/src/runtime/routes/slack-channel-routes.ts +188 -0
  570. package/src/runtime/routes/workspace-routes.ts +25 -10
  571. package/src/runtime/services/conversation-serializer.ts +30 -4
  572. package/src/runtime/sync/resource-sync-events.ts +106 -38
  573. package/src/runtime/sync/sync-publisher.test.ts +49 -0
  574. package/src/runtime/sync/sync-publisher.ts +2 -1
  575. package/src/runtime/verification-outbound-actions.ts +73 -1
  576. package/src/schedule/integration-status.ts +3 -1
  577. package/src/security/__tests__/oauth2-device-code.test.ts +479 -0
  578. package/src/security/oauth2-device-code.ts +307 -0
  579. package/src/security/oauth2.ts +26 -9
  580. package/src/security/secure-keys.ts +5 -0
  581. package/src/skills/catalog-install.ts +6 -2
  582. package/src/telemetry/types.ts +12 -0
  583. package/src/telemetry/usage-telemetry-reporter.test.ts +48 -0
  584. package/src/telemetry/usage-telemetry-reporter.ts +1 -0
  585. package/src/tools/acp/spawn.test.ts +119 -0
  586. package/src/tools/acp/spawn.ts +15 -2
  587. package/src/tools/apps/definitions.ts +2 -8
  588. package/src/tools/ask-question/ask-question-tool.test.ts +3 -3
  589. package/src/tools/ask-question/ask-question-tool.ts +38 -45
  590. package/src/tools/browser/__tests__/pinned-tabs.test.ts +150 -0
  591. package/src/tools/browser/browser-execution.ts +106 -0
  592. package/src/tools/browser/cdp-client/__tests__/browser-tabs-factory.test.ts +402 -0
  593. package/src/tools/browser/cdp-client/__tests__/factory.test.ts +28 -0
  594. package/src/tools/browser/cdp-client/__tests__/types.test.ts +4 -0
  595. package/src/tools/browser/cdp-client/cdp-inspect-client.ts +22 -0
  596. package/src/tools/browser/cdp-client/extension-cdp-client.ts +42 -2
  597. package/src/tools/browser/cdp-client/factory.ts +171 -4
  598. package/src/tools/browser/cdp-client/local-cdp-client.ts +21 -0
  599. package/src/tools/browser/cdp-client/types.ts +101 -0
  600. package/src/tools/browser/pinned-tabs.ts +146 -0
  601. package/src/tools/computer-use/definitions.ts +22 -78
  602. package/src/tools/credential-execution/make-authenticated-request.ts +3 -9
  603. package/src/tools/credential-execution/manage-secure-command-tool.ts +3 -9
  604. package/src/tools/credential-execution/run-authenticated-command.ts +3 -9
  605. package/src/tools/credentials/vault.ts +3 -9
  606. package/src/tools/document/document-comment-tool.test.ts +379 -0
  607. package/src/tools/document/document-comment-tool.ts +156 -0
  608. package/src/tools/document/document-tool.ts +187 -2
  609. package/src/tools/execution-target.ts +21 -23
  610. package/src/tools/executor.ts +6 -1
  611. package/src/tools/filesystem/edit.ts +3 -9
  612. package/src/tools/filesystem/list.ts +3 -9
  613. package/src/tools/filesystem/read.ts +3 -9
  614. package/src/tools/filesystem/write.ts +3 -9
  615. package/src/tools/host-filesystem/edit.ts +3 -9
  616. package/src/tools/host-filesystem/read.ts +3 -9
  617. package/src/tools/host-filesystem/transfer.ts +3 -9
  618. package/src/tools/host-filesystem/write.ts +3 -9
  619. package/src/tools/host-terminal/host-shell.ts +3 -9
  620. package/src/tools/mcp/mcp-tool-factory.ts +1 -8
  621. package/src/tools/memory/register.test.ts +1 -1
  622. package/src/tools/memory/register.ts +4 -9
  623. package/src/tools/network/__tests__/web-fetch-metadata.test.ts +229 -0
  624. package/src/tools/network/__tests__/web-search-metadata.test.ts +346 -0
  625. package/src/tools/network/domain-normalize.ts +17 -0
  626. package/src/tools/network/web-fetch.ts +216 -73
  627. package/src/tools/network/web-search.ts +216 -98
  628. package/src/tools/registry.ts +7 -23
  629. package/src/tools/schema-transforms.ts +1 -1
  630. package/src/tools/skills/execute.ts +3 -9
  631. package/src/tools/skills/load.ts +3 -9
  632. package/src/tools/skills/skill-tool-factory.ts +1 -8
  633. package/src/tools/subagent/notify-parent.ts +3 -9
  634. package/src/tools/system/request-permission.ts +3 -9
  635. package/src/tools/terminal/safe-env.ts +3 -2
  636. package/src/tools/terminal/shell.ts +3 -9
  637. package/src/tools/tool-approval-handler.ts +19 -12
  638. package/src/tools/tool-defaults.ts +94 -0
  639. package/src/tools/types.ts +31 -98
  640. package/src/tools/ui-surface/definitions.ts +9 -23
  641. package/src/types/onboarding-context.ts +4 -0
  642. package/src/usage/pricing.ts +23 -0
  643. package/src/usage/types.ts +12 -0
  644. package/src/util/__tests__/favicon.test.ts +84 -0
  645. package/src/util/favicon.ts +40 -0
  646. package/src/util/logger.ts +16 -7
  647. package/src/util/platform.ts +7 -7
  648. package/src/util/sqlite3-runtime.ts +65 -0
  649. package/src/workspace/git-service.ts +75 -4
  650. package/src/workspace/migrations/086-revert-stale-gemini-mis-rewrites.ts +1 -0
  651. package/src/workspace/migrations/088-deprecate-background-conversation-override.ts +103 -0
  652. package/src/workspace/migrations/089-move-memory-tree-out-of-v3.ts +86 -0
  653. package/src/workspace/migrations/registry.ts +4 -0
  654. package/src/__tests__/compaction-strip-metadata-clear.test.ts +0 -206
  655. package/src/__tests__/message-complete-display-id.test.ts +0 -175
  656. package/src/config/bundled-skills/document/SKILL.md +0 -54
  657. package/src/config/bundled-skills/document/TOOLS.json +0 -106
  658. package/src/daemon/seed-files.ts +0 -18
  659. package/src/prompts/cache-boundary.ts +0 -8
  660. package/src/runtime/routes/interface-routes.ts +0 -43
  661. /package/src/config/bundled-skills/{document → document-editor}/tools/document-create.ts +0 -0
  662. /package/src/config/bundled-skills/{document → document-editor}/tools/document-delete.ts +0 -0
  663. /package/src/config/bundled-skills/{document → document-editor}/tools/document-list.ts +0 -0
  664. /package/src/config/bundled-skills/{document → document-editor}/tools/document-read.ts +0 -0
  665. /package/src/config/bundled-skills/{document → document-editor}/tools/document-update.ts +0 -0
@@ -5,6 +5,7 @@ import {
5
5
  mkdirSync,
6
6
  readFileSync,
7
7
  rmSync,
8
+ statSync,
8
9
  writeFileSync,
9
10
  } from "node:fs";
10
11
  import { tmpdir } from "node:os";
@@ -87,6 +88,58 @@ describe("WorkspaceGitService", () => {
87
88
  expect(userEmail).toBe("assistant@vellum.ai");
88
89
  });
89
90
 
91
+ test("installs branch guard hook that blocks non-main branches", async () => {
92
+ const service = new WorkspaceGitService(testDir);
93
+ await service.ensureInitialized();
94
+
95
+ const hooksPath = execFileSync("git", ["config", "core.hooksPath"], {
96
+ cwd: testDir,
97
+ encoding: "utf-8",
98
+ }).trim();
99
+ expect(hooksPath).toBe(".githooks");
100
+
101
+ const hookPath = join(testDir, ".githooks", "reference-transaction");
102
+ expect(existsSync(hookPath)).toBe(true);
103
+ expect(statSync(hookPath).mode & 0o111).not.toBe(0);
104
+
105
+ const hookContent = readFileSync(hookPath, "utf-8");
106
+ expect(hookContent).toContain(
107
+ "assistant workspace git branches are disabled",
108
+ );
109
+
110
+ expect(() =>
111
+ execFileSync("git", ["branch", "apollo/test-branch"], {
112
+ cwd: testDir,
113
+ encoding: "utf-8",
114
+ }),
115
+ ).toThrow(/assistant workspace git branches are disabled/);
116
+ });
117
+
118
+ test("branch guard allows deleting old non-main branches", async () => {
119
+ const service = new WorkspaceGitService(testDir);
120
+ await service.ensureInitialized();
121
+
122
+ execFileSync(
123
+ "git",
124
+ ["-c", "core.hooksPath=/dev/null", "branch", "old-branch"],
125
+ {
126
+ cwd: testDir,
127
+ },
128
+ );
129
+
130
+ execFileSync("git", ["branch", "-D", "old-branch"], { cwd: testDir });
131
+
132
+ const branches = execFileSync(
133
+ "git",
134
+ ["branch", "--format=%(refname:short)"],
135
+ {
136
+ cwd: testDir,
137
+ encoding: "utf-8",
138
+ },
139
+ );
140
+ expect(branches).not.toContain("old-branch");
141
+ });
142
+
90
143
  test("multiple ensureInitialized calls are idempotent", async () => {
91
144
  const service = new WorkspaceGitService(testDir);
92
145
 
@@ -368,11 +421,12 @@ describe("WorkspaceGitService", () => {
368
421
 
369
422
  await Promise.all(commits);
370
423
 
371
- // All commits should have succeeded
372
- const log = execFileSync("git", ["log", "--oneline"], {
373
- cwd: testDir,
374
- encoding: "utf-8",
375
- });
424
+ // Read through the service so GIT_* vars set by CI runners are stripped
425
+ // (matches the env used for the commits themselves).
426
+ const { stdout: log } = await service.runReadOnlyGit([
427
+ "log",
428
+ "--oneline",
429
+ ]);
376
430
 
377
431
  for (let i = 0; i < 10; i++) {
378
432
  expect(log).toContain(`Add file ${i}`);
@@ -487,7 +541,7 @@ describe("WorkspaceGitService", () => {
487
541
  // Set up a pre-existing git repo on a feature branch
488
542
  execFileSync("git", ["init", "-b", "main"], { cwd: testDir });
489
543
  execFileSync("git", ["config", "user.name", "Test"], { cwd: testDir });
490
- execFileSync("git", ["config", "user.email", "test@test.com"], {
544
+ execFileSync("git", ["config", "user.email", "user@example.com"], {
491
545
  cwd: testDir,
492
546
  });
493
547
  writeFileSync(join(testDir, "file.txt"), "content");
@@ -527,7 +581,7 @@ describe("WorkspaceGitService", () => {
527
581
  // Set up a pre-existing git repo then detach HEAD
528
582
  execFileSync("git", ["init", "-b", "main"], { cwd: testDir });
529
583
  execFileSync("git", ["config", "user.name", "Test"], { cwd: testDir });
530
- execFileSync("git", ["config", "user.email", "test@test.com"], {
584
+ execFileSync("git", ["config", "user.email", "user@example.com"], {
531
585
  cwd: testDir,
532
586
  });
533
587
  writeFileSync(join(testDir, "file.txt"), "content");
@@ -571,7 +625,7 @@ describe("WorkspaceGitService", () => {
571
625
  // This exercises the --discard-changes fallback in ensureOnMainLocked().
572
626
  execFileSync("git", ["init", "-b", "main"], { cwd: testDir });
573
627
  execFileSync("git", ["config", "user.name", "Test"], { cwd: testDir });
574
- execFileSync("git", ["config", "user.email", "test@test.com"], {
628
+ execFileSync("git", ["config", "user.email", "user@example.com"], {
575
629
  cwd: testDir,
576
630
  });
577
631
  writeFileSync(join(testDir, "file.txt"), "original content");
@@ -619,7 +673,7 @@ describe("WorkspaceGitService", () => {
619
673
  // Set up a pre-existing git repo without our gitignore rules
620
674
  execFileSync("git", ["init", "-b", "main"], { cwd: testDir });
621
675
  execFileSync("git", ["config", "user.name", "Test"], { cwd: testDir });
622
- execFileSync("git", ["config", "user.email", "test@test.com"], {
676
+ execFileSync("git", ["config", "user.email", "user@example.com"], {
623
677
  cwd: testDir,
624
678
  });
625
679
  writeFileSync(join(testDir, ".gitignore"), "node_modules/\n");
@@ -648,7 +702,7 @@ describe("WorkspaceGitService", () => {
648
702
  // Set up a pre-existing git repo with the OLD broad data/ rule
649
703
  execFileSync("git", ["init", "-b", "main"], { cwd: testDir });
650
704
  execFileSync("git", ["config", "user.name", "Test"], { cwd: testDir });
651
- execFileSync("git", ["config", "user.email", "test@test.com"], {
705
+ execFileSync("git", ["config", "user.email", "user@example.com"], {
652
706
  cwd: testDir,
653
707
  });
654
708
  const oldGitignore =
@@ -711,6 +765,36 @@ describe("WorkspaceGitService", () => {
711
765
  expect(userEmail).toBe("assistant@vellum.ai");
712
766
  });
713
767
 
768
+ test("existing repo gets branch guard installed on init", async () => {
769
+ execFileSync("git", ["init", "-b", "main"], { cwd: testDir });
770
+ execFileSync("git", ["config", "user.name", "Test"], { cwd: testDir });
771
+ execFileSync("git", ["config", "user.email", "user@example.com"], {
772
+ cwd: testDir,
773
+ });
774
+ writeFileSync(join(testDir, "file.txt"), "content");
775
+ execFileSync("git", ["add", "-A"], { cwd: testDir });
776
+ execFileSync("git", ["commit", "-m", "init"], { cwd: testDir });
777
+
778
+ const service = new WorkspaceGitService(testDir);
779
+ await service.ensureInitialized();
780
+
781
+ const hooksPath = execFileSync("git", ["config", "core.hooksPath"], {
782
+ cwd: testDir,
783
+ encoding: "utf-8",
784
+ }).trim();
785
+ expect(hooksPath).toBe(".githooks");
786
+ expect(
787
+ existsSync(join(testDir, ".githooks", "reference-transaction")),
788
+ ).toBe(true);
789
+
790
+ expect(() =>
791
+ execFileSync("git", ["branch", "feature-after-init"], {
792
+ cwd: testDir,
793
+ encoding: "utf-8",
794
+ }),
795
+ ).toThrow(/assistant workspace git branches are disabled/);
796
+ });
797
+
714
798
  test("existing repo with correct config is idempotent", async () => {
715
799
  // Set up a repo that already has everything configured correctly
716
800
  execFileSync("git", ["init", "-b", "main"], { cwd: testDir });
@@ -0,0 +1,158 @@
1
+ import {
2
+ existsSync,
3
+ mkdirSync,
4
+ mkdtempSync,
5
+ readFileSync,
6
+ rmSync,
7
+ writeFileSync,
8
+ } from "node:fs";
9
+ import { tmpdir } from "node:os";
10
+ import { join } from "node:path";
11
+ import { afterEach, beforeEach, describe, expect, test } from "bun:test";
12
+
13
+ import { deprecateBackgroundConversationOverrideMigration } from "../workspace/migrations/088-deprecate-background-conversation-override.js";
14
+
15
+ let workspaceDir: string;
16
+
17
+ beforeEach(() => {
18
+ workspaceDir = mkdtempSync(join(tmpdir(), "vellum-migration-088-test-"));
19
+ });
20
+
21
+ afterEach(() => {
22
+ if (existsSync(workspaceDir)) {
23
+ rmSync(workspaceDir, { recursive: true, force: true });
24
+ }
25
+ });
26
+
27
+ function promptSystemDir(): string {
28
+ return join(workspaceDir, "prompts", "system");
29
+ }
30
+
31
+ function writeOverride(body: string): string {
32
+ const dir = promptSystemDir();
33
+ mkdirSync(dir, { recursive: true });
34
+ const filePath = join(dir, "08-background-conversation.md");
35
+ writeFileSync(filePath, body, "utf-8");
36
+ return filePath;
37
+ }
38
+
39
+ describe("088-deprecate-background-conversation-override migration", () => {
40
+ test("has expected id and description", () => {
41
+ expect(deprecateBackgroundConversationOverrideMigration.id).toBe(
42
+ "088-deprecate-background-conversation-override",
43
+ );
44
+ expect(
45
+ deprecateBackgroundConversationOverrideMigration.description,
46
+ ).toContain("08-background-conversation");
47
+ });
48
+
49
+ test("renames the override to .deprecated, preserving body", () => {
50
+ const body = "## Custom\n\nUser-customized background note.\n";
51
+ writeOverride(body);
52
+
53
+ deprecateBackgroundConversationOverrideMigration.run(workspaceDir);
54
+
55
+ const originalPath = join(
56
+ promptSystemDir(),
57
+ "08-background-conversation.md",
58
+ );
59
+ const deprecatedPath = join(
60
+ promptSystemDir(),
61
+ "08-background-conversation.md.deprecated",
62
+ );
63
+
64
+ expect(existsSync(originalPath)).toBe(false);
65
+ expect(existsSync(deprecatedPath)).toBe(true);
66
+ expect(readFileSync(deprecatedPath, "utf-8")).toBe(body);
67
+ });
68
+
69
+ test("no-ops when the override is absent", () => {
70
+ expect(() =>
71
+ deprecateBackgroundConversationOverrideMigration.run(workspaceDir),
72
+ ).not.toThrow();
73
+
74
+ const deprecatedPath = join(
75
+ promptSystemDir(),
76
+ "08-background-conversation.md.deprecated",
77
+ );
78
+ expect(existsSync(deprecatedPath)).toBe(false);
79
+ });
80
+
81
+ test("does not touch unrelated section overrides", () => {
82
+ const dir = promptSystemDir();
83
+ mkdirSync(dir, { recursive: true });
84
+ const otherPath = join(dir, "07-external-content.md");
85
+ writeFileSync(otherPath, "## External Content\n\nUntouched.\n", "utf-8");
86
+ writeOverride("body");
87
+
88
+ deprecateBackgroundConversationOverrideMigration.run(workspaceDir);
89
+
90
+ expect(readFileSync(otherPath, "utf-8")).toContain("Untouched");
91
+ });
92
+
93
+ test("is safe to re-run after the rename has happened", () => {
94
+ writeOverride("body");
95
+
96
+ deprecateBackgroundConversationOverrideMigration.run(workspaceDir);
97
+ expect(() =>
98
+ deprecateBackgroundConversationOverrideMigration.run(workspaceDir),
99
+ ).not.toThrow();
100
+
101
+ const deprecatedPath = join(
102
+ promptSystemDir(),
103
+ "08-background-conversation.md.deprecated",
104
+ );
105
+ expect(readFileSync(deprecatedPath, "utf-8")).toBe("body");
106
+ });
107
+
108
+ test("drops the .md and keeps the .deprecated copy when both exist", () => {
109
+ // A user re-created the override after a prior partial run. The bundled
110
+ // section is gone, so the .md would render unconditionally — drop it.
111
+ const dir = promptSystemDir();
112
+ mkdirSync(dir, { recursive: true });
113
+ const deprecatedPath = join(
114
+ dir,
115
+ "08-background-conversation.md.deprecated",
116
+ );
117
+ writeFileSync(deprecatedPath, "preserved.\n", "utf-8");
118
+ const recreatedPath = writeOverride("re-created body\n");
119
+
120
+ deprecateBackgroundConversationOverrideMigration.run(workspaceDir);
121
+
122
+ expect(existsSync(recreatedPath)).toBe(false);
123
+ expect(readFileSync(deprecatedPath, "utf-8")).toBe("preserved.\n");
124
+ });
125
+
126
+ test("down() restores the override when only .deprecated exists", () => {
127
+ writeOverride("body");
128
+ deprecateBackgroundConversationOverrideMigration.run(workspaceDir);
129
+
130
+ deprecateBackgroundConversationOverrideMigration.down(workspaceDir);
131
+
132
+ const overridePath = join(
133
+ promptSystemDir(),
134
+ "08-background-conversation.md",
135
+ );
136
+ const deprecatedPath = join(
137
+ promptSystemDir(),
138
+ "08-background-conversation.md.deprecated",
139
+ );
140
+ expect(existsSync(overridePath)).toBe(true);
141
+ expect(existsSync(deprecatedPath)).toBe(false);
142
+ expect(readFileSync(overridePath, "utf-8")).toBe("body");
143
+ });
144
+
145
+ test("down() is a no-op when only the .md exists", () => {
146
+ writeOverride("body");
147
+
148
+ expect(() =>
149
+ deprecateBackgroundConversationOverrideMigration.down(workspaceDir),
150
+ ).not.toThrow();
151
+
152
+ const overridePath = join(
153
+ promptSystemDir(),
154
+ "08-background-conversation.md",
155
+ );
156
+ expect(readFileSync(overridePath, "utf-8")).toBe("body");
157
+ });
158
+ });
@@ -0,0 +1,86 @@
1
+ import * as fs from "node:fs";
2
+ import { tmpdir } from "node:os";
3
+ import { join } from "node:path";
4
+ import { afterEach, beforeEach, describe, expect, test } from "bun:test";
5
+
6
+ import { moveMemoryTreeOutOfV3Migration } from "../workspace/migrations/089-move-memory-tree-out-of-v3.js";
7
+
8
+ describe("workspace migration 089 — move memory tree out of v3", () => {
9
+ let ws: string;
10
+
11
+ beforeEach(() => {
12
+ ws = fs.mkdtempSync(join(tmpdir(), "ws-mig-089-"));
13
+ });
14
+
15
+ afterEach(() => {
16
+ fs.rmSync(ws, { recursive: true, force: true });
17
+ });
18
+
19
+ function writeOldTree(): void {
20
+ const oldTree = join(ws, "memory", "v3", "tree");
21
+ fs.mkdirSync(join(oldTree, "people"), { recursive: true });
22
+ fs.writeFileSync(join(oldTree, "_root.md"), "root");
23
+ fs.writeFileSync(join(oldTree, "people", "alice.md"), "alice");
24
+ }
25
+
26
+ test("moves memory/v3/tree -> memory/tree (incl. nested) and drops the empty v3 wrapper", () => {
27
+ writeOldTree();
28
+ moveMemoryTreeOutOfV3Migration.run(ws);
29
+
30
+ expect(fs.existsSync(join(ws, "memory", "v3"))).toBe(false);
31
+ expect(
32
+ fs.readFileSync(join(ws, "memory", "tree", "_root.md"), "utf-8"),
33
+ ).toBe("root");
34
+ expect(
35
+ fs.readFileSync(
36
+ join(ws, "memory", "tree", "people", "alice.md"),
37
+ "utf-8",
38
+ ),
39
+ ).toBe("alice");
40
+ });
41
+
42
+ test("is idempotent — re-running after the move changes nothing", () => {
43
+ writeOldTree();
44
+ moveMemoryTreeOutOfV3Migration.run(ws);
45
+ moveMemoryTreeOutOfV3Migration.run(ws);
46
+
47
+ expect(
48
+ fs.readFileSync(join(ws, "memory", "tree", "_root.md"), "utf-8"),
49
+ ).toBe("root");
50
+ });
51
+
52
+ test("no-op on a fresh workspace with no old tree", () => {
53
+ moveMemoryTreeOutOfV3Migration.run(ws);
54
+ expect(fs.existsSync(join(ws, "memory", "tree"))).toBe(false);
55
+ });
56
+
57
+ test("never clobbers an existing memory/tree", () => {
58
+ writeOldTree();
59
+ const newTree = join(ws, "memory", "tree");
60
+ fs.mkdirSync(newTree, { recursive: true });
61
+ fs.writeFileSync(join(newTree, "_root.md"), "existing");
62
+
63
+ moveMemoryTreeOutOfV3Migration.run(ws);
64
+
65
+ // Destination preserved; source left in place for manual resolution.
66
+ expect(fs.readFileSync(join(newTree, "_root.md"), "utf-8")).toBe(
67
+ "existing",
68
+ );
69
+ expect(fs.existsSync(join(ws, "memory", "v3", "tree", "_root.md"))).toBe(
70
+ true,
71
+ );
72
+ });
73
+
74
+ test("down() restores memory/tree back to memory/v3/tree", () => {
75
+ const newTree = join(ws, "memory", "tree");
76
+ fs.mkdirSync(newTree, { recursive: true });
77
+ fs.writeFileSync(join(newTree, "_root.md"), "root");
78
+
79
+ moveMemoryTreeOutOfV3Migration.down(ws);
80
+
81
+ expect(fs.existsSync(join(ws, "memory", "tree"))).toBe(false);
82
+ expect(
83
+ fs.readFileSync(join(ws, "memory", "v3", "tree", "_root.md"), "utf-8"),
84
+ ).toBe("root");
85
+ });
86
+ });
@@ -0,0 +1,146 @@
1
+ /**
2
+ * Tests for `prepareAgentEnv` — the shared helper that injects required env
3
+ * vars onto an `AcpAgentConfig` and preflights that they're set.
4
+ *
5
+ * The route-level test in `runtime/routes/acp-routes.test.ts` covers the same
6
+ * behavior through the HTTP handler; these tests pin the helper in isolation
7
+ * so the contract is clear and a future refactor can't silently break it.
8
+ */
9
+
10
+ import { beforeEach, describe, expect, mock, test } from "bun:test";
11
+
12
+ // Stub the secure-keys backend BEFORE importing the helper. Bun's
13
+ // `mock.module` is process-global and only takes effect for imports that
14
+ // follow it — the dynamic import below ensures correctness.
15
+ const secureKeyStore = new Map<string, string>();
16
+
17
+ mock.module("../../security/secure-keys.js", () => ({
18
+ getSecureKeyAsync: async (key: string) => secureKeyStore.get(key),
19
+ }));
20
+
21
+ const { prepareAgentEnv } = await import("../prepare-agent-env.js");
22
+
23
+ beforeEach(() => {
24
+ secureKeyStore.clear();
25
+ });
26
+
27
+ describe("prepareAgentEnv — claude-agent-acp gating", () => {
28
+ test("injects CLAUDE_CODE_OAUTH_TOKEN from the secure store when agent.env has no override", async () => {
29
+ secureKeyStore.set("credential/acp/claude_oauth_token", "vault-AAA");
30
+
31
+ const prepared = await prepareAgentEnv({
32
+ command: "claude-agent-acp",
33
+ args: [],
34
+ });
35
+
36
+ expect(prepared.env?.CLAUDE_CODE_OAUTH_TOKEN).toBe("vault-AAA");
37
+ });
38
+
39
+ test("accepts CLAUDE_CODE_OAUTH_TOKEN from agent.env (config.json override) with no vault entry", async () => {
40
+ const prepared = await prepareAgentEnv({
41
+ command: "claude-agent-acp",
42
+ args: [],
43
+ env: { CLAUDE_CODE_OAUTH_TOKEN: "config-BBB" },
44
+ });
45
+
46
+ expect(prepared.env?.CLAUDE_CODE_OAUTH_TOKEN).toBe("config-BBB");
47
+ });
48
+
49
+ test("agent.env override wins over the secure-store entry (precedence pin)", async () => {
50
+ // The config-supplied env wins so users can rotate per-workspace without
51
+ // racing the vault. Mirrors the route-level precedence test.
52
+ secureKeyStore.set("credential/acp/claude_oauth_token", "vault-CCC");
53
+
54
+ const prepared = await prepareAgentEnv({
55
+ command: "claude-agent-acp",
56
+ args: [],
57
+ env: { CLAUDE_CODE_OAUTH_TOKEN: "config-DDD" },
58
+ });
59
+
60
+ expect(prepared.env?.CLAUDE_CODE_OAUTH_TOKEN).toBe("config-DDD");
61
+ });
62
+
63
+ test("preserves unrelated env vars on agent.env when injecting from the vault", async () => {
64
+ secureKeyStore.set("credential/acp/claude_oauth_token", "vault-EEE");
65
+
66
+ const prepared = await prepareAgentEnv({
67
+ command: "claude-agent-acp",
68
+ args: [],
69
+ env: { OTHER_VAR: "keep-me" },
70
+ });
71
+
72
+ expect(prepared.env?.CLAUDE_CODE_OAUTH_TOKEN).toBe("vault-EEE");
73
+ expect(prepared.env?.OTHER_VAR).toBe("keep-me");
74
+ });
75
+
76
+ test("throws FailedDependencyError when no token is provided from either route", async () => {
77
+ // secureKeyStore empty, no agent.env override — the preflight must throw
78
+ // so callers fail fast instead of spawning a zombie subprocess that the
79
+ // SDK rejects with 'Authentication required' after the first prompt.
80
+ await expect(
81
+ prepareAgentEnv({ command: "claude-agent-acp", args: [] }),
82
+ ).rejects.toThrow("CLAUDE_CODE_OAUTH_TOKEN");
83
+ });
84
+
85
+ test("gates on the resolved command BASENAME (alias to /custom/path/claude-agent-acp still gets the token)", async () => {
86
+ // A user-supplied `acp.agents.my-claude = { command: "/opt/.../claude-agent-acp" }`
87
+ // is the only realistic path that lands a non-bare basename here. The
88
+ // helper must still recognize it.
89
+ secureKeyStore.set("credential/acp/claude_oauth_token", "vault-FFF");
90
+
91
+ const prepared = await prepareAgentEnv({
92
+ command: "/opt/bin/claude-agent-acp",
93
+ args: [],
94
+ });
95
+
96
+ expect(prepared.env?.CLAUDE_CODE_OAUTH_TOKEN).toBe("vault-FFF");
97
+ });
98
+
99
+ test("does NOT mutate the caller's agentConfig", async () => {
100
+ // Callers pass `resolved.agent` which is shared state from the resolver's
101
+ // config cache. The helper must clone before mutating, otherwise repeated
102
+ // spawns would race on the same object.
103
+ secureKeyStore.set("credential/acp/claude_oauth_token", "vault-GGG");
104
+ const original = {
105
+ command: "claude-agent-acp",
106
+ args: [],
107
+ env: { OTHER: "keep" },
108
+ };
109
+ const beforeEnv = { ...original.env };
110
+
111
+ const prepared = await prepareAgentEnv(original);
112
+
113
+ expect(prepared).not.toBe(original);
114
+ expect(prepared.env).not.toBe(original.env);
115
+ expect(original.env).toEqual(beforeEnv);
116
+ expect(original.env).not.toHaveProperty("CLAUDE_CODE_OAUTH_TOKEN");
117
+ });
118
+ });
119
+
120
+ describe("prepareAgentEnv — non-claude commands", () => {
121
+ test("returns the config unchanged for codex-acp (no required env vars today)", async () => {
122
+ // codex-acp inherits auth from the underlying `codex` CLI binary
123
+ // (codex login / CODEX_API_KEY / OPENAI_API_KEY in process.env) — no
124
+ // ACP-level env injection. Pin that contract so a future change has
125
+ // to update this test explicitly.
126
+ const prepared = await prepareAgentEnv({
127
+ command: "codex-acp",
128
+ args: [],
129
+ });
130
+
131
+ expect(prepared.env).toEqual({});
132
+ });
133
+
134
+ test("returns the config unchanged for an unrecognized command basename", async () => {
135
+ secureKeyStore.set("credential/acp/claude_oauth_token", "vault-HHH");
136
+
137
+ const prepared = await prepareAgentEnv({
138
+ command: "some-future-adapter",
139
+ args: [],
140
+ env: { FOO: "bar" },
141
+ });
142
+
143
+ // No injection — basename gate skipped.
144
+ expect(prepared.env).toEqual({ FOO: "bar" });
145
+ });
146
+ });
@@ -0,0 +1,78 @@
1
+ /**
2
+ * Inject required env vars for an ACP agent and preflight that they're set.
3
+ *
4
+ * Called by every code path that hands an `AcpAgentConfig` to
5
+ * `AcpSessionManager.spawn`. There are TWO such paths today — the HTTP
6
+ * route `/v1/acp/spawn` (`runtime/routes/acp-routes.ts:spawnSession`) and
7
+ * the skill tool `acp_spawn` (`tools/acp/spawn.ts:executeAcpSpawn`) — and
8
+ * before this helper existed the env-injection logic lived inline in the
9
+ * route only. The skill-tool path bypassed it entirely, so spawns landed
10
+ * with no `CLAUDE_CODE_OAUTH_TOKEN`, the SDK rejected the first prompt
11
+ * with "Authentication required", and the subprocess died as a zombie
12
+ * with no completion notification.
13
+ *
14
+ * The fix: have this single helper own injection + preflight, and have
15
+ * every caller route through it before calling `manager.spawn`.
16
+ */
17
+
18
+ import { basename } from "node:path";
19
+
20
+ import { FailedDependencyError } from "../runtime/routes/errors.js";
21
+ import { credentialKey } from "../security/credential-key.js";
22
+ import { getSecureKeyAsync } from "../security/secure-keys.js";
23
+ import type { AcpAgentConfig } from "./types.js";
24
+
25
+ /**
26
+ * Returns a NEW config with any required credentials merged into `env`.
27
+ * Does NOT mutate the input. Throws `FailedDependencyError` if a required
28
+ * credential is missing from both the user-supplied env override and the
29
+ * secure store.
30
+ *
31
+ * Gating is keyed off the resolved agent COMMAND (basename), not the
32
+ * user-facing agent id, so a custom `acp.agents.my-claude = { command:
33
+ * "claude-agent-acp", ... }` alias still gets the env it needs.
34
+ *
35
+ * For `claude-agent-acp` the only required env var is
36
+ * `CLAUDE_CODE_OAUTH_TOKEN`. Two provisioning routes converge on it, with
37
+ * config.json winning over the vault so explicit user overrides
38
+ * (per-workspace, rotated, etc.) are never silently clobbered:
39
+ * 1. `acp.agents.<id>.env.CLAUDE_CODE_OAUTH_TOKEN` in `config.json` —
40
+ * the user-supplied env override on the resolved agent config.
41
+ * 2. Secure store via CLI: `assistant credentials set --service acp \
42
+ * --field claude_oauth_token <token>` — written to the canonical
43
+ * `credential/{service}/{field}` key built by `credentialKey()`,
44
+ * used as fallback when (1) is unset.
45
+ * After resolution, this asserts the token is present (from either route)
46
+ * before spawning. The "fail-fast" throw is symmetric with the existing
47
+ * `binary_not_found` preflight in `resolveAcpAgent` and strictly better
48
+ * than a `warn` + zombie subprocess 10 seconds later.
49
+ */
50
+ export async function prepareAgentEnv(
51
+ agentConfig: AcpAgentConfig,
52
+ ): Promise<AcpAgentConfig> {
53
+ // Clone caller's config + env so we never mutate the resolver's cached
54
+ // agent reference. The local `env` binding sidesteps TS narrowing
55
+ // limitations on the optional `AcpAgentConfig.env` field.
56
+ const env: Record<string, string> = { ...(agentConfig.env ?? {}) };
57
+ const commandBasename = basename(agentConfig.command);
58
+
59
+ if (commandBasename === "claude-agent-acp") {
60
+ if (!env.CLAUDE_CODE_OAUTH_TOKEN) {
61
+ const claudeToken = await getSecureKeyAsync(
62
+ credentialKey("acp", "claude_oauth_token"),
63
+ );
64
+ if (claudeToken) {
65
+ env.CLAUDE_CODE_OAUTH_TOKEN = claudeToken;
66
+ }
67
+ }
68
+ if (!env.CLAUDE_CODE_OAUTH_TOKEN) {
69
+ throw new FailedDependencyError(
70
+ "claude-agent-acp requires CLAUDE_CODE_OAUTH_TOKEN. " +
71
+ "Run: assistant credentials set --service acp --field claude_oauth_token <token> " +
72
+ "(or set it under acp.agents.<id>.env in config.json).",
73
+ );
74
+ }
75
+ }
76
+
77
+ return { ...agentConfig, env };
78
+ }
@@ -306,7 +306,7 @@ export class AcpSessionManager {
306
306
  */
307
307
  private teardownSession(acpSessionId: string, entry: SessionEntry): void {
308
308
  for (const requestId of entry.clientHandler.pendingRequestIds) {
309
- const interaction = pendingInteractions.resolve(requestId);
309
+ const interaction = pendingInteractions.resolve(requestId, "cancelled");
310
310
  if (interaction?.directResolve) {
311
311
  interaction.directResolve("deny");
312
312
  }
@@ -38,6 +38,7 @@ export function attachmentsToContentBlocks(
38
38
  filename: attachment.filename,
39
39
  },
40
40
  extracted_text: attachment.extractedText,
41
+ ...(attachment.id ? { _attachmentId: attachment.id } : {}),
41
42
  } as ContentBlock;
42
43
  });
43
44
  }