@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
@@ -1,94 +0,0 @@
1
- /**
2
- * Tests for the `acp_status` tool's projection of session state.
3
- *
4
- * The state the manager tracks feeds three surfaces with different budgets:
5
- * the HTTP route, the SSE picker, and this tool, whose output is spent on
6
- * LLM context. Only the fields an agent can act on belong here.
7
- */
8
-
9
- import { describe, expect, mock, test } from "bun:test";
10
-
11
- import type { AcpSessionState } from "../../acp/types.js";
12
- import type { ToolContext } from "../types.js";
13
-
14
- const RUNNING_STATE: AcpSessionState = {
15
- id: "acp-1",
16
- agentId: "claude",
17
- acpSessionId: "proto-1",
18
- parentConversationId: "conv-1",
19
- status: "running",
20
- startedAt: 1234,
21
- task: "refactor the parser",
22
- model: "claude-opus-4-5",
23
- availableModels: [
24
- { value: "sonnet", label: "Sonnet" },
25
- { value: "opus", label: "Opus", description: "Most capable" },
26
- ],
27
- };
28
-
29
- let statusResult: AcpSessionState | AcpSessionState[] = RUNNING_STATE;
30
-
31
- const realAcpModule = await import("../../acp/index.js");
32
- mock.module("../../acp/index.js", () => ({
33
- ...realAcpModule,
34
- getAcpSessionManager: () => ({ getStatus: () => statusResult }),
35
- }));
36
-
37
- const { executeAcpStatus } = await import("./status.js");
38
-
39
- const context = {
40
- conversationId: "conv-1",
41
- workingDir: "/tmp",
42
- } as unknown as ToolContext;
43
-
44
- describe("executeAcpStatus", () => {
45
- test("a single session reports its model but not the picker", async () => {
46
- statusResult = RUNNING_STATE;
47
-
48
- const result = await executeAcpStatus({ acp_session_id: "acp-1" }, context);
49
-
50
- expect(result.isError).toBe(false);
51
- const payload = JSON.parse(result.content);
52
- expect(payload).toEqual({
53
- id: "acp-1",
54
- agentId: "claude",
55
- acpSessionId: "proto-1",
56
- parentConversationId: "conv-1",
57
- status: "running",
58
- startedAt: 1234,
59
- task: "refactor the parser",
60
- model: "claude-opus-4-5",
61
- });
62
- expect(result.content).not.toContain("Most capable");
63
- });
64
-
65
- test("the listing drops the picker from every entry", async () => {
66
- statusResult = [
67
- RUNNING_STATE,
68
- { ...RUNNING_STATE, id: "acp-2", model: "sonnet" },
69
- ];
70
-
71
- const result = await executeAcpStatus({}, context);
72
-
73
- const payload = JSON.parse(result.content) as Array<
74
- Record<string, unknown>
75
- >;
76
- expect(payload).toHaveLength(2);
77
- expect(payload.map((entry) => entry.model)).toEqual([
78
- "claude-opus-4-5",
79
- "sonnet",
80
- ]);
81
- for (const entry of payload) {
82
- expect(entry).not.toHaveProperty("availableModels");
83
- }
84
- });
85
-
86
- test("an empty listing says so rather than rendering an empty array", async () => {
87
- statusResult = [];
88
-
89
- const result = await executeAcpStatus({}, context);
90
-
91
- expect(result.content).toBe("No ACP sessions found.");
92
- expect(result.isError).toBe(false);
93
- });
94
- });
@@ -1,57 +0,0 @@
1
- import { afterEach, describe, expect, test } from "bun:test";
2
-
3
- import { runSanitizedBash } from "../sanitized-bash.js";
4
-
5
- describe("runSanitizedBash", () => {
6
- const priorToken = process.env.CES_SERVICE_TOKEN;
7
- const priorSocket = process.env.CES_LOCAL_SOCKET;
8
-
9
- afterEach(() => {
10
- if (priorToken == null) {
11
- delete process.env.CES_SERVICE_TOKEN;
12
- } else {
13
- process.env.CES_SERVICE_TOKEN = priorToken;
14
- }
15
- if (priorSocket == null) {
16
- delete process.env.CES_LOCAL_SOCKET;
17
- } else {
18
- process.env.CES_LOCAL_SOCKET = priorSocket;
19
- }
20
- });
21
-
22
- test("runs a command and returns stdout", async () => {
23
- const result = await runSanitizedBash("echo hello", 5_000);
24
- expect(result.error).toBeUndefined();
25
- expect(result.timedOut).toBe(false);
26
- expect(result.exitCode).toBe(0);
27
- expect(result.stdout.trim()).toBe("hello");
28
- });
29
-
30
- test("forwards CES_SERVICE_TOKEN to the child", async () => {
31
- process.env.CES_SERVICE_TOKEN = "vault-bearer";
32
- const result = await runSanitizedBash("printenv CES_SERVICE_TOKEN", 5_000);
33
- expect(result.error).toBeUndefined();
34
- expect(result.exitCode).toBe(0);
35
- expect(result.stdout.trim()).toBe("vault-bearer");
36
- });
37
-
38
- test("forwards CES_LOCAL_SOCKET to the child", async () => {
39
- process.env.CES_LOCAL_SOCKET = "/tmp/ces.sock";
40
- const result = await runSanitizedBash("printenv CES_LOCAL_SOCKET", 5_000);
41
- expect(result.error).toBeUndefined();
42
- expect(result.exitCode).toBe(0);
43
- expect(result.stdout.trim()).toBe("/tmp/ces.sock");
44
- });
45
-
46
- test("times out a hung command", async () => {
47
- const result = await runSanitizedBash("sleep 5", 200);
48
- expect(result.error).toBeUndefined();
49
- expect(result.timedOut).toBe(true);
50
- });
51
-
52
- test("rejects an empty command", async () => {
53
- const result = await runSanitizedBash("");
54
- expect(result.error).toBe("command is required");
55
- expect(result.exitCode).toBeNull();
56
- });
57
- });
@@ -1,105 +0,0 @@
1
- /**
2
- * Spawn a shell command with the same sanitized environment the bash tool
3
- * forwards to tool-call subprocesses.
4
- *
5
- * Used by `assistant bash` so a CLI invocation sees the same allowlisted
6
- * env, workspace cwd, and platform shell as a bash tool call, without
7
- * round-tripping through the assistant HTTP or IPC API.
8
- */
9
-
10
- import { spawn } from "node:child_process";
11
-
12
- import {
13
- buildShellInvocation,
14
- terminateProcessTree,
15
- } from "../../util/host-process.js";
16
- import { getWorkspaceDir } from "../../util/platform.js";
17
- import { buildSanitizedEnv } from "./safe-env.js";
18
-
19
- export const DEFAULT_SANITIZED_BASH_TIMEOUT_MS = 30_000;
20
-
21
- export interface SanitizedBashResult {
22
- stdout: string;
23
- stderr: string;
24
- exitCode: number | null;
25
- timedOut: boolean;
26
- error?: string;
27
- }
28
-
29
- export function runSanitizedBash(
30
- command: string,
31
- timeoutMs: number = DEFAULT_SANITIZED_BASH_TIMEOUT_MS,
32
- ): Promise<SanitizedBashResult> {
33
- if (!command) {
34
- return Promise.resolve({
35
- stdout: "",
36
- stderr: "",
37
- exitCode: null,
38
- timedOut: false,
39
- error: "command is required",
40
- });
41
- }
42
-
43
- const effectiveTimeout =
44
- typeof timeoutMs === "number" && timeoutMs > 0
45
- ? timeoutMs
46
- : DEFAULT_SANITIZED_BASH_TIMEOUT_MS;
47
-
48
- return new Promise<SanitizedBashResult>((resolve) => {
49
- const stdoutChunks: Buffer[] = [];
50
- const stderrChunks: Buffer[] = [];
51
- let timedOut = false;
52
- let settled = false;
53
-
54
- const finish = (result: SanitizedBashResult) => {
55
- if (settled) {
56
- return;
57
- }
58
- settled = true;
59
- resolve(result);
60
- };
61
-
62
- const wrapped = buildShellInvocation(command);
63
- const child = spawn(wrapped.command, wrapped.args, {
64
- cwd: getWorkspaceDir(),
65
- stdio: ["ignore", "pipe", "pipe"],
66
- detached: true,
67
- env: buildSanitizedEnv(),
68
- windowsHide: true,
69
- });
70
-
71
- const timer = setTimeout(() => {
72
- timedOut = true;
73
- terminateProcessTree(child);
74
- }, effectiveTimeout);
75
-
76
- child.stdout.on("data", (data: Buffer) => {
77
- stdoutChunks.push(data);
78
- });
79
-
80
- child.stderr.on("data", (data: Buffer) => {
81
- stderrChunks.push(data);
82
- });
83
-
84
- child.on("close", (code) => {
85
- clearTimeout(timer);
86
- finish({
87
- stdout: Buffer.concat(stdoutChunks).toString(),
88
- stderr: Buffer.concat(stderrChunks).toString(),
89
- exitCode: code,
90
- timedOut,
91
- });
92
- });
93
-
94
- child.on("error", (err) => {
95
- clearTimeout(timer);
96
- finish({
97
- stdout: "",
98
- stderr: "",
99
- exitCode: null,
100
- timedOut: false,
101
- error: err.message,
102
- });
103
- });
104
- });
105
- }
@@ -1,13 +0,0 @@
1
- import { readFile, writeFile } from "node:fs/promises";
2
-
3
- export async function writeCombinedCABundle(
4
- systemBundlePath: string,
5
- extraCAPath: string,
6
- outputPath: string,
7
- ): Promise<void> {
8
- const [systemCAs, extraCAs] = await Promise.all([
9
- readFile(systemBundlePath, "utf-8"),
10
- readFile(extraCAPath, "utf-8"),
11
- ]);
12
- await writeFile(outputPath, `${systemCAs}\n${extraCAs}`, { mode: 0o644 });
13
- }
@@ -1,66 +0,0 @@
1
- /**
2
- * NUL-terminated `git status --porcelain -z` parsing.
3
- *
4
- * Status reporting and batched staging share this parser so rename/copy
5
- * origin paths cannot drift between the two readers.
6
- */
7
-
8
- export interface PorcelainEntry {
9
- /** Two-character XY status from porcelain v1. */
10
- status: string;
11
- /** Path git reports for this record (the destination for rename/copy). */
12
- path: string;
13
- /** Pre-rename/copy path. Present when the record is a rename or copy. */
14
- origin?: string;
15
- }
16
-
17
- /**
18
- * Parse NUL-terminated `git status --porcelain -z` output into status/path
19
- * records. NUL termination is required so paths with special characters
20
- * (non-ASCII, quotes, newlines) arrive verbatim instead of C-style quoted.
21
- *
22
- * A rename/copy record is followed by a bare origin-path entry, captured on
23
- * {@link PorcelainEntry.origin}.
24
- */
25
- export function parsePorcelainZ(stdout: string): PorcelainEntry[] {
26
- const entries = stdout.split("\0");
27
- const parsed: PorcelainEntry[] = [];
28
- for (let i = 0; i < entries.length; i++) {
29
- const entry = entries[i] ?? "";
30
- if (entry.length < 4) {
31
- continue;
32
- }
33
- const status = entry.substring(0, 2);
34
- const path = entry.substring(3);
35
- if (status[0] === "R" || status[0] === "C") {
36
- i++;
37
- const origin = entries[i];
38
- if (origin && origin.length > 0) {
39
- parsed.push({ status, path, origin });
40
- continue;
41
- }
42
- }
43
- parsed.push({ status, path });
44
- }
45
- return parsed;
46
- }
47
-
48
- /**
49
- * Every path git status knows about, including rename/copy origins.
50
- * Origins still need to be staged so a deletion is not left behind when a
51
- * rename is split across add batches.
52
- */
53
- export function collectDirtyPathsFromPorcelain(stdout: string): string[] {
54
- const paths: string[] = [];
55
- const seen = new Set<string>();
56
- for (const entry of parsePorcelainZ(stdout)) {
57
- for (const path of [entry.path, entry.origin]) {
58
- if (!path || seen.has(path)) {
59
- continue;
60
- }
61
- seen.add(path);
62
- paths.push(path);
63
- }
64
- }
65
- return paths;
66
- }
@@ -1,258 +0,0 @@
1
- import { existsSync, readFileSync, renameSync, writeFileSync } from "node:fs";
2
- import { join } from "node:path";
3
- import { Database } from "bun:sqlite";
4
-
5
- import type { WorkspaceMigration } from "./types.js";
6
-
7
- /**
8
- * Repair `gpt-5.4` and `gpt-5.4-mini` pins on fragments that dispatch
9
- * through the ChatGPT subscription.
10
- *
11
- * OpenAI serves neither model under ChatGPT sign-in: the Codex endpoint
12
- * rejects them with HTTP 400 ("not supported when using Codex with a
13
- * ChatGPT account"), so both are out of `CODEX_SUBSCRIPTION_MODEL_IDS`.
14
- * API-key access is unaffected, so a fragment on any other route keeps
15
- * its model.
16
- *
17
- * Two stored shapes dispatch through the subscription. The `chatgpt`
18
- * routing identity fails `LLMSchema.superRefine` once the allowlist drops
19
- * the model, and the loader's per-section salvage then resets the whole
20
- * `llm` section, losing every profile and call-site tuning: this is the
21
- * repair that prevents data loss. A profile bound to the subscription row
22
- * (row kind `chatgpt`, or an `oauth_subscription` auth on the
23
- * pre-DB-migration-366 row shape) bypasses the auto-resolution compat
24
- * gate and 400s on every request; the row is named by the legacy
25
- * `provider_connection` binding when present (dispatch honors it first,
26
- * and the name is only ever a row name), otherwise by an entry-name
27
- * `provider`. Both shapes are swept in `llm.default`, `llm.callSites.*`,
28
- * and `llm.profiles.*`; call-site fragments carry no binding (the schema
29
- * strips a raw `provider_connection`), so only their declared provider
30
- * counts.
31
- *
32
- * A providerless call-site pin is deliberately left alone. It overlays
33
- * whichever profile wins the site for a turn: on an API-key or managed
34
- * winner it still serves the model, and on a subscription winner the
35
- * request already fails upstream and keeps failing, with no config loss
36
- * either way. Rewriting such pins would change API-key users' model and
37
- * price to cover a winner that may never be selected.
38
- *
39
- * Replacements: `gpt-5.4` becomes `gpt-5.5` (its successor) and
40
- * `gpt-5.4-mini` becomes `gpt-5.6-luna` (the subscription's Balanced model;
41
- * on the subscription every model bills the same).
42
- */
43
- export const repairRetiredCodexGpt54ModelIdsMigration: WorkspaceMigration = {
44
- id: "154-repair-retired-codex-gpt-5-4-model-ids",
45
- description:
46
- "Repair gpt-5.4 and gpt-5.4-mini pins on ChatGPT-subscription LLM fragments in workspace config",
47
- run(workspaceDir: string): void {
48
- const configPath = join(workspaceDir, "config.json");
49
- if (!existsSync(configPath)) {
50
- return;
51
- }
52
-
53
- // Read outside the parse catch: a transient filesystem error (EIO,
54
- // EACCES) must reach the runner so the migration retries, while
55
- // malformed JSON is a permanent state this migration cannot repair.
56
- const rawText = readFileSync(configPath, "utf-8");
57
-
58
- let config: Record<string, unknown>;
59
- try {
60
- const raw = JSON.parse(rawText);
61
- if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
62
- return;
63
- }
64
- config = raw as Record<string, unknown>;
65
- } catch {
66
- return;
67
- }
68
-
69
- const llm = readObject(config.llm);
70
- if (llm === null) {
71
- return;
72
- }
73
-
74
- // Entry rows load lazily: only a stale fragment naming a row needs
75
- // them. An unreadable DB then fails the run (retried next boot) rather
76
- // than checkpointing a pass that skips entry-bound profiles.
77
- let rows: Map<string, boolean> | null | undefined;
78
- const isSubscriptionRow = (name: unknown): boolean => {
79
- if (typeof name !== "string" || name.length === 0) {
80
- return false;
81
- }
82
- if (rows === undefined) {
83
- rows = readConnectionRows(workspaceDir);
84
- }
85
- if (rows === null) {
86
- throw new Error(
87
- "provider_connections is not readable; retrying the model-ID repair on the next run",
88
- );
89
- }
90
- return rows.get(name) === true;
91
- };
92
- // A `provider` value: the identity dispatches to the subscription, a
93
- // known vendor never does, and any other value is an entry name.
94
- const isSubscriptionProvider = (provider: unknown): boolean =>
95
- provider === CHATGPT_IDENTITY ||
96
- (typeof provider === "string" &&
97
- !KNOWN_PROVIDERS.has(provider) &&
98
- isSubscriptionRow(provider));
99
- // The binding is authoritative when present, since dispatch honors it
100
- // ahead of the declared provider; the identity is repaired regardless
101
- // (the schema rejects the pair whatever the binding).
102
- const isBound = (fragment: Record<string, unknown>): boolean => {
103
- if (fragment.provider === CHATGPT_IDENTITY) {
104
- return true;
105
- }
106
- const binding = fragment.provider_connection;
107
- return typeof binding === "string" && binding.length > 0
108
- ? isSubscriptionRow(binding)
109
- : isSubscriptionProvider(fragment.provider);
110
- };
111
- const isProviderBound = (fragment: Record<string, unknown>): boolean =>
112
- isSubscriptionProvider(fragment.provider);
113
-
114
- let changed = false;
115
-
116
- changed = repairFragment(readObject(llm.default), isBound) || changed;
117
-
118
- const callSites = readObject(llm.callSites);
119
- if (callSites !== null) {
120
- for (const rawConfig of Object.values(callSites)) {
121
- changed =
122
- repairFragment(readObject(rawConfig), isProviderBound) || changed;
123
- }
124
- }
125
-
126
- const profiles = readObject(llm.profiles);
127
- if (profiles !== null) {
128
- for (const rawProfile of Object.values(profiles)) {
129
- changed = repairFragment(readObject(rawProfile), isBound) || changed;
130
- }
131
- }
132
-
133
- if (!changed) {
134
- return;
135
- }
136
-
137
- // Write-then-rename so an interrupted write cannot leave config.json
138
- // truncated: a torn in-place write would parse as invalid JSON on the
139
- // retry, which the catch above treats as "nothing to do", letting the
140
- // runner checkpoint the migration as completed against a corrupt file.
141
- const tmpPath = `${configPath}.migration-154.tmp`;
142
- writeFileSync(tmpPath, JSON.stringify(config, null, 2) + "\n");
143
- renameSync(tmpPath, configPath);
144
- },
145
- // The exact-match rewrite is idempotent, so a transient failure (full
146
- // disk, I/O error) is safe to retry on later startups.
147
- retryFailedCheckpoint: true,
148
- down(_workspaceDir: string): void {
149
- // Forward-only: reintroducing the retired model IDs would fail schema
150
- // validation once the allowlist no longer carries them.
151
- },
152
- };
153
-
154
- // ---------------------------------------------------------------------------
155
- // Helpers: self-contained per workspace migrations AGENTS.md
156
- // ---------------------------------------------------------------------------
157
-
158
- const CHATGPT_IDENTITY = "chatgpt";
159
-
160
- // Frozen snapshot of `KNOWN_LLM_PROVIDERS`: the vendor and identity values
161
- // that dispatch without a connection row, so none of them is an entry name.
162
- const KNOWN_PROVIDERS = new Set([
163
- "anthropic",
164
- "openai",
165
- "gemini",
166
- "ollama",
167
- "fireworks",
168
- "openrouter",
169
- "vercel-ai-gateway",
170
- "openai-compatible",
171
- "minimax",
172
- "atlascloud",
173
- "together",
174
- "litellm",
175
- "opencode",
176
- "baseten",
177
- "poolside",
178
- "vellum",
179
- "chatgpt",
180
- ]);
181
-
182
- const REPLACEMENTS: ReadonlyMap<string, string> = new Map([
183
- ["gpt-5.4", "gpt-5.5"],
184
- ["gpt-5.4-mini", "gpt-5.6-luna"],
185
- ]);
186
-
187
- function repairFragment(
188
- fragment: Record<string, unknown> | null,
189
- isSubscriptionRouted: (fragment: Record<string, unknown>) => boolean,
190
- ): boolean {
191
- if (fragment === null || typeof fragment.model !== "string") {
192
- return false;
193
- }
194
- const replacement = REPLACEMENTS.get(fragment.model);
195
- if (replacement === undefined) {
196
- return false;
197
- }
198
- if (!isSubscriptionRouted(fragment)) {
199
- return false;
200
- }
201
- fragment.model = replacement;
202
- return true;
203
- }
204
-
205
- /**
206
- * `provider_connections` row name to whether the row dispatches to the
207
- * ChatGPT subscription, or null when the DB or table is not readable. The
208
- * caller fails the run on null: entry-name providers must be judged against
209
- * real rows, never guessed. An absent DB file is a real state (no rows, so
210
- * every entry name is dangling).
211
- */
212
- function readConnectionRows(workspaceDir: string): Map<string, boolean> | null {
213
- const dbPath = join(workspaceDir, "data", "db", "assistant.db");
214
- if (!existsSync(dbPath)) {
215
- return new Map();
216
- }
217
- let db: Database;
218
- try {
219
- db = new Database(dbPath, { readonly: true });
220
- } catch {
221
- return null;
222
- }
223
- try {
224
- const rows = db
225
- .query(`SELECT name, provider, auth FROM provider_connections`)
226
- .all() as Array<{ name: string; provider: string; auth: string }>;
227
- return new Map(
228
- rows.map((row) => [
229
- row.name,
230
- row.provider === CHATGPT_IDENTITY || isSubscriptionAuth(row.auth),
231
- ]),
232
- );
233
- } catch {
234
- return null;
235
- } finally {
236
- db.close();
237
- }
238
- }
239
-
240
- function isSubscriptionAuth(auth: string): boolean {
241
- try {
242
- const parsed: unknown = JSON.parse(auth);
243
- return (
244
- parsed !== null &&
245
- typeof parsed === "object" &&
246
- (parsed as { type?: unknown }).type === "oauth_subscription"
247
- );
248
- } catch {
249
- return false;
250
- }
251
- }
252
-
253
- function readObject(value: unknown): Record<string, unknown> | null {
254
- if (value === null || typeof value !== "object" || Array.isArray(value)) {
255
- return null;
256
- }
257
- return value as Record<string, unknown>;
258
- }
@@ -1,78 +0,0 @@
1
- import { existsSync, readFileSync, renameSync, writeFileSync } from "node:fs";
2
- import { join } from "node:path";
3
-
4
- import { getLogger } from "../../util/logger.js";
5
- import type { WorkspaceMigration } from "./types.js";
6
-
7
- const log = getLogger("workspace-migration-155");
8
-
9
- /**
10
- * Move `liveVoice.frontModel` to `voice.frontModel` in `config.json`.
11
- *
12
- * The front-door tuning (endpointing budgets and progress narration cadence)
13
- * is read by phone calls as well as live voice, so it lives under a
14
- * transport-agnostic key. A `voice.frontModel` already present wins field by
15
- * field; the `liveVoice` block is removed either way so raw-config saves do
16
- * not write it back.
17
- */
18
- export const moveFrontModelConfigToVoiceMigration: WorkspaceMigration = {
19
- id: "155-move-front-model-config-to-voice",
20
- description: "Move liveVoice.frontModel to voice.frontModel in config.json",
21
- run(workspaceDir: string): void {
22
- const configPath = join(workspaceDir, "config.json");
23
- if (!existsSync(configPath)) {
24
- return;
25
- }
26
-
27
- let config: Record<string, unknown>;
28
- try {
29
- const raw = JSON.parse(readFileSync(configPath, "utf-8"));
30
- if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
31
- return;
32
- }
33
- config = raw as Record<string, unknown>;
34
- } catch {
35
- return;
36
- }
37
-
38
- const liveVoice = readObject(config.liveVoice);
39
- if (liveVoice === null || !Object.hasOwn(liveVoice, "frontModel")) {
40
- return;
41
- }
42
- const legacy = readObject(liveVoice.frontModel);
43
- delete liveVoice.frontModel;
44
-
45
- if (legacy !== null) {
46
- const voice = readObject(config.voice) ?? {};
47
- const current = readObject(voice.frontModel) ?? {};
48
- const legacyProgress = readObject(legacy.progress) ?? {};
49
- const currentProgress = readObject(current.progress) ?? {};
50
- const merged: Record<string, unknown> = { ...legacy, ...current };
51
- if (
52
- Object.keys(legacyProgress).length > 0 ||
53
- Object.keys(currentProgress).length > 0
54
- ) {
55
- merged.progress = { ...legacyProgress, ...currentProgress };
56
- }
57
- voice.frontModel = merged;
58
- config.voice = voice;
59
- }
60
-
61
- const tmpPath = `${configPath}.migration-155.tmp`;
62
- writeFileSync(tmpPath, JSON.stringify(config, null, 2) + "\n");
63
- renameSync(tmpPath, configPath);
64
- log.info("Moved liveVoice.frontModel to voice.frontModel in config.json");
65
- },
66
- retryFailedCheckpoint: true,
67
- down(_workspaceDir: string): void {
68
- // Forward-only: the schema reads voice.frontModel and strips unknown
69
- // liveVoice keys, so a block moved back is dropped on the next load.
70
- },
71
- };
72
-
73
- function readObject(value: unknown): Record<string, unknown> | null {
74
- if (value === null || typeof value !== "object" || Array.isArray(value)) {
75
- return null;
76
- }
77
- return value as Record<string, unknown>;
78
- }