@gajae-code/coding-agent 0.17.1 → 0.17.4

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 (375) hide show
  1. package/CHANGELOG.md +266 -0
  2. package/dist/types/async/job-manager.d.ts +7 -6
  3. package/dist/types/cli/daemon-cli.d.ts +3 -1
  4. package/dist/types/cli/github-release.d.ts +17 -0
  5. package/dist/types/cli/public-command-entry.d.ts +56 -0
  6. package/dist/types/cli/public-command-errors.d.ts +126 -0
  7. package/dist/types/cli/public-command-evidence.d.ts +99 -0
  8. package/dist/types/cli/public-command-help.d.ts +65 -0
  9. package/dist/types/cli/public-command-registry.d.ts +69 -0
  10. package/dist/types/cli/session-picker.d.ts +1 -1
  11. package/dist/types/cli/setup-cli.d.ts +1 -0
  12. package/dist/types/cli/skills-cli.d.ts +5 -0
  13. package/dist/types/cli.d.ts +3 -0
  14. package/dist/types/commands/daemon.d.ts +4 -50
  15. package/dist/types/commands/sdk.d.ts +20 -37
  16. package/dist/types/commands/setup.d.ts +3 -0
  17. package/dist/types/commands/skills.d.ts +9 -0
  18. package/dist/types/config/autorouting-tier-map.d.ts +24 -0
  19. package/dist/types/config/file-lock.d.ts +10 -1
  20. package/dist/types/config/model-profile-activation.d.ts +63 -4
  21. package/dist/types/config/model-registry.d.ts +20 -2
  22. package/dist/types/config/settings-schema.d.ts +11 -0
  23. package/dist/types/coordinator-mcp/question-state.d.ts +6 -1
  24. package/dist/types/coordinator-mcp/server.d.ts +3 -0
  25. package/dist/types/daemon/operator-contract.d.ts +5 -1
  26. package/dist/types/eval/js/worker-protocol.d.ts +2 -0
  27. package/dist/types/extensibility/extensions/types.d.ts +12 -0
  28. package/dist/types/extensibility/gjc-plugins/registry.d.ts +4 -0
  29. package/dist/types/extensibility/runtime-skill-discovery.d.ts +18 -0
  30. package/dist/types/extensibility/shared-events.d.ts +3 -1
  31. package/dist/types/gjc-runtime/session-state-lock.d.ts +61 -0
  32. package/dist/types/internal-urls/embedded-protocol.d.ts +9 -0
  33. package/dist/types/internal-urls/index.d.ts +1 -0
  34. package/dist/types/internal-urls/parse.d.ts +9 -1
  35. package/dist/types/main.d.ts +22 -0
  36. package/dist/types/modes/acp/acp-agent.d.ts +94 -1
  37. package/dist/types/modes/acp/startup-provenance.d.ts +16 -0
  38. package/dist/types/modes/components/custom-provider-wizard.d.ts +19 -1
  39. package/dist/types/modes/components/session-selector.d.ts +5 -2
  40. package/dist/types/modes/components/thinking-selector.d.ts +2 -1
  41. package/dist/types/modes/components/user-message-selector.d.ts +5 -2
  42. package/dist/types/modes/controllers/command-controller.d.ts +1 -1
  43. package/dist/types/modes/controllers/selector-controller.d.ts +1 -1
  44. package/dist/types/modes/interactive-mode.d.ts +1 -1
  45. package/dist/types/modes/shared/agent-wire/workflow-gate-broker.d.ts +11 -1
  46. package/dist/types/modes/shared/agent-wire/workflow-gate-types.d.ts +14 -1
  47. package/dist/types/modes/types.d.ts +2 -2
  48. package/dist/types/runtime/process-lifecycle.d.ts +2 -0
  49. package/dist/types/runtime-mcp/manager.d.ts +56 -0
  50. package/dist/types/runtime-mcp/pool.d.ts +17 -0
  51. package/dist/types/runtime-mcp/redaction.d.ts +20 -0
  52. package/dist/types/runtime-mcp/startup-policy.d.ts +6 -0
  53. package/dist/types/runtime-mcp/tool-bridge.d.ts +9 -0
  54. package/dist/types/runtime-mcp/transports/http.d.ts +11 -0
  55. package/dist/types/sdk/acp/adapter.d.ts +27 -0
  56. package/dist/types/sdk/acp/final-text.d.ts +8 -0
  57. package/dist/types/sdk/broker/broker.d.ts +13 -2
  58. package/dist/types/sdk/broker/ensure.d.ts +46 -1
  59. package/dist/types/sdk/broker/identity.d.ts +3 -1
  60. package/dist/types/sdk/broker/lifecycle-ledger.d.ts +23 -3
  61. package/dist/types/sdk/broker/lifecycle.d.ts +15 -8
  62. package/dist/types/sdk/broker/runtime.d.ts +1 -1
  63. package/dist/types/sdk/broker/session-index.d.ts +22 -3
  64. package/dist/types/sdk/broker/spawn-authority.d.ts +4 -0
  65. package/dist/types/sdk/broker/stderr-drainer.d.ts +13 -0
  66. package/dist/types/sdk/bus/index.d.ts +19 -0
  67. package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +3 -1
  68. package/dist/types/sdk/bus/telegram-daemon.d.ts +5 -0
  69. package/dist/types/sdk/cli/master-cli.d.ts +6 -10
  70. package/dist/types/sdk/cli/rows.d.ts +19 -1
  71. package/dist/types/sdk/cli/session-cli.d.ts +22 -5
  72. package/dist/types/sdk/client/client.d.ts +2 -0
  73. package/dist/types/sdk/guides/cli.d.ts +3 -4
  74. package/dist/types/sdk/guides/verify.d.ts +2 -0
  75. package/dist/types/sdk/host/host.d.ts +9 -0
  76. package/dist/types/sdk/host/session-runtime.d.ts +31 -0
  77. package/dist/types/sdk/host/types.d.ts +10 -0
  78. package/dist/types/sdk/index.d.ts +1 -0
  79. package/dist/types/sdk/prompt-deadline-flush.d.ts +83 -0
  80. package/dist/types/sdk/prompt-deadline-manager.d.ts +38 -1
  81. package/dist/types/sdk/prompt-failure.d.ts +30 -1
  82. package/dist/types/sdk/prompt-status.d.ts +8 -0
  83. package/dist/types/sdk/prompt-tool-boundary.d.ts +73 -0
  84. package/dist/types/sdk/router/replay-retention-gap-cache.d.ts +13 -0
  85. package/dist/types/sdk/router/session-router.d.ts +2 -0
  86. package/dist/types/sdk/startup-capability.d.ts +2 -0
  87. package/dist/types/sdk/transport/relay.d.ts +1 -0
  88. package/dist/types/sdk/transport/serve-cli.d.ts +73 -2
  89. package/dist/types/sdk/transport/stdio.d.ts +5 -1
  90. package/dist/types/session/agent-session.d.ts +168 -21
  91. package/dist/types/session/fallback-chain-controller.d.ts +6 -6
  92. package/dist/types/session/fold-coordinator.d.ts +17 -3
  93. package/dist/types/session/internal/managed-session-storage.d.ts +7 -1
  94. package/dist/types/session/session-manager.d.ts +64 -1
  95. package/dist/types/session/session-work-lease.d.ts +14 -0
  96. package/dist/types/setup/model-onboarding-guidance.d.ts +1 -1
  97. package/dist/types/setup/provider-onboarding.d.ts +81 -1
  98. package/dist/types/thinking.d.ts +3 -1
  99. package/dist/types/tools/bash.d.ts +37 -11
  100. package/dist/types/tools/job.d.ts +1 -1
  101. package/dist/types/tools/steer-fold.d.ts +31 -0
  102. package/dist/types/utils/git.d.ts +28 -2
  103. package/dist/types/utils/mupdf-embedded.d.ts +2 -0
  104. package/dist/types/utils/mupdf-wasm-embedded.d.ts +2 -0
  105. package/dist/types/utils/mupdf.d.ts +4 -0
  106. package/dist/types/utils/session-title-generation.d.ts +6 -0
  107. package/dist/types/utils/title-generator.d.ts +11 -2
  108. package/dist/types/web/scrapers/types.d.ts +3 -0
  109. package/package.json +18 -10
  110. package/scripts/build-binary.ts +9 -3
  111. package/scripts/compile-args.ts +0 -9
  112. package/scripts/embed-mupdf.ts +52 -0
  113. package/scripts/generate-sdk-operation-inventory.ts +31 -1
  114. package/scripts/vendor-markit.ts +196 -0
  115. package/src/async/job-manager.ts +60 -9
  116. package/src/cli/daemon-cli.ts +53 -18
  117. package/src/cli/github-release.ts +87 -5
  118. package/src/cli/mcp-cli.ts +38 -4
  119. package/src/cli/public-command-entry.ts +450 -0
  120. package/src/cli/public-command-errors.ts +581 -0
  121. package/src/cli/public-command-evidence.ts +717 -0
  122. package/src/cli/public-command-help.ts +360 -0
  123. package/src/cli/public-command-registry.ts +535 -0
  124. package/src/cli/session-picker.ts +2 -1
  125. package/src/cli/setup-cli.ts +9 -1
  126. package/src/cli/skills-cli.ts +46 -2
  127. package/src/cli.ts +61 -1
  128. package/src/commands/daemon.ts +65 -69
  129. package/src/commands/sdk.ts +232 -100
  130. package/src/commands/setup.ts +2 -0
  131. package/src/commands/skills.ts +11 -0
  132. package/src/config/autorouting-tier-map.ts +16 -0
  133. package/src/config/file-lock.ts +199 -68
  134. package/src/config/model-profile-activation.ts +406 -53
  135. package/src/config/model-registry.ts +204 -25
  136. package/src/config/settings-schema.ts +26 -2
  137. package/src/coordinator-mcp/policy.ts +10 -5
  138. package/src/coordinator-mcp/question-gate-codec.ts +17 -0
  139. package/src/coordinator-mcp/question-state.ts +175 -8
  140. package/src/coordinator-mcp/server.ts +528 -87
  141. package/src/coordinator-mcp/session-reaper.ts +6 -4
  142. package/src/crash/record-loader.ts +6 -2
  143. package/src/daemon/operator-contract.ts +26 -12
  144. package/src/debug/report-bundle.ts +114 -24
  145. package/src/defaults/gjc/skills/ultragoal/SKILL.md +1 -1
  146. package/src/eval/js/context-manager.ts +8 -8
  147. package/src/eval/js/worker-core.ts +9 -4
  148. package/src/eval/js/worker-protocol.ts +2 -0
  149. package/src/extensibility/extensions/runner.ts +52 -4
  150. package/src/extensibility/extensions/types.ts +10 -0
  151. package/src/extensibility/gjc-plugins/registry.ts +196 -37
  152. package/src/extensibility/runtime-skill-discovery.ts +61 -3
  153. package/src/extensibility/shared-events.ts +3 -1
  154. package/src/gjc-runtime/managed-owner-admission.ts +67 -50
  155. package/src/gjc-runtime/session-state-lock.ts +165 -24
  156. package/src/gjc-runtime/ultragoal-succession.ts +31 -3
  157. package/src/internal-urls/docs-index.generated.ts +21 -19
  158. package/src/internal-urls/embedded-protocol.ts +83 -0
  159. package/src/internal-urls/index.ts +1 -0
  160. package/src/internal-urls/parse.ts +21 -1
  161. package/src/internal-urls/router.ts +4 -2
  162. package/src/main.ts +123 -55
  163. package/src/modes/acp/acp-agent.ts +593 -47
  164. package/src/modes/acp/acp-event-mapper.ts +9 -0
  165. package/src/modes/acp/startup-provenance.ts +59 -0
  166. package/src/modes/components/custom-provider-wizard.ts +308 -7
  167. package/src/modes/components/model-selector.ts +31 -15
  168. package/src/modes/components/oauth-selector.ts +9 -0
  169. package/src/modes/components/session-selector.ts +47 -4
  170. package/src/modes/components/status-line/segments.ts +6 -1
  171. package/src/modes/components/thinking-selector.ts +7 -3
  172. package/src/modes/components/user-message-selector.ts +57 -15
  173. package/src/modes/controllers/command-controller.ts +58 -32
  174. package/src/modes/controllers/extension-ui-controller.ts +33 -7
  175. package/src/modes/controllers/input-controller.ts +4 -0
  176. package/src/modes/controllers/selector-controller.ts +177 -18
  177. package/src/modes/interactive-mode.ts +21 -7
  178. package/src/modes/runtime-init.ts +1 -0
  179. package/src/modes/shared/agent-wire/workflow-gate-broker.ts +124 -7
  180. package/src/modes/shared/agent-wire/workflow-gate-types.ts +16 -2
  181. package/src/modes/types.ts +2 -2
  182. package/src/prompts/agent-fragments/browser-aside.md +1 -0
  183. package/src/prompts/system/title-system.md +1 -1
  184. package/src/prompts/tools/bash.md +1 -1
  185. package/src/prompts/tools/job.md +1 -1
  186. package/src/prompts/tools/read.md +2 -0
  187. package/src/runtime/network-prewarm-service.test.ts +36 -1
  188. package/src/runtime/network-prewarm-service.ts +28 -3
  189. package/src/runtime/process-lifecycle.ts +22 -11
  190. package/src/runtime-mcp/config.ts +16 -1
  191. package/src/runtime-mcp/manager.ts +689 -55
  192. package/src/runtime-mcp/pool.test.ts +31 -0
  193. package/src/runtime-mcp/pool.ts +304 -28
  194. package/src/runtime-mcp/redaction.ts +42 -0
  195. package/src/runtime-mcp/startup-policy.ts +7 -0
  196. package/src/runtime-mcp/tool-bridge.ts +71 -0
  197. package/src/runtime-mcp/transports/http.ts +108 -25
  198. package/src/sdk/acp/adapter.ts +90 -9
  199. package/src/sdk/acp/final-text.ts +19 -2
  200. package/src/sdk/broker/broker.ts +378 -52
  201. package/src/sdk/broker/ensure.ts +97 -19
  202. package/src/sdk/broker/identity.ts +9 -1
  203. package/src/sdk/broker/lifecycle-ledger.ts +95 -31
  204. package/src/sdk/broker/lifecycle.ts +690 -141
  205. package/src/sdk/broker/runtime.ts +1 -1
  206. package/src/sdk/broker/session-index.ts +97 -4
  207. package/src/sdk/broker/spawn-authority.ts +35 -7
  208. package/src/sdk/broker/stderr-drainer.ts +59 -0
  209. package/src/sdk/bus/chat-daemon-control.ts +2 -2
  210. package/src/sdk/bus/chat-daemon-runtime.ts +1 -0
  211. package/src/sdk/bus/index.ts +721 -84
  212. package/src/sdk/bus/telegram-daemon-cli.ts +31 -2
  213. package/src/sdk/bus/telegram-daemon-contract.ts +3 -1
  214. package/src/sdk/bus/telegram-daemon.ts +10 -3
  215. package/src/sdk/cli/master-cli.ts +47 -36
  216. package/src/sdk/cli/rows.ts +30 -7
  217. package/src/sdk/cli/session-cli.ts +687 -184
  218. package/src/sdk/client/client.ts +18 -0
  219. package/src/sdk/guides/catalog.ts +2 -2
  220. package/src/sdk/guides/cli.ts +20 -62
  221. package/src/sdk/guides/verify.ts +14 -0
  222. package/src/sdk/host/host.ts +49 -5
  223. package/src/sdk/host/session-runtime.test.ts +636 -9
  224. package/src/sdk/host/session-runtime.ts +499 -118
  225. package/src/sdk/host/types.ts +12 -1
  226. package/src/sdk/host/websocket-transport.lifecycle.test.ts +84 -0
  227. package/src/sdk/host/websocket-transport.ts +40 -6
  228. package/src/sdk/index.ts +11 -0
  229. package/src/sdk/prompt-deadline-flush.ts +334 -0
  230. package/src/sdk/prompt-deadline-manager.ts +136 -4
  231. package/src/sdk/prompt-failure.ts +43 -1
  232. package/src/sdk/prompt-status.ts +8 -0
  233. package/src/sdk/prompt-tool-boundary.ts +121 -0
  234. package/src/sdk/protocol/operation-inventory.generated.json +106 -0
  235. package/src/sdk/router/replay-retention-gap-cache.ts +27 -0
  236. package/src/sdk/router/session-router.ts +31 -4
  237. package/src/sdk/session.ts +194 -16
  238. package/src/sdk/startup-capability.ts +1 -1
  239. package/src/sdk/transport/relay.ts +71 -6
  240. package/src/sdk/transport/serve-cli.ts +494 -49
  241. package/src/sdk/transport/socket.ts +12 -11
  242. package/src/sdk/transport/stdio.ts +7 -3
  243. package/src/session/agent-session.ts +2437 -400
  244. package/src/session/fallback-chain-controller.ts +6 -7
  245. package/src/session/fold-coordinator.ts +24 -5
  246. package/src/session/internal/managed-session-scope.ts +58 -18
  247. package/src/session/internal/managed-session-storage.ts +304 -11
  248. package/src/session/session-manager.ts +382 -44
  249. package/src/session/session-work-lease.ts +34 -0
  250. package/src/session-import/codex.ts +12 -3
  251. package/src/setup/model-onboarding-guidance.ts +1 -1
  252. package/src/setup/provider-onboarding.ts +397 -24
  253. package/src/slash-commands/builtin-registry.ts +258 -14
  254. package/src/task/index.ts +14 -2
  255. package/src/thinking.ts +21 -2
  256. package/src/tools/bash.ts +98 -78
  257. package/src/tools/fetch.ts +119 -20
  258. package/src/tools/job.ts +151 -25
  259. package/src/tools/output-meta.ts +15 -2
  260. package/src/tools/path-utils.ts +27 -3
  261. package/src/tools/read.ts +3 -3
  262. package/src/tools/steer-fold.ts +107 -0
  263. package/src/tools/tool-catalog.generated.ts +29 -2
  264. package/src/tools/tool-errors.ts +4 -0
  265. package/src/utils/git.ts +53 -3
  266. package/src/utils/markit.ts +55 -41
  267. package/src/utils/mupdf-assets.d.ts +4 -0
  268. package/src/utils/mupdf-embedded.ts +4 -0
  269. package/src/utils/mupdf-wasm-embedded.ts +3 -0
  270. package/src/utils/mupdf-wasm.ts +24 -2
  271. package/src/utils/mupdf.ts +129 -0
  272. package/src/utils/session-title-generation.ts +29 -0
  273. package/src/utils/title-generator.ts +46 -2
  274. package/src/web/scrapers/types.ts +24 -3
  275. package/vendor/markit-ai/LICENSE +21 -0
  276. package/vendor/markit-ai/MANIFEST.json +412 -0
  277. package/vendor/markit-ai/dist/commands/config.d.ts +4 -0
  278. package/vendor/markit-ai/dist/commands/config.js +139 -0
  279. package/vendor/markit-ai/dist/commands/convert.d.ts +6 -0
  280. package/vendor/markit-ai/dist/commands/convert.js +113 -0
  281. package/vendor/markit-ai/dist/commands/formats.d.ts +2 -0
  282. package/vendor/markit-ai/dist/commands/formats.js +92 -0
  283. package/vendor/markit-ai/dist/commands/init.d.ts +2 -0
  284. package/vendor/markit-ai/dist/commands/init.js +29 -0
  285. package/vendor/markit-ai/dist/commands/onboard.d.ts +2 -0
  286. package/vendor/markit-ai/dist/commands/onboard.js +61 -0
  287. package/vendor/markit-ai/dist/commands/plugin.d.ts +4 -0
  288. package/vendor/markit-ai/dist/commands/plugin.js +58 -0
  289. package/vendor/markit-ai/dist/config.d.ts +26 -0
  290. package/vendor/markit-ai/dist/config.js +42 -0
  291. package/vendor/markit-ai/dist/converters/audio.d.ts +7 -0
  292. package/vendor/markit-ai/dist/converters/audio.js +104 -0
  293. package/vendor/markit-ai/dist/converters/csv.d.ts +7 -0
  294. package/vendor/markit-ai/dist/converters/csv.js +83 -0
  295. package/vendor/markit-ai/dist/converters/docx.d.ts +6 -0
  296. package/vendor/markit-ai/dist/converters/docx.js +57 -0
  297. package/vendor/markit-ai/dist/converters/epub.d.ts +8 -0
  298. package/vendor/markit-ai/dist/converters/epub.js +128 -0
  299. package/vendor/markit-ai/dist/converters/github.d.ts +18 -0
  300. package/vendor/markit-ai/dist/converters/github.js +148 -0
  301. package/vendor/markit-ai/dist/converters/html.d.ts +6 -0
  302. package/vendor/markit-ai/dist/converters/html.js +30 -0
  303. package/vendor/markit-ai/dist/converters/image.d.ts +6 -0
  304. package/vendor/markit-ai/dist/converters/image.js +124 -0
  305. package/vendor/markit-ai/dist/converters/ipynb.d.ts +6 -0
  306. package/vendor/markit-ai/dist/converters/ipynb.js +75 -0
  307. package/vendor/markit-ai/dist/converters/iwork.d.ts +20 -0
  308. package/vendor/markit-ai/dist/converters/iwork.js +391 -0
  309. package/vendor/markit-ai/dist/converters/json.d.ts +6 -0
  310. package/vendor/markit-ai/dist/converters/json.js +21 -0
  311. package/vendor/markit-ai/dist/converters/pdf/columns.d.ts +35 -0
  312. package/vendor/markit-ai/dist/converters/pdf/columns.js +93 -0
  313. package/vendor/markit-ai/dist/converters/pdf/extract.d.ts +19 -0
  314. package/vendor/markit-ai/dist/converters/pdf/extract.js +514 -0
  315. package/vendor/markit-ai/dist/converters/pdf/grid.d.ts +25 -0
  316. package/vendor/markit-ai/dist/converters/pdf/grid.js +795 -0
  317. package/vendor/markit-ai/dist/converters/pdf/headers.d.ts +24 -0
  318. package/vendor/markit-ai/dist/converters/pdf/headers.js +108 -0
  319. package/vendor/markit-ai/dist/converters/pdf/index.d.ts +19 -0
  320. package/vendor/markit-ai/dist/converters/pdf/index.js +136 -0
  321. package/vendor/markit-ai/dist/converters/pdf/mupdf-loader.js +9 -0
  322. package/vendor/markit-ai/dist/converters/pdf/render.d.ts +24 -0
  323. package/vendor/markit-ai/dist/converters/pdf/render.js +513 -0
  324. package/vendor/markit-ai/dist/converters/pdf/types.d.ts +75 -0
  325. package/vendor/markit-ai/dist/converters/pdf/types.js +1 -0
  326. package/vendor/markit-ai/dist/converters/plain-text.d.ts +6 -0
  327. package/vendor/markit-ai/dist/converters/plain-text.js +87 -0
  328. package/vendor/markit-ai/dist/converters/pptx.d.ts +8 -0
  329. package/vendor/markit-ai/dist/converters/pptx.js +289 -0
  330. package/vendor/markit-ai/dist/converters/rss.d.ts +11 -0
  331. package/vendor/markit-ai/dist/converters/rss.js +138 -0
  332. package/vendor/markit-ai/dist/converters/wikipedia.d.ts +6 -0
  333. package/vendor/markit-ai/dist/converters/wikipedia.js +33 -0
  334. package/vendor/markit-ai/dist/converters/xlsx.d.ts +8 -0
  335. package/vendor/markit-ai/dist/converters/xlsx.js +147 -0
  336. package/vendor/markit-ai/dist/converters/xml.d.ts +6 -0
  337. package/vendor/markit-ai/dist/converters/xml.js +18 -0
  338. package/vendor/markit-ai/dist/converters/yaml.d.ts +6 -0
  339. package/vendor/markit-ai/dist/converters/yaml.js +17 -0
  340. package/vendor/markit-ai/dist/converters/zip.d.ts +8 -0
  341. package/vendor/markit-ai/dist/converters/zip.js +57 -0
  342. package/vendor/markit-ai/dist/index.d.ts +30 -0
  343. package/vendor/markit-ai/dist/index.js +26 -0
  344. package/vendor/markit-ai/dist/main.d.ts +2 -0
  345. package/vendor/markit-ai/dist/main.js +191 -0
  346. package/vendor/markit-ai/dist/markit.d.ts +45 -0
  347. package/vendor/markit-ai/dist/markit.js +267 -0
  348. package/vendor/markit-ai/dist/plugins/api.d.ts +7 -0
  349. package/vendor/markit-ai/dist/plugins/api.js +42 -0
  350. package/vendor/markit-ai/dist/plugins/index.d.ts +4 -0
  351. package/vendor/markit-ai/dist/plugins/index.js +3 -0
  352. package/vendor/markit-ai/dist/plugins/installer.d.ts +25 -0
  353. package/vendor/markit-ai/dist/plugins/installer.js +176 -0
  354. package/vendor/markit-ai/dist/plugins/loader.d.ts +6 -0
  355. package/vendor/markit-ai/dist/plugins/loader.js +61 -0
  356. package/vendor/markit-ai/dist/plugins/types.d.ts +25 -0
  357. package/vendor/markit-ai/dist/plugins/types.js +1 -0
  358. package/vendor/markit-ai/dist/providers/anthropic.d.ts +2 -0
  359. package/vendor/markit-ai/dist/providers/anthropic.js +47 -0
  360. package/vendor/markit-ai/dist/providers/index.d.ts +21 -0
  361. package/vendor/markit-ai/dist/providers/index.js +56 -0
  362. package/vendor/markit-ai/dist/providers/openai.d.ts +2 -0
  363. package/vendor/markit-ai/dist/providers/openai.js +76 -0
  364. package/vendor/markit-ai/dist/providers/types.d.ts +26 -0
  365. package/vendor/markit-ai/dist/providers/types.js +1 -0
  366. package/vendor/markit-ai/dist/types.d.ts +36 -0
  367. package/vendor/markit-ai/dist/types.js +1 -0
  368. package/vendor/markit-ai/dist/utils/exit-codes.d.ts +4 -0
  369. package/vendor/markit-ai/dist/utils/exit-codes.js +4 -0
  370. package/vendor/markit-ai/dist/utils/output.d.ts +22 -0
  371. package/vendor/markit-ai/dist/utils/output.js +31 -0
  372. package/vendor/markit-ai/dist/utils/turndown.d.ts +8 -0
  373. package/vendor/markit-ai/dist/utils/turndown.js +70 -0
  374. package/vendor/markit-ai/package.json +74 -0
  375. package/vendor/markit-ai.patch +49 -0
@@ -1,5 +1,5 @@
1
1
  import { ThinkingLevel } from "@gajae-code/agent-core";
2
- import type { Api, Model } from "@gajae-code/ai/core";
2
+ import { type Api, isKnownProvider, type Model } from "@gajae-code/ai/core";
3
3
  import { logger } from "@gajae-code/utils";
4
4
  import type { AgentSession, DefaultFallbackRuntimeState } from "../session/agent-session";
5
5
  import { clampExplicitThinkingLevelForModel, formatClampedModelSelector } from "../thinking";
@@ -10,6 +10,7 @@ import {
10
10
  formatModelProfileDisplayLabel,
11
11
  type ModelProfileDefinition,
12
12
  PROXY_ROUTABLE_PROVIDER_IDS,
13
+ type ResolvedProfileBinding,
13
14
  resolveProfileBindings,
14
15
  } from "./model-profiles";
15
16
 
@@ -21,11 +22,13 @@ import {
21
22
  isAuthenticated,
22
23
  kNoAuth,
23
24
  type ModelRegistry,
25
+ registrySelectorResolvesToModel,
24
26
  } from "./model-registry";
25
27
  import {
26
28
  formatModelSelectorValue,
27
29
  formatModelString,
28
30
  parseModelString,
31
+ resolveConfiguredModelPatterns,
29
32
  resolveModelChainWithAuth,
30
33
  resolveModelRoleValue,
31
34
  splitSelectorThinkingSuffix,
@@ -69,7 +72,8 @@ type ModelProfileActivationSession = Pick<
69
72
  | "resolveModelByLookupAlias"
70
73
  | "authStorage"
71
74
  | "isCredentiallessProvider"
72
- >;
75
+ > &
76
+ Partial<Pick<ModelRegistry, "getAvailableForProfileActivation">>;
73
77
  getConfiguredModelChainState?: (role: string) => ConfiguredModelChainState | undefined;
74
78
  };
75
79
 
@@ -105,6 +109,7 @@ export interface PrepareModelProfileActivationOptions {
105
109
  | "getSessionCanonicalVariant"
106
110
  | "restoreSessionCanonicalVariant"
107
111
  | "getConfiguredProviderIds"
112
+ | "isKnownProvider"
108
113
  >
109
114
  > & {
110
115
  getError?: ModelRegistry["getError"];
@@ -248,7 +253,12 @@ function concretizeMaterializedAssignmentValues(
248
253
  const sessionId = (options.session as { sessionId?: string }).sessionId;
249
254
  const credentialSessionId = options.session.credentialSessionId ?? sessionId;
250
255
  if (!modelRegistry || !sessionId) return assignments;
251
- const availableModels = modelRegistry.getAvailable();
256
+ // Materialized assignments are persisted into `modelRoles` and
257
+ // `task.agentModelOverrides` and later consumed by profile execution, so they
258
+ // must resolve against the descriptor-backed profile-activation catalog, not
259
+ // the broadened general one: otherwise a bare assignment can persist a
260
+ // bundled model that fresh live profile evidence excludes.
261
+ const availableModels = modelRegistry.getAvailableForProfileActivation?.() ?? modelRegistry.getAvailable();
252
262
  const authenticatedModels = availableModels.filter(model => {
253
263
  const isCredentiallessProvider = modelRegistry.isCredentiallessProvider?.bind(modelRegistry);
254
264
  const hasUsableAuth = modelRegistry.authStorage?.hasUsableAuth?.bind(modelRegistry.authStorage);
@@ -449,7 +459,7 @@ export function materializeActiveModelProfileAssignments(options: MaterializeMod
449
459
  }
450
460
 
451
461
  export class ModelProfileCredentialError extends Error {
452
- readonly code = "authentication_failed";
462
+ readonly code: string = "authentication_failed";
453
463
  readonly profileLabel: string;
454
464
  readonly providers: readonly string[];
455
465
  readonly role: string | undefined;
@@ -466,6 +476,28 @@ export class ModelProfileCredentialError extends Error {
466
476
  export function formatModelProfileCredentialError(profileLabel: string, providers: readonly string[]): string {
467
477
  return `Model profile "${profileLabel}" requires credentials for: ${providers.join(", ")}. Run /login and configure the missing provider(s), then retry.`;
468
478
  }
479
+ export function formatModelProfileUnknownProviderError(profileLabel: string, providers: readonly string[]): string {
480
+ return `Model profile "${profileLabel}" requires provider(s) this build does not know: ${providers.join(", ")}. The profile likely targets a newer or custom build; declare the provider(s) in models.yml or use a build that ships them.`;
481
+ }
482
+
483
+ /**
484
+ * A required profile provider that this build cannot know: it is neither a
485
+ * built-in provider id nor declared in models.yml. That is a build/config
486
+ * mismatch (for example a profile authored on a newer or custom build), not a
487
+ * credential gap, so the diagnosis must not send the user to /login.
488
+ *
489
+ * Extends {@link ModelProfileCredentialError} so existing startup recovery
490
+ * (interactive toast-and-continue) keeps working with the sharper message.
491
+ */
492
+ export class ModelProfileUnknownProviderError extends ModelProfileCredentialError {
493
+ readonly code = "unknown_provider";
494
+
495
+ constructor(profileLabel: string, providers: readonly string[], role?: string) {
496
+ super(profileLabel, providers, role);
497
+ this.name = "ModelProfileUnknownProviderError";
498
+ this.message = formatModelProfileUnknownProviderError(profileLabel, providers);
499
+ }
500
+ }
469
501
 
470
502
  /**
471
503
  * Rewrite a selector only within the selector provider's own alternative group.
@@ -534,6 +566,14 @@ function rewriteBindingsProviders(
534
566
  ),
535
567
  };
536
568
  }
569
+ export function isModelProfileProxyConfigured(
570
+ provider: string,
571
+ configuredProviders: readonly string[] | undefined,
572
+ credentialless: boolean,
573
+ ): boolean {
574
+ return configuredProviders?.includes(provider) === true || (provider === "opencodex" && credentialless);
575
+ }
576
+
537
577
  /**
538
578
  * Resolve the explicitly configured OpenAI-compatible proxy provider id for a
539
579
  * preset. Returns undefined when unset or empty. Passwords/labels are never
@@ -608,6 +648,245 @@ export function requiresQualifiedModelProfileRoleResolution(profile: Pick<ModelP
608
648
  return profile.source === "user" || profile.source === "registry";
609
649
  }
610
650
 
651
+ /** Resolve a removed saved-session default through the durable profile without mutating persistent state. */
652
+ export async function resolveMissingSessionModelRecovery(options: {
653
+ modelRegistry: PrepareModelProfileActivationOptions["modelRegistry"];
654
+ settings: Pick<Settings, "get" | "getModelRole">;
655
+ defaultEntries: readonly string[];
656
+ skips: Array<{ selector: string; reason: string }>;
657
+ savedDefault: string | undefined;
658
+ credentialSessionId: string;
659
+ aliasIntent?: "preset-equivalent";
660
+ }): Promise<
661
+ | {
662
+ profileName: string;
663
+ entries: string[];
664
+ model?: Model<Api>;
665
+ thinkingLevel?: ThinkingLevel;
666
+ explicitThinkingLevel: boolean;
667
+ activeIndex: number;
668
+ skips: Array<{ selector: string; reason: string }>;
669
+ }
670
+ | undefined
671
+ > {
672
+ const allSelectorsUnknown =
673
+ options.skips.length === options.defaultEntries.length &&
674
+ options.skips.every(skip => skip.reason === "unknown_model");
675
+ if (!allSelectorsUnknown) return undefined;
676
+ const fullCatalog = options.modelRegistry.getAll();
677
+ const savedSelectorsMissingFromCatalog = resolveConfiguredModelPatterns(
678
+ options.defaultEntries,
679
+ options.settings,
680
+ ).every(selector => {
681
+ if (
682
+ resolveModelRoleValue(selector, fullCatalog, {
683
+ settings: options.settings,
684
+ modelRegistry: options.modelRegistry,
685
+ credentialSessionId: options.credentialSessionId,
686
+ ...(options.aliasIntent ? { aliasIntent: options.aliasIntent } : {}),
687
+ }).model
688
+ )
689
+ return false;
690
+ return !registrySelectorResolvesToModel(selector, fullCatalog);
691
+ });
692
+ const savedConcreteDefault = options.savedDefault ? parseModelString(options.savedDefault) : undefined;
693
+ const savedConcreteDefaultMissingFromCatalog =
694
+ savedConcreteDefault === undefined ||
695
+ !fullCatalog.some(
696
+ model =>
697
+ model.provider.toLowerCase() === savedConcreteDefault.provider.toLowerCase() &&
698
+ model.id.toLowerCase() === savedConcreteDefault.id.toLowerCase(),
699
+ );
700
+ const durableProfile = options.settings.get("modelProfile.default");
701
+ if (!savedSelectorsMissingFromCatalog || !savedConcreteDefaultMissingFromCatalog || !durableProfile)
702
+ return undefined;
703
+ return resolveModelProfileDefaultChain({
704
+ modelRegistry: options.modelRegistry,
705
+ settings: options.settings,
706
+ profileName: durableProfile,
707
+ credentialSessionId: options.credentialSessionId,
708
+ });
709
+ }
710
+
711
+ /** Resolve a durable profile's effective default chain without mutating session or settings state. */
712
+ export async function resolveModelProfileDefaultChain(options: {
713
+ modelRegistry: PrepareModelProfileActivationOptions["modelRegistry"];
714
+ settings: Pick<Settings, "get">;
715
+ profileName: string;
716
+ credentialSessionId: string;
717
+ }): Promise<{
718
+ profileName: string;
719
+ entries: string[];
720
+ model?: Model<Api>;
721
+ thinkingLevel?: ThinkingLevel;
722
+ explicitThinkingLevel: boolean;
723
+ activeIndex: number;
724
+ skips: Array<{ selector: string; reason: string }>;
725
+ }> {
726
+ const profiles = options.modelRegistry.getModelProfiles();
727
+ const profileName = validateModelProfileName(options.profileName, profiles, options.modelRegistry.getError?.());
728
+ const profile = profiles.get(profileName) ?? options.modelRegistry.getModelProfile(profileName)!;
729
+ const profileLabel = formatModelProfileDisplayLabel(profile);
730
+ const requiredProviders = aggregateModelProfileRequiredProviders(profile.requiredProviders, profile);
731
+ const alternativeGroups = profile.alternativeProviderGroups ?? [];
732
+ const alternativeSet = new Set(alternativeGroups.flat());
733
+ const requiredProviderSet = new Set(requiredProviders);
734
+ const authenticatedProviders = new Set<string>();
735
+ const missingProviders: string[] = [];
736
+ const configuredProviderIds = options.modelRegistry.getConfiguredProviderIds?.();
737
+ if (configuredProviderIds !== undefined || options.modelRegistry.isKnownProvider !== undefined) {
738
+ const isProviderKnown = (provider: string): boolean =>
739
+ (options.modelRegistry.isKnownProvider?.(provider) ?? false) ||
740
+ isKnownProvider(provider) ||
741
+ configuredProviderIds?.includes(provider) === true;
742
+ const unknownProviderIds = new Set<string>();
743
+ for (const provider of requiredProviders) {
744
+ if (!alternativeSet.has(provider) && !isProviderKnown(provider)) unknownProviderIds.add(provider);
745
+ }
746
+ for (const group of alternativeGroups) {
747
+ if (group.some(isProviderKnown)) continue;
748
+ for (const provider of group) {
749
+ if (!isProviderKnown(provider)) unknownProviderIds.add(provider);
750
+ }
751
+ }
752
+ const unknownProviders = [...unknownProviderIds].sort();
753
+ if (unknownProviders.length > 0) throw new ModelProfileUnknownProviderError(profileLabel, unknownProviders);
754
+ }
755
+ for (const provider of new Set([
756
+ ...requiredProviders,
757
+ ...alternativeSet,
758
+ ...deriveModelProfileMappedProviders(profile),
759
+ ])) {
760
+ let apiKey: string | undefined;
761
+ try {
762
+ apiKey = await options.modelRegistry.getApiKeyForProvider(provider, options.credentialSessionId);
763
+ } catch (error) {
764
+ if (requiredProviderSet.has(provider) && !alternativeSet.has(provider)) throw error;
765
+ continue;
766
+ }
767
+ if (apiKey === kNoAuth || isAuthenticated(apiKey)) authenticatedProviders.add(provider);
768
+ else if (requiredProviderSet.has(provider)) missingProviders.push(provider);
769
+ }
770
+ const proxyProvider = profile.source !== "user" ? resolveProxyProviderId(options.settings) : undefined;
771
+ const proxyMode = profile.source !== "user" ? resolveProxyMode(options.settings) : "fallback";
772
+ const proxyRoutableProviders =
773
+ profile.source === "user"
774
+ ? new Set<string>()
775
+ : profile.source === "registry"
776
+ ? new Set([
777
+ ...PROXY_ROUTABLE_PROVIDER_IDS,
778
+ ...profile.requiredProviders,
779
+ ...deriveModelProfileMappedProviders(profile),
780
+ ])
781
+ : PROXY_ROUTABLE_PROVIDER_IDS;
782
+ if (proxyMode === "always" && proxyProvider === undefined)
783
+ throw new Error('modelProfile.proxyMode "always" requires modelProfile.proxyProvider');
784
+ const proxyApiKey =
785
+ proxyProvider === undefined
786
+ ? undefined
787
+ : await options.modelRegistry.getApiKeyForProvider(proxyProvider, options.credentialSessionId);
788
+ if (
789
+ proxyProvider !== undefined &&
790
+ !isModelProfileProxyConfigured(proxyProvider, configuredProviderIds, proxyApiKey === kNoAuth)
791
+ ) {
792
+ throw new Error(
793
+ `modelProfile.proxyProvider "${proxyProvider}" is not configured. Configure it with \`gjc setup provider\` before activating a preset.`,
794
+ );
795
+ }
796
+ const proxyAuthenticated = proxyApiKey !== undefined && (proxyApiKey === kNoAuth || isAuthenticated(proxyApiKey));
797
+ if (proxyMode === "always" && !proxyAuthenticated)
798
+ throw new ModelProfileCredentialError(profileLabel, [proxyProvider!]);
799
+ const strictMissing = missingProviders.filter(
800
+ provider => !proxyRoutableProviders.has(provider) && !alternativeSet.has(provider),
801
+ );
802
+ if (strictMissing.length > 0) throw new ModelProfileCredentialError(profileLabel, strictMissing);
803
+ const strictRoutableMissing = missingProviders.filter(
804
+ provider => proxyRoutableProviders.has(provider) && !alternativeSet.has(provider),
805
+ );
806
+ if (strictRoutableMissing.length > 0 && !proxyAuthenticated) {
807
+ throw new ModelProfileCredentialError(
808
+ profileLabel,
809
+ proxyProvider === undefined ? strictRoutableMissing : [proxyProvider],
810
+ );
811
+ }
812
+ for (const group of alternativeGroups) {
813
+ if (group.some(provider => authenticatedProviders.has(provider))) continue;
814
+ const allRoutable = group.every(provider => proxyRoutableProviders.has(provider));
815
+ if (allRoutable && proxyAuthenticated) continue;
816
+ throw new ModelProfileCredentialError(
817
+ profileLabel,
818
+ allRoutable && proxyProvider !== undefined ? [proxyProvider] : [...group],
819
+ );
820
+ }
821
+ const availableModels =
822
+ options.modelRegistry.getAvailableForProfileActivation?.() ??
823
+ options.modelRegistry.getAvailable?.() ??
824
+ options.modelRegistry.getAll();
825
+ let bindings = resolveProfileBindings(profile);
826
+ if (alternativeGroups.length > 0)
827
+ bindings = rewriteBindingsProviders(bindings, authenticatedProviders, alternativeGroups);
828
+ if (proxyProvider !== undefined && proxyAuthenticated && profile.source !== "user") {
829
+ bindings = rewriteBindingsForProxy(
830
+ bindings,
831
+ proxyProvider,
832
+ proxyMode,
833
+ availableModels,
834
+ authenticatedProviders,
835
+ proxyRoutableProviders,
836
+ );
837
+ }
838
+ await preflightModelProfileRoleBindings({
839
+ profile,
840
+ bindings,
841
+ roleCatalogModels: options.modelRegistry.getAll(),
842
+ settings: options.settings as Settings,
843
+ modelRegistry: options.modelRegistry as ModelRegistry,
844
+ sessionId: "",
845
+ credentialSessionId: options.credentialSessionId,
846
+ profileLabel,
847
+ });
848
+ if (!bindings.defaultSelector)
849
+ return { profileName, entries: [], explicitThinkingLevel: false, activeIndex: 0, skips: [] };
850
+ const defaultChain = normalizeModelSelectorValue(
851
+ await resolveAndClampSelectorValue(
852
+ bindings.defaultSelector,
853
+ availableModels,
854
+ {
855
+ settings: options.settings as Settings,
856
+ modelRegistry: options.modelRegistry as ModelRegistry,
857
+ sessionId: "",
858
+ credentialSessionId: options.credentialSessionId,
859
+ aliasIntent: "preset-equivalent",
860
+ },
861
+ profileLabel,
862
+ "default",
863
+ ),
864
+ );
865
+ const resolution = await resolveModelChainWithAuth(
866
+ defaultChain,
867
+ {
868
+ getAvailable: () => availableModels,
869
+ getApiKey: (model, sessionId) =>
870
+ options.modelRegistry.getApiKeyForProvider(model.provider, sessionId, model.baseUrl),
871
+ resolveCanonicalModel: options.modelRegistry.resolveCanonicalModel?.bind(options.modelRegistry),
872
+ getCanonicalVariants: options.modelRegistry.getCanonicalVariants?.bind(options.modelRegistry),
873
+ getCanonicalId: options.modelRegistry.getCanonicalId?.bind(options.modelRegistry),
874
+ resolveModelByLookupAlias: options.modelRegistry.resolveModelByLookupAlias?.bind(options.modelRegistry),
875
+ lookupAliasExists: options.modelRegistry.lookupAliasExists?.bind(options.modelRegistry),
876
+ clearCanonicalVariant: options.modelRegistry.clearCanonicalVariant?.bind(options.modelRegistry),
877
+ } as ModelRegistry,
878
+ options.settings as Settings,
879
+ options.credentialSessionId,
880
+ {
881
+ managedFallback: true,
882
+ aliasIntent: "preset-equivalent",
883
+ canonicalSessionId: null,
884
+ credentialSessionId: options.credentialSessionId,
885
+ },
886
+ );
887
+ return { profileName, entries: defaultChain, ...resolution };
888
+ }
889
+
611
890
  export function rewriteSelectorForProxy(
612
891
  selector: string,
613
892
  proxyProvider: string,
@@ -620,9 +899,13 @@ export function rewriteSelectorForProxy(
620
899
  const baseSelector = suffix.selector;
621
900
  const slash = baseSelector.indexOf("/");
622
901
  const proxyModels = allModels.filter(model => model.provider === proxyProvider);
902
+ const matchingProxyModels = (id: string): Model<Api>[] => {
903
+ const publicMatches = proxyModels.filter(model => model.id === id);
904
+ return publicMatches.length > 0 ? publicMatches : proxyModels.filter(model => model.wireModelId === id);
905
+ };
623
906
  if (slash < 0) {
624
907
  if (proxyMode === "fallback") return selector;
625
- const exactMatches = proxyModels.filter(model => model.id === baseSelector);
908
+ const exactMatches = matchingProxyModels(baseSelector);
626
909
  const finalSegmentMatches = proxyModels.filter(model => model.id.split("/").at(-1) === baseSelector);
627
910
  const matches = exactMatches.length > 0 ? exactMatches : finalSegmentMatches;
628
911
  if (matches.length !== 1) {
@@ -640,8 +923,8 @@ export function rewriteSelectorForProxy(
640
923
  throw new Error(`Configured proxy "${proxyProvider}" cannot route its own direct selector "${baseSelector}"`);
641
924
  }
642
925
  const directModelId = baseSelector.substring(slash + 1);
643
- const exactMatches = proxyModels.filter(model => model.id === `${directProvider}/${directModelId}`);
644
- const flatMatches = proxyModels.filter(model => model.id === directModelId);
926
+ const exactMatches = matchingProxyModels(`${directProvider}/${directModelId}`);
927
+ const flatMatches = matchingProxyModels(directModelId);
645
928
  const matches = exactMatches.length > 0 ? exactMatches : flatMatches;
646
929
  if (matches.length === 0) {
647
930
  throw new Error(`Configured proxy "${proxyProvider}" does not expose a model for "${baseSelector}"`);
@@ -851,6 +1134,49 @@ async function resolveAndClampSelectorValue(
851
1134
  return clamped.length === 1 && typeof selectorValue === "string" ? clamped[0] : clamped;
852
1135
  }
853
1136
 
1137
+ /** Resolve every non-default binding under the profile activation contract without installing it. */
1138
+ async function preflightModelProfileRoleBindings(options: {
1139
+ profile: ModelProfileDefinition;
1140
+ bindings: ResolvedProfileBinding;
1141
+ roleCatalogModels: Model<Api>[];
1142
+ settings: Settings;
1143
+ modelRegistry: ModelRegistry;
1144
+ sessionId: string;
1145
+ credentialSessionId: string;
1146
+ profileLabel: string;
1147
+ }): Promise<{
1148
+ modelRoles: Record<string, ModelSelectorValue>;
1149
+ agentModelOverrides: Record<string, ModelSelectorValue>;
1150
+ }> {
1151
+ const resolveBindings = async (bindings: Record<string, ModelSelectorValue>) => {
1152
+ const resolved: Record<string, ModelSelectorValue> = {};
1153
+ for (const [role, selectorValue] of Object.entries(bindings) as [
1154
+ GjcModelAssignmentTargetId,
1155
+ ModelSelectorValue,
1156
+ ][]) {
1157
+ resolved[role] = await resolveAndClampSelectorValue(
1158
+ selectorValue,
1159
+ options.roleCatalogModels,
1160
+ {
1161
+ settings: options.settings,
1162
+ modelRegistry: options.modelRegistry,
1163
+ sessionId: options.sessionId,
1164
+ credentialSessionId: options.credentialSessionId,
1165
+ aliasIntent: "preset-equivalent",
1166
+ requireQualifiedResolution: requiresQualifiedModelProfileRoleResolution(options.profile),
1167
+ },
1168
+ options.profileLabel,
1169
+ role,
1170
+ );
1171
+ }
1172
+ return resolved;
1173
+ };
1174
+ return {
1175
+ modelRoles: await resolveBindings(options.bindings.modelRoles),
1176
+ agentModelOverrides: await resolveBindings(options.bindings.agentModelOverrides),
1177
+ };
1178
+ }
1179
+
854
1180
  async function concretizeProfileSelectorValue(
855
1181
  selectorValue: ModelSelectorValue,
856
1182
  prepared: PreparedModelProfileActivation,
@@ -957,6 +1283,33 @@ export async function prepareModelProfileActivation(
957
1283
  ...alternativeSet,
958
1284
  ...deriveModelProfileMappedProviders(profile),
959
1285
  ]);
1286
+ // A required provider this build cannot know is a build/config mismatch,
1287
+ // not a credential gap: diagnose it before any auth probing so the user
1288
+ // is never sent to /login for a provider this binary cannot serve (for
1289
+ // example a models.yml profile authored on a newer or custom build). A
1290
+ // registry without provider visibility keeps the legacy
1291
+ // credential diagnosis.
1292
+ const configuredProviderIds = options.modelRegistry.getConfiguredProviderIds?.();
1293
+ if (configuredProviderIds !== undefined || options.modelRegistry.isKnownProvider !== undefined) {
1294
+ const isProviderKnown = (provider: string): boolean =>
1295
+ (options.modelRegistry.isKnownProvider?.(provider) ?? false) ||
1296
+ isKnownProvider(provider) ||
1297
+ configuredProviderIds?.includes(provider) === true;
1298
+ const unknownRequiredProviders = new Set<string>();
1299
+ for (const provider of requiredProviders) {
1300
+ if (!alternativeSet.has(provider) && !isProviderKnown(provider)) unknownRequiredProviders.add(provider);
1301
+ }
1302
+ for (const group of alternativeGroups) {
1303
+ if (group.some(isProviderKnown)) continue;
1304
+ for (const provider of group) {
1305
+ if (!isProviderKnown(provider)) unknownRequiredProviders.add(provider);
1306
+ }
1307
+ }
1308
+ const unknownProviderIds = [...unknownRequiredProviders].sort();
1309
+ if (unknownProviderIds.length > 0) {
1310
+ throw new ModelProfileUnknownProviderError(profileLabel, unknownProviderIds);
1311
+ }
1312
+ }
960
1313
 
961
1314
  const missingProviders: string[] = [];
962
1315
  const authenticatedProviders: string[] = [];
@@ -995,18 +1348,18 @@ export async function prepareModelProfileActivation(
995
1348
  if (proxyMode === "always" && proxyProvider === undefined) {
996
1349
  throw new Error('modelProfile.proxyMode "always" requires modelProfile.proxyProvider');
997
1350
  }
1351
+ const proxyApiKey =
1352
+ proxyProvider === undefined
1353
+ ? undefined
1354
+ : await options.modelRegistry.getApiKeyForProvider(proxyProvider, credentialSessionId);
998
1355
  if (proxyProvider !== undefined) {
999
1356
  const configuredProxyProviders = options.modelRegistry.getConfiguredProviderIds?.();
1000
- if (!configuredProxyProviders?.includes(proxyProvider)) {
1357
+ if (!isModelProfileProxyConfigured(proxyProvider, configuredProxyProviders, proxyApiKey === kNoAuth)) {
1001
1358
  throw new Error(
1002
1359
  `modelProfile.proxyProvider "${proxyProvider}" is not configured. Configure it with \`gjc setup provider\` before activating a preset.`,
1003
1360
  );
1004
1361
  }
1005
1362
  }
1006
- const proxyApiKey =
1007
- proxyProvider === undefined
1008
- ? undefined
1009
- : await options.modelRegistry.getApiKeyForProvider(proxyProvider, credentialSessionId);
1010
1363
  const proxyAuthenticated =
1011
1364
  proxyProvider !== undefined &&
1012
1365
  proxyApiKey !== undefined &&
@@ -1118,47 +1471,16 @@ export async function prepareModelProfileActivation(
1118
1471
  throw new Error(`Model profile "${profileLabel}" default selectors did not resolve to an authenticated model`);
1119
1472
  }
1120
1473
 
1121
- const modelRoles: Record<string, ModelSelectorValue> = {};
1122
- for (const [role, selectorValue] of Object.entries(bindings.modelRoles) as [
1123
- GjcModelAssignmentTargetId,
1124
- ModelSelectorValue,
1125
- ][]) {
1126
- modelRoles[role] = await resolveAndClampSelectorValue(
1127
- selectorValue,
1128
- roleCatalogModels,
1129
- {
1130
- settings: options.settings as Settings,
1131
- modelRegistry: options.modelRegistry as ModelRegistry,
1132
- sessionId: options.session.sessionId,
1133
- credentialSessionId,
1134
- aliasIntent: "preset-equivalent",
1135
- requireQualifiedResolution: requiresQualifiedModelProfileRoleResolution(profile),
1136
- },
1137
- profileLabel,
1138
- role,
1139
- );
1140
- }
1141
-
1142
- const agentModelOverrides: Record<string, ModelSelectorValue> = {};
1143
- for (const [role, selectorValue] of Object.entries(bindings.agentModelOverrides) as [
1144
- GjcModelAssignmentTargetId,
1145
- ModelSelectorValue,
1146
- ][]) {
1147
- agentModelOverrides[role] = await resolveAndClampSelectorValue(
1148
- selectorValue,
1149
- roleCatalogModels,
1150
- {
1151
- settings: options.settings as Settings,
1152
- modelRegistry: options.modelRegistry as ModelRegistry,
1153
- sessionId: options.session.sessionId,
1154
- credentialSessionId,
1155
- aliasIntent: "preset-equivalent",
1156
- requireQualifiedResolution: requiresQualifiedModelProfileRoleResolution(profile),
1157
- },
1158
- profileLabel,
1159
- role,
1160
- );
1161
- }
1474
+ const { modelRoles, agentModelOverrides } = await preflightModelProfileRoleBindings({
1475
+ profile,
1476
+ bindings,
1477
+ roleCatalogModels,
1478
+ settings: options.settings as Settings,
1479
+ modelRegistry: options.modelRegistry as ModelRegistry,
1480
+ sessionId: options.session.sessionId,
1481
+ credentialSessionId,
1482
+ profileLabel,
1483
+ });
1162
1484
 
1163
1485
  return {
1164
1486
  profileName,
@@ -1660,3 +1982,34 @@ export async function activateModelProfile(
1660
1982
  const prepared = await prepareModelProfileActivation(options);
1661
1983
  await applyPreparedModelProfileActivation(prepared, applyOptions);
1662
1984
  }
1985
+
1986
+ /** Install only a profile's runtime role layer, preserving session model and configured-chain intent. */
1987
+ export async function applyModelProfileRuntimeBindings(options: PrepareModelProfileActivationOptions): Promise<void> {
1988
+ const prepared = await prepareModelProfileActivation(options);
1989
+ try {
1990
+ prepared.settings.override("modelRoles", {
1991
+ ...prepared.baseModelRoles,
1992
+ ...prepared.modelRoles,
1993
+ });
1994
+ prepared.settings.override("task.agentModelOverrides", {
1995
+ ...prepared.baseAgentModelOverrides,
1996
+ ...prepared.agentModelOverrides,
1997
+ });
1998
+ prepared.session.setActiveModelProfile?.(prepared.profileName);
1999
+ prepared.session.noteProfileInstalledOverrides?.(
2000
+ Object.keys(prepared.modelRoles),
2001
+ Object.keys(prepared.agentModelOverrides),
2002
+ prepared.previousModel,
2003
+ );
2004
+ try {
2005
+ await prepared.session.syncEagerDelegation?.();
2006
+ } catch (error) {
2007
+ logger.warn("Failed to sync eager delegation after recovered profile runtime bindings", {
2008
+ profile: prepared.profileName,
2009
+ error: error instanceof Error ? error.message : String(error),
2010
+ });
2011
+ }
2012
+ } finally {
2013
+ restoreCanonicalVariant(prepared.modelRegistry, prepared.session.sessionId, prepared.previousCanonicalVariant);
2014
+ }
2015
+ }