@ashx-j/lunr 0.2.21 → 0.2.22

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 (438) hide show
  1. package/CHANGELOG.md +1 -1
  2. package/README.md +20 -4
  3. package/dist/builtin-extensions/index.d.ts.map +1 -1
  4. package/dist/builtin-extensions/index.js +1 -0
  5. package/dist/builtin-extensions/index.js.map +1 -1
  6. package/dist/builtin-extensions/lunr-browser.d.ts +3 -0
  7. package/dist/builtin-extensions/lunr-browser.d.ts.map +1 -0
  8. package/dist/builtin-extensions/lunr-browser.js +56 -0
  9. package/dist/builtin-extensions/lunr-browser.js.map +1 -0
  10. package/dist/builtin-extensions/lunr-todos.d.ts.map +1 -1
  11. package/dist/builtin-extensions/lunr-todos.js +15 -0
  12. package/dist/builtin-extensions/lunr-todos.js.map +1 -1
  13. package/dist/builtin-extensions/pi-intercom/index.d.ts.map +1 -1
  14. package/dist/builtin-extensions/pi-intercom/index.js +3 -0
  15. package/dist/builtin-extensions/pi-intercom/index.js.map +1 -1
  16. package/dist/builtin-extensions/pi-subagents/src/extension/control-notices.d.ts +1 -1
  17. package/dist/builtin-extensions/pi-subagents/src/extension/control-notices.d.ts.map +1 -1
  18. package/dist/builtin-extensions/pi-subagents/src/extension/control-notices.js +5 -1
  19. package/dist/builtin-extensions/pi-subagents/src/extension/control-notices.js.map +1 -1
  20. package/dist/builtin-extensions/pi-subagents/src/extension/index.d.ts +2 -2
  21. package/dist/builtin-extensions/pi-subagents/src/extension/index.d.ts.map +1 -1
  22. package/dist/builtin-extensions/pi-subagents/src/extension/index.js +18 -5
  23. package/dist/builtin-extensions/pi-subagents/src/extension/index.js.map +1 -1
  24. package/dist/builtin-extensions/pi-subagents/src/extension/tool-description.d.ts +4 -3
  25. package/dist/builtin-extensions/pi-subagents/src/extension/tool-description.d.ts.map +1 -1
  26. package/dist/builtin-extensions/pi-subagents/src/extension/tool-description.js +3 -0
  27. package/dist/builtin-extensions/pi-subagents/src/extension/tool-description.js.map +1 -1
  28. package/dist/builtin-extensions/pi-subagents/src/intercom/communication.d.ts +17 -0
  29. package/dist/builtin-extensions/pi-subagents/src/intercom/communication.d.ts.map +1 -0
  30. package/dist/builtin-extensions/pi-subagents/src/intercom/communication.js +45 -0
  31. package/dist/builtin-extensions/pi-subagents/src/intercom/communication.js.map +1 -0
  32. package/dist/builtin-extensions/pi-subagents/src/intercom/intercom-bridge.d.ts.map +1 -1
  33. package/dist/builtin-extensions/pi-subagents/src/intercom/intercom-bridge.js +4 -11
  34. package/dist/builtin-extensions/pi-subagents/src/intercom/intercom-bridge.js.map +1 -1
  35. package/dist/builtin-extensions/pi-subagents/src/intercom/native-supervisor-channel.d.ts +4 -1
  36. package/dist/builtin-extensions/pi-subagents/src/intercom/native-supervisor-channel.d.ts.map +1 -1
  37. package/dist/builtin-extensions/pi-subagents/src/intercom/native-supervisor-channel.js +160 -51
  38. package/dist/builtin-extensions/pi-subagents/src/intercom/native-supervisor-channel.js.map +1 -1
  39. package/dist/builtin-extensions/pi-subagents/src/intercom/supervisor-ask.d.ts.map +1 -1
  40. package/dist/builtin-extensions/pi-subagents/src/intercom/supervisor-ask.js +5 -0
  41. package/dist/builtin-extensions/pi-subagents/src/intercom/supervisor-ask.js.map +1 -1
  42. package/dist/builtin-extensions/pi-subagents/src/intercom/supervisor-questions.d.ts +2 -0
  43. package/dist/builtin-extensions/pi-subagents/src/intercom/supervisor-questions.d.ts.map +1 -1
  44. package/dist/builtin-extensions/pi-subagents/src/intercom/supervisor-questions.js +3 -2
  45. package/dist/builtin-extensions/pi-subagents/src/intercom/supervisor-questions.js.map +1 -1
  46. package/dist/builtin-extensions/pi-subagents/src/runs/background/auto-drain.d.ts +1 -0
  47. package/dist/builtin-extensions/pi-subagents/src/runs/background/auto-drain.d.ts.map +1 -1
  48. package/dist/builtin-extensions/pi-subagents/src/runs/background/auto-drain.js +2 -1
  49. package/dist/builtin-extensions/pi-subagents/src/runs/background/auto-drain.js.map +1 -1
  50. package/dist/builtin-extensions/pi-subagents/src/runs/background/subagent-wait.d.ts +1 -0
  51. package/dist/builtin-extensions/pi-subagents/src/runs/background/subagent-wait.d.ts.map +1 -1
  52. package/dist/builtin-extensions/pi-subagents/src/runs/background/subagent-wait.js +2 -0
  53. package/dist/builtin-extensions/pi-subagents/src/runs/background/subagent-wait.js.map +1 -1
  54. package/dist/builtin-extensions/pi-subagents/src/runs/shared/pi-args.d.ts.map +1 -1
  55. package/dist/builtin-extensions/pi-subagents/src/runs/shared/pi-args.js +3 -0
  56. package/dist/builtin-extensions/pi-subagents/src/runs/shared/pi-args.js.map +1 -1
  57. package/dist/builtin-extensions/pi-subagents/src/runs/shared/subagent-control.d.ts +1 -0
  58. package/dist/builtin-extensions/pi-subagents/src/runs/shared/subagent-control.d.ts.map +1 -1
  59. package/dist/builtin-extensions/pi-subagents/src/runs/shared/subagent-control.js +3 -0
  60. package/dist/builtin-extensions/pi-subagents/src/runs/shared/subagent-control.js.map +1 -1
  61. package/dist/builtin-extensions/pi-subagents/src/runs/shared/subagent-prompt-runtime.d.ts.map +1 -1
  62. package/dist/builtin-extensions/pi-subagents/src/runs/shared/subagent-prompt-runtime.js +1 -1
  63. package/dist/builtin-extensions/pi-subagents/src/runs/shared/subagent-prompt-runtime.js.map +1 -1
  64. package/dist/builtin-extensions/pi-subagents/src/shared/types.d.ts +1 -0
  65. package/dist/builtin-extensions/pi-subagents/src/shared/types.d.ts.map +1 -1
  66. package/dist/builtin-extensions/pi-subagents/src/shared/types.js.map +1 -1
  67. package/dist/builtin-extensions/pi-subagents/src/tui/communication.d.ts +18 -0
  68. package/dist/builtin-extensions/pi-subagents/src/tui/communication.d.ts.map +1 -0
  69. package/dist/builtin-extensions/pi-subagents/src/tui/communication.js +47 -0
  70. package/dist/builtin-extensions/pi-subagents/src/tui/communication.js.map +1 -0
  71. package/dist/builtin-extensions/pi-web-access/index.d.ts.map +1 -1
  72. package/dist/builtin-extensions/pi-web-access/index.js +11 -7
  73. package/dist/builtin-extensions/pi-web-access/index.js.map +1 -1
  74. package/dist/cli/args.d.ts.map +1 -1
  75. package/dist/cli/args.js +2 -1
  76. package/dist/cli/args.js.map +1 -1
  77. package/dist/cli/install-cli.d.ts.map +1 -1
  78. package/dist/cli/install-cli.js +15 -45
  79. package/dist/cli/install-cli.js.map +1 -1
  80. package/dist/core/agent-session-runtime.d.ts +9 -0
  81. package/dist/core/agent-session-runtime.d.ts.map +1 -1
  82. package/dist/core/agent-session-runtime.js +126 -29
  83. package/dist/core/agent-session-runtime.js.map +1 -1
  84. package/dist/core/agent-session.d.ts +3 -0
  85. package/dist/core/agent-session.d.ts.map +1 -1
  86. package/dist/core/agent-session.js +20 -2
  87. package/dist/core/agent-session.js.map +1 -1
  88. package/dist/core/browser/network.d.ts +9 -0
  89. package/dist/core/browser/network.d.ts.map +1 -0
  90. package/dist/core/browser/network.js +146 -0
  91. package/dist/core/browser/network.js.map +1 -0
  92. package/dist/core/browser/runtime.d.ts +24 -0
  93. package/dist/core/browser/runtime.d.ts.map +1 -0
  94. package/dist/core/browser/runtime.js +289 -0
  95. package/dist/core/browser/runtime.js.map +1 -0
  96. package/dist/core/browser/schema.d.ts +16 -0
  97. package/dist/core/browser/schema.d.ts.map +1 -0
  98. package/dist/core/browser/schema.js +36 -0
  99. package/dist/core/browser/schema.js.map +1 -0
  100. package/dist/core/browser/settings.d.ts +8 -0
  101. package/dist/core/browser/settings.d.ts.map +1 -0
  102. package/dist/core/browser/settings.js +30 -0
  103. package/dist/core/browser/settings.js.map +1 -0
  104. package/dist/core/browser/setup.d.ts +2 -0
  105. package/dist/core/browser/setup.d.ts.map +1 -0
  106. package/dist/core/browser/setup.js +16 -0
  107. package/dist/core/browser/setup.js.map +1 -0
  108. package/dist/core/customize.d.ts.map +1 -1
  109. package/dist/core/customize.js +15 -14
  110. package/dist/core/customize.js.map +1 -1
  111. package/dist/core/export-html/index.d.ts.map +1 -1
  112. package/dist/core/export-html/index.js +1 -1
  113. package/dist/core/export-html/index.js.map +1 -1
  114. package/dist/core/extensions/runner.d.ts +1 -0
  115. package/dist/core/extensions/runner.d.ts.map +1 -1
  116. package/dist/core/extensions/runner.js +1 -1
  117. package/dist/core/extensions/runner.js.map +1 -1
  118. package/dist/core/extensions/types.d.ts +1 -1
  119. package/dist/core/extensions/types.d.ts.map +1 -1
  120. package/dist/core/extensions/types.js.map +1 -1
  121. package/dist/core/install-features.d.ts.map +1 -1
  122. package/dist/core/install-features.js +10 -8
  123. package/dist/core/install-features.js.map +1 -1
  124. package/dist/core/memory-cap.d.ts.map +1 -1
  125. package/dist/core/memory-cap.js +5 -3
  126. package/dist/core/memory-cap.js.map +1 -1
  127. package/dist/core/model-tiers.d.ts.map +1 -1
  128. package/dist/core/model-tiers.js +9 -6
  129. package/dist/core/model-tiers.js.map +1 -1
  130. package/dist/core/permissions.d.ts.map +1 -1
  131. package/dist/core/permissions.js +9 -0
  132. package/dist/core/permissions.js.map +1 -1
  133. package/dist/core/plan-mode.d.ts.map +1 -1
  134. package/dist/core/plan-mode.js +3 -0
  135. package/dist/core/plan-mode.js.map +1 -1
  136. package/dist/core/process-registry.d.ts.map +1 -1
  137. package/dist/core/process-registry.js +6 -4
  138. package/dist/core/process-registry.js.map +1 -1
  139. package/dist/core/runtime-scope.d.ts +11 -0
  140. package/dist/core/runtime-scope.d.ts.map +1 -0
  141. package/dist/core/runtime-scope.js +3 -0
  142. package/dist/core/runtime-scope.js.map +1 -0
  143. package/dist/core/sdk.d.ts.map +1 -1
  144. package/dist/core/sdk.js +13 -0
  145. package/dist/core/sdk.js.map +1 -1
  146. package/dist/core/session-handoff.d.ts +35 -0
  147. package/dist/core/session-handoff.d.ts.map +1 -0
  148. package/dist/core/session-handoff.js +214 -0
  149. package/dist/core/session-handoff.js.map +1 -0
  150. package/dist/core/session-manager.d.ts +20 -0
  151. package/dist/core/session-manager.d.ts.map +1 -1
  152. package/dist/core/session-manager.js +184 -22
  153. package/dist/core/session-manager.js.map +1 -1
  154. package/dist/core/session-ownership.d.ts +28 -0
  155. package/dist/core/session-ownership.d.ts.map +1 -0
  156. package/dist/core/session-ownership.js +138 -0
  157. package/dist/core/session-ownership.js.map +1 -0
  158. package/dist/core/session-retention.d.ts.map +1 -1
  159. package/dist/core/session-retention.js +11 -2
  160. package/dist/core/session-retention.js.map +1 -1
  161. package/dist/core/settings-manager.d.ts +7 -0
  162. package/dist/core/settings-manager.d.ts.map +1 -1
  163. package/dist/core/settings-manager.js +18 -0
  164. package/dist/core/settings-manager.js.map +1 -1
  165. package/dist/core/slash-commands.d.ts.map +1 -1
  166. package/dist/core/slash-commands.js +2 -0
  167. package/dist/core/slash-commands.js.map +1 -1
  168. package/dist/core/system-prompt.d.ts.map +1 -1
  169. package/dist/core/system-prompt.js +5 -2
  170. package/dist/core/system-prompt.js.map +1 -1
  171. package/dist/core/todo-settings.d.ts +5 -0
  172. package/dist/core/todo-settings.d.ts.map +1 -0
  173. package/dist/core/todo-settings.js +7 -0
  174. package/dist/core/todo-settings.js.map +1 -0
  175. package/dist/core/tools/bash.d.ts.map +1 -1
  176. package/dist/core/tools/bash.js +4 -4
  177. package/dist/core/tools/bash.js.map +1 -1
  178. package/dist/core/tools/edit.d.ts.map +1 -1
  179. package/dist/core/tools/edit.js +5 -3
  180. package/dist/core/tools/edit.js.map +1 -1
  181. package/dist/core/tools/find.d.ts.map +1 -1
  182. package/dist/core/tools/find.js +4 -4
  183. package/dist/core/tools/find.js.map +1 -1
  184. package/dist/core/tools/grep.d.ts.map +1 -1
  185. package/dist/core/tools/grep.js +4 -4
  186. package/dist/core/tools/grep.js.map +1 -1
  187. package/dist/core/tools/ls.d.ts.map +1 -1
  188. package/dist/core/tools/ls.js +4 -4
  189. package/dist/core/tools/ls.js.map +1 -1
  190. package/dist/core/tools/read.d.ts.map +1 -1
  191. package/dist/core/tools/read.js +4 -4
  192. package/dist/core/tools/read.js.map +1 -1
  193. package/dist/core/tools/render-utils.d.ts +11 -2
  194. package/dist/core/tools/render-utils.d.ts.map +1 -1
  195. package/dist/core/tools/render-utils.js +31 -4
  196. package/dist/core/tools/render-utils.js.map +1 -1
  197. package/dist/core/tools/write.d.ts.map +1 -1
  198. package/dist/core/tools/write.js +4 -4
  199. package/dist/core/tools/write.js.map +1 -1
  200. package/dist/core/usage-service.d.ts.map +1 -1
  201. package/dist/core/usage-service.js +5 -3
  202. package/dist/core/usage-service.js.map +1 -1
  203. package/dist/gateway/adapters/discord.d.ts +12 -1
  204. package/dist/gateway/adapters/discord.d.ts.map +1 -1
  205. package/dist/gateway/adapters/discord.js +112 -17
  206. package/dist/gateway/adapters/discord.js.map +1 -1
  207. package/dist/gateway/adapters/telegram.d.ts +4 -2
  208. package/dist/gateway/adapters/telegram.d.ts.map +1 -1
  209. package/dist/gateway/adapters/telegram.js +34 -11
  210. package/dist/gateway/adapters/telegram.js.map +1 -1
  211. package/dist/gateway/agent-bridge.d.ts +14 -3
  212. package/dist/gateway/agent-bridge.d.ts.map +1 -1
  213. package/dist/gateway/agent-bridge.js +252 -60
  214. package/dist/gateway/agent-bridge.js.map +1 -1
  215. package/dist/gateway/approval.d.ts +1 -0
  216. package/dist/gateway/approval.d.ts.map +1 -1
  217. package/dist/gateway/approval.js +60 -18
  218. package/dist/gateway/approval.js.map +1 -1
  219. package/dist/gateway/authz.d.ts +2 -0
  220. package/dist/gateway/authz.d.ts.map +1 -1
  221. package/dist/gateway/authz.js +13 -0
  222. package/dist/gateway/authz.js.map +1 -1
  223. package/dist/gateway/buttons.d.ts +3 -1
  224. package/dist/gateway/buttons.d.ts.map +1 -1
  225. package/dist/gateway/buttons.js +18 -3
  226. package/dist/gateway/buttons.js.map +1 -1
  227. package/dist/gateway/command.d.ts.map +1 -1
  228. package/dist/gateway/command.js +49 -4
  229. package/dist/gateway/command.js.map +1 -1
  230. package/dist/gateway/commands.d.ts.map +1 -1
  231. package/dist/gateway/commands.js +18 -3
  232. package/dist/gateway/commands.js.map +1 -1
  233. package/dist/gateway/config.d.ts +5 -0
  234. package/dist/gateway/config.d.ts.map +1 -1
  235. package/dist/gateway/config.js +5 -0
  236. package/dist/gateway/config.js.map +1 -1
  237. package/dist/gateway/conversations.d.ts +14 -0
  238. package/dist/gateway/conversations.d.ts.map +1 -0
  239. package/dist/gateway/conversations.js +30 -0
  240. package/dist/gateway/conversations.js.map +1 -0
  241. package/dist/gateway/download.d.ts +2 -0
  242. package/dist/gateway/download.d.ts.map +1 -0
  243. package/dist/gateway/download.js +36 -0
  244. package/dist/gateway/download.js.map +1 -0
  245. package/dist/gateway/index.d.ts.map +1 -1
  246. package/dist/gateway/index.js +85 -26
  247. package/dist/gateway/index.js.map +1 -1
  248. package/dist/gateway/mobile-commands.d.ts +24 -0
  249. package/dist/gateway/mobile-commands.d.ts.map +1 -0
  250. package/dist/gateway/mobile-commands.js +422 -0
  251. package/dist/gateway/mobile-commands.js.map +1 -0
  252. package/dist/gateway/presenter.d.ts +16 -0
  253. package/dist/gateway/presenter.d.ts.map +1 -0
  254. package/dist/gateway/presenter.js +210 -0
  255. package/dist/gateway/presenter.js.map +1 -0
  256. package/dist/gateway/router.d.ts +1 -0
  257. package/dist/gateway/router.d.ts.map +1 -1
  258. package/dist/gateway/router.js +32 -3
  259. package/dist/gateway/router.js.map +1 -1
  260. package/dist/gateway/service.d.ts +46 -0
  261. package/dist/gateway/service.d.ts.map +1 -0
  262. package/dist/gateway/service.js +395 -0
  263. package/dist/gateway/service.js.map +1 -0
  264. package/dist/gateway/setup.d.ts +4 -0
  265. package/dist/gateway/setup.d.ts.map +1 -0
  266. package/dist/gateway/setup.js +146 -0
  267. package/dist/gateway/setup.js.map +1 -0
  268. package/dist/gateway/types.d.ts +4 -2
  269. package/dist/gateway/types.d.ts.map +1 -1
  270. package/dist/gateway/types.js.map +1 -1
  271. package/dist/index.d.ts +2 -0
  272. package/dist/index.d.ts.map +1 -1
  273. package/dist/index.js +2 -0
  274. package/dist/index.js.map +1 -1
  275. package/dist/main.d.ts.map +1 -1
  276. package/dist/main.js +2 -1
  277. package/dist/main.js.map +1 -1
  278. package/dist/modes/interactive/components/assistant-message.d.ts +11 -2
  279. package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  280. package/dist/modes/interactive/components/assistant-message.js +53 -16
  281. package/dist/modes/interactive/components/assistant-message.js.map +1 -1
  282. package/dist/modes/interactive/components/copyable-text.d.ts +31 -0
  283. package/dist/modes/interactive/components/copyable-text.d.ts.map +1 -0
  284. package/dist/modes/interactive/components/copyable-text.js +165 -0
  285. package/dist/modes/interactive/components/copyable-text.js.map +1 -0
  286. package/dist/modes/interactive/components/custom-entry.d.ts +1 -0
  287. package/dist/modes/interactive/components/custom-entry.d.ts.map +1 -1
  288. package/dist/modes/interactive/components/custom-entry.js +8 -0
  289. package/dist/modes/interactive/components/custom-entry.js.map +1 -1
  290. package/dist/modes/interactive/components/custom-message.d.ts +1 -0
  291. package/dist/modes/interactive/components/custom-message.d.ts.map +1 -1
  292. package/dist/modes/interactive/components/custom-message.js +8 -0
  293. package/dist/modes/interactive/components/custom-message.js.map +1 -1
  294. package/dist/modes/interactive/components/session-selector.d.ts.map +1 -1
  295. package/dist/modes/interactive/components/session-selector.js +16 -0
  296. package/dist/modes/interactive/components/session-selector.js.map +1 -1
  297. package/dist/modes/interactive/components/settings-selector.d.ts +5 -0
  298. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  299. package/dist/modes/interactive/components/settings-selector.js +38 -0
  300. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  301. package/dist/modes/interactive/interactive-mode.d.ts +3 -0
  302. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  303. package/dist/modes/interactive/interactive-mode.js +151 -7
  304. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  305. package/dist/node-runtime/agent-session-services-NQ6GKOIK.js +49 -0
  306. package/dist/node-runtime/{builtin-extensions-JCOPAAB5.js → builtin-extensions-GVC6IFDU.js} +6 -5
  307. package/dist/node-runtime/{chunk-LTYWTR3V.js → chunk-2MI5OPMN.js} +17 -2
  308. package/dist/node-runtime/{chunk-W3CVH5RX.js → chunk-2TKODGBZ.js} +11 -6
  309. package/dist/node-runtime/chunk-4EULYYR4.js +62 -0
  310. package/dist/node-runtime/chunk-5BNJ4JUH.js +672 -0
  311. package/dist/node-runtime/{chunk-6N22HULO.js → chunk-5D7LC2ZQ.js} +7 -2
  312. package/dist/node-runtime/{chunk-KBKMCJDU.js → chunk-5ZQXRPMC.js} +19 -4
  313. package/dist/node-runtime/{chunk-6KDIOJL3.js → chunk-6427XAWG.js} +3 -3
  314. package/dist/node-runtime/{chunk-BOHIDQT4.js → chunk-6B2POMK7.js} +1 -1
  315. package/dist/node-runtime/{chunk-RNBHABBA.js → chunk-7QWNYZDI.js} +7 -0
  316. package/dist/node-runtime/chunk-AZJHNQKQ.js +205 -0
  317. package/dist/node-runtime/{chunk-A3KMVBZV.js → chunk-BBUVIEZB.js} +1 -10
  318. package/dist/node-runtime/chunk-BFNXONG3.js +521 -0
  319. package/dist/node-runtime/{chunk-IRPJXI6U.js → chunk-BX2RB477.js} +1 -1
  320. package/dist/node-runtime/chunk-CCCN2UCX.js +14 -0
  321. package/dist/node-runtime/{chunk-25I2BHAA.js → chunk-CSUZVNYE.js} +1 -1
  322. package/dist/node-runtime/{chunk-QZMODZQ2.js → chunk-E24EO34J.js} +2 -1
  323. package/dist/node-runtime/{chunk-2BUAYZ7K.js → chunk-EQ63ANHL.js} +422 -123
  324. package/dist/node-runtime/{chunk-GB2MGFLI.js → chunk-GJSAD4AB.js} +216 -201
  325. package/dist/node-runtime/{chunk-W3SILANP.js → chunk-GMHJCCEN.js} +8 -8
  326. package/dist/node-runtime/{chunk-DDWHZ633.js → chunk-GNN7H3B7.js} +1 -1
  327. package/dist/node-runtime/chunk-GS66LV4M.js +2830 -0
  328. package/dist/node-runtime/{chunk-6BEIBLQ3.js → chunk-H3XF4UVQ.js} +1 -1
  329. package/dist/node-runtime/chunk-H4K3JDRB.js +47 -0
  330. package/dist/node-runtime/{chunk-YMEAYRBE.js → chunk-HTFRRDSF.js} +2 -7
  331. package/dist/node-runtime/chunk-IMLCWLPI.js +9 -0
  332. package/dist/node-runtime/{chunk-Y5KOEMBH.js → chunk-IQIEU7SB.js} +9 -674
  333. package/dist/node-runtime/{chunk-OPEK5RRY.js → chunk-IVXYUAJE.js} +1 -1
  334. package/dist/node-runtime/{chunk-PDNXVXMD.js → chunk-IWOWXRWU.js} +58 -48
  335. package/dist/node-runtime/chunk-KKUTQQV7.js +144 -0
  336. package/dist/node-runtime/{chunk-AWVD5IEY.js → chunk-LMBNLFXQ.js} +23 -12
  337. package/dist/node-runtime/{chunk-7NBZ5P7I.js → chunk-NAY6UUQZ.js} +1 -1
  338. package/dist/node-runtime/chunk-OAR4TYZE.js +146 -0
  339. package/dist/node-runtime/{chunk-STERBGUB.js → chunk-OFKSVRV7.js} +2 -2
  340. package/dist/node-runtime/{chunk-JZQ7F36T.js → chunk-ORH324EP.js} +19 -3
  341. package/dist/node-runtime/{chunk-2SJB2AWP.js → chunk-PC2Z5TKZ.js} +3 -3
  342. package/dist/node-runtime/{chunk-SY2TFMLO.js → chunk-QDGKKKUM.js} +46 -151
  343. package/dist/node-runtime/chunk-R3K2F5GI.js +122 -0
  344. package/dist/node-runtime/chunk-RMQZU2YU.js +117 -0
  345. package/dist/node-runtime/{chunk-XI77KVKA.js → chunk-TDL7UWJ7.js} +283 -2999
  346. package/dist/node-runtime/{chunk-G6LRAP36.js → chunk-TQGPP4SC.js} +1 -1
  347. package/dist/node-runtime/chunk-UAEOTO52.js +119 -0
  348. package/dist/node-runtime/{chunk-VZR3NCM7.js → chunk-UAFLNHSH.js} +18 -14
  349. package/dist/node-runtime/{chunk-AY6CAJSL.js → chunk-UJOCPOMX.js} +6 -3
  350. package/dist/node-runtime/chunk-UP2XBVH5.js +40 -0
  351. package/dist/node-runtime/{chunk-WJVFOIB5.js → chunk-UQUCFAJ3.js} +1 -1
  352. package/dist/node-runtime/chunk-URD2SLIT.js +1019 -0
  353. package/dist/node-runtime/chunk-US544NN6.js +13 -0
  354. package/dist/node-runtime/chunk-UWPJL22I.js +341 -0
  355. package/dist/node-runtime/chunk-V2A7CEXK.js +355 -0
  356. package/dist/node-runtime/chunk-VJPTNWAP.js +708 -0
  357. package/dist/node-runtime/{chunk-WKDK4C5P.js → chunk-VSSXXL36.js} +38 -164
  358. package/dist/node-runtime/{chunk-4I23VTC4.js → chunk-VWCE2HSZ.js} +21 -124
  359. package/dist/node-runtime/{chunk-WLLDXJRT.js → chunk-WADV2VDS.js} +22 -1014
  360. package/dist/node-runtime/{chunk-GKLEQ3I4.js → chunk-XLTL257W.js} +126 -27
  361. package/dist/node-runtime/chunk-YPHAIRZT.js +10 -0
  362. package/dist/node-runtime/cli-runtime.js +2 -2
  363. package/dist/node-runtime/command-3JHHXOPX.js +45 -0
  364. package/dist/node-runtime/commands-2JVNFGMQ.js +36 -0
  365. package/dist/node-runtime/{commands-MV5KOZ64.js → commands-KAMO2T6P.js} +10 -10
  366. package/dist/node-runtime/config-RORQUQFG.js +20 -0
  367. package/dist/node-runtime/{customize-LF5VST47.js → customize-VFJV3U6A.js} +2 -1
  368. package/dist/node-runtime/{direct-tool-executor-BK7CLEBX.js → direct-tool-executor-YAVOLDFY.js} +8 -8
  369. package/dist/node-runtime/{export-html-TEXVV5RP.js → export-html-KBFVV63J.js} +4 -3
  370. package/dist/node-runtime/{extension-input-O4HSAEM4.js → extension-input-K24TVKVW.js} +4 -4
  371. package/dist/node-runtime/{extension-selector-X5FCX43D.js → extension-selector-SPNF7EDR.js} +4 -4
  372. package/dist/node-runtime/{extract-XLQSJN4V.js → extract-EQJE7FZZ.js} +2 -2
  373. package/dist/node-runtime/{gateway-BM6NLOH4.js → gateway-VFO6SFKK.js} +275 -994
  374. package/dist/node-runtime/{gemini-search-U7SUMPQA.js → gemini-search-35OCRFLN.js} +1 -1
  375. package/dist/node-runtime/{gemini-url-context-PXWCBQHK.js → gemini-url-context-UQY3PHHW.js} +2 -2
  376. package/dist/node-runtime/index.js +104 -65
  377. package/dist/node-runtime/{init-3C7Z24OI.js → init-X2LIUB2H.js} +3 -3
  378. package/dist/node-runtime/{install-cli-EXMJQESX.js → install-cli-C3CF7O7N.js} +21 -82
  379. package/dist/node-runtime/interactive-mode-LOM6AIF6.js +72 -0
  380. package/dist/node-runtime/{interactive-view-ILS6TAN5.js → interactive-view-IDSCPPK7.js} +8 -8
  381. package/dist/node-runtime/lunr-browser-YNW7FTYX.js +87 -0
  382. package/dist/node-runtime/{lunr-cron-4VHP4E4B.js → lunr-cron-BKHGNBKT.js} +19 -5
  383. package/dist/node-runtime/main.js +44 -31
  384. package/dist/node-runtime/{memory-cap-3S4XRLNP.js → memory-cap-EL3KL4JJ.js} +2 -1
  385. package/dist/node-runtime/mobile-commands-HMP25WBC.js +32 -0
  386. package/dist/node-runtime/model-runtime-PLQKAG4B.js +16 -0
  387. package/dist/node-runtime/{model-tiers-NJLHUEGK.js → model-tiers-OU3U5CZG.js} +2 -1
  388. package/dist/node-runtime/{package-manager-cli-N37546V5.js → package-manager-cli-VCK4E2RC.js} +22 -15
  389. package/dist/node-runtime/{pi-intercom-NV2LW6X7.js → pi-intercom-HBPK5HSJ.js} +4 -1
  390. package/dist/node-runtime/{pi-mcp-adapter-GUFZWW54.js → pi-mcp-adapter-E6WULBKF.js} +4 -4
  391. package/dist/node-runtime/{pi-subagents-6MUIFNDM.js → pi-subagents-FEUDLJOE.js} +201 -78
  392. package/dist/node-runtime/{pi-web-access-2CQGFLT2.js → pi-web-access-WTGMNZ32.js} +15 -15
  393. package/dist/node-runtime/process-registry-4FAKZQOL.js +31 -0
  394. package/dist/node-runtime/{proxy-modes-V6YVFH3C.js → proxy-modes-OSQCWRBI.js} +9 -9
  395. package/dist/node-runtime/rpc-entry.js +44 -31
  396. package/dist/node-runtime/{rpc-mode-W5ZTLTMZ.js → rpc-mode-P5ODXPEG.js} +2 -2
  397. package/dist/node-runtime/runtime-4VA6JKNF.js +373 -0
  398. package/dist/node-runtime/{runtime-bridges-2VQTLPOZ.js → runtime-bridges-3XUQ46XW.js} +6 -5
  399. package/dist/node-runtime/service-ISSP6VHE.js +36 -0
  400. package/dist/node-runtime/session-handoff-HC7R5E24.js +33 -0
  401. package/dist/node-runtime/{session-manager-E7AREDTV.js → session-manager-CFN4UFM2.js} +2 -1
  402. package/dist/node-runtime/{session-selector-FJ7M2AIX.js → session-selector-LHRMJOKT.js} +5 -4
  403. package/dist/node-runtime/{settings-manager-CUGAZWAB.js → settings-manager-UUZ6NUXI.js} +7 -2
  404. package/dist/node-runtime/setup-JBKOLJ6F.js +18 -0
  405. package/dist/node-runtime/setup-NRXVZBLJ.js +155 -0
  406. package/dist/node-runtime/{subagent-executor-MH4A7CCF.js → subagent-executor-MLUMBWCP.js} +22 -18
  407. package/dist/node-runtime/theme-U7IGOA7O.js +68 -0
  408. package/dist/node-runtime/trust-manager-MMISNCYO.js +17 -0
  409. package/dist/node-runtime/{update-cli-XTZMZGOL.js → update-cli-4TP25CNW.js} +7 -2
  410. package/dist/node-runtime/usage-service-LFB2SWYV.js +37 -0
  411. package/dist/node-runtime/{video-extract-OYT5WKS5.js → video-extract-OOZHR7SU.js} +2 -2
  412. package/dist/node-runtime/{youtube-extract-TQYKGFGS.js → youtube-extract-FNPAUNHU.js} +6 -6
  413. package/docs/browser.md +86 -0
  414. package/docs/extensions.md +2 -0
  415. package/docs/features.md +94 -16
  416. package/docs/interactive-startup.md +2 -1
  417. package/docs/sessions.md +10 -0
  418. package/docs/settings.md +1 -0
  419. package/docs/tui.md +2 -0
  420. package/docs/usage.md +16 -0
  421. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  422. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  423. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  424. package/examples/extensions/gondolin/package-lock.json +2 -2
  425. package/examples/extensions/gondolin/package.json +1 -1
  426. package/examples/extensions/sandbox/package-lock.json +2 -2
  427. package/examples/extensions/sandbox/package.json +1 -1
  428. package/examples/extensions/with-deps/package-lock.json +2 -2
  429. package/examples/extensions/with-deps/package.json +1 -1
  430. package/package.json +7 -4
  431. package/scripts/install-browser.mjs +20 -0
  432. package/dist/node-runtime/agent-session-services-C743TYQE.js +0 -37
  433. package/dist/node-runtime/chunk-VGYZ3APQ.js +0 -59
  434. package/dist/node-runtime/command-P4NYCJ2M.js +0 -13
  435. package/dist/node-runtime/interactive-mode-EVVBA64D.js +0 -59
  436. package/dist/node-runtime/{chunk-UWQYRSYQ.js → chunk-YJMMG7C6.js} +25 -25
  437. package/dist/node-runtime/{mcp-panel-IIGMXQGP.js → mcp-panel-KTTFXJZ4.js} +3 -3
  438. package/dist/node-runtime/{src-BPQFJR76.js → src-IVPNZ2BX.js} +9 -9
@@ -0,0 +1,2830 @@
1
+ import { createRequire as __lunrRequire } from "node:module"; const require = __lunrRequire(import.meta.url);
2
+ import {
3
+ require_proper_lockfile
4
+ } from "./chunk-URD2SLIT.js";
5
+ import {
6
+ getShellConfig
7
+ } from "./chunk-CSFI6YXL.js";
8
+ import {
9
+ clearPlanUsageCache
10
+ } from "./chunk-2MI5OPMN.js";
11
+ import {
12
+ VERSION,
13
+ getAgentDir,
14
+ getPackageDir,
15
+ normalizePath
16
+ } from "./chunk-FQMM2EZ2.js";
17
+ import {
18
+ __toESM
19
+ } from "./chunk-BRJX2PRC.js";
20
+
21
+ // packages/coding-agent/dist/core/model-runtime.js
22
+ import { dirname as dirname5, join as join7 } from "node:path";
23
+ import { createModels, lazyStream as lazyStream2, ModelsError } from "@ashx-j/lunr-ai";
24
+ import * as builtinProviderCatalog from "@ashx-j/lunr-ai/providers/all";
25
+
26
+ // packages/coding-agent/dist/core/auth-storage.js
27
+ var import_proper_lockfile = __toESM(require_proper_lockfile(), 1);
28
+ import { chmodSync, existsSync, mkdirSync, readFileSync, renameSync, unlinkSync, writeFileSync } from "fs";
29
+ import { dirname, join } from "path";
30
+
31
+ // packages/coding-agent/dist/core/resolve-config-value.js
32
+ import { execSync, spawnSync } from "child_process";
33
+ var commandResultCache = /* @__PURE__ */ new Map(), ENV_VAR_NAME_RE = /^[A-Za-z_][A-Za-z0-9_]*$/, ENV_VAR_NAME_PREFIX_RE = /^[A-Za-z_][A-Za-z0-9_]*/;
34
+ function appendLiteral(parts, value) {
35
+ if (!value)
36
+ return;
37
+ let previousPart = parts[parts.length - 1];
38
+ if (previousPart?.type === "literal") {
39
+ previousPart.value += value;
40
+ return;
41
+ }
42
+ parts.push({ type: "literal", value });
43
+ }
44
+ function parseConfigValueTemplate(config) {
45
+ let parts = [], index = 0;
46
+ for (; index < config.length; ) {
47
+ let dollarIndex = config.indexOf("$", index);
48
+ if (dollarIndex < 0) {
49
+ appendLiteral(parts, config.slice(index));
50
+ break;
51
+ }
52
+ appendLiteral(parts, config.slice(index, dollarIndex));
53
+ let nextChar = config[dollarIndex + 1];
54
+ if (nextChar === "$" || nextChar === "!") {
55
+ appendLiteral(parts, nextChar), index = dollarIndex + 2;
56
+ continue;
57
+ }
58
+ if (nextChar === "{") {
59
+ let endIndex = config.indexOf("}", dollarIndex + 2);
60
+ if (endIndex < 0) {
61
+ appendLiteral(parts, "$"), index = dollarIndex + 1;
62
+ continue;
63
+ }
64
+ let name = config.slice(dollarIndex + 2, endIndex);
65
+ ENV_VAR_NAME_RE.test(name) ? parts.push({ type: "env", name }) : appendLiteral(parts, config.slice(dollarIndex, endIndex + 1)), index = endIndex + 1;
66
+ continue;
67
+ }
68
+ let match = config.slice(dollarIndex + 1).match(ENV_VAR_NAME_PREFIX_RE);
69
+ if (match) {
70
+ parts.push({ type: "env", name: match[0] }), index = dollarIndex + 1 + match[0].length;
71
+ continue;
72
+ }
73
+ appendLiteral(parts, "$"), index = dollarIndex + 1;
74
+ }
75
+ return parts;
76
+ }
77
+ function parseConfigValueReference(config) {
78
+ return config.startsWith("!") ? { type: "command", config } : { type: "template", parts: parseConfigValueTemplate(config) };
79
+ }
80
+ function resolveEnvConfigValue(name, env) {
81
+ return env?.[name] || process.env[name] || void 0;
82
+ }
83
+ function getTemplateEnvVarNames(parts) {
84
+ let names = [];
85
+ for (let part of parts)
86
+ part.type !== "env" || names.includes(part.name) || names.push(part.name);
87
+ return names;
88
+ }
89
+ function resolveTemplate(parts, env) {
90
+ let resolved = "";
91
+ for (let part of parts) {
92
+ if (part.type === "literal") {
93
+ resolved += part.value;
94
+ continue;
95
+ }
96
+ let envValue = resolveEnvConfigValue(part.name, env);
97
+ if (envValue === void 0)
98
+ return;
99
+ resolved += envValue;
100
+ }
101
+ return resolved;
102
+ }
103
+ function getConfigValueEnvVarNames(config) {
104
+ let reference = parseConfigValueReference(config);
105
+ return reference.type === "template" ? getTemplateEnvVarNames(reference.parts) : [];
106
+ }
107
+ function getMissingConfigValueEnvVarNames(config, env) {
108
+ return getConfigValueEnvVarNames(config).filter((name) => resolveEnvConfigValue(name, env) === void 0);
109
+ }
110
+ function isCommandConfigValue(config) {
111
+ return parseConfigValueReference(config).type === "command";
112
+ }
113
+ function isConfigValueConfigured(config, env) {
114
+ return getMissingConfigValueEnvVarNames(config, env).length === 0;
115
+ }
116
+ function resolveConfigValue(config, env) {
117
+ let reference = parseConfigValueReference(config);
118
+ return reference.type === "command" ? executeCommand(reference.config) : resolveTemplate(reference.parts, env);
119
+ }
120
+ function executeWithConfiguredShell(command) {
121
+ try {
122
+ let { shell, args, commandTransport } = getShellConfig(), commandFromStdin = commandTransport === "stdin", result = spawnSync(shell, commandFromStdin ? args : [...args, command], {
123
+ encoding: "utf-8",
124
+ input: commandFromStdin ? command : void 0,
125
+ timeout: 1e4,
126
+ stdio: [commandFromStdin ? "pipe" : "ignore", "pipe", "ignore"],
127
+ shell: !1,
128
+ windowsHide: !0
129
+ });
130
+ return result.error ? result.error.code === "ENOENT" ? { executed: !1, value: void 0 } : { executed: !0, value: void 0 } : result.status !== 0 ? { executed: !0, value: void 0 } : { executed: !0, value: (result.stdout ?? "").trim() || void 0 };
131
+ } catch {
132
+ return { executed: !1, value: void 0 };
133
+ }
134
+ }
135
+ function executeWithDefaultShell(command) {
136
+ try {
137
+ return execSync(command, {
138
+ encoding: "utf-8",
139
+ timeout: 1e4,
140
+ stdio: ["ignore", "pipe", "ignore"]
141
+ }).trim() || void 0;
142
+ } catch {
143
+ return;
144
+ }
145
+ }
146
+ function executeCommandUncached(commandConfig) {
147
+ let command = commandConfig.slice(1);
148
+ return process.platform === "win32" ? (() => {
149
+ let configuredResult = executeWithConfiguredShell(command);
150
+ return configuredResult.executed ? configuredResult.value : executeWithDefaultShell(command);
151
+ })() : executeWithDefaultShell(command);
152
+ }
153
+ function executeCommand(commandConfig) {
154
+ if (commandResultCache.has(commandConfig))
155
+ return commandResultCache.get(commandConfig);
156
+ let result = executeCommandUncached(commandConfig);
157
+ return commandResultCache.set(commandConfig, result), result;
158
+ }
159
+ function resolveConfigValueUncached(config, env) {
160
+ let reference = parseConfigValueReference(config);
161
+ return reference.type === "command" ? executeCommandUncached(reference.config) : resolveTemplate(reference.parts, env);
162
+ }
163
+ function resolveConfigValueOrThrow(config, description, env) {
164
+ let resolvedValue = resolveConfigValueUncached(config, env);
165
+ if (resolvedValue !== void 0)
166
+ return resolvedValue;
167
+ let reference = parseConfigValueReference(config);
168
+ if (reference.type === "command")
169
+ throw new Error(`Failed to resolve ${description} from shell command: ${reference.config.slice(1)}`);
170
+ if (reference.type === "template") {
171
+ let missingEnvVars = getMissingConfigValueEnvVarNames(config, env);
172
+ if (missingEnvVars.length === 1)
173
+ throw new Error(`Failed to resolve ${description} from environment variable: ${missingEnvVars[0]}`);
174
+ if (missingEnvVars.length > 1)
175
+ throw new Error(`Failed to resolve ${description} from environment variables: ${missingEnvVars.join(", ")}`);
176
+ }
177
+ throw new Error(`Failed to resolve ${description}`);
178
+ }
179
+ function resolveHeadersOrThrow(headers, description, env) {
180
+ if (!headers)
181
+ return;
182
+ let resolved = {};
183
+ for (let [key, value] of Object.entries(headers))
184
+ resolved[key] = resolveConfigValueOrThrow(value, `${description} header "${key}"`, env);
185
+ return Object.keys(resolved).length > 0 ? resolved : void 0;
186
+ }
187
+
188
+ // packages/coding-agent/dist/core/auth-storage.js
189
+ var AUTH_FILE_WRITE_OPTIONS = { encoding: "utf-8", mode: 384 }, AUTH_LOCK_STALE_MS = 12e4;
190
+ function writeAuthFileAtomic(authPath, contents) {
191
+ let tmp = `${authPath}.${process.pid}.${Date.now()}.tmp`;
192
+ writeFileSync(tmp, contents, AUTH_FILE_WRITE_OPTIONS);
193
+ try {
194
+ chmodSync(tmp, 384);
195
+ } catch {
196
+ }
197
+ try {
198
+ if (process.platform === "win32" && existsSync(authPath)) {
199
+ writeFileSync(authPath, contents, AUTH_FILE_WRITE_OPTIONS), chmodSync(authPath, 384);
200
+ return;
201
+ }
202
+ renameSync(tmp, authPath);
203
+ try {
204
+ chmodSync(authPath, 384);
205
+ } catch {
206
+ }
207
+ } finally {
208
+ try {
209
+ unlinkSync(tmp);
210
+ } catch {
211
+ }
212
+ }
213
+ }
214
+ var FileAuthStorageBackend = class {
215
+ authPath;
216
+ constructor(authPath = join(getAgentDir(), "auth.json")) {
217
+ this.authPath = normalizePath(authPath);
218
+ }
219
+ ensureParentDir() {
220
+ let dir = dirname(this.authPath);
221
+ existsSync(dir) || mkdirSync(dir, { recursive: !0, mode: 448 });
222
+ }
223
+ ensureFileExists() {
224
+ existsSync(this.authPath) || (writeFileSync(this.authPath, "{}", AUTH_FILE_WRITE_OPTIONS), chmodSync(this.authPath, 384));
225
+ }
226
+ acquireLockSyncWithRetry(path) {
227
+ let lastError;
228
+ for (let attempt = 1; attempt <= 10; attempt++)
229
+ try {
230
+ return import_proper_lockfile.default.lockSync(path, { realpath: !1, stale: AUTH_LOCK_STALE_MS });
231
+ } catch (error) {
232
+ if ((typeof error == "object" && error !== null && "code" in error ? String(error.code) : void 0) !== "ELOCKED" || attempt === 10)
233
+ throw error;
234
+ lastError = error;
235
+ let start = Date.now();
236
+ for (; Date.now() - start < 20; )
237
+ ;
238
+ }
239
+ throw lastError ?? new Error("Failed to acquire auth storage lock");
240
+ }
241
+ withLock(fn) {
242
+ this.ensureParentDir(), this.ensureFileExists();
243
+ let release;
244
+ try {
245
+ release = this.acquireLockSyncWithRetry(this.authPath);
246
+ let current = existsSync(this.authPath) ? readFileSync(this.authPath, "utf-8") : void 0, { result, next } = fn(current);
247
+ return next !== void 0 && writeAuthFileAtomic(this.authPath, next), result;
248
+ } finally {
249
+ release && release();
250
+ }
251
+ }
252
+ async withLockAsync(fn) {
253
+ this.ensureParentDir(), this.ensureFileExists();
254
+ let release, lockCompromised = !1, lockCompromisedError, throwIfCompromised = () => {
255
+ if (lockCompromised)
256
+ throw lockCompromisedError ?? new Error("Auth storage lock was compromised");
257
+ };
258
+ try {
259
+ release = await import_proper_lockfile.default.lock(this.authPath, {
260
+ retries: {
261
+ retries: 10,
262
+ factor: 2,
263
+ minTimeout: 100,
264
+ maxTimeout: 1e4,
265
+ randomize: !0
266
+ },
267
+ stale: AUTH_LOCK_STALE_MS,
268
+ onCompromised: (err) => {
269
+ lockCompromised = !0, lockCompromisedError = err;
270
+ }
271
+ }), throwIfCompromised();
272
+ let current = existsSync(this.authPath) ? readFileSync(this.authPath, "utf-8") : void 0, { result, next } = await fn(current);
273
+ return throwIfCompromised(), next !== void 0 && writeAuthFileAtomic(this.authPath, next), throwIfCompromised(), result;
274
+ } finally {
275
+ if (release)
276
+ try {
277
+ await release();
278
+ } catch {
279
+ }
280
+ }
281
+ }
282
+ }, InMemoryAuthStorageBackend = class {
283
+ value;
284
+ withLock(fn) {
285
+ let { result, next } = fn(this.value);
286
+ return next !== void 0 && (this.value = next), result;
287
+ }
288
+ async withLockAsync(fn) {
289
+ let { result, next } = await fn(this.value);
290
+ return next !== void 0 && (this.value = next), result;
291
+ }
292
+ }, AuthStorage = class _AuthStorage {
293
+ data = {};
294
+ storage;
295
+ constructor(storage) {
296
+ this.storage = storage, this.reload();
297
+ }
298
+ static create(authPath) {
299
+ return new _AuthStorage(new FileAuthStorageBackend(authPath ?? join(getAgentDir(), "auth.json")));
300
+ }
301
+ static fromStorage(storage) {
302
+ return new _AuthStorage(storage);
303
+ }
304
+ static inMemory(data = {}) {
305
+ let storage = new InMemoryAuthStorageBackend();
306
+ return storage.withLock(() => ({ result: void 0, next: JSON.stringify(data, null, 2) })), _AuthStorage.fromStorage(storage);
307
+ }
308
+ parseStorageData(content) {
309
+ return content ? JSON.parse(content) : {};
310
+ }
311
+ /**
312
+ * Reload credentials from storage.
313
+ */
314
+ reload() {
315
+ let content;
316
+ try {
317
+ this.storage.withLock((current) => (content = current, { result: void 0 })), this.data = this.parseStorageData(content);
318
+ } catch {
319
+ }
320
+ }
321
+ async read(provider) {
322
+ let credential = this.data[provider];
323
+ return credential?.type !== "api_key" || credential.key === void 0 ? credential : { ...credential, key: resolveConfigValue(credential.key, credential.env) };
324
+ }
325
+ async modify(provider, fn) {
326
+ return this.storage.withLockAsync(async (content) => {
327
+ let currentData = this.parseStorageData(content), next = await fn(currentData[provider]);
328
+ if (next === void 0)
329
+ return this.data = currentData, { result: currentData[provider] };
330
+ let merged = { ...currentData, [provider]: next };
331
+ return this.data = merged, { result: next, next: JSON.stringify(merged, null, 2) };
332
+ });
333
+ }
334
+ async delete(provider) {
335
+ await this.storage.withLockAsync(async (content) => {
336
+ let currentData = this.parseStorageData(content);
337
+ return delete currentData[provider], this.data = currentData, { result: void 0, next: JSON.stringify(currentData, null, 2) };
338
+ });
339
+ }
340
+ /** List credential metadata without resolving configured key values. */
341
+ async list() {
342
+ return Object.entries(this.data).map(([providerId, credential]) => ({ providerId, type: credential.type }));
343
+ }
344
+ };
345
+ function readStoredCredential(providerId, authPath = join(getAgentDir(), "auth.json")) {
346
+ try {
347
+ return JSON.parse(readFileSync(normalizePath(authPath), "utf-8"))[providerId];
348
+ } catch {
349
+ return;
350
+ }
351
+ }
352
+
353
+ // packages/coding-agent/dist/core/catalog-cache-scope.js
354
+ import { createHash } from "node:crypto";
355
+ function catalogCacheScope(provider, baseUrl, credential) {
356
+ let identity = credential?.type === "oauth" ? typeof credential.accountId == "string" ? credential.accountId : credential.refresh || credential.access : credential?.key;
357
+ return createHash("sha256").update(JSON.stringify([provider, baseUrl.replace(/\/+$/, ""), identity ?? null])).digest("hex");
358
+ }
359
+
360
+ // packages/coding-agent/dist/core/catalog-merge.js
361
+ import { withOpenAiEffortMetadata, withXaiEffortMetadata } from "@ashx-j/lunr-ai";
362
+
363
+ // packages/coding-agent/dist/core/official-catalog.js
364
+ import { createHash as createHash2, randomUUID } from "node:crypto";
365
+ import { existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync as readFileSync2, renameSync as renameSync2, unlinkSync as unlinkSync2, writeFileSync as writeFileSync2 } from "node:fs";
366
+ import { dirname as dirname2, join as join2 } from "node:path";
367
+ import { fileURLToPath } from "node:url";
368
+
369
+ // packages/coding-agent/dist/utils/pi-user-agent.js
370
+ function getPiUserAgent(version) {
371
+ let runtime = process.versions.bun ? `bun/${process.versions.bun}` : `node/${process.version}`;
372
+ return `pi/${version} (${process.platform}; ${runtime}; ${process.arch})`;
373
+ }
374
+
375
+ // packages/coding-agent/dist/core/official-catalog.js
376
+ var OFFICIAL_CATALOG_DEFAULT_URL = "https://raw.githubusercontent.com/ashx-j/lunR/master/catalog", VERSIONED_CATALOG_URL = "https://raw.githubusercontent.com/ashx-j/lunR/model-catalog/catalog", OFFICIAL_CATALOG_TIMEOUT_MS = 4e3, OFFICIAL_CATALOG_CACHE_FILENAME = "official-catalog-cache.json", THINKING_LEVEL_KEYS = ["off", "minimal", "low", "medium", "high", "xhigh", "max"], META_KEYS = /* @__PURE__ */ new Set(["version", "updatedAt", "generatedAt", "sourceCommit", "providerCount", "modelCount"]), BUNDLED_OFFICIAL_CATALOG = {
377
+ version: 1,
378
+ updatedAt: "2026-08-15T00:00:00Z",
379
+ models: [
380
+ {
381
+ id: "grok-4.6",
382
+ name: "Grok 4.6",
383
+ api: "openai-completions",
384
+ provider: "xai",
385
+ baseUrl: "https://api.x.ai/v1",
386
+ reasoning: !0,
387
+ input: ["text", "image"],
388
+ cost: { input: 2, output: 6, cacheRead: 0.5, cacheWrite: 0 },
389
+ contextWindow: 5e5,
390
+ maxTokens: 5e5
391
+ }
392
+ ]
393
+ };
394
+ function officialCatalogCachePath(agentDir = getAgentDir()) {
395
+ return join2(agentDir, OFFICIAL_CATALOG_CACHE_FILENAME);
396
+ }
397
+ function officialCatalogBaseUrl(override) {
398
+ return ((override ?? process.env.LUNR_OFFICIAL_CATALOG_URL)?.trim() || OFFICIAL_CATALOG_DEFAULT_URL).replace(/\/+$/, "");
399
+ }
400
+ function officialCatalogUrlFor(path, base) {
401
+ let normalized = path.replace(/^\/+/, "");
402
+ return `${officialCatalogBaseUrl(base)}/${normalized}`;
403
+ }
404
+ function modelKey(provider, id) {
405
+ return `${provider}/${id}`;
406
+ }
407
+ function isRecord(value) {
408
+ return typeof value == "object" && value !== null && !Array.isArray(value);
409
+ }
410
+ function asFiniteNumber(value) {
411
+ if (typeof value == "number" && Number.isFinite(value))
412
+ return value;
413
+ if (typeof value == "string" && value.trim()) {
414
+ let parsed = Number(value);
415
+ if (Number.isFinite(parsed))
416
+ return parsed;
417
+ }
418
+ }
419
+ function parseCost(value) {
420
+ if (!isRecord(value))
421
+ return;
422
+ let input = asFiniteNumber(value.input), output = asFiniteNumber(value.output);
423
+ if (!(input === void 0 || output === void 0))
424
+ return {
425
+ input,
426
+ output,
427
+ cacheRead: asFiniteNumber(value.cacheRead) ?? 0,
428
+ cacheWrite: asFiniteNumber(value.cacheWrite) ?? 0,
429
+ ...Array.isArray(value.tiers) ? {
430
+ tiers: value.tiers.flatMap((tier) => {
431
+ if (!isRecord(tier) || !(typeof tier.inputTokensAbove == "number" && tier.inputTokensAbove >= 0))
432
+ return [];
433
+ let rates = parseCost({
434
+ input: tier.input,
435
+ output: tier.output,
436
+ cacheRead: tier.cacheRead,
437
+ cacheWrite: tier.cacheWrite
438
+ });
439
+ return rates ? [{ ...rates, inputTokensAbove: tier.inputTokensAbove }] : [];
440
+ })
441
+ } : {}
442
+ };
443
+ }
444
+ function parseInput(value) {
445
+ if (!Array.isArray(value))
446
+ return;
447
+ let input = [];
448
+ for (let entry of value)
449
+ (entry === "text" || entry === "image") && input.push(entry);
450
+ return input.length > 0 ? input : void 0;
451
+ }
452
+ function parseThinkingLevelMap(value) {
453
+ if (!isRecord(value))
454
+ return;
455
+ let map = {}, any = !1;
456
+ for (let level of THINKING_LEVEL_KEYS) {
457
+ let mapped = value[level];
458
+ (mapped === null || typeof mapped == "string") && (map[level] = mapped, any = !0);
459
+ }
460
+ return any ? map : void 0;
461
+ }
462
+ function parseHeaders(value) {
463
+ if (!isRecord(value))
464
+ return;
465
+ let headers = {};
466
+ for (let [name, headerValue] of Object.entries(value))
467
+ typeof headerValue == "string" && (headers[name] = headerValue);
468
+ return Object.keys(headers).length > 0 ? headers : void 0;
469
+ }
470
+ function parseOfficialEntry(value) {
471
+ if (!isRecord(value))
472
+ return;
473
+ let id = typeof value.id == "string" ? value.id.trim() : "", provider = typeof value.provider == "string" ? value.provider.trim() : "";
474
+ if (!id || !provider)
475
+ return;
476
+ let api = typeof value.api == "string" && value.api.trim() ? value.api.trim() : "openai-completions", name = typeof value.name == "string" && value.name.trim() ? value.name.trim() : id, baseUrl = typeof value.baseUrl == "string" ? value.baseUrl.trim() : "", cost = parseCost(value.cost) ?? { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, input = parseInput(value.input) ?? ["text"], compat = isRecord(value.compat) ? value.compat : void 0, thinkingLevelMap = parseThinkingLevelMap(value.thinkingLevelMap), headers = parseHeaders(value.headers);
477
+ return {
478
+ id,
479
+ ...isRecord(value.catalog) && value.catalog.source === "provider" && Array.isArray(value.catalog.supplied) ? { catalog: value.catalog } : {},
480
+ name,
481
+ api,
482
+ provider,
483
+ baseUrl,
484
+ reasoning: value.reasoning === !0,
485
+ input,
486
+ cost,
487
+ contextWindow: asFiniteNumber(value.contextWindow) ?? 128e3,
488
+ maxTokens: asFiniteNumber(value.maxTokens) ?? 8192,
489
+ ...compat ? { compat } : {},
490
+ ...thinkingLevelMap ? { thinkingLevelMap } : {},
491
+ ...headers ? { headers } : {}
492
+ };
493
+ }
494
+ function catalogFile(models, value) {
495
+ let version = value ? asFiniteNumber(value.version) ?? 1 : 1, updatedAt = value && typeof value.updatedAt == "string" && value.updatedAt.trim() ? value.updatedAt : "";
496
+ return { version, updatedAt, models };
497
+ }
498
+ function parseKeyedCatalog(value) {
499
+ let models = [];
500
+ for (let [key, entry] of Object.entries(value))
501
+ if (!(META_KEYS.has(key) || !isRecord(entry))) {
502
+ if (typeof entry.id == "string") {
503
+ let parsed = parseOfficialEntry(entry);
504
+ parsed && models.push(parsed);
505
+ continue;
506
+ }
507
+ for (let [modelId, model] of Object.entries(entry)) {
508
+ if (!isRecord(model))
509
+ continue;
510
+ let parsed = parseOfficialEntry({
511
+ ...model,
512
+ id: typeof model.id == "string" && model.id.trim() ? model.id : modelId,
513
+ provider: typeof model.provider == "string" && model.provider.trim() ? model.provider : key
514
+ });
515
+ parsed && models.push(parsed);
516
+ }
517
+ }
518
+ return models.length > 0 ? catalogFile(models, value) : void 0;
519
+ }
520
+ function parseOfficialCatalog(value) {
521
+ if (isRecord(value)) {
522
+ if (Array.isArray(value.models)) {
523
+ let models = [];
524
+ for (let entry of value.models) {
525
+ let parsed = parseOfficialEntry(entry);
526
+ parsed && models.push(parsed);
527
+ }
528
+ return catalogFile(models, value);
529
+ }
530
+ if (!("models" in value))
531
+ return parseKeyedCatalog(value);
532
+ }
533
+ }
534
+ function parseProviderIndex(value) {
535
+ if (!(!Array.isArray(value) || !value.every((entry) => typeof entry == "string")))
536
+ return value;
537
+ }
538
+ function readCatalogFile(path) {
539
+ try {
540
+ return existsSync2(path) ? parseOfficialCatalog(JSON.parse(readFileSync2(path, "utf-8"))) : void 0;
541
+ } catch {
542
+ return;
543
+ }
544
+ }
545
+ function bundledCatalogCandidates() {
546
+ let here = dirname2(fileURLToPath(new URL("../core/official-catalog.js", import.meta.url).href)), packageDir = getPackageDir();
547
+ return [
548
+ join2(packageDir, "dist", "catalog", "models.json"),
549
+ join2(packageDir, "..", "..", "catalog", "models.json"),
550
+ join2(here, "../../../../catalog/models.json"),
551
+ join2(packageDir, "catalog", "models.json"),
552
+ join2(here, "../catalog/models.json"),
553
+ join2(here, "models.json"),
554
+ join2(packageDir, "dist", "catalog", "official-models.json"),
555
+ join2(packageDir, "..", "..", "catalog", "official-models.json"),
556
+ join2(here, "../../../../catalog/official-models.json"),
557
+ join2(here, "official-models.json"),
558
+ join2(here, "../catalog/official-models.json")
559
+ ];
560
+ }
561
+ function loadBundledOfficialCatalog() {
562
+ for (let path of bundledCatalogCandidates()) {
563
+ let parsed = readCatalogFile(path);
564
+ if (parsed)
565
+ return parsed;
566
+ }
567
+ return BUNDLED_OFFICIAL_CATALOG;
568
+ }
569
+ function loadCachedOfficialCatalog(cachePath) {
570
+ if (cachePath)
571
+ return readCatalogFile(cachePath);
572
+ }
573
+ function writeOfficialCatalogCache(catalog, cachePath) {
574
+ let temporary = `${cachePath}.${randomUUID()}.tmp`;
575
+ try {
576
+ mkdirSync2(dirname2(cachePath), { recursive: !0, mode: 448 }), writeFileSync2(temporary, `${JSON.stringify(catalog, null, 2)}
577
+ `, { encoding: "utf-8", mode: 384 }), renameSync2(temporary, cachePath);
578
+ } catch {
579
+ } finally {
580
+ try {
581
+ unlinkSync2(temporary);
582
+ } catch {
583
+ }
584
+ }
585
+ }
586
+ function officialModelsByProvider(catalog) {
587
+ let byProvider = /* @__PURE__ */ new Map();
588
+ for (let model of catalog.models) {
589
+ let list = byProvider.get(model.provider) ?? [];
590
+ list.push(model), byProvider.set(model.provider, list);
591
+ }
592
+ return byProvider;
593
+ }
594
+ function mergeOfficialCatalogByProvider(base, replacements, updatedAt) {
595
+ let byProvider = officialModelsByProvider(base);
596
+ for (let [providerId, models] of replacements)
597
+ byProvider.set(providerId, models);
598
+ return {
599
+ version: base.version || 1,
600
+ updatedAt: updatedAt ?? (/* @__PURE__ */ new Date()).toISOString(),
601
+ models: [...byProvider.values()].flat()
602
+ };
603
+ }
604
+ function officialCatalogBase(bundled, cachePath) {
605
+ let cached = loadCachedOfficialCatalog(cachePath);
606
+ return cached ? mergeOfficialCatalogByProvider(bundled, officialModelsByProvider(cached), cached.updatedAt) : bundled;
607
+ }
608
+ function preferOfficialCatalog(previous, next) {
609
+ return next.source === "github" ? next : previous?.source === "github" ? { ...previous, errors: next.errors } : next;
610
+ }
611
+ function officialModelKeys(catalog) {
612
+ return new Set(catalog.models.map((model) => modelKey(model.provider, model.id)));
613
+ }
614
+ var ZERO_COST = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 };
615
+ function officialEntryToModel(entry, template) {
616
+ return {
617
+ catalog: entry.catalog,
618
+ id: entry.id,
619
+ name: entry.name,
620
+ api: entry.api || template?.api || "openai-completions",
621
+ provider: entry.provider,
622
+ baseUrl: entry.baseUrl || template?.baseUrl || "",
623
+ reasoning: entry.reasoning,
624
+ input: entry.input.length > 0 ? entry.input : template?.input ?? ["text"],
625
+ cost: entry.cost ?? template?.cost ?? ZERO_COST,
626
+ contextWindow: entry.contextWindow,
627
+ maxTokens: entry.maxTokens,
628
+ compat: entry.compat ?? template?.compat,
629
+ thinkingLevelMap: entry.thinkingLevelMap ?? template?.thinkingLevelMap,
630
+ headers: entry.headers ?? template?.headers
631
+ };
632
+ }
633
+ function resolveBundledCatalog(bundled) {
634
+ return bundled || loadBundledOfficialCatalog();
635
+ }
636
+ function fallbackCatalog(bundled, cachePath) {
637
+ let cached = loadCachedOfficialCatalog(cachePath);
638
+ if (cached)
639
+ return { catalog: cached, source: "cache" };
640
+ let resolved = resolveBundledCatalog(bundled);
641
+ return resolved.models.length > 0 ? { catalog: resolved, source: "bundled" } : { catalog: BUNDLED_OFFICIAL_CATALOG, source: "bundled" };
642
+ }
643
+ async function fetchJson(url, options) {
644
+ let controller = new AbortController(), timer = setTimeout(() => controller.abort(), options.timeoutMs), onParentAbort = () => controller.abort();
645
+ options.signal?.addEventListener("abort", onParentAbort, { once: !0 }), options.signal?.aborted && controller.abort();
646
+ try {
647
+ let abortError = () => {
648
+ let error = new Error("The operation was aborted");
649
+ return error.name = "AbortError", error;
650
+ };
651
+ return await Promise.race([
652
+ (async () => {
653
+ let response = await options.fetchImpl(url, {
654
+ headers: options.headers,
655
+ signal: controller.signal
656
+ });
657
+ return response.ok ? { ok: !0, value: await response.json() } : { ok: !1, status: response.status };
658
+ })(),
659
+ new Promise((_, reject) => {
660
+ controller.signal.addEventListener("abort", () => reject(abortError()), { once: !0 }), controller.signal.aborted && reject(abortError());
661
+ })
662
+ ]);
663
+ } catch {
664
+ return { ok: !1 };
665
+ } finally {
666
+ clearTimeout(timer), options.signal?.removeEventListener("abort", onParentAbort);
667
+ }
668
+ }
669
+ async function loadOfficialCatalog(options = {}) {
670
+ let cachePath = options.cachePath;
671
+ if (!options.allowNetwork)
672
+ return fallbackCatalog(options.bundled, cachePath);
673
+ let bundled = resolveBundledCatalog(options.bundled), timeoutMs = options.timeoutMs ?? OFFICIAL_CATALOG_TIMEOUT_MS, fetchImpl = options.fetchImpl ?? fetch, headers = {
674
+ accept: "application/json",
675
+ "User-Agent": getPiUserAgent(VERSION)
676
+ }, fetchOptions = { timeoutMs, signal: options.signal, fetchImpl, headers }, unavailable = () => ({
677
+ ...fallbackCatalog(bundled, cachePath),
678
+ errors: Object.fromEntries((options.providerIds ?? []).map((id) => [id, "Published catalog unavailable; using cached metadata"]))
679
+ }), base = options.url ?? officialCatalogBaseUrl(), manifest;
680
+ if (!options.url && !process.env.LUNR_OFFICIAL_CATALOG_URL) {
681
+ let result = await fetchJson(`${VERSIONED_CATALOG_URL}/publication.json`, fetchOptions);
682
+ result.ok && isRecord(result.value) && result.value.version === 2 && typeof result.value.revision == "string" && /^sha256-[a-f0-9]{64}$/.test(result.value.revision) && isRecord(result.value.shards) && parseProviderIndex(result.value.providers) && (manifest = result.value, base = `${VERSIONED_CATALOG_URL}/snapshots/${result.value.revision}`);
683
+ }
684
+ try {
685
+ let indexResult = manifest ? { ok: !0, value: manifest.providers } : await fetchJson(officialCatalogUrlFor("providers.json", base), fetchOptions);
686
+ if (!indexResult.ok)
687
+ return unavailable();
688
+ let index = parseProviderIndex(indexResult.value);
689
+ if (!index)
690
+ return unavailable();
691
+ let wanted = new Set(index), shardIds = (options.providerIds ?? []).filter((providerId) => wanted.has(providerId));
692
+ if (shardIds.length === 0)
693
+ return fallbackCatalog(bundled, cachePath);
694
+ let replacements = /* @__PURE__ */ new Map(), errors = {};
695
+ if (await Promise.all(shardIds.map(async (providerId) => {
696
+ let result = await fetchJson(officialCatalogUrlFor(`providers/${encodeURIComponent(providerId)}.json`, base), fetchOptions);
697
+ if (!result.ok) {
698
+ errors[providerId] = "Catalog shard unavailable; using cached metadata";
699
+ return;
700
+ }
701
+ if (manifest && manifest.shards[providerId] !== createHash2("sha256").update(JSON.stringify(result.value)).digest("hex")) {
702
+ errors[providerId] = "Catalog shard checksum mismatch; using cached metadata";
703
+ return;
704
+ }
705
+ let parsed = parseOfficialCatalog(result.value);
706
+ if (!parsed || parsed.models.length === 0 || parsed.models.some((model) => model.provider !== providerId)) {
707
+ errors[providerId] = "Invalid catalog shard; using cached metadata";
708
+ return;
709
+ }
710
+ replacements.set(providerId, parsed.models);
711
+ })), replacements.size === 0)
712
+ return { ...fallbackCatalog(bundled, cachePath), errors };
713
+ let catalog = mergeOfficialCatalogByProvider(officialCatalogBase(bundled, cachePath), replacements, typeof manifest?.generatedAt == "string" ? manifest.generatedAt : void 0);
714
+ return cachePath && writeOfficialCatalogCache(catalog, cachePath), { catalog, source: "github", ...Object.keys(errors).length ? { errors } : {} };
715
+ } catch {
716
+ return unavailable();
717
+ }
718
+ }
719
+
720
+ // packages/coding-agent/dist/core/catalog-merge.js
721
+ function mergeCatalogLayers(args) {
722
+ let byId = /* @__PURE__ */ new Map();
723
+ for (let model of args.bakedIn)
724
+ byId.set(model.id, model);
725
+ for (let model of args.live ?? [])
726
+ byId.set(model.id, model);
727
+ for (let model of args.user ?? [])
728
+ byId.set(model.id, model);
729
+ for (let model of args.official ?? [])
730
+ byId.set(model.id, model);
731
+ let seen = /* @__PURE__ */ new Set(), result = [];
732
+ for (let baked of args.bakedIn) {
733
+ let merged = byId.get(baked.id);
734
+ merged && (result.push(merged), seen.add(baked.id));
735
+ }
736
+ for (let model of [...args.live ?? [], ...args.user ?? [], ...args.official ?? []]) {
737
+ if (seen.has(model.id))
738
+ continue;
739
+ let winner = byId.get(model.id);
740
+ winner && (result.push(winner), seen.add(model.id));
741
+ }
742
+ let liveById = new Map((args.live ?? []).map((model) => [model.id, model])), pricedIds = new Set([...args.bakedIn, ...args.official ?? [], ...args.user ?? []].filter((model) => model.catalog?.pricing !== "unknown").map((model) => model.id));
743
+ return result.map((model) => {
744
+ let resolved = withXaiEffortMetadata(model);
745
+ model.catalog?.supplied.includes("thinkingLevelMap") || (resolved = withOpenAiEffortMetadata(resolved));
746
+ let live = liveById.get(model.id);
747
+ if (!live?.catalog)
748
+ return resolved;
749
+ resolved = { ...resolved, catalog: { ...live.catalog } };
750
+ for (let field of live.catalog.supplied)
751
+ Object.assign(resolved, { [field]: live[field] });
752
+ return (pricedIds.has(model.id) || live.catalog.supplied.includes("cost")) && delete resolved.catalog.pricing, resolved;
753
+ });
754
+ }
755
+ var CatalogOverlaySource = class {
756
+ official = /* @__PURE__ */ new Map();
757
+ user = /* @__PURE__ */ new Map();
758
+ live = /* @__PURE__ */ new Map();
759
+ setOfficial(models) {
760
+ this.official = groupByProvider(models);
761
+ }
762
+ setUser(models) {
763
+ this.user = groupByProvider(models);
764
+ }
765
+ setLive(providerId, models) {
766
+ this.live.set(providerId, [...models]);
767
+ }
768
+ officialFor(providerId) {
769
+ return this.official.get(providerId) ?? [];
770
+ }
771
+ userFor(providerId) {
772
+ return this.user.get(providerId) ?? [];
773
+ }
774
+ liveFor(providerId) {
775
+ return this.live.get(providerId) ?? [];
776
+ }
777
+ /** Codex's complete account catalog is authoritative for picker availability only. */
778
+ isAvailable(model) {
779
+ if (model.catalog?.hidden)
780
+ return !1;
781
+ let live = this.liveFor(model.provider);
782
+ return model.provider !== "openai-codex" || !live.length || live.some((row) => row.id === model.id && !row.catalog?.hidden);
783
+ }
784
+ };
785
+ function groupByProvider(models) {
786
+ let byProvider = /* @__PURE__ */ new Map();
787
+ for (let model of models) {
788
+ let list = byProvider.get(model.provider) ?? [];
789
+ list.push(model), byProvider.set(model.provider, list);
790
+ }
791
+ return byProvider;
792
+ }
793
+ function withCatalogOverlay(provider, overlay) {
794
+ let bakedIn = () => provider.getModels();
795
+ return {
796
+ ...provider,
797
+ getModels: () => mergeCatalogLayers({
798
+ bakedIn: bakedIn(),
799
+ live: overlay.liveFor(provider.id),
800
+ user: overlay.userFor(provider.id),
801
+ official: overlay.officialFor(provider.id)
802
+ })
803
+ };
804
+ }
805
+ function formatCatalogRefreshSummary(input) {
806
+ let parts = [];
807
+ if (input.official?.source === "github") {
808
+ let evicted = input.official.evictedUserRows > 0 ? `; replaced ${input.official.evictedUserRows} user-filled row` : "", plural = input.official.evictedUserRows === 1 ? "" : input.official.evictedUserRows > 0 ? "s" : "";
809
+ parts.push(`Official catalog updated (${input.official.modelCount} models)${evicted}${plural}.`);
810
+ }
811
+ let refreshed = [], failed = [];
812
+ for (let provider of input.providers)
813
+ if (provider.status === "ok") {
814
+ let added = provider.added ?? 0, total = provider.total ?? 0;
815
+ refreshed.push(added > 0 ? `${provider.id} (+${added})` : `${provider.id} (${total})`);
816
+ } else provider.status === "timeout" ? failed.push(`${provider.id} timed out (cached)`) : provider.status === "error" && failed.push(formatLiveProviderError(provider));
817
+ return refreshed.length > 0 ? parts.push(`Refreshed ${refreshed.join(", ")}.`) : input.providers.some((provider) => provider.status === "ok") && parts.push("Refreshed model catalogs."), failed.length > 0 && parts.push(`${failed.join("; ")}.`), input.asked && input.asked.length > 0 && parts.push(`Asked for missing metadata on ${input.asked.join(", ")}.`), input.extraDefaults && input.extraDefaults > 0 && parts.push(`+${input.extraDefaults} more using defaults.`), input.ollama && parts.push(input.ollama), parts.length === 0 ? "Model catalogs refreshed." : parts.join(" ");
818
+ }
819
+ function formatLiveProviderError(provider) {
820
+ return provider.id === "xai" && provider.error && /invalid_grant|refresh token revoked/i.test(provider.error) && !/timed out|aborted|cancelled|ECONN|ENOTFOUND|network/i.test(provider.error) ? "xai login expired (run /login xai)" : provider.error ? `${provider.id} failed (${provider.error})` : `${provider.id} failed`;
821
+ }
822
+ function knownModelKeys(bakedIn, official, user) {
823
+ let keys = new Set(official);
824
+ for (let key of user)
825
+ keys.add(key);
826
+ for (let model of bakedIn)
827
+ keys.add(modelKey(model.provider, model.id));
828
+ return keys;
829
+ }
830
+
831
+ // packages/coding-agent/dist/core/grok-cli-auth.js
832
+ var import_proper_lockfile2 = __toESM(require_proper_lockfile(), 1);
833
+ import { chmodSync as chmodSync2, existsSync as existsSync3, mkdirSync as mkdirSync3, readFileSync as readFileSync3, renameSync as renameSync3, unlinkSync as unlinkSync3, writeFileSync as writeFileSync3 } from "node:fs";
834
+ import { homedir } from "node:os";
835
+ import { dirname as dirname3, join as join3 } from "node:path";
836
+ var XAI_PROVIDER_ID = "xai", XAI_GROK_CLI_CLIENT_ID = "b1a00492-073a-47ea-816f-4c329264a828", REFRESH_SKEW_MS = 300 * 1e3, AUTH_FILE_WRITE_OPTIONS2 = { encoding: "utf-8", mode: 384 };
837
+ function grokHomeDir(grokHome) {
838
+ if (grokHome)
839
+ return grokHome;
840
+ let fromEnv = process.env.GROK_HOME?.trim();
841
+ return fromEnv || join3(homedir(), ".grok");
842
+ }
843
+ function grokAuthPath(grokHome) {
844
+ return join3(grokHomeDir(grokHome), "auth.json");
845
+ }
846
+ function grokOidcEntryKey(clientId = XAI_GROK_CLI_CLIENT_ID) {
847
+ return `https://auth.x.ai::${clientId}`;
848
+ }
849
+ function parseGrokExpiresAt(value) {
850
+ if (typeof value == "number" && Number.isFinite(value) && value > 0)
851
+ return value < 1e12 ? Math.round(value * 1e3) : Math.round(value);
852
+ if (typeof value == "string" && value.trim()) {
853
+ let numeric = Number(value);
854
+ if (Number.isFinite(numeric) && numeric > 0)
855
+ return numeric < 1e12 ? Math.round(numeric * 1e3) : Math.round(numeric);
856
+ let parsed = Date.parse(value);
857
+ if (Number.isFinite(parsed))
858
+ return parsed;
859
+ }
860
+ }
861
+ function formatGrokExpiresAt(expires) {
862
+ return new Date(expires).toISOString();
863
+ }
864
+ function grokEntryToOAuth(entry) {
865
+ if (!entry || typeof entry != "object" || Array.isArray(entry))
866
+ return;
867
+ let record = entry, access = typeof record.key == "string" ? record.key : void 0, refresh = typeof record.refresh_token == "string" ? record.refresh_token : void 0, expires = parseGrokExpiresAt(record.expires_at);
868
+ if (!(!access || !refresh || expires === void 0))
869
+ return { type: "oauth", access, refresh, expires };
870
+ }
871
+ function readGrokCliXaiOAuth(options = {}) {
872
+ try {
873
+ let raw = readFileSync3(grokAuthPath(options.grokHome), "utf-8"), parsed = JSON.parse(raw);
874
+ return !parsed || typeof parsed != "object" || Array.isArray(parsed) ? void 0 : grokEntryToOAuth(parsed[grokOidcEntryKey()]);
875
+ } catch {
876
+ return;
877
+ }
878
+ }
879
+ function hasGrokCliXaiAuth(options = {}) {
880
+ return readGrokCliXaiOAuth(options) !== void 0;
881
+ }
882
+ function chooseXaiOAuth(lunr, grok) {
883
+ if (lunr?.type === "api_key")
884
+ return lunr;
885
+ let lunrOAuth = lunr?.type === "oauth" ? lunr : void 0;
886
+ if (lunrOAuth && grok) {
887
+ if (lunrOAuth.refresh === grok.refresh)
888
+ return grok.expires >= lunrOAuth.expires ? grok : lunrOAuth;
889
+ let now = Date.now(), lunrLive = now < lunrOAuth.expires, grokLive = now < grok.expires;
890
+ return grokLive && !lunrLive ? grok : lunrLive && !grokLive ? lunrOAuth : !lunrLive && !grokLive && grok.expires >= lunrOAuth.expires ? grok : lunrOAuth;
891
+ }
892
+ return grok ?? lunrOAuth ?? lunr;
893
+ }
894
+ function oauthRefreshFailed(error) {
895
+ let parts = [], current = error, seen = /* @__PURE__ */ new Set();
896
+ for (; current && typeof current == "object" && !seen.has(current); ) {
897
+ if (seen.add(current), current instanceof Error) {
898
+ parts.push(current.message), current = current.cause;
899
+ continue;
900
+ }
901
+ break;
902
+ }
903
+ let chain = parts.join(" ");
904
+ return /timed out|aborted|cancelled|ECONN|ENOTFOUND|network/i.test(chain) ? !1 : /invalid_grant|refresh token revoked/i.test(chain);
905
+ }
906
+ function shouldAdopt(lunr, chosen) {
907
+ return !chosen || chosen.type !== "oauth" ? !1 : !lunr || lunr.type !== "oauth" ? !0 : lunr.access !== chosen.access || lunr.refresh !== chosen.refresh;
908
+ }
909
+ function writeAuthFileAtomic2(authPath, contents) {
910
+ let tmp = `${authPath}.${process.pid}.${Date.now()}.tmp`;
911
+ writeFileSync3(tmp, contents, AUTH_FILE_WRITE_OPTIONS2);
912
+ try {
913
+ chmodSync2(tmp, 384);
914
+ } catch {
915
+ }
916
+ try {
917
+ if (process.platform === "win32" && existsSync3(authPath)) {
918
+ writeFileSync3(authPath, contents, AUTH_FILE_WRITE_OPTIONS2), chmodSync2(authPath, 384);
919
+ return;
920
+ }
921
+ renameSync3(tmp, authPath);
922
+ try {
923
+ chmodSync2(authPath, 384);
924
+ } catch {
925
+ }
926
+ } finally {
927
+ try {
928
+ unlinkSync3(tmp);
929
+ } catch {
930
+ }
931
+ }
932
+ }
933
+ function acquireGrokLock(authPath) {
934
+ let lastError;
935
+ for (let attempt = 1; attempt <= 10; attempt++)
936
+ try {
937
+ return import_proper_lockfile2.default.lockSync(authPath, { realpath: !1, stale: 12e4 });
938
+ } catch (error) {
939
+ if ((typeof error == "object" && error !== null && "code" in error ? String(error.code) : void 0) !== "ELOCKED" || attempt === 10)
940
+ throw error;
941
+ lastError = error;
942
+ let start = Date.now();
943
+ for (; Date.now() - start < 20; )
944
+ ;
945
+ }
946
+ throw lastError ?? new Error("Failed to acquire Grok CLI auth lock");
947
+ }
948
+ function writeGrokCliXaiOAuth(credential, options = {}) {
949
+ let authPath = grokAuthPath(options.grokHome);
950
+ if (options.onlyIfFileExists !== !1 && !existsSync3(authPath))
951
+ return !1;
952
+ let dir = dirname3(authPath);
953
+ existsSync3(dir) || mkdirSync3(dir, { recursive: !0, mode: 448 }), existsSync3(authPath) || writeAuthFileAtomic2(authPath, `{}
954
+ `);
955
+ let release;
956
+ try {
957
+ release = acquireGrokLock(authPath);
958
+ let data = {};
959
+ try {
960
+ let parsed = JSON.parse(readFileSync3(authPath, "utf-8"));
961
+ if (parsed && typeof parsed == "object" && !Array.isArray(parsed))
962
+ data = parsed;
963
+ else
964
+ return !1;
965
+ } catch {
966
+ return !1;
967
+ }
968
+ let key = grokOidcEntryKey(), previous = data[key] && typeof data[key] == "object" && !Array.isArray(data[key]) ? data[key] : {}, existing = grokEntryToOAuth(previous);
969
+ return existing && existing.refresh !== credential.refresh && existing.expires > credential.expires + REFRESH_SKEW_MS ? !1 : (data[key] = {
970
+ ...previous,
971
+ key: credential.access,
972
+ refresh_token: credential.refresh,
973
+ expires_at: formatGrokExpiresAt(credential.expires)
974
+ }, writeAuthFileAtomic2(authPath, `${JSON.stringify(data, null, 2)}
975
+ `), !0);
976
+ } finally {
977
+ if (release)
978
+ try {
979
+ release();
980
+ } catch {
981
+ }
982
+ }
983
+ }
984
+ function wrapXaiGrokCliCredentials(store, options = {}) {
985
+ let grokHome = options.grokHome;
986
+ return {
987
+ async read(providerId) {
988
+ let stored = await store.read(providerId);
989
+ if (providerId !== XAI_PROVIDER_ID || stored?.type === "api_key")
990
+ return stored;
991
+ let grok = readGrokCliXaiOAuth({ grokHome }), chosen = chooseXaiOAuth(stored, grok);
992
+ if (shouldAdopt(stored, chosen) && chosen?.type === "oauth")
993
+ try {
994
+ await store.modify(providerId, async (current) => {
995
+ if (current?.type === "api_key")
996
+ return;
997
+ let latestGrok = readGrokCliXaiOAuth({ grokHome }), latestChosen = chooseXaiOAuth(current, latestGrok);
998
+ if (shouldAdopt(current, latestChosen) && latestChosen?.type === "oauth")
999
+ return latestChosen;
1000
+ });
1001
+ } catch {
1002
+ }
1003
+ return chosen;
1004
+ },
1005
+ async list() {
1006
+ let entries = new Map((await store.list()).map((entry) => [entry.providerId, entry]));
1007
+ return !entries.has(XAI_PROVIDER_ID) && hasGrokCliXaiAuth({ grokHome }) && entries.set(XAI_PROVIDER_ID, { providerId: XAI_PROVIDER_ID, type: "oauth" }), [...entries.values()];
1008
+ },
1009
+ modify(providerId, fn) {
1010
+ return providerId !== XAI_PROVIDER_ID ? store.modify(providerId, fn) : store.modify(providerId, async (lunrCurrent) => {
1011
+ if (lunrCurrent?.type === "api_key")
1012
+ return fn(lunrCurrent);
1013
+ let grok = readGrokCliXaiOAuth({ grokHome }), chosen = chooseXaiOAuth(lunrCurrent, grok), next;
1014
+ try {
1015
+ next = await fn(chosen);
1016
+ } catch (error) {
1017
+ let retryGrok = readGrokCliXaiOAuth({ grokHome });
1018
+ if (!(oauthRefreshFailed(error) && retryGrok && !(chosen?.type === "oauth" && retryGrok.refresh === chosen.refresh)))
1019
+ throw error;
1020
+ try {
1021
+ next = await fn(retryGrok);
1022
+ } catch {
1023
+ throw error;
1024
+ }
1025
+ }
1026
+ if (next?.type === "oauth")
1027
+ try {
1028
+ writeGrokCliXaiOAuth(next, { grokHome, onlyIfFileExists: !0 });
1029
+ } catch {
1030
+ }
1031
+ return next;
1032
+ });
1033
+ },
1034
+ delete(providerId) {
1035
+ return store.delete(providerId);
1036
+ }
1037
+ };
1038
+ }
1039
+
1040
+ // packages/coding-agent/dist/core/live-catalog.js
1041
+ import { isOpenAiChatModel, parseOpenAiGptVersion } from "@ashx-j/lunr-ai";
1042
+ import { codexModelsUrl, resolveCodexCatalogVersion } from "@ashx-j/lunr-ai/catalog/codex";
1043
+ import { normalizeCatalogPricing } from "@ashx-j/lunr-ai/catalog/metadata";
1044
+
1045
+ // packages/coding-agent/dist/core/codex-catalog.js
1046
+ import { parseCodexCatalog } from "@ashx-j/lunr-ai/catalog/codex";
1047
+ function discoverCodexModels(payload, baseUrl) {
1048
+ return parseCodexCatalog(payload, baseUrl).map((model) => ({
1049
+ model,
1050
+ supplied: {
1051
+ name: model.catalog.supplied.includes("name"),
1052
+ contextWindow: model.catalog.supplied.includes("contextWindow"),
1053
+ maxTokens: model.catalog.supplied.includes("maxTokens"),
1054
+ input: model.catalog.supplied.includes("input"),
1055
+ cost: !1,
1056
+ reasoning: model.catalog.supplied.includes("reasoning")
1057
+ }
1058
+ }));
1059
+ }
1060
+
1061
+ // packages/coding-agent/dist/core/live-catalog.js
1062
+ var LIVE_CATALOG_TIMEOUT_MS = 4e3;
1063
+ var DEFAULT_CONTEXT_WINDOW = 128e3, DEFAULT_MAX_TOKENS = 8192, LIVE_LIST_PROVIDER_IDS = [
1064
+ "openai-codex",
1065
+ "xai",
1066
+ "openrouter",
1067
+ "qwen-cloud",
1068
+ "qwen-cloud-cn",
1069
+ "groq",
1070
+ "openai",
1071
+ "deepseek"
1072
+ ], LIVE_LIST_PROVIDER_SET = new Set(LIVE_LIST_PROVIDER_IDS);
1073
+ var ZERO_COST2 = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, NONE_SUPPLIED = {
1074
+ contextWindow: !1,
1075
+ maxTokens: !1,
1076
+ input: !1,
1077
+ name: !1,
1078
+ cost: !1,
1079
+ reasoning: !1
1080
+ };
1081
+ function isRecord2(value) {
1082
+ return typeof value == "object" && value !== null && !Array.isArray(value);
1083
+ }
1084
+ function asFiniteNumber2(value) {
1085
+ if (typeof value == "number" && Number.isFinite(value))
1086
+ return value;
1087
+ if (typeof value == "string" && value.trim()) {
1088
+ let parsed = Number(value);
1089
+ if (Number.isFinite(parsed))
1090
+ return parsed;
1091
+ }
1092
+ }
1093
+ function roundCost(value) {
1094
+ return Number(value.toFixed(6));
1095
+ }
1096
+ function modelsListUrl(baseUrl) {
1097
+ return `${baseUrl.replace(/\/+$/u, "")}/models`;
1098
+ }
1099
+ function credentialAuthHeaders(credential) {
1100
+ return credential ? credential.type === "api_key" && credential.key ? { Authorization: `Bearer ${credential.key}` } : credential.type === "oauth" && typeof credential.access == "string" && credential.access ? { Authorization: `Bearer ${credential.access}` } : {} : {};
1101
+ }
1102
+ function parseOpenAIModelsList(value) {
1103
+ let entries = isRecord2(value) && Array.isArray(value.data) ? value.data : Array.isArray(value) ? value : [], rows = [];
1104
+ for (let entry of entries) {
1105
+ if (typeof entry == "string" && entry.trim()) {
1106
+ rows.push({ id: entry.trim() });
1107
+ continue;
1108
+ }
1109
+ isRecord2(entry) && typeof entry.id == "string" && entry.id.trim() && rows.push(entry);
1110
+ }
1111
+ return rows;
1112
+ }
1113
+ function firstBakedInModel(models) {
1114
+ return models[0];
1115
+ }
1116
+ function selectLiveTemplate(providerId, id, bakedIn) {
1117
+ let exact = bakedIn.find((model) => model.id === id);
1118
+ if (exact)
1119
+ return exact;
1120
+ let version = parseOpenAiGptVersion(id);
1121
+ if (providerId !== "openai" || !version || version.major < 5 || isOpenAiChatModel(id))
1122
+ return firstBakedInModel(bakedIn);
1123
+ let reasoning;
1124
+ for (let model of bakedIn)
1125
+ model.reasoning && parseOpenAiGptVersion(model.id) && (reasoning = model);
1126
+ return reasoning ?? firstBakedInModel(bakedIn);
1127
+ }
1128
+ function uniqueApis(models) {
1129
+ let seen = /* @__PURE__ */ new Set(), apis = [];
1130
+ for (let model of models)
1131
+ seen.has(model.api) || (seen.add(model.api), apis.push(model.api));
1132
+ return apis;
1133
+ }
1134
+ function synthesizeLiveModel(id, template, raw = {}) {
1135
+ let name = typeof raw.name == "string" && raw.name.trim() ? raw.name.trim() : id, exact = id === template.id, discovery = {
1136
+ model: {
1137
+ id,
1138
+ name,
1139
+ api: template.api,
1140
+ provider: template.provider,
1141
+ baseUrl: template.baseUrl,
1142
+ reasoning: template.reasoning,
1143
+ input: exact ? template.input : ["text"],
1144
+ cost: ZERO_COST2,
1145
+ contextWindow: DEFAULT_CONTEXT_WINDOW,
1146
+ maxTokens: DEFAULT_MAX_TOKENS,
1147
+ compat: template.compat,
1148
+ thinkingLevelMap: exact ? template.thinkingLevelMap : void 0,
1149
+ catalog: { source: "provider", supplied: typeof raw.name == "string" ? ["name"] : [], pricing: "unknown" }
1150
+ },
1151
+ supplied: {
1152
+ ...NONE_SUPPLIED,
1153
+ name: typeof raw.name == "string" && raw.name.trim().length > 0
1154
+ }
1155
+ }, context = asFiniteNumber2(raw.context_window ?? raw.context_length ?? raw.max_context_length), output = asFiniteNumber2(raw.max_output_tokens ?? raw.max_completion_tokens);
1156
+ if (context && context > 0 && (discovery.model.contextWindow = context, discovery.supplied.contextWindow = !0), output && output > 0 && (discovery.model.maxTokens = output, discovery.supplied.maxTokens = !0), typeof raw.reasoning == "boolean" && (discovery.model.reasoning = raw.reasoning, discovery.supplied.reasoning = !0), Array.isArray(raw.input_modalities)) {
1157
+ let input = raw.input_modalities.filter((value) => value === "text" || value === "image");
1158
+ input.length && (discovery.model.input = input, discovery.supplied.input = !0);
1159
+ }
1160
+ return discovery.model.catalog.supplied = Object.entries(discovery.supplied).filter(([, value]) => value).map(([field]) => field), discovery;
1161
+ }
1162
+ function mapOpenRouterModel(raw, template) {
1163
+ let id = typeof raw.id == "string" ? raw.id.trim() : "";
1164
+ if (!id)
1165
+ return;
1166
+ let supported = Array.isArray(raw.supported_parameters) ? raw.supported_parameters : [];
1167
+ if (!supported.includes("tools"))
1168
+ return;
1169
+ let architecture = isRecord2(raw.architecture) ? raw.architecture : void 0, modality = typeof architecture?.modality == "string" ? architecture.modality : "", input = ["text"];
1170
+ modality.includes("image") && input.push("image");
1171
+ let pricing = isRecord2(raw.pricing) ? raw.pricing : void 0, inputCost = roundCost((asFiniteNumber2(pricing?.prompt) ?? 0) * 1e6), outputCost = roundCost((asFiniteNumber2(pricing?.completion) ?? 0) * 1e6), cacheReadCost = roundCost((asFiniteNumber2(pricing?.input_cache_read) ?? 0) * 1e6), cacheWriteCost = roundCost((asFiniteNumber2(pricing?.input_cache_write) ?? 0) * 1e6), topProvider = isRecord2(raw.top_provider) ? raw.top_provider : void 0, contextWindow = asFiniteNumber2(topProvider?.context_length) ?? asFiniteNumber2(raw.context_length), maxTokens = asFiniteNumber2(topProvider?.max_completion_tokens) ?? asFiniteNumber2(raw.max_completion_tokens), name = typeof raw.name == "string" && raw.name.trim() ? raw.name.trim() : id;
1172
+ return {
1173
+ model: {
1174
+ id,
1175
+ name,
1176
+ api: template.api,
1177
+ provider: template.provider,
1178
+ baseUrl: template.baseUrl,
1179
+ reasoning: supported.includes("reasoning") || template.reasoning,
1180
+ input,
1181
+ cost: {
1182
+ input: inputCost,
1183
+ output: outputCost,
1184
+ cacheRead: cacheReadCost,
1185
+ cacheWrite: cacheWriteCost
1186
+ },
1187
+ contextWindow: contextWindow ?? DEFAULT_CONTEXT_WINDOW,
1188
+ maxTokens: maxTokens ?? DEFAULT_MAX_TOKENS,
1189
+ compat: template.compat,
1190
+ thinkingLevelMap: template.thinkingLevelMap
1191
+ },
1192
+ supplied: {
1193
+ contextWindow: contextWindow !== void 0,
1194
+ maxTokens: maxTokens !== void 0,
1195
+ input: !0,
1196
+ name: typeof raw.name == "string" && raw.name.trim().length > 0,
1197
+ cost: asFiniteNumber2(pricing?.prompt) !== void 0 && asFiniteNumber2(pricing?.completion) !== void 0,
1198
+ reasoning: supported.includes("reasoning")
1199
+ }
1200
+ };
1201
+ }
1202
+ function discoverLiveModels(providerId, payload, bakedIn) {
1203
+ if (providerId === "openai-codex")
1204
+ return discoverCodexModels(payload, bakedIn[0]?.baseUrl ?? "https://chatgpt.com/backend-api");
1205
+ let fallback = firstBakedInModel(bakedIn);
1206
+ if (!fallback)
1207
+ return [];
1208
+ let rows = parseOpenAIModelsList(payload), discoveries = [];
1209
+ for (let raw of rows) {
1210
+ let id = typeof raw.id == "string" ? raw.id.trim() : "";
1211
+ if (!id || raw.tool_call === !1 || raw.type === "embedding" || providerId === "openai" && /^(?:text-embedding-|tts-|whisper-|dall-e-|gpt-image-|gpt-audio|gpt-realtime|sora-|.*moderation)/i.test(id))
1212
+ continue;
1213
+ let template = { ...selectLiveTemplate(providerId, id, bakedIn) ?? fallback, provider: providerId };
1214
+ if (providerId === "openrouter") {
1215
+ let mapped = mapOpenRouterModel(raw, template);
1216
+ mapped && (mapped.model.catalog = {
1217
+ source: "provider",
1218
+ ...mapped.supplied.cost ? {} : { pricing: "unknown" },
1219
+ supplied: Object.entries(mapped.supplied).filter(([, supplied]) => supplied).map(([key]) => key)
1220
+ }, mapped.model = normalizeCatalogPricing(mapped.model), mapped.model.catalog?.pricing === "unknown" && (mapped.supplied.cost = !1), discoveries.push(mapped));
1221
+ continue;
1222
+ }
1223
+ discoveries.push(synthesizeLiveModel(id, template, raw));
1224
+ }
1225
+ return discoveries;
1226
+ }
1227
+ function missingLiveFields(supplied) {
1228
+ let missing = [];
1229
+ return supplied.contextWindow || missing.push("contextWindow"), supplied.maxTokens || missing.push("maxTokens"), supplied.input || missing.push("input"), missing;
1230
+ }
1231
+ function isLiveModelIncomplete(discovery, knownKeys) {
1232
+ return knownKeys.has(modelKey(discovery.model.provider, discovery.model.id)) ? !1 : missingLiveFields(discovery.supplied).length > 0;
1233
+ }
1234
+ function collectIncompleteLiveModels(discoveries, bakedIn, knownKeys) {
1235
+ let apis = uniqueApis(bakedIn), incomplete = [];
1236
+ for (let discovery of discoveries)
1237
+ isLiveModelIncomplete(discovery, knownKeys) && incomplete.push({
1238
+ provider: discovery.model.provider,
1239
+ id: discovery.model.id,
1240
+ name: discovery.model.name,
1241
+ missing: missingLiveFields(discovery.supplied),
1242
+ draft: discovery.model,
1243
+ availableApis: apis
1244
+ });
1245
+ return incomplete;
1246
+ }
1247
+ function buildLiveOverlay(bakedIn, discoveries) {
1248
+ let bakedById = new Map(bakedIn.map((model) => [model.id, model])), overlay = [];
1249
+ for (let discovery of discoveries) {
1250
+ let baked = bakedById.get(discovery.model.id);
1251
+ if (!baked) {
1252
+ overlay.push(discovery.model);
1253
+ continue;
1254
+ }
1255
+ overlay.push({
1256
+ ...baked,
1257
+ catalog: discovery.model.catalog,
1258
+ thinkingLevelMap: discovery.model.catalog?.supplied.includes("thinkingLevelMap") ? discovery.model.thinkingLevelMap : baked.thinkingLevelMap,
1259
+ name: discovery.supplied.name ? discovery.model.name : baked.name,
1260
+ contextWindow: discovery.supplied.contextWindow ? discovery.model.contextWindow : baked.contextWindow,
1261
+ maxTokens: discovery.supplied.maxTokens ? discovery.model.maxTokens : baked.maxTokens,
1262
+ input: discovery.supplied.input ? discovery.model.input : baked.input,
1263
+ cost: discovery.supplied.cost ? discovery.model.cost : baked.cost,
1264
+ reasoning: discovery.supplied.reasoning ? discovery.model.reasoning : baked.reasoning
1265
+ });
1266
+ }
1267
+ return overlay;
1268
+ }
1269
+ async function fetchLiveProviderModels(options) {
1270
+ let empty = {
1271
+ providerId: options.providerId,
1272
+ status: "skipped",
1273
+ discoveries: [],
1274
+ added: 0,
1275
+ total: 0,
1276
+ incomplete: []
1277
+ };
1278
+ if (!firstBakedInModel(options.bakedIn) && options.providerId !== "openai-codex" || !options.baseUrl)
1279
+ return empty;
1280
+ let timeoutMs = options.timeoutMs ?? LIVE_CATALOG_TIMEOUT_MS, controller = new AbortController(), timedOut = !1, timer = setTimeout(() => {
1281
+ timedOut = !0, controller.abort();
1282
+ }, timeoutMs), onParentAbort = () => controller.abort();
1283
+ options.signal?.addEventListener("abort", onParentAbort, { once: !0 }), options.signal?.aborted && controller.abort();
1284
+ try {
1285
+ let fetchImpl = options.fetchImpl ?? fetch, codex = options.providerId === "openai-codex", accountId = options.credential?.type === "oauth" && typeof options.credential.accountId == "string" ? options.credential.accountId : void 0, discoveryClientVersion = options.discoveryClientVersion, payload = await Promise.race([
1286
+ (async () => {
1287
+ codex && (discoveryClientVersion = await resolveCodexCatalogVersion(fetchImpl, controller.signal, discoveryClientVersion));
1288
+ let response = await fetchImpl(codex ? codexModelsUrl(options.baseUrl, discoveryClientVersion) : modelsListUrl(options.baseUrl), {
1289
+ headers: {
1290
+ accept: "application/json",
1291
+ "User-Agent": getPiUserAgent(VERSION),
1292
+ ...credentialAuthHeaders(options.credential),
1293
+ ...accountId ? { "ChatGPT-Account-ID": accountId } : {}
1294
+ },
1295
+ signal: controller.signal
1296
+ });
1297
+ if (!response.ok)
1298
+ throw new Error(`HTTP ${response.status}`);
1299
+ return response.json();
1300
+ })(),
1301
+ new Promise((_, reject) => {
1302
+ let abortError = new Error("The operation was aborted");
1303
+ abortError.name = "AbortError", controller.signal.addEventListener("abort", () => reject(abortError), { once: !0 }), controller.signal.aborted && reject(abortError);
1304
+ })
1305
+ ]), discoveries = codex ? discoverCodexModels(payload, options.baseUrl) : discoverLiveModels(options.providerId, payload, options.bakedIn);
1306
+ if (!discoveries.length)
1307
+ throw new Error("No usable models returned; retaining cached models");
1308
+ let bakedIds = new Set(options.bakedIn.map((model) => model.id)), added = discoveries.filter((discovery) => !bakedIds.has(discovery.model.id)).length;
1309
+ return {
1310
+ providerId: options.providerId,
1311
+ discoveryClientVersion,
1312
+ status: "ok",
1313
+ discoveries,
1314
+ added,
1315
+ total: discoveries.length,
1316
+ incomplete: collectIncompleteLiveModels(discoveries, options.bakedIn, options.knownKeys)
1317
+ };
1318
+ } catch (error) {
1319
+ return options.signal?.aborted && !timedOut ? { ...empty, status: "skipped", error: "aborted" } : timedOut || error instanceof Error && error.name === "AbortError" ? { ...empty, status: "timeout", error: "timed out" } : {
1320
+ ...empty,
1321
+ status: "error",
1322
+ error: error instanceof Error ? error.message : String(error)
1323
+ };
1324
+ } finally {
1325
+ clearTimeout(timer), options.signal?.removeEventListener("abort", onParentAbort);
1326
+ }
1327
+ }
1328
+
1329
+ // packages/coding-agent/dist/core/model-config.js
1330
+ import { readFile } from "node:fs/promises";
1331
+ import { Type } from "typebox";
1332
+ import { Compile } from "typebox/compile";
1333
+
1334
+ // packages/coding-agent/dist/utils/json.js
1335
+ function stripJsonComments(input) {
1336
+ return input.replace(/"(?:\\.|[^"\\])*"|\/\/[^\n]*/g, (m) => m[0] === '"' ? m : "").replace(/"(?:\\.|[^"\\])*"|,(\s*[}\]])/g, (m, tail) => tail ?? (m[0] === '"' ? m : ""));
1337
+ }
1338
+
1339
+ // packages/coding-agent/dist/core/model-config.js
1340
+ var PercentileCutoffsSchema = Type.Object({
1341
+ p50: Type.Optional(Type.Number()),
1342
+ p75: Type.Optional(Type.Number()),
1343
+ p90: Type.Optional(Type.Number()),
1344
+ p99: Type.Optional(Type.Number())
1345
+ }), OpenRouterRoutingSchema = Type.Object({
1346
+ allow_fallbacks: Type.Optional(Type.Boolean()),
1347
+ require_parameters: Type.Optional(Type.Boolean()),
1348
+ data_collection: Type.Optional(Type.Union([Type.Literal("deny"), Type.Literal("allow")])),
1349
+ zdr: Type.Optional(Type.Boolean()),
1350
+ enforce_distillable_text: Type.Optional(Type.Boolean()),
1351
+ order: Type.Optional(Type.Array(Type.String())),
1352
+ only: Type.Optional(Type.Array(Type.String())),
1353
+ ignore: Type.Optional(Type.Array(Type.String())),
1354
+ quantizations: Type.Optional(Type.Array(Type.String())),
1355
+ sort: Type.Optional(Type.Union([
1356
+ Type.String(),
1357
+ Type.Object({
1358
+ by: Type.Optional(Type.String()),
1359
+ partition: Type.Optional(Type.Union([Type.String(), Type.Null()]))
1360
+ })
1361
+ ])),
1362
+ max_price: Type.Optional(Type.Object({
1363
+ prompt: Type.Optional(Type.Union([Type.Number(), Type.String()])),
1364
+ completion: Type.Optional(Type.Union([Type.Number(), Type.String()])),
1365
+ image: Type.Optional(Type.Union([Type.Number(), Type.String()])),
1366
+ audio: Type.Optional(Type.Union([Type.Number(), Type.String()])),
1367
+ request: Type.Optional(Type.Union([Type.Number(), Type.String()]))
1368
+ })),
1369
+ preferred_min_throughput: Type.Optional(Type.Union([Type.Number(), PercentileCutoffsSchema])),
1370
+ preferred_max_latency: Type.Optional(Type.Union([Type.Number(), PercentileCutoffsSchema]))
1371
+ }), VercelGatewayRoutingSchema = Type.Object({
1372
+ only: Type.Optional(Type.Array(Type.String())),
1373
+ order: Type.Optional(Type.Array(Type.String()))
1374
+ }), ThinkingLevelMapValueSchema = Type.Union([Type.String(), Type.Null()]), ThinkingLevelMapSchema = Type.Object({
1375
+ off: Type.Optional(ThinkingLevelMapValueSchema),
1376
+ minimal: Type.Optional(ThinkingLevelMapValueSchema),
1377
+ low: Type.Optional(ThinkingLevelMapValueSchema),
1378
+ medium: Type.Optional(ThinkingLevelMapValueSchema),
1379
+ high: Type.Optional(ThinkingLevelMapValueSchema),
1380
+ xhigh: Type.Optional(ThinkingLevelMapValueSchema),
1381
+ max: Type.Optional(ThinkingLevelMapValueSchema)
1382
+ }), ChatTemplateKwargScalarSchema = Type.Union([Type.String(), Type.Number(), Type.Boolean(), Type.Null()]), ChatTemplateKwargVariableSchema = Type.Object({
1383
+ $var: Type.Union([Type.Literal("thinking.enabled"), Type.Literal("thinking.effort")]),
1384
+ omitWhenOff: Type.Optional(Type.Boolean())
1385
+ }), ChatTemplateKwargSchema = Type.Union([ChatTemplateKwargScalarSchema, ChatTemplateKwargVariableSchema]), OpenAICompletionsCompatSchema = Type.Object({
1386
+ supportsStore: Type.Optional(Type.Boolean()),
1387
+ supportsDeveloperRole: Type.Optional(Type.Boolean()),
1388
+ supportsReasoningEffort: Type.Optional(Type.Boolean()),
1389
+ supportsUsageInStreaming: Type.Optional(Type.Boolean()),
1390
+ maxTokensField: Type.Optional(Type.Union([Type.Literal("max_completion_tokens"), Type.Literal("max_tokens")])),
1391
+ requiresToolResultName: Type.Optional(Type.Boolean()),
1392
+ requiresAssistantAfterToolResult: Type.Optional(Type.Boolean()),
1393
+ requiresThinkingAsText: Type.Optional(Type.Boolean()),
1394
+ requiresReasoningContentOnAssistantMessages: Type.Optional(Type.Boolean()),
1395
+ thinkingFormat: Type.Optional(Type.Union([
1396
+ Type.Literal("openai"),
1397
+ Type.Literal("openrouter"),
1398
+ Type.Literal("together"),
1399
+ Type.Literal("deepseek"),
1400
+ Type.Literal("zai"),
1401
+ Type.Literal("qwen"),
1402
+ Type.Literal("chat-template"),
1403
+ Type.Literal("qwen-chat-template"),
1404
+ Type.Literal("string-thinking"),
1405
+ Type.Literal("ant-ling")
1406
+ ])),
1407
+ chatTemplateKwargs: Type.Optional(Type.Record(Type.String(), ChatTemplateKwargSchema)),
1408
+ cacheControlFormat: Type.Optional(Type.Literal("anthropic")),
1409
+ openRouterRouting: Type.Optional(OpenRouterRoutingSchema),
1410
+ vercelGatewayRouting: Type.Optional(VercelGatewayRoutingSchema),
1411
+ supportsStrictMode: Type.Optional(Type.Boolean()),
1412
+ sendSessionAffinityHeaders: Type.Optional(Type.Boolean()),
1413
+ deferredToolsMode: Type.Optional(Type.Literal("kimi")),
1414
+ sessionAffinityFormat: Type.Optional(Type.Union([Type.Literal("openai"), Type.Literal("openai-nosession"), Type.Literal("openrouter")])),
1415
+ supportsLongCacheRetention: Type.Optional(Type.Boolean())
1416
+ }), OpenAIResponsesCompatSchema = Type.Object({
1417
+ supportsDeveloperRole: Type.Optional(Type.Boolean()),
1418
+ sessionAffinityFormat: Type.Optional(Type.Union([Type.Literal("openai"), Type.Literal("openai-nosession"), Type.Literal("openrouter")])),
1419
+ supportsLongCacheRetention: Type.Optional(Type.Boolean()),
1420
+ supportsToolSearch: Type.Optional(Type.Boolean())
1421
+ }), AnthropicMessagesCompatSchema = Type.Object({
1422
+ supportsEagerToolInputStreaming: Type.Optional(Type.Boolean()),
1423
+ supportsLongCacheRetention: Type.Optional(Type.Boolean()),
1424
+ sendSessionAffinityHeaders: Type.Optional(Type.Boolean()),
1425
+ supportsCacheControlOnTools: Type.Optional(Type.Boolean()),
1426
+ forceAdaptiveThinking: Type.Optional(Type.Boolean()),
1427
+ supportsToolReferences: Type.Optional(Type.Boolean())
1428
+ }), ProviderCompatSchema = Type.Union([
1429
+ OpenAICompletionsCompatSchema,
1430
+ OpenAIResponsesCompatSchema,
1431
+ AnthropicMessagesCompatSchema
1432
+ ]), ModelCostRatesSchema = {
1433
+ input: Type.Number(),
1434
+ output: Type.Number(),
1435
+ cacheRead: Type.Number(),
1436
+ cacheWrite: Type.Number()
1437
+ }, ModelCostTierSchema = Type.Object({
1438
+ inputTokensAbove: Type.Number(),
1439
+ ...ModelCostRatesSchema
1440
+ }), ModelCostSchema = Type.Object({
1441
+ ...ModelCostRatesSchema,
1442
+ tiers: Type.Optional(Type.Array(ModelCostTierSchema))
1443
+ }), ModelDefinitionSchema = Type.Object({
1444
+ id: Type.String({ minLength: 1 }),
1445
+ name: Type.Optional(Type.String({ minLength: 1 })),
1446
+ api: Type.Optional(Type.String({ minLength: 1 })),
1447
+ baseUrl: Type.Optional(Type.String({ minLength: 1 })),
1448
+ reasoning: Type.Optional(Type.Boolean()),
1449
+ thinkingLevelMap: Type.Optional(ThinkingLevelMapSchema),
1450
+ input: Type.Optional(Type.Array(Type.Union([Type.Literal("text"), Type.Literal("image")]))),
1451
+ cost: Type.Optional(ModelCostSchema),
1452
+ contextWindow: Type.Optional(Type.Number()),
1453
+ maxTokens: Type.Optional(Type.Number()),
1454
+ headers: Type.Optional(Type.Record(Type.String(), Type.String())),
1455
+ compat: Type.Optional(ProviderCompatSchema)
1456
+ }), ModelOverrideSchema = Type.Object({
1457
+ name: Type.Optional(Type.String({ minLength: 1 })),
1458
+ reasoning: Type.Optional(Type.Boolean()),
1459
+ thinkingLevelMap: Type.Optional(ThinkingLevelMapSchema),
1460
+ input: Type.Optional(Type.Array(Type.Union([Type.Literal("text"), Type.Literal("image")]))),
1461
+ cost: Type.Optional(Type.Object({
1462
+ input: Type.Optional(Type.Number()),
1463
+ output: Type.Optional(Type.Number()),
1464
+ cacheRead: Type.Optional(Type.Number()),
1465
+ cacheWrite: Type.Optional(Type.Number()),
1466
+ tiers: Type.Optional(Type.Array(ModelCostTierSchema))
1467
+ })),
1468
+ contextWindow: Type.Optional(Type.Number()),
1469
+ maxTokens: Type.Optional(Type.Number()),
1470
+ headers: Type.Optional(Type.Record(Type.String(), Type.String())),
1471
+ compat: Type.Optional(ProviderCompatSchema)
1472
+ }), ProviderConfigSchema = Type.Object({
1473
+ name: Type.Optional(Type.String({ minLength: 1 })),
1474
+ baseUrl: Type.Optional(Type.String({ minLength: 1 })),
1475
+ apiKey: Type.Optional(Type.String({ minLength: 1 })),
1476
+ api: Type.Optional(Type.String({ minLength: 1 })),
1477
+ oauth: Type.Optional(Type.Literal("radius")),
1478
+ headers: Type.Optional(Type.Record(Type.String(), Type.String())),
1479
+ compat: Type.Optional(ProviderCompatSchema),
1480
+ authHeader: Type.Optional(Type.Boolean()),
1481
+ models: Type.Optional(Type.Array(ModelDefinitionSchema)),
1482
+ modelOverrides: Type.Optional(Type.Record(Type.String(), ModelOverrideSchema))
1483
+ }), ModelsConfigSchema = Type.Object({
1484
+ providers: Type.Record(Type.String(), ProviderConfigSchema)
1485
+ }), validateModelsConfig = Compile(ModelsConfigSchema);
1486
+ function formatValidationPath(error) {
1487
+ if (error.keyword === "required") {
1488
+ let requiredProperty = error.params.requiredProperties?.[0];
1489
+ if (requiredProperty) {
1490
+ let basePath = error.instancePath.replace(/^\//, "").replace(/\//g, ".");
1491
+ return basePath ? `${basePath}.${requiredProperty}` : requiredProperty;
1492
+ }
1493
+ }
1494
+ return error.instancePath.replace(/^\//, "").replace(/\//g, ".") || "root";
1495
+ }
1496
+ function deepFreeze(value) {
1497
+ if (typeof value != "object" || value === null || Object.isFrozen(value))
1498
+ return value;
1499
+ for (let child of Object.values(value))
1500
+ deepFreeze(child);
1501
+ return Object.freeze(value);
1502
+ }
1503
+ var ModelConfig = class _ModelConfig {
1504
+ providers;
1505
+ error;
1506
+ constructor(providers, error) {
1507
+ this.providers = providers, this.error = error;
1508
+ }
1509
+ static async load(modelsJsonPath) {
1510
+ if (!modelsJsonPath)
1511
+ return new _ModelConfig(/* @__PURE__ */ new Map());
1512
+ let path = normalizePath(modelsJsonPath), content;
1513
+ try {
1514
+ content = await readFile(path, "utf-8");
1515
+ } catch (error) {
1516
+ return error.code === "ENOENT" ? new _ModelConfig(/* @__PURE__ */ new Map()) : new _ModelConfig(/* @__PURE__ */ new Map(), `Failed to load models.json: ${error instanceof Error ? error.message : error}
1517
+
1518
+ File: ${path}`);
1519
+ }
1520
+ let parsed;
1521
+ try {
1522
+ parsed = JSON.parse(stripJsonComments(content));
1523
+ } catch (error) {
1524
+ return new _ModelConfig(/* @__PURE__ */ new Map(), `Failed to parse models.json: ${error instanceof Error ? error.message : error}
1525
+
1526
+ File: ${path}`);
1527
+ }
1528
+ if (!validateModelsConfig.Check(parsed)) {
1529
+ let errors = validateModelsConfig.Errors(parsed).map((error) => ` - ${formatValidationPath(error)}: ${error.message}`).join(`
1530
+ `) || "Unknown schema error";
1531
+ return new _ModelConfig(/* @__PURE__ */ new Map(), `Invalid models.json schema:
1532
+ ${errors}
1533
+
1534
+ File: ${path}`);
1535
+ }
1536
+ let config = parsed, providers = /* @__PURE__ */ new Map();
1537
+ for (let [providerId, provider] of Object.entries(config.providers))
1538
+ providers.set(providerId, deepFreeze(structuredClone(provider)));
1539
+ return new _ModelConfig(providers);
1540
+ }
1541
+ getProvider(providerId) {
1542
+ return this.providers.get(providerId);
1543
+ }
1544
+ getProviderIds() {
1545
+ return [...this.providers.keys()];
1546
+ }
1547
+ getError() {
1548
+ return this.error;
1549
+ }
1550
+ };
1551
+
1552
+ // packages/coding-agent/dist/core/models-store.js
1553
+ import { join as join4 } from "node:path";
1554
+ var InMemoryCodingAgentModelsStore = class {
1555
+ entries = /* @__PURE__ */ new Map();
1556
+ async read(providerId) {
1557
+ return this.entries.get(providerId);
1558
+ }
1559
+ async write(providerId, entry) {
1560
+ this.entries.set(providerId, entry);
1561
+ }
1562
+ async delete(providerId) {
1563
+ this.entries.delete(providerId);
1564
+ }
1565
+ }, FileModelsStore = class {
1566
+ storage;
1567
+ constructor(path = join4(getAgentDir(), "models-store.json")) {
1568
+ this.storage = new FileAuthStorageBackend(path);
1569
+ }
1570
+ parse(content) {
1571
+ let trimmed = content?.replace(/^\uFEFF/, "").trim();
1572
+ if (!trimmed)
1573
+ return {};
1574
+ try {
1575
+ let parsed = JSON.parse(trimmed);
1576
+ return !parsed || typeof parsed != "object" || Array.isArray(parsed) ? {} : parsed;
1577
+ } catch {
1578
+ return {};
1579
+ }
1580
+ }
1581
+ async read(providerId) {
1582
+ return this.storage.withLock((content) => ({
1583
+ result: structuredClone(this.parse(content)[providerId])
1584
+ }));
1585
+ }
1586
+ async write(providerId, entry) {
1587
+ await this.storage.withLockAsync(async (content) => {
1588
+ let current = this.parse(content);
1589
+ return current[providerId] = structuredClone(entry), { result: void 0, next: JSON.stringify(current, null, 2) };
1590
+ });
1591
+ }
1592
+ async delete(providerId) {
1593
+ await this.storage.withLockAsync(async (content) => {
1594
+ let current = this.parse(content);
1595
+ return delete current[providerId], { result: void 0, next: JSON.stringify(current, null, 2) };
1596
+ });
1597
+ }
1598
+ };
1599
+
1600
+ // packages/coding-agent/dist/core/provider-composer.js
1601
+ import { lazyStream } from "@ashx-j/lunr-ai";
1602
+ import { getApiProvider } from "@ashx-j/lunr-ai/compat";
1603
+ function mergeCompat(base, override) {
1604
+ if (!override)
1605
+ return base;
1606
+ let merged = { ...base, ...override }, baseNested = base, overrideNested = override, mergedNested = merged;
1607
+ for (let key of ["openRouterRouting", "vercelGatewayRouting", "chatTemplateKwargs"]) {
1608
+ let baseValue = baseNested?.[key], overrideValue = overrideNested[key];
1609
+ (typeof baseValue == "object" && baseValue !== null || typeof overrideValue == "object" && overrideValue !== null) && (mergedNested[key] = { ...baseValue, ...overrideValue });
1610
+ }
1611
+ return merged;
1612
+ }
1613
+ function applyModelOverride(model, override) {
1614
+ return {
1615
+ ...model,
1616
+ name: override.name ?? model.name,
1617
+ reasoning: override.reasoning ?? model.reasoning,
1618
+ thinkingLevelMap: override.thinkingLevelMap ? { ...model.thinkingLevelMap, ...override.thinkingLevelMap } : model.thinkingLevelMap,
1619
+ input: override.input ?? model.input,
1620
+ cost: override.cost ? {
1621
+ input: override.cost.input ?? model.cost.input,
1622
+ output: override.cost.output ?? model.cost.output,
1623
+ cacheRead: override.cost.cacheRead ?? model.cost.cacheRead,
1624
+ cacheWrite: override.cost.cacheWrite ?? model.cost.cacheWrite,
1625
+ tiers: override.cost.tiers ?? model.cost.tiers
1626
+ } : model.cost,
1627
+ contextWindow: override.contextWindow ?? model.contextWindow,
1628
+ maxTokens: override.maxTokens ?? model.maxTokens,
1629
+ compat: mergeCompat(model.compat, override.compat)
1630
+ };
1631
+ }
1632
+ function modelFromJson(providerId, definition, providerConfig, defaults) {
1633
+ let api = definition.api ?? providerConfig.api ?? defaults?.api;
1634
+ if (!api)
1635
+ throw new Error(`Provider ${providerId}, model ${definition.id}: no "api" specified. Set at provider or model level.`);
1636
+ let baseUrl = definition.baseUrl ?? providerConfig.baseUrl ?? defaults?.baseUrl;
1637
+ if (!baseUrl)
1638
+ throw new Error(`Provider ${providerId}: "baseUrl" is required when defining custom models.`);
1639
+ if (definition.contextWindow !== void 0 && definition.contextWindow <= 0)
1640
+ throw new Error(`Provider ${providerId}, model ${definition.id}: invalid contextWindow`);
1641
+ if (definition.maxTokens !== void 0 && definition.maxTokens <= 0)
1642
+ throw new Error(`Provider ${providerId}, model ${definition.id}: invalid maxTokens`);
1643
+ return {
1644
+ id: definition.id,
1645
+ name: definition.name ?? definition.id,
1646
+ api,
1647
+ provider: providerId,
1648
+ baseUrl,
1649
+ reasoning: definition.reasoning ?? !1,
1650
+ thinkingLevelMap: definition.thinkingLevelMap,
1651
+ input: definition.input ?? ["text"],
1652
+ cost: definition.cost ?? { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
1653
+ contextWindow: definition.contextWindow ?? 128e3,
1654
+ maxTokens: definition.maxTokens ?? 16384,
1655
+ headers: void 0,
1656
+ compat: mergeCompat(providerConfig.compat, definition.compat)
1657
+ };
1658
+ }
1659
+ function applyModelsJson(providerId, baseModels, config) {
1660
+ if (!config)
1661
+ return [...baseModels];
1662
+ if (config.oauth && !config.baseUrl)
1663
+ throw new Error(`Provider ${providerId}: "baseUrl" is required when "oauth" is set.`);
1664
+ let hasOverrides = config.modelOverrides && Object.keys(config.modelOverrides).length > 0;
1665
+ if (!config.models?.length && !config.baseUrl && !config.headers && !config.compat && !hasOverrides && !config.apiKey && !config.oauth && config.authHeader === void 0)
1666
+ throw new Error(`Provider ${providerId}: must specify "baseUrl", "headers", "compat", "modelOverrides", or "models".`);
1667
+ let models = baseModels.map((model) => ({
1668
+ ...model,
1669
+ baseUrl: config.oauth === "radius" ? model.baseUrl : config.baseUrl ?? model.baseUrl,
1670
+ compat: mergeCompat(model.compat, config.compat)
1671
+ }));
1672
+ for (let definition of config.models ?? []) {
1673
+ let existingIndex = models.findIndex((model2) => model2.id === definition.id), defaults = existingIndex >= 0 ? models[existingIndex] : models[0], model = modelFromJson(providerId, definition, config, defaults);
1674
+ existingIndex >= 0 ? models[existingIndex] = model : models.push(model);
1675
+ }
1676
+ return models;
1677
+ }
1678
+ function applyExtension(providerId, models, config) {
1679
+ return config ? config.models ? config.models.map((definition) => {
1680
+ let defaults = models.find((model) => model.id === definition.id) ?? models[0], api = definition.api ?? config.api ?? defaults?.api;
1681
+ if (!api)
1682
+ throw new Error(`Provider ${providerId}, model ${definition.id}: no "api" specified. Set at provider or model level.`);
1683
+ let baseUrl = definition.baseUrl ?? config.baseUrl ?? defaults?.baseUrl;
1684
+ if (!baseUrl)
1685
+ throw new Error(`Provider ${providerId}: "baseUrl" is required when defining custom models.`);
1686
+ return {
1687
+ ...definition,
1688
+ api,
1689
+ provider: providerId,
1690
+ baseUrl,
1691
+ headers: void 0
1692
+ };
1693
+ }) : config.baseUrl ? models.map((model) => ({ ...model, baseUrl: config.baseUrl })) : [...models] : [...models];
1694
+ }
1695
+ function adaptOAuth(config) {
1696
+ return {
1697
+ name: config.name,
1698
+ login: async (callbacks) => ({ ...await config.login({
1699
+ onAuth: (info) => callbacks.notify({ type: "auth_url", ...info }),
1700
+ onDeviceCode: (info) => callbacks.notify({ type: "device_code", ...info }),
1701
+ onPrompt: (prompt) => callbacks.prompt({ type: "text", ...prompt }),
1702
+ onProgress: (message) => callbacks.notify({ type: "progress", message }),
1703
+ onManualCodeInput: () => callbacks.prompt({ type: "manual_code", message: "Paste the authorization code" }),
1704
+ onSelect: (prompt) => callbacks.prompt({ type: "select", ...prompt }),
1705
+ signal: callbacks.signal
1706
+ }), type: "oauth" }),
1707
+ refresh: async (credential) => ({ ...await config.refreshToken(credential), type: "oauth" }),
1708
+ toAuth: async (credential) => ({ apiKey: config.getApiKey(credential) })
1709
+ };
1710
+ }
1711
+ function withConfiguredAuth(auth, headers, authHeader) {
1712
+ let mergedHeaders = auth.headers || headers ? { ...auth.headers, ...headers } : void 0;
1713
+ if (authHeader) {
1714
+ if (!auth.apiKey)
1715
+ throw new Error("authHeader requires a resolved API key");
1716
+ mergedHeaders = { ...mergedHeaders, Authorization: `Bearer ${auth.apiKey}` };
1717
+ }
1718
+ return { ...auth, headers: mergedHeaders };
1719
+ }
1720
+ function configuredApiKey(config, extension) {
1721
+ return extension?.apiKey ?? config?.apiKey;
1722
+ }
1723
+ function configuredHeaders(config, extension) {
1724
+ if (!(!config?.headers && !extension?.headers))
1725
+ return { ...config?.headers, ...extension?.headers };
1726
+ }
1727
+ async function configContextEnv(values, ctx, explicit) {
1728
+ let env = { ...explicit };
1729
+ for (let name of new Set(values.flatMap(getConfigValueEnvVarNames))) {
1730
+ if (env[name] !== void 0)
1731
+ continue;
1732
+ let value = await ctx.env(name);
1733
+ value !== void 0 && (env[name] = value);
1734
+ }
1735
+ return Object.keys(env).length > 0 ? env : void 0;
1736
+ }
1737
+ function composeApiKeyAuth(providerId, base, config, extension) {
1738
+ let inherited = base?.auth.apiKey, rawKey = configuredApiKey(config, extension), oauth = extension?.oauth ?? base?.auth.oauth;
1739
+ if (!inherited && rawKey === void 0 && oauth)
1740
+ return;
1741
+ let rawHeaders = configuredHeaders(config, extension), authHeader = extension?.authHeader ?? config?.authHeader ?? !1;
1742
+ return {
1743
+ name: inherited?.name ?? "API key",
1744
+ login: inherited?.login ?? (async (interaction) => ({
1745
+ type: "api_key",
1746
+ key: await interaction.prompt({ type: "secret", message: "Enter API key" })
1747
+ })),
1748
+ check: async (input) => {
1749
+ if (input.credential) {
1750
+ if (inherited?.check)
1751
+ return inherited.check(input);
1752
+ if (input.credential.key)
1753
+ return { type: "api_key", source: "stored credential" };
1754
+ let resolved2 = await inherited?.resolve(input);
1755
+ return resolved2 ? { type: "api_key", source: resolved2.source } : void 0;
1756
+ }
1757
+ if (rawKey !== void 0) {
1758
+ if (isCommandConfigValue(rawKey))
1759
+ return { type: "api_key", source: "configured API key" };
1760
+ let envNames = getConfigValueEnvVarNames(rawKey);
1761
+ for (let name of envNames)
1762
+ if (await input.ctx.env(name) === void 0)
1763
+ return;
1764
+ return { type: "api_key", source: "configured API key" };
1765
+ }
1766
+ if (inherited?.check)
1767
+ return inherited.check(input);
1768
+ let resolved = await inherited?.resolve(input);
1769
+ return resolved ? { type: "api_key", source: resolved.source } : void 0;
1770
+ },
1771
+ resolve: async (input) => {
1772
+ let result;
1773
+ if (input.credential)
1774
+ result = inherited ? await inherited.resolve(input) : input.credential.key ? { auth: { apiKey: input.credential.key }, env: input.credential.env, source: "stored credential" } : void 0;
1775
+ else if (rawKey !== void 0) {
1776
+ let env = await configContextEnv([rawKey], input.ctx), key = resolveConfigValueOrThrow(rawKey, `API key for provider "${providerId}"`, env);
1777
+ result = inherited ? await inherited.resolve({ ...input, credential: { type: "api_key", key } }) : { auth: { apiKey: key }, source: "configured API key" };
1778
+ } else
1779
+ result = await inherited?.resolve(input);
1780
+ if (!result)
1781
+ return;
1782
+ let explicitEnv = { ...input.credential?.env ?? {}, ...result.env ?? {} }, headerEnv = await configContextEnv(Object.values(rawHeaders ?? {}), input.ctx, explicitEnv), headers = resolveHeadersOrThrow(rawHeaders, `provider "${providerId}"`, headerEnv);
1783
+ return { ...result, auth: withConfiguredAuth(result.auth, headers, authHeader) };
1784
+ }
1785
+ };
1786
+ }
1787
+ function composeOAuthAuth(providerId, base, config, extension) {
1788
+ let oauth = extension?.oauth ? adaptOAuth(extension.oauth) : base?.auth.oauth;
1789
+ if (!oauth)
1790
+ return;
1791
+ let rawHeaders = configuredHeaders(config, extension), authHeader = extension?.authHeader ?? config?.authHeader ?? !1;
1792
+ return {
1793
+ ...oauth,
1794
+ toAuth: async (credential) => {
1795
+ let auth = await oauth.toAuth(credential), env = credential.env, headers = resolveHeadersOrThrow(rawHeaders, `provider "${providerId}"`, typeof env == "object" && env !== null ? env : void 0);
1796
+ return withConfiguredAuth(auth, headers, authHeader);
1797
+ }
1798
+ };
1799
+ }
1800
+ function rawModelHeaders(model, config, extension) {
1801
+ let definition = config?.models?.find((entry) => entry.id === model.id), extensionModel = extension?.models?.find((entry) => entry.id === model.id), headers = {
1802
+ ...config?.modelOverrides?.[model.id]?.headers,
1803
+ ...definition?.headers,
1804
+ ...extensionModel?.headers
1805
+ };
1806
+ return Object.keys(headers).length > 0 ? headers : void 0;
1807
+ }
1808
+ function validateExtensionProvider(providerId, base, modelsConfig, extension) {
1809
+ if (extension.streamSimple && !extension.api)
1810
+ throw new Error(`Provider ${providerId}: "api" is required when registering streamSimple.`);
1811
+ applyExtension(providerId, applyModelsJson(providerId, base?.getModels() ?? [], modelsConfig), extension);
1812
+ }
1813
+ function composeModelProvider(providerId, base, modelConfig, extension) {
1814
+ let config = modelConfig.getProvider(providerId), extensionOAuthCredential, refreshedExtensionModels, currentExtension = () => extension && refreshedExtensionModels ? { ...extension, models: refreshedExtensionModels } : extension, getModels = () => {
1815
+ let models = applyExtension(providerId, applyModelsJson(providerId, base?.getModels() ?? [], config), currentExtension());
1816
+ return extensionOAuthCredential && extension?.oauth?.modifyModels && (models = extension.oauth.modifyModels(models, extensionOAuthCredential)), models.map((model) => {
1817
+ let override = config?.modelOverrides?.[model.id];
1818
+ return override ? applyModelOverride(model, override) : model;
1819
+ });
1820
+ };
1821
+ getModels();
1822
+ let apiKey = composeApiKeyAuth(providerId, base, config, extension), oauth = composeOAuthAuth(providerId, base, config, extension);
1823
+ if (!apiKey && !oauth)
1824
+ throw new Error(`Provider ${providerId}: no authentication method configured.`);
1825
+ let supportsBaseApi = (model) => base?.getModels().some((entry) => entry.api === model.api) ?? !1, streamWith = (model, context, options, simple) => lazyStream(model, async () => {
1826
+ if (extension?.streamSimple && model.api === extension.api)
1827
+ return extension.streamSimple(model, context, options);
1828
+ if (base && supportsBaseApi(model))
1829
+ return simple ? base.streamSimple(model, context, options) : base.stream(model, context, options);
1830
+ let api = getApiProvider(model.api);
1831
+ if (!api)
1832
+ throw new Error(`No API provider registered for api: ${model.api}`);
1833
+ return simple ? api.streamSimple(model, context, options) : api.stream(model, context, options);
1834
+ });
1835
+ return {
1836
+ id: providerId,
1837
+ name: extension?.name ?? config?.name ?? base?.name ?? extension?.oauth?.name ?? providerId,
1838
+ baseUrl: extension?.baseUrl ?? config?.baseUrl ?? base?.baseUrl,
1839
+ headers: base?.headers,
1840
+ auth: { ...apiKey ? { apiKey } : {}, ...oauth ? { oauth } : {} },
1841
+ getModels,
1842
+ refreshModels: base?.refreshModels || extension?.refreshModels || extension?.oauth?.modifyModels ? async (context) => {
1843
+ if (await base?.refreshModels?.(context), extension?.refreshModels) {
1844
+ let refreshed = await extension.refreshModels(context);
1845
+ context.signal?.aborted || (applyExtension(providerId, applyModelsJson(providerId, base?.getModels() ?? [], config), {
1846
+ ...extension,
1847
+ models: refreshed
1848
+ }), refreshedExtensionModels = refreshed);
1849
+ }
1850
+ extensionOAuthCredential = context.credential?.type === "oauth" ? context.credential : void 0;
1851
+ } : void 0,
1852
+ filterModels: base?.filterModels ? (models, credential) => base.filterModels(models, credential) : void 0,
1853
+ stream: (model, context, options) => streamWith(model, context, options, !1),
1854
+ streamSimple: (model, context, options) => streamWith(model, context, options, !0)
1855
+ };
1856
+ }
1857
+ function resolveConfiguredModelHeaders(model, config, extension, env) {
1858
+ return resolveHeadersOrThrow(rawModelHeaders(model, config, extension), `model "${model.provider}/${model.id}"`, env);
1859
+ }
1860
+ function resolveCompatibilityRequestConfig(model, config, extension) {
1861
+ let configured = resolveHeadersOrThrow({ ...configuredHeaders(config, extension), ...rawModelHeaders(model, config, extension) }, `model "${model.provider}/${model.id}"`);
1862
+ return {
1863
+ headers: model.headers || configured ? { ...model.headers, ...configured } : void 0,
1864
+ authHeader: extension?.authHeader ?? config?.authHeader ?? !1
1865
+ };
1866
+ }
1867
+ function configuredRequestAuthStatus(config, extension) {
1868
+ let value = configuredApiKey(config, extension);
1869
+ if (value === void 0)
1870
+ return;
1871
+ if (isCommandConfigValue(value))
1872
+ return { configured: !0, source: "models_json_command" };
1873
+ let names = getConfigValueEnvVarNames(value);
1874
+ return names.length > 0 ? isConfigValueConfigured(value) ? { configured: !0, source: "environment", label: names.join(", ") } : { configured: !1 } : { configured: !0, source: extension?.apiKey !== void 0 ? "fallback" : "models_json_key" };
1875
+ }
1876
+
1877
+ // packages/coding-agent/dist/core/runtime-credentials.js
1878
+ var RuntimeCredentials = class {
1879
+ store;
1880
+ overrides = /* @__PURE__ */ new Map();
1881
+ constructor(store) {
1882
+ this.store = store;
1883
+ }
1884
+ setRuntimeApiKey(providerId, apiKey) {
1885
+ this.overrides.set(providerId, apiKey);
1886
+ }
1887
+ removeRuntimeApiKey(providerId) {
1888
+ this.overrides.delete(providerId);
1889
+ }
1890
+ hasRuntimeApiKey(providerId) {
1891
+ return this.overrides.has(providerId);
1892
+ }
1893
+ async read(providerId) {
1894
+ let override = this.overrides.get(providerId);
1895
+ return override ? { type: "api_key", key: override } : this.store.read(providerId);
1896
+ }
1897
+ async list() {
1898
+ let entries = new Map((await this.store.list()).map((entry) => [entry.providerId, entry]));
1899
+ for (let providerId of this.overrides.keys())
1900
+ entries.set(providerId, { providerId, type: "api_key" });
1901
+ return [...entries.values()];
1902
+ }
1903
+ modify(providerId, fn) {
1904
+ return this.store.modify(providerId, fn);
1905
+ }
1906
+ async delete(providerId) {
1907
+ this.overrides.delete(providerId), await this.store.delete(providerId);
1908
+ }
1909
+ };
1910
+
1911
+ // packages/coding-agent/dist/core/subscriptions.js
1912
+ import { join as join5 } from "path";
1913
+
1914
+ // packages/coding-agent/dist/core/usage-limit.js
1915
+ var USAGE_LIMIT_ERROR_PATTERNS = [
1916
+ // Provider-declared subscription/free-tier limit error types and wording
1917
+ // (pi-ai NON_RETRYABLE_PROVIDER_LIMIT_ERROR_PATTERN spirit).
1918
+ "GoUsageLimitError",
1919
+ "FreeUsageLimitError",
1920
+ "Monthly usage limit reached",
1921
+ "available balance",
1922
+ "insufficient_quota",
1923
+ "out of budget",
1924
+ "quota exceeded",
1925
+ "billing"
1926
+ ], USAGE_LIMIT_ERROR_REGEXES = [
1927
+ // Goal runtime USAGE_LIMIT_GOAL_ERROR_PATTERNS: usage caps, quota exhaustion,
1928
+ // credit/balance exhaustion, payment required.
1929
+ /usage[_\s-]*(?:limit|cap)|chatgpt.{0,32}usage/i,
1930
+ /quota.{0,32}(?:reached|exceeded|exhausted|depleted)|(?:reached|exceeded|exhausted|depleted).{0,32}quota/i,
1931
+ /insufficient[_\s-]*(?:quota|credits?)|out of credits|out of budget|available balance|payment required/i,
1932
+ /(?:credit|balance).{0,32}(?:low|exhausted|depleted)|billing/i
1933
+ ], AUTH_INVALID_ERROR_PATTERN = /\b401\b|unauthori[sz]ed|unauthenticated|invalid.{0,16}(?:api.?key|token|credentials?)|authentication.{0,16}failed/i;
1934
+ function isUsageLimitError(errorMessage) {
1935
+ return errorMessage ? USAGE_LIMIT_ERROR_PATTERNS.some((pattern) => errorMessage.toLowerCase().includes(pattern.toLowerCase())) ? !0 : USAGE_LIMIT_ERROR_REGEXES.some((pattern) => pattern.test(errorMessage)) : !1;
1936
+ }
1937
+ function isAuthInvalidError(errorMessage) {
1938
+ return errorMessage ? AUTH_INVALID_ERROR_PATTERN.test(errorMessage) : !1;
1939
+ }
1940
+ var RESET_TIME_PATTERNS = [
1941
+ /reset(?:s|ting)?\s*(?:in|after|at)?\s*(\d+)\s*s(ec)?/i,
1942
+ /reset(?:s|ting)?\s*(?:in|after|at)?\s*(\d+)\s*m(in)?/i,
1943
+ /reset(?:s|ting)?\s*(?:in|after|at)?\s*(\d+)\s*h(our|r)?/i,
1944
+ /(?:retry|try(?:\s+again)?|available)\s+(?:in|after|at)\s*(\d+)\s*s(ec)?/i,
1945
+ /(?:retry|try(?:\s+again)?|available)\s+(?:in|after|at)\s*(\d+)\s*m(in)?/i,
1946
+ /(?:retry|try(?:\s+again)?|available)\s+(?:in|after|at)\s*(\d+)\s*h(our|r)?/i
1947
+ ];
1948
+ function parseResetTimeMs(errorMessage) {
1949
+ if (!errorMessage)
1950
+ return;
1951
+ let now = Date.now();
1952
+ for (let pattern of RESET_TIME_PATTERNS) {
1953
+ let match = errorMessage.match(pattern);
1954
+ if (!match)
1955
+ continue;
1956
+ let value = Number.parseInt(match[1] ?? "", 10);
1957
+ if (!Number.isFinite(value) || value <= 0)
1958
+ continue;
1959
+ let unit = pattern.source.includes("\\s*h") ? 36e5 : pattern.source.includes("\\s*m") ? 6e4 : 1e3;
1960
+ return now + value * unit;
1961
+ }
1962
+ let isoMatch = errorMessage.match(/(?:reset|available).{0,12}(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}(:\d{2})?(?:\.\d+)?(?:Z|[+-]\d{2}:?\d{2})?)/i);
1963
+ if (isoMatch?.[1]) {
1964
+ let parsed = Date.parse(isoMatch[1]);
1965
+ if (Number.isFinite(parsed) && parsed > now)
1966
+ return parsed;
1967
+ }
1968
+ }
1969
+
1970
+ // packages/coding-agent/dist/core/subscriptions.js
1971
+ var SubscriptionManager = class _SubscriptionManager {
1972
+ data = {};
1973
+ loaded = !1;
1974
+ storage;
1975
+ authStorage;
1976
+ // In-process write queue so mutations serialize even before the file lock.
1977
+ queue = Promise.resolve();
1978
+ // Per-provider ids of keys exhausted without a parseable reset time.
1979
+ // Process-local on purpose: infinite exhaustion is never persisted.
1980
+ memoryExhausted = /* @__PURE__ */ new Map();
1981
+ constructor(authStorage, storage) {
1982
+ this.authStorage = authStorage, this.storage = storage;
1983
+ }
1984
+ static create(authStorage, path) {
1985
+ return new _SubscriptionManager(authStorage, new FileAuthStorageBackend(path ?? join5(getAgentDir(), "subscriptions.json")));
1986
+ }
1987
+ static fromStorage(authStorage, storage) {
1988
+ return new _SubscriptionManager(authStorage, storage);
1989
+ }
1990
+ static inMemory(authStorage, data = {}) {
1991
+ let storage = new InMemoryAuthStorageBackend();
1992
+ return storage.withLock(() => ({ result: void 0, next: JSON.stringify(data, null, 2) })), _SubscriptionManager.fromStorage(authStorage, storage);
1993
+ }
1994
+ parseStorageData(content) {
1995
+ return content ? JSON.parse(content) : {};
1996
+ }
1997
+ ensureLoaded() {
1998
+ if (this.loaded)
1999
+ return;
2000
+ this.loaded = !0;
2001
+ let content;
2002
+ try {
2003
+ this.storage.withLock((current) => (content = current, { result: void 0 })), this.data = this.parseStorageData(content);
2004
+ } catch {
2005
+ }
2006
+ }
2007
+ enqueue(fn) {
2008
+ let next = this.queue.then(fn);
2009
+ return this.queue = next.catch(() => {
2010
+ }), next;
2011
+ }
2012
+ persist() {
2013
+ return this.storage.withLockAsync(async () => ({
2014
+ result: void 0,
2015
+ next: JSON.stringify(this.data, null, 2)
2016
+ }));
2017
+ }
2018
+ /** Raw stored credential read via the modify path (returning undefined leaves it unchanged). */
2019
+ async readRawCredential(providerId) {
2020
+ let current;
2021
+ return await this.authStorage.modify(providerId, async (credential) => {
2022
+ current = credential;
2023
+ }), current;
2024
+ }
2025
+ /**
2026
+ * Pool for a provider, lazy-importing an existing stored api_key credential
2027
+ * as "Sub 1" on first access. OAuth credentials are not imported.
2028
+ */
2029
+ async ensurePool(providerId) {
2030
+ this.ensureLoaded();
2031
+ let existing = this.data[providerId];
2032
+ if (existing)
2033
+ return existing;
2034
+ let credential = await this.readRawCredential(providerId);
2035
+ if (credential?.type !== "api_key" || credential.key === void 0)
2036
+ return;
2037
+ let pool = {
2038
+ active: "1",
2039
+ keys: [{ id: "1", name: "Sub 1", key: credential.key, addedAt: Date.now() }]
2040
+ };
2041
+ return this.data = { ...this.data, [providerId]: pool }, await this.persist(), pool;
2042
+ }
2043
+ nextId(pool) {
2044
+ let max = 0;
2045
+ for (let entry of pool.keys) {
2046
+ let numeric = Number.parseInt(entry.id, 10);
2047
+ Number.isFinite(numeric) && numeric > max && (max = numeric);
2048
+ }
2049
+ return String(max + 1);
2050
+ }
2051
+ async mirrorActive(providerId, key) {
2052
+ await this.authStorage.modify(providerId, async () => ({ type: "api_key", key }));
2053
+ }
2054
+ async list(providerId) {
2055
+ return this.enqueue(async () => {
2056
+ let pool = await this.ensurePool(providerId);
2057
+ return pool ? [...pool.keys] : [];
2058
+ });
2059
+ }
2060
+ async getActive(providerId) {
2061
+ return this.enqueue(async () => {
2062
+ let pool = await this.ensurePool(providerId);
2063
+ return pool?.keys.find((entry) => entry.id === pool.active);
2064
+ });
2065
+ }
2066
+ async addKey(providerId, key, name) {
2067
+ return this.enqueue(async () => {
2068
+ this.ensureLoaded();
2069
+ let pool = await this.ensurePool(providerId), id = pool ? this.nextId(pool) : "1", entry = { id, name: name ?? `Sub ${id}`, key, addedAt: Date.now() }, keys = [...pool?.keys ?? [], entry];
2070
+ return this.data = { ...this.data, [providerId]: { active: id, keys } }, await this.persist(), await this.mirrorActive(providerId, key), entry;
2071
+ });
2072
+ }
2073
+ async removeKey(providerId, id) {
2074
+ return this.enqueue(async () => {
2075
+ let pool = await this.ensurePool(providerId);
2076
+ if (!pool || !pool.keys.some((entry) => entry.id === id))
2077
+ return;
2078
+ let keys = pool.keys.filter((entry) => entry.id !== id);
2079
+ if (this.memoryExhausted.get(providerId)?.delete(id), keys.length === 0) {
2080
+ let data = { ...this.data };
2081
+ delete data[providerId], this.data = data, await this.persist(), await this.authStorage.delete(providerId);
2082
+ return;
2083
+ }
2084
+ let active = pool.active;
2085
+ if (active === id) {
2086
+ active = keys[0]?.id ?? active, this.data = { ...this.data, [providerId]: { active, keys } }, await this.persist();
2087
+ let promoted = keys.find((entry) => entry.id === active);
2088
+ promoted && await this.mirrorActive(providerId, promoted.key);
2089
+ return;
2090
+ }
2091
+ this.data = { ...this.data, [providerId]: { active, keys } }, await this.persist();
2092
+ });
2093
+ }
2094
+ async renameKey(providerId, id, name) {
2095
+ return this.enqueue(async () => {
2096
+ let pool = await this.ensurePool(providerId);
2097
+ if (!pool)
2098
+ return;
2099
+ let keys = pool.keys.map((entry) => entry.id === id ? { ...entry, name } : entry);
2100
+ this.data = { ...this.data, [providerId]: { ...pool, keys } }, await this.persist();
2101
+ });
2102
+ }
2103
+ async setActive(providerId, id) {
2104
+ return this.enqueue(async () => {
2105
+ let pool = await this.ensurePool(providerId), entry = pool?.keys.find((candidate) => candidate.id === id);
2106
+ !pool || !entry || (this.data = { ...this.data, [providerId]: { ...pool, active: id } }, await this.persist(), await this.mirrorActive(providerId, entry.key));
2107
+ });
2108
+ }
2109
+ /**
2110
+ * Mark the active key exhausted and rotate to the next non-exhausted key in
2111
+ * round-robin order. A parseable reset time is persisted as exhaustedUntil;
2112
+ * otherwise the exhaustion is process-local only. Returns the new active key,
2113
+ * or null when no non-exhausted alternative exists (current key stays active).
2114
+ */
2115
+ async rotateOnFailure(providerId, errorMessage, now = Date.now()) {
2116
+ return this.enqueue(async () => {
2117
+ let pool = await this.ensurePool(providerId);
2118
+ if (!pool)
2119
+ return null;
2120
+ let currentIndex = pool.keys.findIndex((entry) => entry.id === pool.active);
2121
+ if (currentIndex === -1)
2122
+ return null;
2123
+ let current = pool.keys[currentIndex];
2124
+ if (!current)
2125
+ return null;
2126
+ let resetAt = parseResetTimeMs(errorMessage), keys = pool.keys;
2127
+ if (resetAt !== void 0 && resetAt > now)
2128
+ keys = pool.keys.map((entry) => entry.id === current.id ? { ...entry, exhaustedUntil: resetAt, lastError: errorMessage } : entry);
2129
+ else {
2130
+ let set = this.memoryExhausted.get(providerId) ?? /* @__PURE__ */ new Set();
2131
+ set.add(current.id), this.memoryExhausted.set(providerId, set);
2132
+ }
2133
+ let isExhausted = (entry) => this.memoryExhausted.get(providerId)?.has(entry.id) === !0 || entry.exhaustedUntil !== void 0 && entry.exhaustedUntil > now;
2134
+ for (let offset = 1; offset < keys.length; offset++) {
2135
+ let candidate = keys[(currentIndex + offset) % keys.length];
2136
+ if (!(!candidate || isExhausted(candidate)))
2137
+ return this.data = { ...this.data, [providerId]: { active: candidate.id, keys } }, await this.persist(), await this.mirrorActive(providerId, candidate.key), candidate;
2138
+ }
2139
+ return keys !== pool.keys && (this.data = { ...this.data, [providerId]: { ...pool, keys } }, await this.persist()), null;
2140
+ });
2141
+ }
2142
+ /** Manual reactivate: clears persisted and process-local exhaustion for a key. */
2143
+ async clearExhaustion(providerId, id) {
2144
+ return this.enqueue(async () => {
2145
+ this.memoryExhausted.get(providerId)?.delete(id);
2146
+ let pool = await this.ensurePool(providerId);
2147
+ if (!pool)
2148
+ return;
2149
+ let target = pool.keys.find((entry) => entry.id === id);
2150
+ if (!target || target.exhaustedUntil === void 0 && target.lastError === void 0)
2151
+ return;
2152
+ let keys = pool.keys.map((entry) => {
2153
+ if (entry.id !== id)
2154
+ return entry;
2155
+ let { exhaustedUntil: _exhaustedUntil, lastError: _lastError, ...rest } = entry;
2156
+ return rest;
2157
+ });
2158
+ this.data = { ...this.data, [providerId]: { ...pool, keys } }, await this.persist();
2159
+ });
2160
+ }
2161
+ };
2162
+
2163
+ // packages/coding-agent/dist/core/user-models.js
2164
+ import { existsSync as existsSync4, mkdirSync as mkdirSync4, readFileSync as readFileSync4, writeFileSync as writeFileSync4 } from "node:fs";
2165
+ import { dirname as dirname4, join as join6 } from "node:path";
2166
+ var USER_MODELS_FILENAME = "user-models.json";
2167
+ function userModelsPath(agentDir = getAgentDir()) {
2168
+ return join6(agentDir, USER_MODELS_FILENAME);
2169
+ }
2170
+ function isRecord3(value) {
2171
+ return typeof value == "object" && value !== null && !Array.isArray(value);
2172
+ }
2173
+ function asFiniteNumber3(value) {
2174
+ if (typeof value == "number" && Number.isFinite(value))
2175
+ return value;
2176
+ }
2177
+ function parseUserEntry(value) {
2178
+ if (!isRecord3(value))
2179
+ return;
2180
+ let id = typeof value.id == "string" ? value.id.trim() : "", provider = typeof value.provider == "string" ? value.provider.trim() : "";
2181
+ if (!id || !provider)
2182
+ return;
2183
+ let parsedInput = Array.isArray(value.input) ? value.input.filter((entry) => entry === "text" || entry === "image") : ["text"], input = parsedInput.length > 0 ? parsedInput : ["text"], cost = isRecord3(value.cost) ? {
2184
+ input: asFiniteNumber3(value.cost.input) ?? 0,
2185
+ output: asFiniteNumber3(value.cost.output) ?? 0,
2186
+ cacheRead: asFiniteNumber3(value.cost.cacheRead) ?? 0,
2187
+ cacheWrite: asFiniteNumber3(value.cost.cacheWrite) ?? 0
2188
+ } : { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 };
2189
+ return {
2190
+ id,
2191
+ name: typeof value.name == "string" && value.name.trim() ? value.name : id,
2192
+ api: typeof value.api == "string" && value.api.trim() ? value.api : "openai-completions",
2193
+ provider,
2194
+ baseUrl: typeof value.baseUrl == "string" ? value.baseUrl : "",
2195
+ reasoning: value.reasoning === !0,
2196
+ input,
2197
+ cost,
2198
+ contextWindow: asFiniteNumber3(value.contextWindow) ?? 128e3,
2199
+ maxTokens: asFiniteNumber3(value.maxTokens) ?? 8192,
2200
+ compat: isRecord3(value.compat) ? value.compat : void 0,
2201
+ thinkingLevelMap: isRecord3(value.thinkingLevelMap) ? value.thinkingLevelMap : void 0,
2202
+ source: "user"
2203
+ };
2204
+ }
2205
+ function emptyUserModels() {
2206
+ return { version: 1, models: [] };
2207
+ }
2208
+ function readUserModels(path) {
2209
+ try {
2210
+ if (!existsSync4(path))
2211
+ return emptyUserModels();
2212
+ let parsed = JSON.parse(readFileSync4(path, "utf-8"));
2213
+ if (!isRecord3(parsed) || !Array.isArray(parsed.models))
2214
+ return emptyUserModels();
2215
+ let models = [];
2216
+ for (let entry of parsed.models) {
2217
+ let model = parseUserEntry(entry);
2218
+ model && models.push(model);
2219
+ }
2220
+ return { version: asFiniteNumber3(parsed.version) ?? 1, models };
2221
+ } catch {
2222
+ return emptyUserModels();
2223
+ }
2224
+ }
2225
+ function writeUserModels(file, path) {
2226
+ mkdirSync4(dirname4(path), { recursive: !0, mode: 448 }), writeFileSync4(path, `${JSON.stringify({ version: file.version ?? 1, models: file.models }, null, 2)}
2227
+ `, "utf-8");
2228
+ }
2229
+ function evictUserModelsOnOfficial(user, officialKeys) {
2230
+ let hits = new Set(officialKeys), kept = [], evicted = [];
2231
+ for (let model of user.models)
2232
+ hits.has(modelKey(model.provider, model.id)) ? evicted.push(model) : kept.push(model);
2233
+ return { next: { version: user.version, models: kept }, evicted };
2234
+ }
2235
+ function evictUserModelsByProvider(user, providerId) {
2236
+ let kept = [], evicted = [];
2237
+ for (let model of user.models)
2238
+ model.provider === providerId ? evicted.push(model) : kept.push(model);
2239
+ return { next: { version: user.version, models: kept }, evicted };
2240
+ }
2241
+ function upsertUserModels(existing, rows) {
2242
+ let byKey = new Map(existing.models.map((model) => [modelKey(model.provider, model.id), model]));
2243
+ for (let row of rows)
2244
+ byKey.set(modelKey(row.provider, row.id), { ...row, source: "user" });
2245
+ return { version: existing.version ?? 1, models: [...byKey.values()] };
2246
+ }
2247
+ function userEntryToModel(entry) {
2248
+ return {
2249
+ id: entry.id,
2250
+ name: entry.name,
2251
+ api: entry.api,
2252
+ provider: entry.provider,
2253
+ baseUrl: entry.baseUrl,
2254
+ reasoning: entry.reasoning,
2255
+ input: entry.input,
2256
+ cost: entry.cost,
2257
+ contextWindow: entry.contextWindow,
2258
+ maxTokens: entry.maxTokens,
2259
+ compat: entry.compat,
2260
+ thinkingLevelMap: entry.thinkingLevelMap
2261
+ };
2262
+ }
2263
+ var UserModelsStore = class {
2264
+ path;
2265
+ file;
2266
+ constructor(path) {
2267
+ this.path = path, this.file = path ? readUserModels(path) : emptyUserModels();
2268
+ }
2269
+ list() {
2270
+ return this.file.models;
2271
+ }
2272
+ keys() {
2273
+ return new Set(this.file.models.map((model) => modelKey(model.provider, model.id)));
2274
+ }
2275
+ modelsFor(providerId) {
2276
+ return this.file.models.filter((model) => model.provider === providerId).map(userEntryToModel);
2277
+ }
2278
+ evictOfficial(officialKeys) {
2279
+ let { next, evicted } = evictUserModelsOnOfficial(this.file, officialKeys);
2280
+ return evicted.length > 0 && (this.file = next, this.persist()), evicted;
2281
+ }
2282
+ evictProvider(providerId) {
2283
+ let { next, evicted } = evictUserModelsByProvider(this.file, providerId);
2284
+ return evicted.length > 0 && (this.file = next, this.persist()), evicted;
2285
+ }
2286
+ upsert(rows) {
2287
+ rows.length !== 0 && (this.file = upsertUserModels(this.file, rows), this.persist());
2288
+ }
2289
+ persist() {
2290
+ if (this.path)
2291
+ try {
2292
+ writeUserModels(this.file, this.path);
2293
+ } catch {
2294
+ }
2295
+ }
2296
+ };
2297
+
2298
+ // packages/coding-agent/dist/core/model-runtime.js
2299
+ function mergeHeaders(base, override) {
2300
+ if (!base && !override)
2301
+ return;
2302
+ let merged = { ...base };
2303
+ for (let [name, value] of Object.entries(override ?? {})) {
2304
+ let lowerName = name.toLowerCase();
2305
+ for (let existingName of Object.keys(merged))
2306
+ existingName.toLowerCase() === lowerName && delete merged[existingName];
2307
+ merged[name] = value;
2308
+ }
2309
+ return merged;
2310
+ }
2311
+ var ModelRuntime = class _ModelRuntime {
2312
+ models;
2313
+ credentials;
2314
+ /** lunr: per-provider subscription-key pools; rotation mirrors the active key into the credential store. */
2315
+ subscriptionManager;
2316
+ defaultBuiltins;
2317
+ builtins = /* @__PURE__ */ new Map();
2318
+ extensionProviders = /* @__PURE__ */ new Map();
2319
+ compositionErrors = /* @__PURE__ */ new Map();
2320
+ modelsPath;
2321
+ allowModelNetwork;
2322
+ config;
2323
+ snapshot = {
2324
+ all: [],
2325
+ available: [],
2326
+ configuredProviders: /* @__PURE__ */ new Set(),
2327
+ storedProviders: /* @__PURE__ */ new Set(),
2328
+ auth: /* @__PURE__ */ new Map()
2329
+ };
2330
+ availabilityRefresh;
2331
+ availabilityError;
2332
+ modelsStore;
2333
+ overlay = new CatalogOverlaySource();
2334
+ userModels;
2335
+ officialCachePath;
2336
+ lastCatalogRefresh = { aborted: !1, errors: /* @__PURE__ */ new Map(), live: [], incomplete: [] };
2337
+ lastOfficial;
2338
+ catalogRefresh;
2339
+ catalogRefreshAllowsNetwork = !1;
2340
+ nextAutomaticRefresh = 0;
2341
+ automaticRefreshIdentity = "";
2342
+ grokHome;
2343
+ constructor(credentials, config, modelsPath, modelsStore, providers, allowModelNetwork, subscriptionManager, catalogDir, grokHome) {
2344
+ this.credentials = credentials, this.config = config, this.modelsPath = modelsPath, this.modelsStore = modelsStore, this.allowModelNetwork = allowModelNetwork, this.subscriptionManager = subscriptionManager, this.userModels = new UserModelsStore(catalogDir ? userModelsPath(catalogDir) : void 0), this.officialCachePath = catalogDir ? officialCatalogCachePath(catalogDir) : void 0, this.grokHome = grokHome, this.defaultBuiltins = new Map(providers.map((provider) => [provider.id, provider]));
2345
+ for (let [providerId, provider] of this.defaultBuiltins)
2346
+ this.builtins.set(providerId, provider);
2347
+ this.models = createModels({ credentials, modelsStore }), this.rebuildProviders();
2348
+ }
2349
+ static async create(options = {}) {
2350
+ let rawStore = options.credentials ?? AuthStorage.create(options.authPath), grokHomeDisabled = options.grokHome === null || options.grokHome === void 0 && options.credentials !== void 0, grokHome = grokHomeDisabled ? void 0 : options.grokHome ?? void 0, baseStore = grokHomeDisabled ? rawStore : wrapXaiGrokCliCredentials(rawStore, { grokHome }), credentials = new RuntimeCredentials(baseStore), subscriptionManager = options.subscriptions ?? (options.credentials && !options.authPath ? SubscriptionManager.inMemory(baseStore) : SubscriptionManager.create(baseStore, options.authPath ? join7(dirname5(options.authPath), "subscriptions.json") : void 0)), modelsPath = options.modelsPath === null ? void 0 : options.modelsPath ?? join7(getAgentDir(), "models.json"), config = await ModelConfig.load(modelsPath), modelsStore = options.modelsStore ?? (modelsPath ? new FileModelsStore(options.modelsStorePath ?? join7(dirname5(modelsPath), "models-store.json")) : new InMemoryCodingAgentModelsStore()), providers = builtinProviderCatalog.builtinProviders(), catalogDir = modelsPath ? dirname5(modelsPath) : options.authPath ? dirname5(options.authPath) : void 0, runtime = new _ModelRuntime(credentials, config, modelsPath, modelsStore, providers, options.allowModelNetwork ?? process.env.PI_OFFLINE === void 0, subscriptionManager, catalogDir, grokHome);
2351
+ return runtime.configureRadiusProviders(), runtime.rebuildProviders(), await runtime.refresh({ allowNetwork: !1 }), runtime;
2352
+ }
2353
+ configureRadiusProviders() {
2354
+ this.builtins.clear();
2355
+ for (let [providerId, provider] of this.defaultBuiltins)
2356
+ this.builtins.set(providerId, provider);
2357
+ for (let providerId of this.config.getProviderIds()) {
2358
+ let config = this.config.getProvider(providerId);
2359
+ config?.oauth !== "radius" || !config.baseUrl || this.builtins.set(providerId, builtinProviderCatalog.radiusProvider({
2360
+ id: providerId,
2361
+ name: config.name ?? providerId,
2362
+ gateway: config.baseUrl.replace(/\/v1\/?$/u, "")
2363
+ }));
2364
+ }
2365
+ }
2366
+ providerIds() {
2367
+ return /* @__PURE__ */ new Set([...this.builtins.keys(), ...this.config.getProviderIds(), ...this.extensionProviders.keys()]);
2368
+ }
2369
+ recomposeProvider(providerId) {
2370
+ let base = this.builtins.get(providerId), extension = this.extensionProviders.get(providerId);
2371
+ if (!base && !this.config.getProvider(providerId) && !extension) {
2372
+ this.models.deleteProvider(providerId), this.compositionErrors.delete(providerId);
2373
+ return;
2374
+ }
2375
+ if (base && !this.config.getProvider(providerId) && !extension) {
2376
+ this.models.setProvider(this.withLocalCatalog(base)), this.compositionErrors.delete(providerId);
2377
+ return;
2378
+ }
2379
+ try {
2380
+ this.models.setProvider(composeModelProvider(providerId, base ? this.withLocalCatalog(base) : void 0, this.config, extension)), this.compositionErrors.delete(providerId);
2381
+ } catch (error) {
2382
+ this.compositionErrors.set(providerId, error instanceof Error ? error.message : String(error)), base ? this.models.setProvider(this.withLocalCatalog(base)) : this.models.deleteProvider(providerId);
2383
+ }
2384
+ }
2385
+ withLocalCatalog(provider) {
2386
+ return withCatalogOverlay(provider, this.overlay);
2387
+ }
2388
+ bakedInModels(providerId) {
2389
+ return [...this.defaultBuiltins.get(providerId)?.getModels() ?? []];
2390
+ }
2391
+ rebuildProviders() {
2392
+ this.models.clearProviders(), this.compositionErrors.clear();
2393
+ for (let providerId of this.providerIds())
2394
+ this.recomposeProvider(providerId);
2395
+ this.updateModelSnapshot();
2396
+ }
2397
+ updateModelSnapshot() {
2398
+ let all = [...this.models.getModels()];
2399
+ this.snapshot = {
2400
+ ...this.snapshot,
2401
+ all,
2402
+ available: all.filter((model) => this.snapshot.configuredProviders.has(model.provider) && this.isCatalogModelAvailable(model))
2403
+ };
2404
+ }
2405
+ isCatalogModelAvailable(model) {
2406
+ return !!this.config.getProvider(model.provider)?.models?.some((row) => row.id === model.id) || !!this.extensionProviders.get(model.provider)?.models?.some((row) => row.id === model.id) || this.overlay.isAvailable(model);
2407
+ }
2408
+ async listStoredProviderIds() {
2409
+ let credentials = await this.credentials.list();
2410
+ return new Set(credentials.map((entry) => entry.providerId));
2411
+ }
2412
+ /** `/model` lists stored creds + models.json/extension keys, never ambient envApiKeyAuth. */
2413
+ configuredProviderIds(storedProviders) {
2414
+ let configured = new Set(storedProviders);
2415
+ for (let provider of this.models.getProviders())
2416
+ configuredRequestAuthStatus(this.config.getProvider(provider.id), this.extensionProviders.get(provider.id))?.configured && configured.add(provider.id);
2417
+ return configured;
2418
+ }
2419
+ userModelsForStoredProviders(storedProviders) {
2420
+ return this.userModels.list().filter((row) => storedProviders.has(row.provider)).map(userEntryToModel);
2421
+ }
2422
+ async runAvailabilityRefresh() {
2423
+ let providers = this.models.getProviders(), [available, checks, storedProviders] = await Promise.all([
2424
+ this.models.getAvailable(),
2425
+ Promise.all(providers.map(async (provider) => [
2426
+ provider.id,
2427
+ await this.models.checkAuth(provider.id)
2428
+ ])),
2429
+ this.listStoredProviderIds()
2430
+ ]), auth = new Map(checks), configuredProviders = this.configuredProviderIds(storedProviders);
2431
+ this.snapshot = {
2432
+ all: [...this.models.getModels()],
2433
+ available: available.filter((model) => configuredProviders.has(model.provider) && this.isCatalogModelAvailable(model)),
2434
+ configuredProviders,
2435
+ storedProviders,
2436
+ auth
2437
+ }, this.availabilityError = void 0;
2438
+ }
2439
+ queueAvailabilityRefresh(after) {
2440
+ let tracked = (after ?? Promise.resolve()).catch(() => {
2441
+ }).then(() => this.runAvailabilityRefresh()).catch((error) => {
2442
+ throw this.availabilityError = error instanceof Error ? error.message : String(error), error;
2443
+ }).finally(() => {
2444
+ this.availabilityRefresh === tracked && (this.availabilityRefresh = void 0);
2445
+ });
2446
+ return this.availabilityRefresh = tracked, tracked;
2447
+ }
2448
+ /** Coalesce concurrent readers onto the pending refresh. */
2449
+ refreshAvailability() {
2450
+ return this.availabilityRefresh ?? this.queueAvailabilityRefresh(void 0);
2451
+ }
2452
+ /** Mutations must not observe an in-flight refresh started before them. */
2453
+ forceRefreshAvailability() {
2454
+ return this.queueAvailabilityRefresh(this.availabilityRefresh);
2455
+ }
2456
+ getProviders() {
2457
+ return this.models.getProviders();
2458
+ }
2459
+ getProvider(providerId) {
2460
+ return this.models.getProvider(providerId);
2461
+ }
2462
+ getModels(providerId) {
2463
+ return this.models.getModels(providerId);
2464
+ }
2465
+ getModel(providerId, modelId) {
2466
+ return this.models.getModel(providerId, modelId);
2467
+ }
2468
+ async checkAuth(providerId) {
2469
+ return this.models.checkAuth(providerId);
2470
+ }
2471
+ async getAvailable(providerId) {
2472
+ if (providerId) {
2473
+ if (this.availabilityRefresh)
2474
+ return await this.availabilityRefresh, this.snapshot.available.filter((model) => model.provider === providerId);
2475
+ try {
2476
+ return (await this.models.getAvailable(providerId)).filter((model) => this.isCatalogModelAvailable(model));
2477
+ } catch (error) {
2478
+ throw this.availabilityError = error instanceof Error ? error.message : String(error), error;
2479
+ }
2480
+ }
2481
+ return await this.refreshAvailability(), this.snapshot.available;
2482
+ }
2483
+ getAvailableSnapshot() {
2484
+ return this.snapshot.available;
2485
+ }
2486
+ getError() {
2487
+ let errors = [], configError = this.config.getError();
2488
+ configError && errors.push(configError);
2489
+ for (let [providerId, error] of this.compositionErrors)
2490
+ errors.push(`Provider "${providerId}": ${error}`);
2491
+ return this.availabilityError && errors.push(`Availability refresh: ${this.availabilityError}`), errors.length > 0 ? errors.join(`
2492
+
2493
+ `) : void 0;
2494
+ }
2495
+ getRegisteredProviderConfig(providerId) {
2496
+ return this.extensionProviders.get(providerId);
2497
+ }
2498
+ getRegisteredProviderIds() {
2499
+ return [...this.extensionProviders.keys()];
2500
+ }
2501
+ /** @internal Compatibility fallback for ModelRegistry when provider auth is unconfigured. */
2502
+ getCompatibilityRequestConfig(model) {
2503
+ return resolveCompatibilityRequestConfig(model, this.config.getProvider(model.provider), this.extensionProviders.get(model.provider));
2504
+ }
2505
+ isUsingOAuth(providerId) {
2506
+ return this.snapshot.auth.get(providerId)?.type === "oauth";
2507
+ }
2508
+ hasConfiguredAuth(providerId) {
2509
+ return this.snapshot.configuredProviders.has(providerId);
2510
+ }
2511
+ async getAuth(providerOrModel, overrides = {}) {
2512
+ if (typeof providerOrModel == "string")
2513
+ return this.models.getAuth(providerOrModel, overrides);
2514
+ let resolution = await this.models.getAuth(providerOrModel, overrides);
2515
+ if (!resolution)
2516
+ return;
2517
+ let configuredHeaders2 = resolveConfiguredModelHeaders(providerOrModel, this.config.getProvider(providerOrModel.provider), this.extensionProviders.get(providerOrModel.provider), { ...resolution.env ?? {}, ...overrides.env ?? {} });
2518
+ return {
2519
+ ...resolution,
2520
+ auth: {
2521
+ ...resolution.auth,
2522
+ headers: mergeHeaders(resolution.auth.headers, configuredHeaders2)
2523
+ }
2524
+ };
2525
+ }
2526
+ /** lunr: whether a runtime --api-key override is active for the provider (it shadows auth.json). */
2527
+ hasRuntimeApiKey(providerId) {
2528
+ return this.credentials.hasRuntimeApiKey(providerId);
2529
+ }
2530
+ async setRuntimeApiKey(providerId, apiKey, options) {
2531
+ this.credentials.setRuntimeApiKey(providerId, apiKey);
2532
+ let auth = new Map(this.snapshot.auth).set(providerId, { type: "api_key", source: "runtime API key" }), configuredProviders = new Set(this.snapshot.configuredProviders).add(providerId), storedProviders = new Set(this.snapshot.storedProviders).add(providerId);
2533
+ this.snapshot = {
2534
+ ...this.snapshot,
2535
+ auth,
2536
+ configuredProviders,
2537
+ storedProviders,
2538
+ available: this.snapshot.all.filter((model) => configuredProviders.has(model.provider) && this.isCatalogModelAvailable(model))
2539
+ }, await this.refresh({ allowNetwork: options?.allowNetwork ?? this.allowModelNetwork });
2540
+ }
2541
+ async removeRuntimeApiKey(providerId) {
2542
+ this.credentials.removeRuntimeApiKey(providerId), await this.refresh({ allowNetwork: this.allowModelNetwork });
2543
+ }
2544
+ /** lunr: whether network model-catalog fetches are allowed (offline mode disables them). */
2545
+ isNetworkAllowed() {
2546
+ return this.allowModelNetwork;
2547
+ }
2548
+ listCredentials() {
2549
+ return this.credentials.list();
2550
+ }
2551
+ getProviderAuthStatus(providerId) {
2552
+ if (this.credentials.hasRuntimeApiKey(providerId))
2553
+ return { configured: !0, source: "runtime" };
2554
+ if (this.snapshot.storedProviders.has(providerId))
2555
+ return { configured: !0, source: "stored" };
2556
+ let configured = configuredRequestAuthStatus(this.config.getProvider(providerId), this.extensionProviders.get(providerId));
2557
+ if (configured)
2558
+ return configured;
2559
+ let check = this.snapshot.auth.get(providerId);
2560
+ return check ? { configured: !0, source: "environment", label: check.source } : { configured: !1 };
2561
+ }
2562
+ async prepareRequest(model, options) {
2563
+ let provider = this.models.getProvider(model.provider);
2564
+ if (!provider)
2565
+ throw new ModelsError("provider", `Unknown provider: ${model.provider}`);
2566
+ let resolution = await this.getAuth(model, { apiKey: options?.apiKey, env: options?.env });
2567
+ if (!resolution)
2568
+ throw new ModelsError("auth", `Provider is not configured: ${model.provider}`);
2569
+ let { transformHeaders, ...providerOptions } = options ?? {}, headers = mergeHeaders(resolution.auth.headers, providerOptions.headers);
2570
+ transformHeaders && (headers = await transformHeaders(headers ?? {}));
2571
+ let env = resolution.env || providerOptions.env ? { ...resolution.env ?? {}, ...providerOptions.env ?? {} } : void 0;
2572
+ return {
2573
+ provider,
2574
+ model: resolution.auth.baseUrl ? { ...model, baseUrl: resolution.auth.baseUrl } : model,
2575
+ options: {
2576
+ ...providerOptions,
2577
+ apiKey: providerOptions.apiKey ?? resolution.auth.apiKey,
2578
+ headers,
2579
+ env
2580
+ }
2581
+ };
2582
+ }
2583
+ stream(model, context, options) {
2584
+ return lazyStream2(model, async () => {
2585
+ let prepared = await this.prepareRequest(model, options);
2586
+ return prepared.provider.stream(prepared.model, context, prepared.options);
2587
+ });
2588
+ }
2589
+ complete(model, context, options) {
2590
+ return this.stream(model, context, options).result();
2591
+ }
2592
+ streamSimple(model, context, options) {
2593
+ return lazyStream2(model, async () => {
2594
+ let prepared = await this.prepareRequest(model, options);
2595
+ return prepared.provider.streamSimple(prepared.model, context, prepared.options);
2596
+ });
2597
+ }
2598
+ completeSimple(model, context, options) {
2599
+ return this.streamSimple(model, context, options).result();
2600
+ }
2601
+ async login(providerId, type, interaction) {
2602
+ let credential = await this.models.login(providerId, type, interaction);
2603
+ return clearPlanUsageCache(), await this.refresh({ allowNetwork: this.allowModelNetwork }), credential;
2604
+ }
2605
+ async logout(providerId) {
2606
+ await this.models.logout(providerId), await this.modelsStore.delete(providerId), this.userModels.evictProvider(providerId), this.overlay.setLive(providerId, []), this.recomposeProvider(providerId), clearPlanUsageCache(), await this.refresh({ allowNetwork: this.allowModelNetwork });
2607
+ }
2608
+ /** Copy a live Grok CLI SuperGrok session into lunR `auth.json`. */
2609
+ async importGrokCliXaiAuth() {
2610
+ let grok = readGrokCliXaiOAuth({ grokHome: this.grokHome });
2611
+ if (!grok)
2612
+ return;
2613
+ let stored = await this.credentials.modify("xai", async () => grok);
2614
+ return clearPlanUsageCache(), await this.refresh({ allowNetwork: this.allowModelNetwork }), stored;
2615
+ }
2616
+ async reloadConfig() {
2617
+ this.config = await ModelConfig.load(this.modelsPath), this.configureRadiusProviders(), this.rebuildProviders(), await this.refresh({ allowNetwork: this.allowModelNetwork });
2618
+ }
2619
+ async refresh(options = {}) {
2620
+ let allowNetwork = options.allowNetwork ?? this.allowModelNetwork;
2621
+ if (this.catalogRefresh)
2622
+ return this.catalogRefreshAllowsNetwork || !allowNetwork ? this.catalogRefresh : (await this.catalogRefresh.catch(() => {
2623
+ }), this.refresh({ ...options, allowNetwork }));
2624
+ let run = this.executeCatalogRefresh({ ...options, allowNetwork }).finally(() => {
2625
+ this.catalogRefresh === run && (this.catalogRefresh = void 0, this.catalogRefreshAllowsNetwork = !1);
2626
+ });
2627
+ return this.catalogRefresh = run, this.catalogRefreshAllowsNetwork = allowNetwork, run;
2628
+ }
2629
+ async executeCatalogRefresh(refreshOptions) {
2630
+ let official = await this.refreshOfficialCatalog(refreshOptions.allowNetwork, refreshOptions.signal), live = refreshOptions.allowNetwork ? await this.refreshLiveCatalogs(official ? officialModelKeys(official.catalog) : /* @__PURE__ */ new Set(), refreshOptions.signal) : await this.restoreLiveCatalogs(), result = await this.models.refresh(refreshOptions) ?? {
2631
+ aborted: refreshOptions.signal?.aborted ?? !1,
2632
+ errors: /* @__PURE__ */ new Map()
2633
+ }, errors = new Map(result.errors);
2634
+ for (let [id, error] of Object.entries(official?.errors ?? {}))
2635
+ errors.set(id, new Error(error));
2636
+ for (let entry of live)
2637
+ (entry.status === "error" || entry.status === "timeout") && errors.set(entry.providerId, new Error(entry.error ?? entry.status));
2638
+ this.updateModelSnapshot();
2639
+ try {
2640
+ await this.forceRefreshAvailability();
2641
+ } catch {
2642
+ }
2643
+ let catalogResult = {
2644
+ aborted: result.aborted,
2645
+ errors,
2646
+ official,
2647
+ live,
2648
+ incomplete: live.flatMap((entry) => entry.incomplete)
2649
+ };
2650
+ return this.lastCatalogRefresh = catalogResult, catalogResult;
2651
+ }
2652
+ getLastCatalogRefresh() {
2653
+ return this.lastCatalogRefresh;
2654
+ }
2655
+ /** Called after first paint and by the picker; explicit /refresh always bypasses this gate. */
2656
+ async refreshIfStale(options = {}) {
2657
+ if (!this.allowModelNetwork || options.signal?.aborted)
2658
+ return this.lastCatalogRefresh;
2659
+ if (this.catalogRefresh)
2660
+ return this.refresh({ allowNetwork: !0, signal: options.signal });
2661
+ let providers = [...await this.listStoredProviderIds()].sort(), identity = (await Promise.all(providers.map(async (id) => this.scopeFor(id)))).join(":");
2662
+ if (identity === this.automaticRefreshIdentity && Date.now() < this.nextAutomaticRefresh)
2663
+ return this.lastCatalogRefresh;
2664
+ this.automaticRefreshIdentity = identity, this.nextAutomaticRefresh = Date.now() + 6e4;
2665
+ let result = await this.refresh({ allowNetwork: !0, signal: options.signal });
2666
+ return !result.aborted && !result.errors.size && (this.nextAutomaticRefresh = Date.now() + 36e5), result;
2667
+ }
2668
+ async scopeFor(providerId) {
2669
+ let provider = this.models.getProvider(providerId) ?? this.defaultBuiltins.get(providerId);
2670
+ return catalogCacheScope(providerId, provider?.baseUrl ?? "", await this.credentials.read(providerId));
2671
+ }
2672
+ persistUserModels(rows) {
2673
+ this.userModels.upsert(rows), this.overlay.setUser(this.userModelsForStoredProviders(this.snapshot.storedProviders)), this.updateModelSnapshot();
2674
+ }
2675
+ async refreshOfficialCatalog(allowNetwork, signal) {
2676
+ let storedProviders = await this.listStoredProviderIds(), loaded = preferOfficialCatalog(this.lastOfficial, await loadOfficialCatalog({
2677
+ allowNetwork,
2678
+ cachePath: this.officialCachePath,
2679
+ signal,
2680
+ providerIds: [...storedProviders]
2681
+ }));
2682
+ this.lastOfficial = loaded;
2683
+ let evicted = this.userModels.evictOfficial(officialModelKeys(loaded.catalog)), templateByProvider = /* @__PURE__ */ new Map(), officialModels = loaded.catalog.models.filter((entry) => storedProviders.has(entry.provider)).map((entry) => (templateByProvider.has(entry.provider) || templateByProvider.set(entry.provider, this.bakedInModels(entry.provider)[0]), officialEntryToModel(entry, templateByProvider.get(entry.provider))));
2684
+ return this.overlay.setOfficial(officialModels), this.overlay.setUser(this.userModelsForStoredProviders(storedProviders)), { ...loaded, evictedUserRows: evicted.length };
2685
+ }
2686
+ async restoreLiveCatalogs() {
2687
+ let storedProviders = await this.listStoredProviderIds(), results = [];
2688
+ for (let providerId of LIVE_LIST_PROVIDER_IDS) {
2689
+ let stored = storedProviders.has(providerId) ? await this.modelsStore.read(providerId) : void 0;
2690
+ (!stored?.scope && providerId !== "openai-codex" || stored?.scope === await this.scopeFor(providerId)) && stored?.models ? this.overlay.setLive(providerId, stored.models) : this.overlay.setLive(providerId, []), results.push({
2691
+ providerId,
2692
+ status: "skipped",
2693
+ discoveries: [],
2694
+ added: 0,
2695
+ total: stored?.models.length ?? 0,
2696
+ incomplete: []
2697
+ });
2698
+ }
2699
+ return results;
2700
+ }
2701
+ async refreshLiveCatalogs(officialKeys, signal) {
2702
+ let storedProviders = await this.listStoredProviderIds(), known = knownModelKeys(LIVE_LIST_PROVIDER_IDS.flatMap((id) => this.bakedInModels(id)), officialKeys, this.userModels.keys());
2703
+ return await Promise.all(LIVE_LIST_PROVIDER_IDS.map(async (providerId) => {
2704
+ if (!storedProviders.has(providerId))
2705
+ return this.overlay.setLive(providerId, []), {
2706
+ providerId,
2707
+ status: "skipped",
2708
+ discoveries: [],
2709
+ added: 0,
2710
+ total: 0,
2711
+ incomplete: []
2712
+ };
2713
+ let stored = await this.modelsStore.read(providerId), initialScope = await this.scopeFor(providerId);
2714
+ if (stored?.models && (stored.scope === initialScope || !stored.scope && providerId !== "openai-codex") ? this.overlay.setLive(providerId, stored.models) : this.overlay.setLive(providerId, []), signal?.aborted)
2715
+ return {
2716
+ providerId,
2717
+ status: "skipped",
2718
+ discoveries: [],
2719
+ added: 0,
2720
+ total: stored?.models.length ?? 0,
2721
+ incomplete: [],
2722
+ error: "aborted"
2723
+ };
2724
+ let bakedIn = this.bakedInModels(providerId), baseUrl = (this.models.getProvider(providerId) ?? this.defaultBuiltins.get(providerId))?.baseUrl ?? bakedIn[0]?.baseUrl;
2725
+ if (!baseUrl)
2726
+ return {
2727
+ providerId,
2728
+ status: "skipped",
2729
+ discoveries: [],
2730
+ added: 0,
2731
+ total: 0,
2732
+ incomplete: []
2733
+ };
2734
+ let credential;
2735
+ try {
2736
+ credential = await this.refreshCredentialFor(providerId);
2737
+ } catch (error) {
2738
+ return {
2739
+ providerId,
2740
+ status: "error",
2741
+ discoveries: [],
2742
+ added: 0,
2743
+ total: stored?.models.length ?? 0,
2744
+ incomplete: [],
2745
+ error: error instanceof Error ? error.message : String(error)
2746
+ };
2747
+ }
2748
+ if (!credential)
2749
+ return {
2750
+ providerId,
2751
+ status: "skipped",
2752
+ discoveries: [],
2753
+ added: 0,
2754
+ total: stored?.models.length ?? 0,
2755
+ incomplete: []
2756
+ };
2757
+ let requestScope = catalogCacheScope(providerId, baseUrl, credential), result = await fetchLiveProviderModels({
2758
+ discoveryClientVersion: stored?.scope === requestScope ? stored.discoveryClientVersion : void 0,
2759
+ providerId,
2760
+ baseUrl,
2761
+ bakedIn,
2762
+ credential,
2763
+ knownKeys: known,
2764
+ signal
2765
+ }), accountChanged = await this.scopeFor(providerId) !== requestScope;
2766
+ if (accountChanged && this.overlay.setLive(providerId, []), signal?.aborted || accountChanged)
2767
+ return { ...result, status: "skipped", discoveries: [], incomplete: [] };
2768
+ if (result.status === "ok") {
2769
+ let overlayModels = buildLiveOverlay(bakedIn, result.discoveries);
2770
+ this.overlay.setLive(providerId, overlayModels);
2771
+ try {
2772
+ await this.modelsStore.write(providerId, {
2773
+ models: overlayModels,
2774
+ checkedAt: Date.now(),
2775
+ scope: requestScope,
2776
+ discoveryClientVersion: result.discoveryClientVersion
2777
+ });
2778
+ } catch {
2779
+ }
2780
+ }
2781
+ return result;
2782
+ }));
2783
+ }
2784
+ async refreshCredentialFor(providerId) {
2785
+ let resolved = await this.getAuth(providerId), stored = await this.credentials.read(providerId);
2786
+ if (stored?.type === "oauth")
2787
+ return { ...stored, access: resolved?.auth.apiKey ?? stored.access };
2788
+ if (resolved?.auth.apiKey)
2789
+ return { type: "api_key", key: resolved.auth.apiKey, env: resolved.env };
2790
+ if (stored?.type === "api_key" && stored.key)
2791
+ return stored;
2792
+ }
2793
+ registerProvider(providerId, config) {
2794
+ validateExtensionProvider(providerId, this.builtins.get(providerId), this.config.getProvider(providerId), config);
2795
+ let effective = { ...this.extensionProviders.get(providerId) };
2796
+ for (let [key, value] of Object.entries(config))
2797
+ value !== void 0 && (effective[key] = value);
2798
+ if (this.extensionProviders.set(providerId, effective), this.recomposeProvider(providerId), this.updateModelSnapshot(), this.snapshot.storedProviders.has(providerId) || configuredRequestAuthStatus(this.config.getProvider(providerId), effective)?.configured) {
2799
+ let configuredProviders = new Set(this.snapshot.configuredProviders).add(providerId), auth = new Map(this.snapshot.auth);
2800
+ auth.get(providerId) || auth.set(providerId, {
2801
+ type: effective.oauth && !effective.apiKey ? "oauth" : "api_key",
2802
+ source: "configured provider"
2803
+ }), this.snapshot = {
2804
+ ...this.snapshot,
2805
+ auth,
2806
+ configuredProviders,
2807
+ available: this.snapshot.all.filter((model) => configuredProviders.has(model.provider) && this.isCatalogModelAvailable(model))
2808
+ };
2809
+ }
2810
+ this.refresh({ allowNetwork: !1 });
2811
+ }
2812
+ unregisterProvider(providerId) {
2813
+ this.extensionProviders.delete(providerId), this.recomposeProvider(providerId), this.updateModelSnapshot(), this.refresh({ allowNetwork: !1 });
2814
+ }
2815
+ };
2816
+ async function refreshModelCandidatesForInit(runtime) {
2817
+ return await runtime.refresh({ allowNetwork: !1 }), runtime.getAvailableSnapshot();
2818
+ }
2819
+
2820
+ export {
2821
+ AuthStorage,
2822
+ readStoredCredential,
2823
+ formatCatalogRefreshSummary,
2824
+ hasGrokCliXaiAuth,
2825
+ stripJsonComments,
2826
+ isUsageLimitError,
2827
+ isAuthInvalidError,
2828
+ ModelRuntime,
2829
+ refreshModelCandidatesForInit
2830
+ };