@vellumai/assistant 0.12.1-dev.202609141913.5e16607 → 0.12.1-staging.2

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 (439) hide show
  1. package/AGENTS.md +0 -4
  2. package/ARCHITECTURE.md +12 -11
  3. package/docs/architecture/turn-actor.md +8 -15
  4. package/docs/guardian-request-flow.md +0 -16
  5. package/openapi.yaml +49 -291
  6. package/package.json +1 -1
  7. package/src/__tests__/always-loaded-tools-guard.test.ts +10 -18
  8. package/src/__tests__/app-compiler.test.ts +0 -6
  9. package/src/__tests__/app-control-tool-schemas.test.ts +2 -5
  10. package/src/__tests__/app-dir-path-guard.test.ts +3 -1
  11. package/src/__tests__/app-source-watcher.test.ts +218 -0
  12. package/src/{calls/__tests__ → __tests__}/call-controller.test.ts +82 -503
  13. package/src/__tests__/computer-use-skill-proxy-bridge.test.ts +2 -5
  14. package/src/__tests__/computer-use-tools.test.ts +5 -17
  15. package/src/__tests__/config-schema-cmd.test.ts +2 -2
  16. package/src/__tests__/config-schema.test.ts +29 -28
  17. package/src/__tests__/config-watcher-skill-reseed.test.ts +359 -0
  18. package/src/__tests__/config-watcher.test.ts +8 -23
  19. package/src/__tests__/connection-model-compat.test.ts +2 -2
  20. package/src/__tests__/conversation-key-store-disk-view.test.ts +1 -1
  21. package/src/__tests__/conversation-pairing.test.ts +0 -26
  22. package/src/__tests__/conversation-process-app-control-preactivation.test.ts +10 -4
  23. package/src/__tests__/conversation-queue.test.ts +207 -48
  24. package/src/__tests__/conversation-retry-discard.test.ts +1 -54
  25. package/src/__tests__/conversation-skill-tools.test.ts +0 -27
  26. package/src/__tests__/conversation-surfaces-app-control.test.ts +3 -8
  27. package/src/__tests__/conversation-surfaces-task-progress.test.ts +0 -67
  28. package/src/__tests__/conversation-title-service.test.ts +10 -14
  29. package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +5 -3
  30. package/src/__tests__/conversation-tool-setup-attribution.test.ts +0 -51
  31. package/src/__tests__/credential-record-retire.test.ts +1 -171
  32. package/src/__tests__/credential-routes.test.ts +3 -212
  33. package/src/__tests__/credential-security-invariants.test.ts +2 -4
  34. package/src/__tests__/cu-unified-flow.test.ts +2 -8
  35. package/src/__tests__/document-sync-tags.test.ts +0 -25
  36. package/src/__tests__/drain-kick-guard.test.ts +2 -0
  37. package/src/__tests__/drain-requeue-on-contention.test.ts +6 -0
  38. package/src/__tests__/evict-conversations-for-reload.test.ts +1 -1
  39. package/src/__tests__/host-bash-proxy.test.ts +45 -26
  40. package/src/__tests__/host-browser-proxy.test.ts +17 -6
  41. package/src/__tests__/host-file-proxy-targeted.test.ts +0 -23
  42. package/src/__tests__/host-file-proxy.test.ts +23 -11
  43. package/src/__tests__/host-transfer-proxy-targeted.test.ts +9 -30
  44. package/src/__tests__/llm-catalog-parity.test.ts +0 -25
  45. package/src/__tests__/mcp-auth-routes.test.ts +9 -6
  46. package/src/__tests__/mcp-config-secret-boundary.test.ts +136 -78
  47. package/src/__tests__/mcp-health-check.test.ts +11 -8
  48. package/src/__tests__/mcp-list-plugin-servers.test.ts +10 -8
  49. package/src/{calls/__tests__ → __tests__}/media-stream-audio-transcode.test.ts +1 -1
  50. package/src/{calls/__tests__ → __tests__}/media-stream-output.test.ts +8 -37
  51. package/src/{calls/__tests__ → __tests__}/media-stream-parser.test.ts +1 -1
  52. package/src/{calls/__tests__ → __tests__}/media-stream-server-integration.test.ts +57 -150
  53. package/src/{calls/__tests__ → __tests__}/media-stream-stt-session.test.ts +5 -5
  54. package/src/{calls/__tests__ → __tests__}/media-turn-detector.test.ts +1 -1
  55. package/src/__tests__/messages-after-tiebreaker.test.ts +0 -91
  56. package/src/__tests__/messages-read-boundary-guard.test.ts +1 -1
  57. package/src/__tests__/messaging-send-tool.test.ts +548 -355
  58. package/src/__tests__/model-intents.test.ts +0 -3
  59. package/src/__tests__/notification-vellum-adapter.test.ts +2 -85
  60. package/src/__tests__/outlook-messaging-provider.test.ts +6 -6
  61. package/src/__tests__/platform-callback-registration.test.ts +16 -8
  62. package/src/__tests__/platform-client-verify-credential.test.ts +0 -2
  63. package/src/__tests__/plugin-import-boundary-guard.test.ts +0 -13
  64. package/src/__tests__/script-proxy-certs.test.ts +0 -35
  65. package/src/__tests__/skill-feature-flags-integration.test.ts +1 -1
  66. package/src/__tests__/skill-feature-flags.test.ts +2 -2
  67. package/src/__tests__/speaker-identification.test.ts +56 -0
  68. package/src/__tests__/subagent-tool-gate-mode.test.ts +3 -19
  69. package/src/__tests__/subagent-tools.test.ts +2 -3
  70. package/src/__tests__/telephony-tts-guard.test.ts +3 -38
  71. package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +0 -4
  72. package/src/{calls/__tests__/voice-session-bridge-turn-flow.test.ts → __tests__/voice-session-bridge.test.ts} +12 -20
  73. package/src/__tests__/watch-retro-tool-availability.test.ts +17 -8
  74. package/src/__tests__/workspace-git-service.test.ts +0 -26
  75. package/src/acp/__tests__/agent-process.test.ts +4 -258
  76. package/src/acp/__tests__/auth-required.test.ts +0 -96
  77. package/src/acp/__tests__/client-handler.test.ts +2 -90
  78. package/src/acp/__tests__/session-manager-persistence.test.ts +1 -5
  79. package/src/acp/__tests__/session-manager-resume.test.ts +6 -270
  80. package/src/acp/__tests__/session-manager-usage.test.ts +2 -4
  81. package/src/acp/__tests__/session-manager.test.ts +4 -895
  82. package/src/acp/agent-process.test.ts +1 -4
  83. package/src/acp/agent-process.ts +9 -94
  84. package/src/acp/auth-required.ts +1 -50
  85. package/src/acp/auto-install.test.ts +7 -9
  86. package/src/acp/client-handler.ts +3 -16
  87. package/src/acp/resolve-agent.test.ts +6 -220
  88. package/src/acp/resolve-agent.ts +23 -88
  89. package/src/acp/session-manager.test.ts +3 -196
  90. package/src/acp/session-manager.ts +18 -441
  91. package/src/acp/types.ts +5 -50
  92. package/src/api/events/app-files-changed.ts +3 -4
  93. package/src/api/events/notification-intent.ts +0 -2
  94. package/src/api/index.ts +0 -6
  95. package/src/apps/app-store.ts +1 -1
  96. package/src/bundler/app-compiler.ts +0 -15
  97. package/src/calls/__tests__/voice-control-protocol.test.ts +25 -58
  98. package/src/calls/__tests__/voice-session-bridge.test.ts +1 -37
  99. package/src/calls/__tests__/voice-triage-escalate.test.ts +0 -105
  100. package/src/calls/call-constants.ts +4 -24
  101. package/src/calls/call-controller.ts +199 -499
  102. package/src/calls/call-transport.ts +0 -16
  103. package/src/calls/media-stream-output.ts +0 -32
  104. package/src/calls/media-stream-server.ts +30 -82
  105. package/src/calls/media-stream-stt-session.ts +0 -15
  106. package/src/calls/resolve-call-tts-provider.ts +2 -33
  107. package/src/calls/speaker-identification.ts +233 -0
  108. package/src/calls/tts-call-strategy.ts +5 -9
  109. package/src/calls/types.ts +0 -2
  110. package/src/calls/voice-control-protocol.ts +21 -53
  111. package/src/calls/voice-session-bridge.ts +46 -59
  112. package/src/calls/voice-triage-escalate.ts +56 -175
  113. package/src/cli/commands/apps.help.ts +13 -67
  114. package/src/cli/commands/apps.ts +0 -183
  115. package/src/cli/commands/bash.help.ts +13 -8
  116. package/src/cli/commands/bash.ts +25 -7
  117. package/src/cli/commands/channels/index.help.ts +2 -70
  118. package/src/cli/commands/channels/index.ts +3 -16
  119. package/src/cli/commands/credentials.help.ts +2 -6
  120. package/src/cli/commands/credentials.ts +2 -2
  121. package/src/cli/commands/mcp.help.ts +8 -8
  122. package/src/cli/commands/mcp.ts +1 -1
  123. package/src/cli/commands/roadmap.help.ts +1 -5
  124. package/src/cli/commands/roadmap.ts +1 -1
  125. package/src/cli/lib/bundled-marketplace.json +90 -103
  126. package/src/config/__tests__/default-profile-catalog.test.ts +0 -22
  127. package/src/config/__tests__/memory-retrospective-schema.test.ts +1 -15
  128. package/src/config/__tests__/platform-rehydration.test.ts +9 -99
  129. package/src/config/acp-defaults.test.ts +3 -13
  130. package/src/config/acp-defaults.ts +6 -23
  131. package/src/config/acp-schema.ts +2 -30
  132. package/src/config/bundled-skills/acp/SKILL.md +14 -22
  133. package/src/config/bundled-skills/acp/TOOLS.json +1 -5
  134. package/src/config/bundled-skills/app-builder/SKILL.md +9 -12
  135. package/src/config/bundled-skills/app-builder/references/CUSTOM_ROUTES.md +1 -1
  136. package/src/config/bundled-skills/messaging/SKILL.md +3 -3
  137. package/src/config/bundled-skills/messaging/TOOLS.json +3 -3
  138. package/src/config/bundled-skills/messaging/tools/messaging-send.ts +139 -67
  139. package/src/config/bundled-skills/phone-calls/references/TRANSCRIPTS.md +1 -1
  140. package/src/config/bundled-skills/schedule/SKILL.md +4 -3
  141. package/src/config/bundled-skills/screen-annotation/SKILL.md +1 -8
  142. package/src/config/bundled-skills/screen-annotation/tools/screen-annotation.test.ts +1 -4
  143. package/src/config/bundled-skills/skill-management/TOOLS.json +2 -2
  144. package/src/config/default-profile-catalog.ts +1 -1
  145. package/src/config/env.ts +2 -2
  146. package/src/config/feature-flag-registry.json +12 -24
  147. package/src/config/loader.ts +0 -1
  148. package/src/config/memory-v3-gate.test.ts +0 -31
  149. package/src/config/memory-v3-gate.ts +16 -20
  150. package/src/config/platform-rehydration.ts +27 -11
  151. package/src/config/schema.ts +2 -2
  152. package/src/config/schemas/__tests__/live-voice.test.ts +158 -8
  153. package/src/config/schemas/calls.ts +28 -1
  154. package/src/config/schemas/live-voice.ts +173 -1
  155. package/src/config/schemas/mcp.ts +1 -1
  156. package/src/config/schemas/memory-retrospective.ts +0 -10
  157. package/src/config/schemas/services.ts +0 -8
  158. package/src/config/schemas/skills.ts +14 -0
  159. package/src/credential-execution/process-manager.test.ts +19 -18
  160. package/src/daemon/__tests__/conversation-tool-setup.test.ts +121 -66
  161. package/src/daemon/__tests__/plugin-mcp-reconcile.test.ts +1 -4
  162. package/src/daemon/app-source-watcher.ts +218 -0
  163. package/src/daemon/config-watcher.ts +194 -13
  164. package/src/daemon/conversation-process.ts +64 -35
  165. package/src/daemon/conversation-skill-tools.ts +31 -13
  166. package/src/daemon/conversation-store.ts +1 -1
  167. package/src/daemon/conversation-surfaces.ts +8 -10
  168. package/src/daemon/conversation-tool-setup.ts +43 -37
  169. package/src/daemon/conversation.ts +3 -0
  170. package/src/daemon/host-bash-proxy.ts +12 -8
  171. package/src/daemon/host-browser-proxy.ts +1 -15
  172. package/src/daemon/host-file-proxy.ts +10 -8
  173. package/src/daemon/host-transfer-proxy.ts +18 -14
  174. package/src/daemon/lifecycle.ts +5 -0
  175. package/src/daemon/mcp-reload-service.ts +5 -5
  176. package/src/daemon/message-types/sync.ts +0 -1
  177. package/src/daemon/orphan-reaper.ts +1 -1
  178. package/src/daemon/providers-setup.ts +1 -1
  179. package/src/daemon/shutdown-handlers.ts +9 -1
  180. package/src/daemon/skill-memory-refresh.ts +0 -64
  181. package/src/daemon/tool-side-effects.ts +18 -7
  182. package/src/home/__tests__/feed-writer.test.ts +0 -22
  183. package/src/home/feed-writer.ts +2 -11
  184. package/src/hooks/types.ts +0 -33
  185. package/src/inbound/platform-callback-registration.ts +5 -4
  186. package/src/live-voice/__tests__/live-voice-metrics.test.ts +3 -0
  187. package/src/live-voice/__tests__/live-voice-progress.test.ts +15 -15
  188. package/src/live-voice/__tests__/live-voice-vad.test.ts +2 -2
  189. package/src/{calls → live-voice}/__tests__/progress-narration.test.ts +4 -4
  190. package/src/{calls → live-voice}/__tests__/progress-phrases.test.ts +1 -1
  191. package/src/live-voice/__tests__/runtime-websocket-shell.test.ts +69 -13
  192. package/src/live-voice/live-voice-session.ts +693 -213
  193. package/src/{calls → live-voice}/progress-narration.ts +2 -2
  194. package/src/live-voice/protocol.ts +2 -0
  195. package/src/mcp/__tests__/effective-config.test.ts +2 -2
  196. package/src/mcp/effective-config.ts +3 -3
  197. package/src/mcp/mcp-header-store.ts +45 -29
  198. package/src/mcp/startup.ts +4 -8
  199. package/src/messaging/provider.ts +3 -10
  200. package/src/messaging/providers/callback-routing.ts +0 -18
  201. package/src/messaging/providers/channel-transport.ts +0 -56
  202. package/src/messaging/providers/discord/transport.ts +0 -17
  203. package/src/messaging/providers/slack/__tests__/adapter-token-routing.test.ts +17 -6
  204. package/src/messaging/providers/slack/adapter.ts +44 -7
  205. package/src/messaging/providers/slack/transport.ts +0 -16
  206. package/src/messaging/providers/telegram-bot/adapter.ts +48 -1
  207. package/src/messaging/providers/telegram-bot/client.ts +26 -0
  208. package/src/messaging/providers/telegram-bot/transport.ts +0 -20
  209. package/src/messaging/providers/whatsapp/adapter.ts +48 -1
  210. package/src/messaging/providers/whatsapp/client.ts +29 -0
  211. package/src/messaging/providers/whatsapp/transport.ts +0 -18
  212. package/src/monitoring/__tests__/workspace-git-heartbeat.test.ts +0 -8
  213. package/src/notifications/__tests__/assistant-reply-producer.test.ts +0 -55
  214. package/src/notifications/__tests__/guardian-feed-projection.test.ts +2 -158
  215. package/src/notifications/__tests__/home-feed-side-effect.test.ts +3 -153
  216. package/src/notifications/__tests__/schedule-result-producer.test.ts +3 -99
  217. package/src/notifications/adapters/macos.ts +0 -3
  218. package/src/notifications/assistant-reply-producer.ts +3 -8
  219. package/src/notifications/conversation-pairing.ts +16 -36
  220. package/src/notifications/delivered-post-record.ts +1 -11
  221. package/src/notifications/guardian-feed-projection.ts +5 -125
  222. package/src/notifications/home-feed-side-effect.ts +7 -55
  223. package/src/notifications/schedule-result-producer.ts +22 -66
  224. package/src/oauth/__tests__/seed-providers-managed.test.ts +0 -54
  225. package/src/oauth/byo-connection.test.ts +0 -45
  226. package/src/oauth/byo-connection.ts +6 -36
  227. package/src/oauth/connection-resolver.test.ts +0 -73
  228. package/src/oauth/connection-resolver.ts +2 -95
  229. package/src/oauth/seed-providers.ts +0 -165
  230. package/src/outbound-proxy/certs.ts +5 -3
  231. package/src/permissions/checker.test.ts +6 -11
  232. package/src/persistence/compaction-log-store-clickhouse.ts +3 -3
  233. package/src/persistence/conversation-crud.ts +63 -71
  234. package/src/persistence/conversation-lineage.ts +4 -12
  235. package/src/persistence/conversation-title-service.ts +26 -9
  236. package/src/persistence/llm-request-log-sink-clickhouse.ts +3 -3
  237. package/src/persistence/llm-request-log-source-clickhouse.ts +3 -3
  238. package/src/persistence/message-reads.ts +0 -30
  239. package/src/persistence/migrations/157-invite-contact-id.ts +6 -18
  240. package/src/persistence/schema/memory-core.ts +0 -5
  241. package/src/platform/client.test.ts +2 -4
  242. package/src/platform/client.ts +10 -2
  243. package/src/plugin-api/constants.ts +0 -2
  244. package/src/plugin-api/index.ts +0 -1
  245. package/src/plugin-api/types.ts +0 -2
  246. package/src/plugins/defaults/index.ts +0 -2
  247. package/src/plugins/defaults/memory/__tests__/memory-retrospective-accounting.test.ts +0 -46
  248. package/src/plugins/defaults/memory/__tests__/memory-retrospective-enqueue.test.ts +5 -9
  249. package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +10 -20
  250. package/src/plugins/defaults/memory/__tests__/memory-retrospective-state.test.ts +0 -219
  251. package/src/plugins/defaults/memory/__tests__/memory-retrospective-sweep.test.ts +0 -31
  252. package/src/plugins/defaults/memory/__tests__/memory-retrospective-trigger-check.test.ts +0 -63
  253. package/src/plugins/defaults/memory/__tests__/shutdown-hook.test.ts +0 -4
  254. package/src/plugins/defaults/memory/graph/capability-seed.ts +6 -4
  255. package/src/plugins/defaults/memory/hooks/init.ts +0 -10
  256. package/src/plugins/defaults/memory/hooks/shutdown.ts +0 -2
  257. package/src/plugins/defaults/memory/jobs-worker.ts +0 -13
  258. package/src/plugins/defaults/memory/memory-retrospective-accounting.ts +60 -34
  259. package/src/plugins/defaults/memory/memory-retrospective-enqueue.ts +5 -3
  260. package/src/plugins/defaults/memory/memory-retrospective-job.ts +3 -12
  261. package/src/plugins/defaults/memory/memory-retrospective-state.ts +71 -312
  262. package/src/plugins/defaults/memory/memory-retrospective-sweep.ts +1 -2
  263. package/src/plugins/defaults/memory/memory-retrospective-trigger-check.ts +3 -5
  264. package/src/plugins/defaults/memory/startup.ts +1 -6
  265. package/src/plugins/defaults/memory/substrate/__tests__/skill-content.test.ts +9 -7
  266. package/src/plugins/defaults/memory/substrate/skill-content.ts +2 -2
  267. package/src/plugins/defaults/memory/v3/__tests__/pool-select.test.ts +0 -89
  268. package/src/plugins/defaults/memory/worker.ts +0 -6
  269. package/src/plugins/mcp-servers.ts +75 -15
  270. package/src/providers/__tests__/connection-model-compat.test.ts +3 -3
  271. package/src/providers/gemini/client.ts +23 -9
  272. package/src/providers/inference/auth.ts +3 -2
  273. package/src/providers/inference/connection-availability.ts +8 -27
  274. package/src/providers/inference/resolve-auth.ts +4 -22
  275. package/src/providers/model-catalog.ts +0 -34
  276. package/src/providers/model-intents.ts +5 -10
  277. package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +18 -146
  278. package/src/providers/openai/__tests__/tool-choice-mapping.test.ts +1 -83
  279. package/src/providers/openai/chat-completions-provider.ts +78 -192
  280. package/src/providers/openai/codex-models.ts +4 -0
  281. package/src/runtime/AGENTS.md +0 -2
  282. package/src/runtime/auth/same-actor.ts +3 -38
  283. package/src/runtime/http-server.ts +151 -160
  284. package/src/runtime/routes/__tests__/acp-routes.test.ts +4 -159
  285. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +1 -108
  286. package/src/runtime/routes/__tests__/default-provider-routes.test.ts +2 -2
  287. package/src/runtime/routes/__tests__/mcp-add-default-risk.test.ts +12 -16
  288. package/src/runtime/routes/acp-routes.test.ts +0 -15
  289. package/src/runtime/routes/acp-routes.ts +9 -72
  290. package/src/runtime/routes/app-management-routes.ts +0 -73
  291. package/src/runtime/routes/app-routes.ts +1 -1
  292. package/src/runtime/routes/conversation-list-routes.ts +3 -14
  293. package/src/runtime/routes/conversation-query-routes.ts +0 -40
  294. package/src/runtime/routes/credential-routes.ts +10 -19
  295. package/src/runtime/routes/debug-bash-routes.ts +173 -0
  296. package/src/runtime/routes/diagnostics-routes.ts +3 -55
  297. package/src/runtime/routes/index.ts +2 -4
  298. package/src/runtime/routes/log-export-routes.ts +0 -2
  299. package/src/runtime/routes/mcp-auth-routes.ts +47 -39
  300. package/src/runtime/routes/migration-routes.ts +20 -6
  301. package/src/runtime/routes/platform-routes.ts +15 -18
  302. package/src/runtime/services/__tests__/conversation-serializer.test.ts +0 -28
  303. package/src/runtime/services/conversation-serializer.ts +3 -16
  304. package/src/runtime/sync/resource-sync-events.ts +1 -2
  305. package/src/schedule/worker.ts +1 -1
  306. package/src/security/ces-rpc-record-backend.ts +0 -7
  307. package/src/subagent/consult-context.ts +25 -12
  308. package/src/tools/acp/list-agents.test.ts +1 -3
  309. package/src/tools/acp/spawn.test.ts +11 -146
  310. package/src/tools/acp/spawn.ts +3 -21
  311. package/src/tools/acp/status.ts +3 -40
  312. package/src/tools/app-control/skill-proxy-bridge.ts +1 -2
  313. package/src/tools/capability-offer.test.ts +2 -22
  314. package/src/tools/capability-offer.ts +1 -16
  315. package/src/tools/computer-use/definitions.ts +2 -4
  316. package/src/tools/computer-use/skill-proxy-bridge.ts +1 -2
  317. package/src/tools/credentials/metadata-store.ts +0 -100
  318. package/src/tools/host-filesystem/edit.test.ts +1 -2
  319. package/src/tools/host-filesystem/edit.ts +2 -2
  320. package/src/tools/host-filesystem/read.test.ts +1 -2
  321. package/src/tools/host-filesystem/read.ts +2 -2
  322. package/src/tools/host-filesystem/transfer.test.ts +1 -2
  323. package/src/tools/host-filesystem/transfer.ts +2 -2
  324. package/src/tools/host-filesystem/write.test.ts +1 -2
  325. package/src/tools/host-filesystem/write.ts +2 -2
  326. package/src/tools/host-terminal/host-shell.test.ts +0 -16
  327. package/src/tools/host-terminal/host-shell.ts +20 -4
  328. package/src/tools/policy-context.ts +7 -6
  329. package/src/tools/subagent/spawn.ts +8 -5
  330. package/src/tools/watch/watch-retro-report.ts +8 -0
  331. package/src/util/__tests__/language-subtag.test.ts +1 -23
  332. package/src/util/fs-watcher-error.ts +36 -0
  333. package/src/util/language-subtag.ts +0 -16
  334. package/src/util/platform.ts +0 -8
  335. package/src/workspace/git-service.ts +54 -5
  336. package/src/workspace/migrations/registry.ts +0 -6
  337. package/scripts/smoke-desktop-window-theme.ts +0 -186
  338. package/src/__tests__/git-porcelain.test.ts +0 -47
  339. package/src/__tests__/helpers/set-workspace-mcp.ts +0 -11
  340. package/src/__tests__/message-deleted-hook-dispatch.test.ts +0 -119
  341. package/src/__tests__/resolve-app.test.ts +0 -135
  342. package/src/__tests__/service-account-token.test.ts +0 -247
  343. package/src/__tests__/source-fingerprint.test.ts +0 -184
  344. package/src/__tests__/workspace-migration-154-repair-retired-codex-gpt-5-4-model-ids.test.ts +0 -336
  345. package/src/acp/__tests__/helpers/acp-model-option.ts +0 -51
  346. package/src/acp/model-config.test.ts +0 -166
  347. package/src/acp/model-config.ts +0 -138
  348. package/src/api/events/acp-session-model-update.test.ts +0 -88
  349. package/src/api/events/acp-session-model-update.ts +0 -46
  350. package/src/apps/resolve-app.ts +0 -81
  351. package/src/apps/source-fingerprint.ts +0 -266
  352. package/src/calls/__tests__/barge-in-guard.test.ts +0 -81
  353. package/src/calls/__tests__/voice-leg-coordinator.test.ts +0 -229
  354. package/src/calls/__tests__/voice-progress-cadence.test.ts +0 -274
  355. package/src/calls/barge-in-guard.ts +0 -118
  356. package/src/calls/voice-leg-coordinator.ts +0 -189
  357. package/src/calls/voice-progress-cadence.ts +0 -423
  358. package/src/cli/commands/__tests__/apps.test.ts +0 -245
  359. package/src/cli/commands/__tests__/bash.test.ts +0 -53
  360. package/src/cli/commands/__tests__/roadmap.help.test.ts +0 -19
  361. package/src/cli/commands/channels/__tests__/send.test.ts +0 -218
  362. package/src/cli/commands/channels/send.ts +0 -128
  363. package/src/config/__tests__/platform-identity.test.ts +0 -255
  364. package/src/config/acp-agent-write.ts +0 -43
  365. package/src/config/acp-schema.test.ts +0 -81
  366. package/src/config/platform-identity.ts +0 -201
  367. package/src/config/schemas/__tests__/voice.test.ts +0 -148
  368. package/src/config/schemas/voice.ts +0 -150
  369. package/src/daemon/__tests__/skill-memory-refresh-mtime.test.ts +0 -133
  370. package/src/daemon/app-change-notify.ts +0 -45
  371. package/src/desktop/__tests__/fake-desktop.ts +0 -119
  372. package/src/desktop/desktop-chrome-policy.test.ts +0 -71
  373. package/src/desktop/desktop-chrome-policy.ts +0 -42
  374. package/src/desktop/desktop-dependencies.test.ts +0 -102
  375. package/src/desktop/desktop-dependencies.ts +0 -306
  376. package/src/desktop/desktop-feature.test.ts +0 -18
  377. package/src/desktop/desktop-feature.ts +0 -19
  378. package/src/desktop/desktop-panel-config.test.ts +0 -135
  379. package/src/desktop/desktop-panel-config.ts +0 -149
  380. package/src/desktop/desktop-session-manager.test.ts +0 -627
  381. package/src/desktop/desktop-session-manager.ts +0 -814
  382. package/src/desktop/desktop-stream-bridge.test.ts +0 -395
  383. package/src/desktop/desktop-stream-bridge.ts +0 -214
  384. package/src/desktop/desktop-wallpaper.test.ts +0 -191
  385. package/src/desktop/desktop-wallpaper.ts +0 -113
  386. package/src/desktop/desktop-window-theme.ts +0 -170
  387. package/src/i18n/AGENTS.md +0 -22
  388. package/src/i18n/__tests__/i18n.test.ts +0 -108
  389. package/src/i18n/index.ts +0 -16
  390. package/src/i18n/locales.ts +0 -93
  391. package/src/i18n/messages.ts +0 -61
  392. package/src/i18n/title.ts +0 -25
  393. package/src/mcp/__tests__/workspace-mcp-config.test.ts +0 -135
  394. package/src/mcp/spec-schema.ts +0 -111
  395. package/src/mcp/workspace-mcp-config.ts +0 -188
  396. package/src/messaging/providers/__tests__/proactive-address.test.ts +0 -95
  397. package/src/persistence/conversation-title-placeholders.ts +0 -23
  398. package/src/persistence/message-cursor.ts +0 -78
  399. package/src/persistence/migrations/__tests__/157-invite-contact-id.test.ts +0 -149
  400. package/src/plugins/defaults/memory/__tests__/memory-retrospective-cursor-backfill.test.ts +0 -118
  401. package/src/plugins/defaults/memory/__tests__/memory-retrospective-cursor-preserve.test.ts +0 -83
  402. package/src/plugins/defaults/memory/hooks/message-deleted.ts +0 -21
  403. package/src/plugins/defaults/memory/memory-retrospective-cursor-backfill.ts +0 -126
  404. package/src/plugins/defaults/memory/memory-retrospective-cursor-preserve.ts +0 -79
  405. package/src/plugins/defaults/memory/memory-retrospective-cursor.ts +0 -28
  406. package/src/plugins/defaults/memory/skill-md-mtime-poll.ts +0 -9
  407. package/src/providers/gemini-thought-signature.test.ts +0 -63
  408. package/src/providers/gemini-thought-signature.ts +0 -44
  409. package/src/providers/inference/service-account-token.ts +0 -248
  410. package/src/providers/openai/__tests__/chat-completions-provider-thought-signature.test.ts +0 -613
  411. package/src/providers/openai/__tests__/google-thought-signature.test.ts +0 -235
  412. package/src/providers/openai/google-thought-signature.ts +0 -320
  413. package/src/runtime/__tests__/channel-send.test.ts +0 -443
  414. package/src/runtime/__tests__/desktop-stream-upgrade.test.ts +0 -89
  415. package/src/runtime/__tests__/live-voice-upgrade.test.ts +0 -58
  416. package/src/runtime/__tests__/runtime-ws-test-utils.ts +0 -72
  417. package/src/runtime/__tests__/watch-stream-upgrade.test.ts +0 -59
  418. package/src/runtime/channel-send.ts +0 -316
  419. package/src/runtime/routes/__tests__/apps-refresh-route.test.ts +0 -205
  420. package/src/runtime/routes/__tests__/channel-send-routes.test.ts +0 -127
  421. package/src/runtime/routes/__tests__/dictation-cleanup-guard.test.ts +0 -107
  422. package/src/runtime/routes/channel-send-routes.ts +0 -85
  423. package/src/runtime/routes/desktop-setup-routes.test.ts +0 -74
  424. package/src/runtime/routes/desktop-setup-routes.ts +0 -35
  425. package/src/security/__tests__/ces-http-record-backend.test.ts +0 -137
  426. package/src/security/ces-http-record-backend.ts +0 -120
  427. package/src/skills/__tests__/workspace-skill-md-signature.test.ts +0 -60
  428. package/src/skills/workspace-skill-md-signature.ts +0 -50
  429. package/src/tools/acp/status.test.ts +0 -94
  430. package/src/tools/terminal/__tests__/sanitized-bash.test.ts +0 -57
  431. package/src/tools/terminal/sanitized-bash.ts +0 -105
  432. package/src/util/ca-bundle.ts +0 -13
  433. package/src/workspace/git-porcelain.ts +0 -66
  434. package/src/workspace/migrations/154-repair-retired-codex-gpt-5-4-model-ids.ts +0 -258
  435. package/src/workspace/migrations/155-move-front-model-config-to-voice.ts +0 -78
  436. package/src/workspace/migrations/156-extract-workspace-mcp-json.ts +0 -214
  437. package/src/workspace/migrations/__tests__/155-move-front-model-config-to-voice.test.ts +0 -102
  438. package/src/workspace/migrations/__tests__/156-extract-workspace-mcp-json.test.ts +0 -199
  439. /package/src/{calls → live-voice}/progress-phrases.ts +0 -0
@@ -32,7 +32,6 @@ import { getAttentionStateByConversationIds } from "../persistence/conversation-
32
32
  import {
33
33
  getAssistantMessageIdsInTurn,
34
34
  getMessageById,
35
- getMessagesAfter,
36
35
  type MessageRow,
37
36
  } from "../persistence/conversation-crud.js";
38
37
  import { stringifyMessageContent } from "../persistence/message-content.js";
@@ -40,6 +39,7 @@ import {
40
39
  isPrivateAssistantText,
41
40
  projectPersistedAssistantContent,
42
41
  } from "../persistence/user-facing-content.js";
42
+ import type { ContentBlock } from "../providers/types.js";
43
43
  import { emitNotificationSignal } from "./emit-signal.js";
44
44
  import { hasNotifiedSourceContextSince } from "./events-store.js";
45
45
  import {
@@ -79,72 +79,28 @@ export interface ScheduleResultNotificationParams {
79
79
  }
80
80
 
81
81
  /**
82
- * Whether the run delivered its result through the messaging tool, and the
83
- * call succeeded.
82
+ * Whether a tool call in the run's turn delivered the result somewhere the
83
+ * user will see it, outside the notification pipeline.
84
84
  *
85
- * The messaging tool is the route the schedule skill prescribes for rich
86
- * content, and it writes no `notification_events` row, so the pipeline probe
87
- * cannot see it. Without this check a well-authored Slack digest would post
85
+ * The schedule skill prescribes two such routes for rich content — the
86
+ * messaging tool for email, and the Slack Web API's `chat.postMessage` through
87
+ * bash — and neither writes a `notification_events` row, so the pipeline probe
88
+ * cannot see them. Without this check a well-authored Slack digest would post
88
89
  * its summary and then get a second notification whose body is "Posted the
89
- * digest to #general."
90
- *
91
- * Both conditions are load-bearing. The route has to be recognized, because
92
- * this is a known-routes list rather than a general "did the run do anything?"
93
- * heuristic. And the call has to have succeeded: a `tool_use` block records
94
- * only that the model called the tool, so a send the channel refused leaves
95
- * the same block as one that landed, and suppressing on it costs the user both
96
- * the digest and the run's explanation of the failure. The executor's verdict
97
- * is on the `tool_result` the call produced, so success is read from there,
98
- * and a call with no result counts as undelivered. Either condition unmet gets
99
- * the fallback, which is the safe failure.
100
- *
101
- * The result read starts at the run's first row, so it covers the results
102
- * interleaved through the turn. Rows from a later turn in a reused
103
- * conversation can come back too and are harmless, because only this run's
104
- * own call ids are matched.
105
- *
106
- * A Slack Web API post through bash is deliberately not a route, because its
107
- * success proves nothing about the post. Slack refuses a call with HTTP 200
108
- * and `ok: false` in the body, and the authenticated-request command fails
109
- * only on a non-2xx status, so a post Slack refused still leaves a successful
110
- * tool result. A run that posts that way gets the fallback too: at worst a
111
- * duplicate, never a silence.
90
+ * digest to #general." This is a recognized-routes list, not a general "did
91
+ * the run do anything?" heuristic: a route that is not here gets the fallback,
92
+ * which is the safe failure.
112
93
  */
113
- function deliveredThroughMessagingTool(
114
- conversationId: string,
115
- runRows: readonly MessageRow[],
116
- ): boolean {
117
- const callIds = new Set<string>();
118
- for (const row of runRows) {
119
- for (const block of row.content) {
120
- if (block.type === "tool_use" && block.name === "messaging_send") {
121
- callIds.add(block.id);
122
- }
123
- }
124
- }
125
- if (callIds.size === 0) {
94
+ function isDirectDelivery(block: ContentBlock): boolean {
95
+ if (block.type !== "tool_use") {
126
96
  return false;
127
97
  }
128
- const [firstRunRow] = runRows;
129
- for (const row of getMessagesAfter(conversationId, {
130
- id: firstRunRow.id,
131
- createdAt: firstRunRow.createdAt,
132
- })) {
133
- if (row.role !== "user") {
134
- continue;
135
- }
136
- for (const block of row.content) {
137
- // guard:allow-tool-result-only: the local executor's verdict on a
138
- // delivery it ran. A server-side `web_search_tool_result` carries no
139
- // `is_error` and never delivers anything.
140
- if (
141
- block.type === "tool_result" &&
142
- block.is_error !== true &&
143
- callIds.has(block.tool_use_id)
144
- ) {
145
- return true;
146
- }
147
- }
98
+ if (block.name === "messaging_send") {
99
+ return true;
100
+ }
101
+ if (block.name === "bash") {
102
+ const command = (block.input as { command?: unknown } | undefined)?.command;
103
+ return typeof command === "string" && command.includes("chat.postMessage");
148
104
  }
149
105
  return false;
150
106
  }
@@ -281,11 +237,11 @@ export async function emitScheduleResultNotification(
281
237
  return;
282
238
  }
283
239
 
284
- // The run delivered around the pipeline through the messaging tool, and
285
- // the call succeeded. The user has the result; a notification reading
286
- // "posted it" on top would be the duplicate.
240
+ // The run delivered around the pipeline — an email through the messaging
241
+ // tool, a Slack post through the Web API. The user has the result; a
242
+ // notification reading "posted it" on top would be the duplicate.
287
243
  const runRows = collectRunRows(latestRow, conversationId, runStartedAt);
288
- if (deliveredThroughMessagingTool(conversationId, runRows)) {
244
+ if (runRows.some((row) => row.content.some(isDirectDelivery))) {
289
245
  return;
290
246
  }
291
247
 
@@ -127,60 +127,6 @@ describe("PROVIDER_SEED_DATA managed mode wiring", () => {
127
127
  expect(figma.featureFlag).toBe("figma-oauth");
128
128
  });
129
129
 
130
- test("shopify keeps its per-tenant URL templates", () => {
131
- // Shopify has no global OAuth host: every endpoint lives on the
132
- // merchant's own domain. Hardcoding any host here would send every
133
- // merchant's authorization to the wrong store, so the {tenant_host}
134
- // placeholder the platform substitutes must survive.
135
- const shopify = PROVIDER_SEED_DATA.shopify;
136
- expect(shopify).toBeDefined();
137
- for (const url of [
138
- shopify.authorizeUrl,
139
- shopify.tokenExchangeUrl,
140
- shopify.refreshUrl,
141
- shopify.baseUrl,
142
- shopify.identityUrl,
143
- ]) {
144
- expect(url).toContain("{tenant_host}");
145
- }
146
- });
147
-
148
- test("shopify requests comma-separated scopes", () => {
149
- // Shopify parses `scope` as a comma-separated list; the OAuth2 default
150
- // space separator is read as one malformed scope and the whole
151
- // authorization request is rejected.
152
- expect(PROVIDER_SEED_DATA.shopify.scopeSeparator).toBe(",");
153
- });
154
-
155
- test("shopify does not request approval-gated scopes", () => {
156
- // Shopify rejects the entire authorization request when the app cannot
157
- // grant a requested scope -- the same failure that broke monday and
158
- // Figma. These scopes all require Shopify's prior approval.
159
- const gated = [
160
- "read_all_orders",
161
- "read_customer_payment_methods",
162
- "read_own_subscription_contracts",
163
- "write_own_subscription_contracts",
164
- "read_shopify_payments_dispute_evidences",
165
- "write_shopify_payments_dispute_evidences",
166
- ];
167
- for (const scope of gated) {
168
- expect(PROVIDER_SEED_DATA.shopify.defaultScopes).not.toContain(scope);
169
- }
170
- });
171
-
172
- test("shopify injects the Admin API's own auth header", () => {
173
- // The Admin API reads X-Shopify-Access-Token and ignores an
174
- // Authorization: Bearer header entirely, so a Bearer template here would
175
- // make every proxied request unauthenticated.
176
- const templates = PROVIDER_SEED_DATA.shopify.injectionTemplates;
177
- expect(templates).toBeDefined();
178
- const [template] = templates ?? [];
179
- expect(template?.headerName).toBe("X-Shopify-Access-Token");
180
- expect(template?.valuePrefix).toBe("");
181
- expect(template?.hostPattern).toBe("*.myshopify.com");
182
- });
183
-
184
130
  test("every managedServiceConfigKey resolves to a ServicesSchema key", () => {
185
131
  // Cross-repo invariant: a provider with managedServiceConfigKey but no
186
132
  // matching ServicesSchema entry silently falls back to BYO mode in
@@ -708,51 +708,6 @@ describe("BYOOAuthConnection", () => {
708
708
  expect(headers.get("Authorization")).toBe("Bearer test-access-token");
709
709
  });
710
710
 
711
- test("sends the token in the provider's own header when one is configured", async () => {
712
- // Shopify's Admin API reads X-Shopify-Access-Token and ignores
713
- // Authorization, so a Bearer header reaches the shop unauthenticated.
714
- await setupCredential("google");
715
- const conn = new BYOOAuthConnection({
716
- id: "conn-google",
717
- provider: "google",
718
- baseUrl: "https://example-store.myshopify.com",
719
- accountInfo: null,
720
- tokenHeader: { name: "X-Shopify-Access-Token", valuePrefix: "" },
721
- });
722
-
723
- await conn.request({
724
- method: "GET",
725
- path: "/admin/api/2026-07/shop.json",
726
- // A caller-supplied Authorization must not ride along.
727
- headers: { Authorization: "Bearer caller-supplied" },
728
- });
729
-
730
- const [url, init] = mockFetch.mock.calls[0];
731
- expect(url).toBe(
732
- "https://example-store.myshopify.com/admin/api/2026-07/shop.json",
733
- );
734
- const headers = (init as RequestInit).headers as Headers;
735
- expect(headers.get("X-Shopify-Access-Token")).toBe("test-access-token");
736
- expect(headers.has("Authorization")).toBe(false);
737
- });
738
-
739
- test("keeps the value prefix from the token header template", async () => {
740
- await setupCredential("google");
741
- const conn = new BYOOAuthConnection({
742
- id: "conn-google",
743
- provider: "google",
744
- baseUrl: "https://discord.com/api",
745
- accountInfo: null,
746
- tokenHeader: { name: "Authorization", valuePrefix: "Bot " },
747
- });
748
-
749
- await conn.request({ method: "GET", path: "/users/@me" });
750
-
751
- const [, init] = mockFetch.mock.calls[0];
752
- const headers = (init as RequestInit).headers as Headers;
753
- expect(headers.get("Authorization")).toBe("Bot test-access-token");
754
- });
755
-
756
711
  test("uses Telegram Bot API token URL format without Bearer auth", async () => {
757
712
  await setupTelegramCredential();
758
713
  const conn = createConnection("telegram");
@@ -21,29 +21,11 @@ const log = getLogger("byo-oauth-connection");
21
21
  /** Default per-request timeout to prevent hung requests from blocking indefinitely. */
22
22
  const REQUEST_TIMEOUT_MS = 30_000;
23
23
 
24
- /**
25
- * How the access token is attached to an outbound request. Almost every
26
- * provider reads `Authorization: Bearer <token>`; a few use their own header
27
- * (Shopify's Admin API reads `X-Shopify-Access-Token` and ignores
28
- * Authorization entirely). Derived from the provider's header-type injection
29
- * template so the seed is the single source of truth.
30
- */
31
- export interface BYOTokenHeader {
32
- name: string;
33
- /** Text placed before the token, e.g. `"Bearer "`, `"Bot "`, or `""`. */
34
- valuePrefix: string;
35
- }
36
-
37
24
  export interface BYOOAuthConnectionOptions {
38
25
  id: string;
39
26
  provider: string;
40
27
  baseUrl: string;
41
28
  accountInfo: string | null;
42
- /**
43
- * Token header override. When omitted the connection falls back to
44
- * `Authorization: Bearer` (or `Bot` for discord_channel).
45
- */
46
- tokenHeader?: BYOTokenHeader | null;
47
29
  }
48
30
 
49
31
  export class BYOOAuthConnection implements OAuthConnection {
@@ -52,14 +34,12 @@ export class BYOOAuthConnection implements OAuthConnection {
52
34
  readonly accountInfo: string | null;
53
35
 
54
36
  private readonly baseUrl: string;
55
- private readonly tokenHeader: BYOTokenHeader | null;
56
37
 
57
38
  constructor(opts: BYOOAuthConnectionOptions) {
58
39
  this.id = opts.id;
59
40
  this.provider = opts.provider;
60
41
  this.baseUrl = opts.baseUrl;
61
42
  this.accountInfo = opts.accountInfo;
62
- this.tokenHeader = opts.tokenHeader ?? null;
63
43
  }
64
44
 
65
45
  async request(req: OAuthConnectionRequest): Promise<OAuthConnectionResponse> {
@@ -71,12 +51,8 @@ export class BYOOAuthConnection implements OAuthConnection {
71
51
  // Discord bot tokens authenticate with the `Bot ` scheme, not
72
52
  // `Bearer`. Sending Bearer here reaches Discord as an unusable
73
53
  // credential and comes back 401, which reads as a revoked token.
74
- // Providers with their own token header (Shopify) override the
75
- // whole thing via `tokenHeader`.
76
- const tokenHeader: BYOTokenHeader = this.tokenHeader ?? {
77
- name: "Authorization",
78
- valuePrefix: this.provider === "discord_channel" ? "Bot " : "Bearer ",
79
- };
54
+ const authScheme =
55
+ this.provider === "discord_channel" ? "Bot" : "Bearer";
80
56
  const requestPath = isTelegram
81
57
  ? buildTelegramBotApiPath(req.path, token)
82
58
  : req.path;
@@ -117,22 +93,16 @@ export class BYOOAuthConnection implements OAuthConnection {
117
93
  }
118
94
  }
119
95
  if (!isTelegram) {
120
- // The credential always wins over a caller-supplied value, and a
121
- // provider that reads its own header must not also receive a
122
- // stray Authorization the caller happened to send.
123
- if (tokenHeader.name.toLowerCase() !== "authorization") {
124
- headers.delete("Authorization");
125
- }
126
- headers.set(tokenHeader.name, `${tokenHeader.valuePrefix}${token}`);
96
+ headers.set("Authorization", `${authScheme} ${token}`);
127
97
  }
128
98
 
129
99
  const resp = await fetch(fullUrl, {
130
100
  method: req.method,
131
101
  headers,
132
102
  body: hasBody
133
- ? binaryBody !== undefined
134
- ? Buffer.from(binaryBody)
135
- : (rawBody ?? JSON.stringify(req.body))
103
+ ? (binaryBody !== undefined
104
+ ? Buffer.from(binaryBody)
105
+ : (rawBody ?? JSON.stringify(req.body)))
136
106
  : undefined,
137
107
  // Following a redirect would replay a POST as a GET against a URL
138
108
  // the caller never asked for, and hide the 3xx from them.
@@ -75,7 +75,6 @@ import {
75
75
  resolveEffectiveBaseUrl,
76
76
  resolveOAuthConnection,
77
77
  resolveOAuthConnectionWithMeta,
78
- resolveTokenHeader,
79
78
  } from "./connection-resolver.js";
80
79
  import { PlatformOAuthConnection } from "./platform-connection.js";
81
80
 
@@ -754,75 +753,3 @@ describe("resolveEffectiveBaseUrl", () => {
754
753
  ).toBe("https://gmail.googleapis.com/gmail/v1/users/me");
755
754
  });
756
755
  });
757
-
758
- describe("resolveTokenHeader", () => {
759
- const shopify = JSON.stringify([
760
- {
761
- hostPattern: "*.myshopify.com",
762
- injectionType: "header",
763
- headerName: "X-Shopify-Access-Token",
764
- valuePrefix: "",
765
- },
766
- ]);
767
-
768
- test("returns null when the provider declares no templates", () => {
769
- expect(resolveTokenHeader(undefined, "https://api.example.com")).toBeNull();
770
- expect(resolveTokenHeader(null, "https://api.example.com")).toBeNull();
771
- expect(resolveTokenHeader("[]", "https://api.example.com")).toBeNull();
772
- });
773
-
774
- test("returns null for malformed JSON", () => {
775
- expect(
776
- resolveTokenHeader("{not json", "https://api.example.com"),
777
- ).toBeNull();
778
- });
779
-
780
- test("ignores non-header injection templates", () => {
781
- const query = JSON.stringify([
782
- {
783
- hostPattern: "api.example.com",
784
- injectionType: "query",
785
- headerName: "",
786
- },
787
- ]);
788
- expect(resolveTokenHeader(query, "https://api.example.com")).toBeNull();
789
- });
790
-
791
- test("picks the template whose wildcard host pattern matches the base URL", () => {
792
- const templates = JSON.stringify([
793
- {
794
- hostPattern: "api.other.com",
795
- injectionType: "header",
796
- headerName: "Authorization",
797
- valuePrefix: "Bearer ",
798
- },
799
- ...JSON.parse(shopify),
800
- ]);
801
- expect(
802
- resolveTokenHeader(templates, "https://example-store.myshopify.com"),
803
- ).toEqual({ name: "X-Shopify-Access-Token", valuePrefix: "" });
804
- });
805
-
806
- test("falls back to the first header template when the host cannot be matched", () => {
807
- // A still-templated base URL is not a parseable URL.
808
- expect(resolveTokenHeader(shopify, "https://{tenant_host}")).toEqual({
809
- name: "X-Shopify-Access-Token",
810
- valuePrefix: "",
811
- });
812
- });
813
-
814
- test("preserves the Bot prefix for discord_channel", () => {
815
- const discord = JSON.stringify([
816
- {
817
- hostPattern: "discord.com",
818
- injectionType: "header",
819
- headerName: "Authorization",
820
- valuePrefix: "Bot ",
821
- },
822
- ]);
823
- expect(resolveTokenHeader(discord, "https://discord.com/api")).toEqual({
824
- name: "Authorization",
825
- valuePrefix: "Bot ",
826
- });
827
- });
828
- });
@@ -6,7 +6,7 @@ import {
6
6
  } from "../config/schemas/services.js";
7
7
  import { VellumPlatformClient } from "../platform/client.js";
8
8
  import { getLogger } from "../util/logger.js";
9
- import { BYOOAuthConnection, type BYOTokenHeader } from "./byo-connection.js";
9
+ import { BYOOAuthConnection } from "./byo-connection.js";
10
10
  import type { OAuthConnection } from "./connection.js";
11
11
  import { getConnectionAccessTokenResult } from "./credential-token-resolver.js";
12
12
  import { syncManualTokenConnection } from "./manual-token-connection.js";
@@ -215,108 +215,15 @@ export async function resolveOAuthConnectionWithMeta(
215
215
  );
216
216
  }
217
217
 
218
- const effectiveBaseUrl = resolveEffectiveBaseUrl(
219
- conn.provider,
220
- baseUrl,
221
- conn.metadata,
222
- );
223
218
  const connection = new BYOOAuthConnection({
224
219
  id: conn.id,
225
220
  provider: conn.provider,
226
- baseUrl: effectiveBaseUrl,
221
+ baseUrl: resolveEffectiveBaseUrl(conn.provider, baseUrl, conn.metadata),
227
222
  accountInfo: conn.accountInfo,
228
- tokenHeader: resolveTokenHeader(
229
- providerRow?.injectionTemplates,
230
- effectiveBaseUrl,
231
- ),
232
223
  });
233
224
  return { connection, ambiguous, allAccounts };
234
225
  }
235
226
 
236
- /**
237
- * Pick the header a provider expects its access token in from the seed's
238
- * header-type injection templates.
239
- *
240
- * Prefers the template whose `hostPattern` matches the base URL's host
241
- * (`*.myshopify.com` style globs included), then falls back to the first
242
- * header template. Returns `null` when the provider declares none, which
243
- * leaves `BYOOAuthConnection` on its `Authorization: Bearer` default.
244
- *
245
- * Shopify is why this exists: its Admin API reads `X-Shopify-Access-Token`
246
- * and ignores `Authorization`, so a Bearer header reaches the shop as an
247
- * unauthenticated request and comes back 401.
248
- */
249
- export function resolveTokenHeader(
250
- rawTemplates: string | null | undefined,
251
- baseUrl: string,
252
- ): BYOTokenHeader | null {
253
- if (!rawTemplates) {
254
- return null;
255
- }
256
- let parsed: unknown;
257
- try {
258
- parsed = JSON.parse(rawTemplates);
259
- } catch {
260
- return null;
261
- }
262
- if (!Array.isArray(parsed)) {
263
- return null;
264
- }
265
-
266
- const headerTemplates = parsed.filter(
267
- (
268
- t,
269
- ): t is {
270
- hostPattern?: unknown;
271
- headerName: string;
272
- valuePrefix?: unknown;
273
- } =>
274
- typeof t === "object" &&
275
- t !== null &&
276
- (t as { injectionType?: unknown }).injectionType === "header" &&
277
- typeof (t as { headerName?: unknown }).headerName === "string" &&
278
- (t as { headerName: string }).headerName.trim() !== "",
279
- );
280
- if (headerTemplates.length === 0) {
281
- return null;
282
- }
283
-
284
- let host = "";
285
- try {
286
- host = new URL(baseUrl).hostname.toLowerCase();
287
- } catch {
288
- // Templated or malformed base URLs (e.g. a still-unfilled
289
- // `https://{tenant_host}`) cannot be matched by host; fall through to
290
- // the first header template.
291
- }
292
- const matching =
293
- host === ""
294
- ? undefined
295
- : headerTemplates.find(
296
- (t) =>
297
- typeof t.hostPattern === "string" &&
298
- hostMatchesPattern(host, t.hostPattern),
299
- );
300
- const chosen = matching ?? headerTemplates[0];
301
- return {
302
- name: chosen.headerName.trim(),
303
- valuePrefix:
304
- typeof chosen.valuePrefix === "string" ? chosen.valuePrefix : "",
305
- };
306
- }
307
-
308
- function hostMatchesPattern(host: string, pattern: string): boolean {
309
- const p = pattern.trim().toLowerCase();
310
- if (p === "") {
311
- return false;
312
- }
313
- if (p.startsWith("*.")) {
314
- const suffix = p.slice(1); // ".myshopify.com"
315
- return host.endsWith(suffix) && host.length > suffix.length;
316
- }
317
- return host === p;
318
- }
319
-
320
227
  /**
321
228
  * Resolve the effective API base URL for a connection, preferring per-tenant
322
229
  * values stored on the connection's `metadata` over the provider's static