@fudrouter/fsrouter 0.6.72 → 0.6.74

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 (314) hide show
  1. package/dist/lib/headroom/detect.js +97 -7
  2. package/dist/lib/headroom/process.js +136 -4
  3. package/dist/open-sse/config/appConstants.js +23 -79
  4. package/dist/open-sse/config/cliFingerprints.js +1 -1
  5. package/dist/open-sse/config/errorConfig.js +0 -11
  6. package/dist/open-sse/config/grokCli.js +10 -0
  7. package/dist/open-sse/config/kiroConstants.js +99 -46
  8. package/dist/open-sse/config/runtimeConfig.js +2 -0
  9. package/dist/open-sse/config/ttsModels.js +2 -0
  10. package/dist/open-sse/executors/antigravity.js +250 -164
  11. package/dist/open-sse/executors/base.js +16 -11
  12. package/dist/open-sse/executors/codex.js +269 -1108
  13. package/dist/open-sse/executors/commandCode.js +1 -1
  14. package/dist/open-sse/executors/commandcode.js +10 -4
  15. package/dist/open-sse/executors/cursor.js +96 -203
  16. package/dist/open-sse/executors/default.js +146 -244
  17. package/dist/open-sse/executors/github.js +128 -73
  18. package/dist/open-sse/executors/grok-cli.js +527 -94
  19. package/dist/open-sse/executors/grok-web.js +5 -7
  20. package/dist/open-sse/executors/index.js +12 -0
  21. package/dist/open-sse/executors/kiro.js +150 -61
  22. package/dist/open-sse/executors/opencode-go.js +12 -4
  23. package/dist/open-sse/executors/opencode.js +1 -1
  24. package/dist/open-sse/executors/perplexity-web.js +20 -96
  25. package/dist/open-sse/executors/qoder.js +28 -18
  26. package/dist/open-sse/executors/vertex.js +53 -7
  27. package/dist/open-sse/executors/xiaomi-tokenplan.js +6 -5
  28. package/dist/open-sse/handlers/chatCore/nonStreamingHandler.js +97 -85
  29. package/dist/open-sse/handlers/chatCore/requestDetail.js +32 -8
  30. package/dist/open-sse/handlers/chatCore/sseToJsonHandler.js +13 -7
  31. package/dist/open-sse/handlers/chatCore/streamingHandler.js +74 -25
  32. package/dist/open-sse/handlers/chatCore.js +35 -41
  33. package/dist/open-sse/handlers/embeddingProviders/index.js +1 -0
  34. package/dist/open-sse/handlers/embeddingProviders/openai.js +8 -16
  35. package/dist/open-sse/handlers/imageProviders/blackForestLabs.js +2 -21
  36. package/dist/open-sse/handlers/imageProviders/cloudflareAi.js +2 -30
  37. package/dist/open-sse/handlers/imageProviders/codex.js +2 -20
  38. package/dist/open-sse/handlers/imageProviders/comfyui.js +5 -18
  39. package/dist/open-sse/handlers/imageProviders/falAi.js +2 -22
  40. package/dist/open-sse/handlers/imageProviders/gemini.js +2 -16
  41. package/dist/open-sse/handlers/imageProviders/huggingface.js +2 -17
  42. package/dist/open-sse/handlers/imageProviders/index.js +3 -4
  43. package/dist/open-sse/handlers/imageProviders/leonardo.js +1 -1
  44. package/dist/open-sse/handlers/imageProviders/nanobanana.js +4 -23
  45. package/dist/open-sse/handlers/imageProviders/openai.js +15 -43
  46. package/dist/open-sse/handlers/imageProviders/runwayml.js +2 -26
  47. package/dist/open-sse/handlers/imageProviders/sdwebui.js +4 -20
  48. package/dist/open-sse/handlers/imageProviders/stabilityAi.js +2 -26
  49. package/dist/open-sse/handlers/imageProviders/weavy.js +1 -1
  50. package/dist/open-sse/handlers/search/chatSearch.js +60 -14
  51. package/dist/open-sse/handlers/ttsProviders/gemini.js +14 -3
  52. package/dist/open-sse/handlers/ttsProviders/index.js +4 -2
  53. package/dist/open-sse/handlers/ttsProviders/openai.js +4 -1
  54. package/dist/open-sse/handlers/ttsProviders/openrouter.js +7 -4
  55. package/dist/open-sse/handlers/videoCore.js +166 -0
  56. package/dist/open-sse/handlers/videoProviders/weavy.js +1 -1
  57. package/dist/open-sse/mcp-server/catalog.js +1 -1
  58. package/dist/open-sse/mcp-server/server.js +2 -2
  59. package/dist/open-sse/mcp-server/tools/advancedTools.js +2 -2
  60. package/dist/open-sse/mcp-server/tools/agentSkillTools.js +1 -1
  61. package/dist/open-sse/mcp-server/tools/compressionTools.js +4 -4
  62. package/dist/open-sse/mcp-server/tools/gamificationTools.js +10 -10
  63. package/dist/open-sse/mcp-server/tools/githubSkillTools.js +1 -1
  64. package/dist/open-sse/mcp-server/tools/memoryTools.js +3 -3
  65. package/dist/open-sse/mcp-server/tools/notionTools.js +2 -2
  66. package/dist/open-sse/mcp-server/tools/obsidianTools.js +2 -2
  67. package/dist/open-sse/mcp-server/tools/pickFastestModel.js +1 -1
  68. package/dist/open-sse/mcp-server/tools/pluginTools.js +4 -4
  69. package/dist/open-sse/mcp-server/tools/skillTools.js +2 -2
  70. package/dist/open-sse/providers/capabilities.js +24 -4
  71. package/dist/open-sse/providers/registry/alicode-intl.js +1 -1
  72. package/dist/open-sse/providers/registry/anthropic.js +1 -8
  73. package/dist/open-sse/providers/registry/codex.js +0 -9
  74. package/dist/open-sse/providers/registry/cohere.js +0 -2
  75. package/dist/open-sse/providers/registry/gemini.js +0 -2
  76. package/dist/open-sse/providers/registry/github.js +9 -6
  77. package/dist/open-sse/providers/registry/grok-cli.js +28 -18
  78. package/dist/open-sse/providers/registry/index.js +74 -80
  79. package/dist/open-sse/providers/registry/kiro.js +12 -0
  80. package/dist/open-sse/providers/registry/mistral.js +0 -3
  81. package/dist/open-sse/providers/registry/openai.js +0 -3
  82. package/dist/open-sse/providers/registry/perplexity.js +0 -2
  83. package/dist/open-sse/providers/registry/xai.js +5 -3
  84. package/dist/open-sse/rtk/autodetect.js +10 -2
  85. package/dist/open-sse/rtk/caveman.js +2 -93
  86. package/dist/open-sse/rtk/cavemanPrompts.js +34 -2
  87. package/dist/open-sse/rtk/constants.js +7 -2
  88. package/dist/open-sse/rtk/headroom.js +133 -0
  89. package/dist/open-sse/rtk/ponytail.js +1 -1
  90. package/dist/open-sse/rtk/registry.js +2 -0
  91. package/dist/open-sse/services/accountFallback.js +0 -108
  92. package/dist/open-sse/services/combo/quotaExhaustionCutoff.js +2 -2
  93. package/dist/open-sse/services/combo/quotaShareStrategy.js +1 -1
  94. package/dist/open-sse/services/combo/resolveAutoStrategy.js +1 -1
  95. package/dist/open-sse/services/combo/sessionStickiness.js +1 -1
  96. package/dist/open-sse/services/combo/targetSorters.js +2 -2
  97. package/dist/open-sse/services/combo/validateQuality.js +1 -1
  98. package/dist/open-sse/services/comboConfig.js +1 -1
  99. package/dist/open-sse/services/emergencyFallback.js +1 -1
  100. package/dist/open-sse/services/grokCliModels.js +127 -0
  101. package/dist/open-sse/services/model.js +7 -1
  102. package/dist/open-sse/services/provider.js +1 -1
  103. package/dist/open-sse/services/proxyAutoSelector.js +1 -1
  104. package/dist/open-sse/services/tokenRefresh/providers.js +3 -3
  105. package/dist/open-sse/services/usage/codex.js +148 -214
  106. package/dist/open-sse/services/usage/grok-cli.js +61 -7
  107. package/dist/open-sse/services/usage/misc.js +0 -19
  108. package/dist/open-sse/services/usage.js +0 -2
  109. package/dist/open-sse/translator/concerns/paramSupport.js +2 -2
  110. package/dist/open-sse/translator/concerns/thinkingUnified.js +6 -0
  111. package/dist/open-sse/translator/index.js +97 -59
  112. package/dist/open-sse/translator/request/claude-to-kiro.js +67 -40
  113. package/dist/open-sse/translator/request/openai-responses.js +1 -0
  114. package/dist/open-sse/translator/request/openai-to-commandcode.js +0 -4
  115. package/dist/open-sse/translator/request/openai-to-kiro.js +49 -20
  116. package/dist/open-sse/translator/response/commandcode-to-openai.js +0 -4
  117. package/dist/open-sse/utils/bypassHandler.js +18 -3
  118. package/dist/open-sse/utils/claudeCloaking.js +15 -5
  119. package/dist/open-sse/utils/cursorImages.js +1 -1
  120. package/dist/open-sse/utils/error.js +0 -17
  121. package/dist/open-sse/utils/keepaliveThreshold.js +4 -4
  122. package/dist/open-sse/utils/kiroSessionReplay.js +125 -0
  123. package/dist/open-sse/utils/noThinkingAlias.js +1 -1
  124. package/dist/open-sse/utils/proxyFetch.js +0 -1
  125. package/dist/open-sse/utils/reasoningContentInjector.js +4 -7
  126. package/dist/open-sse/utils/responsesStatePolicy.js +1 -1
  127. package/dist/open-sse/utils/responsesStreamHelpers.js +1 -0
  128. package/dist/open-sse/utils/sessionManager.js +49 -22
  129. package/dist/open-sse/utils/stream.js +54 -77
  130. package/dist/open-sse/utils/streamHandler.js +19 -15
  131. package/dist/open-sse/utils/streamHelpers.js +2 -17
  132. package/dist/open-sse/utils/usageTracking.js +103 -12
  133. package/dist/routes/headroom/extras/route.js +58 -0
  134. package/dist/routes/headroom/restart/route.js +33 -0
  135. package/open-sse/config/appConstants.js +23 -79
  136. package/open-sse/config/errorConfig.js +0 -11
  137. package/open-sse/config/grokCli.js +10 -0
  138. package/open-sse/config/kiroConstants.js +99 -46
  139. package/open-sse/config/runtimeConfig.js +2 -0
  140. package/open-sse/config/ttsModels.js +2 -0
  141. package/open-sse/executors/antigravity.js +250 -164
  142. package/open-sse/executors/base.js +16 -11
  143. package/open-sse/executors/codex.js +269 -1108
  144. package/open-sse/executors/commandcode.js +10 -4
  145. package/open-sse/executors/cursor.js +96 -203
  146. package/open-sse/executors/default.js +146 -244
  147. package/open-sse/executors/github.js +128 -73
  148. package/open-sse/executors/grok-cli.js +527 -94
  149. package/open-sse/executors/grok-web.js +5 -7
  150. package/open-sse/executors/index.js +12 -0
  151. package/open-sse/executors/kiro.js +150 -61
  152. package/open-sse/executors/opencode-go.js +12 -4
  153. package/open-sse/executors/opencode.js +1 -1
  154. package/open-sse/executors/perplexity-web.js +20 -96
  155. package/open-sse/executors/qoder.js +28 -18
  156. package/open-sse/executors/vertex.js +53 -7
  157. package/open-sse/executors/xiaomi-tokenplan.js +6 -5
  158. package/open-sse/handlers/chatCore/nonStreamingHandler.js +97 -85
  159. package/open-sse/handlers/chatCore/requestDetail.js +32 -8
  160. package/open-sse/handlers/chatCore/sseToJsonHandler.js +13 -7
  161. package/open-sse/handlers/chatCore/streamingHandler.js +74 -25
  162. package/open-sse/handlers/chatCore.js +35 -41
  163. package/open-sse/handlers/embeddingProviders/index.js +1 -0
  164. package/open-sse/handlers/embeddingProviders/openai.js +8 -16
  165. package/open-sse/handlers/imageProviders/blackForestLabs.js +2 -21
  166. package/open-sse/handlers/imageProviders/cloudflareAi.js +2 -30
  167. package/open-sse/handlers/imageProviders/codex.js +2 -20
  168. package/open-sse/handlers/imageProviders/comfyui.js +5 -18
  169. package/open-sse/handlers/imageProviders/falAi.js +2 -22
  170. package/open-sse/handlers/imageProviders/gemini.js +2 -16
  171. package/open-sse/handlers/imageProviders/huggingface.js +2 -17
  172. package/open-sse/handlers/imageProviders/index.js +3 -4
  173. package/open-sse/handlers/imageProviders/leonardo.js +1 -1
  174. package/open-sse/handlers/imageProviders/nanobanana.js +4 -23
  175. package/open-sse/handlers/imageProviders/openai.js +15 -43
  176. package/open-sse/handlers/imageProviders/runwayml.js +2 -26
  177. package/open-sse/handlers/imageProviders/sdwebui.js +4 -20
  178. package/open-sse/handlers/imageProviders/stabilityAi.js +2 -26
  179. package/open-sse/handlers/imageProviders/weavy.js +1 -1
  180. package/open-sse/handlers/search/chatSearch.js +60 -14
  181. package/open-sse/handlers/ttsProviders/gemini.js +14 -3
  182. package/open-sse/handlers/ttsProviders/index.js +4 -2
  183. package/open-sse/handlers/ttsProviders/openai.js +4 -1
  184. package/open-sse/handlers/ttsProviders/openrouter.js +7 -4
  185. package/open-sse/handlers/videoCore.js +166 -0
  186. package/open-sse/handlers/videoProviders/weavy.js +1 -1
  187. package/open-sse/mcp-server/audit.js +1 -1
  188. package/open-sse/mcp-server/catalog.js +2 -2
  189. package/open-sse/mcp-server/descriptionCompressor.js +1 -1
  190. package/open-sse/mcp-server/mcpCallerIdentity.js +1 -1
  191. package/open-sse/mcp-server/schemas/tools.js +1 -1
  192. package/open-sse/mcp-server/server.js +4 -4
  193. package/open-sse/mcp-server/tools/advancedTools.js +5 -5
  194. package/open-sse/mcp-server/tools/agentSkillTools.js +1 -1
  195. package/open-sse/mcp-server/tools/compressionTools.js +4 -4
  196. package/open-sse/mcp-server/tools/gamificationTools.js +10 -10
  197. package/open-sse/mcp-server/tools/githubSkillTools.js +1 -1
  198. package/open-sse/mcp-server/tools/memoryTools.js +3 -3
  199. package/open-sse/mcp-server/tools/notionTools.js +2 -2
  200. package/open-sse/mcp-server/tools/obsidianTools.js +2 -2
  201. package/open-sse/mcp-server/tools/pickFastestModel.js +3 -3
  202. package/open-sse/mcp-server/tools/pluginTools.js +4 -4
  203. package/open-sse/mcp-server/tools/skillTools.js +2 -2
  204. package/open-sse/providers/capabilities.js +24 -4
  205. package/open-sse/providers/registry/alicode-intl.js +1 -1
  206. package/open-sse/providers/registry/anthropic.js +1 -8
  207. package/open-sse/providers/registry/codex.js +0 -9
  208. package/open-sse/providers/registry/cohere.js +0 -2
  209. package/open-sse/providers/registry/gemini.js +0 -2
  210. package/open-sse/providers/registry/github.js +9 -6
  211. package/open-sse/providers/registry/grok-cli.js +28 -18
  212. package/open-sse/providers/registry/index.js +74 -80
  213. package/open-sse/providers/registry/kiro.js +12 -0
  214. package/open-sse/providers/registry/mistral.js +0 -3
  215. package/open-sse/providers/registry/openai.js +0 -3
  216. package/open-sse/providers/registry/perplexity.js +0 -2
  217. package/open-sse/providers/registry/xai.js +5 -3
  218. package/open-sse/rtk/autodetect.js +10 -2
  219. package/open-sse/rtk/caveman.js +2 -93
  220. package/open-sse/rtk/cavemanPrompts.js +34 -2
  221. package/open-sse/rtk/constants.js +7 -2
  222. package/open-sse/rtk/headroom.js +133 -0
  223. package/open-sse/rtk/ponytail.js +1 -1
  224. package/open-sse/rtk/registry.js +2 -0
  225. package/open-sse/services/accountFallback.js +0 -108
  226. package/open-sse/services/combo/quotaExhaustionCutoff.js +2 -2
  227. package/open-sse/services/combo/quotaShareStrategy.js +1 -1
  228. package/open-sse/services/combo/resolveAutoStrategy.js +1 -1
  229. package/open-sse/services/combo/sessionStickiness.js +1 -1
  230. package/open-sse/services/combo/shadowRouting.js +1 -1
  231. package/open-sse/services/combo/targetSorters.js +4 -4
  232. package/open-sse/services/combo/validateQuality.js +1 -1
  233. package/open-sse/services/evalRouting.js +1 -1
  234. package/open-sse/services/grokCliModels.js +127 -0
  235. package/open-sse/services/model.js +7 -1
  236. package/open-sse/services/modelCapabilities.js +1 -1
  237. package/open-sse/services/modelFamilyFallback.js +1 -1
  238. package/open-sse/services/provider.js +1 -1
  239. package/open-sse/services/providerCooldownTracker.js +1 -1
  240. package/open-sse/services/rateLimitManager.js +1 -1
  241. package/open-sse/services/tokenRefresh/providers.js +3 -3
  242. package/open-sse/services/usage/codex.js +148 -214
  243. package/open-sse/services/usage/grok-cli.js +61 -7
  244. package/open-sse/services/usage/misc.js +0 -19
  245. package/open-sse/services/usage.js +0 -2
  246. package/open-sse/translator/concerns/paramSupport.js +2 -2
  247. package/open-sse/translator/concerns/thinkingUnified.js +6 -0
  248. package/open-sse/translator/index.js +97 -59
  249. package/open-sse/translator/request/claude-to-kiro.js +67 -40
  250. package/open-sse/translator/request/openai-responses.js +1 -0
  251. package/open-sse/translator/request/openai-to-commandcode.js +0 -4
  252. package/open-sse/translator/request/openai-to-kiro.js +49 -20
  253. package/open-sse/translator/response/commandcode-to-openai.js +0 -4
  254. package/open-sse/utils/bypassHandler.js +18 -3
  255. package/open-sse/utils/claudeCloaking.js +15 -5
  256. package/open-sse/utils/error.js +0 -17
  257. package/open-sse/utils/kiroSessionReplay.js +125 -0
  258. package/open-sse/utils/logger.js +1 -1
  259. package/open-sse/utils/proxyFetch.js +0 -1
  260. package/open-sse/utils/reasoningContentInjector.js +4 -7
  261. package/open-sse/utils/responsesStreamHelpers.js +1 -0
  262. package/open-sse/utils/sessionManager.js +49 -22
  263. package/open-sse/utils/stream.js +54 -77
  264. package/open-sse/utils/streamHandler.js +19 -15
  265. package/open-sse/utils/streamHelpers.js +2 -17
  266. package/open-sse/utils/usageTracking.js +103 -12
  267. package/package.json +4 -7
  268. package/public/assets/EndpointPageClient.C2WMTYy0.js +6 -0
  269. package/public/assets/{Loading.Bj-WGl4k.js → Loading.BHPtQ9vj.js} +1 -1
  270. package/public/assets/{NoAuthProxyCard.qAv57b-0.js → NoAuthProxyCard.BDcXaWvM.js} +1 -1
  271. package/public/assets/index.Be3gbrBl.js +89 -0
  272. package/public/assets/index.COMgQZYj.css +1 -0
  273. package/public/assets/{page.CbkENBd5.js → page.-lpNgYAw.js} +1 -1
  274. package/public/assets/{page.CssmrzTT.js → page.11hpNKmq.js} +1 -1
  275. package/public/assets/{page.C72FTTJr.js → page.B-LxsnqU.js} +1 -1
  276. package/public/assets/{page.sOFOrxqq.js → page.B-dzeIUC.js} +1 -1
  277. package/public/assets/{page.CsxWmPoI.js → page.B-nBR75u.js} +1 -1
  278. package/public/assets/{page.Dx_GRRdT.js → page.B3QqvLep.js} +1 -1
  279. package/public/assets/{page.DPyOkPVo.js → page.B8xdkCWA.js} +1 -1
  280. package/public/assets/{page.DUI8kqOY.js → page.BFb7yUd8.js} +1 -1
  281. package/public/assets/page.BbPPdoas.js +1 -0
  282. package/public/assets/page.BdS20a1O.js +1 -0
  283. package/public/assets/{page.DibhF7f-.js → page.BfmI9KYe.js} +1 -1
  284. package/public/assets/{page.DX4Nno6M.js → page.BgGJovOg.js} +1 -1
  285. package/public/assets/{page.BnmTC5jG.js → page.C0gBvR4O.js} +1 -1
  286. package/public/assets/{page.D5gj98Oe.js → page.C6bYizL7.js} +1 -1
  287. package/public/assets/{page.vla5Mzki.js → page.C8sLEMa6.js} +1 -1
  288. package/public/assets/{page.CXd_R9yU.js → page.CCNsZBXp.js} +1 -1
  289. package/public/assets/{page.CQlVGoXg.js → page.CF_YSLwP.js} +1 -1
  290. package/public/assets/{page.BbO1pspY.js → page.CPTtRDxw.js} +1 -1
  291. package/public/assets/{page.D1oKew1j.js → page.CdMmlUEm.js} +1 -1
  292. package/public/assets/{page.DxMDTbSx.js → page.Cged1bOZ.js} +1 -1
  293. package/public/assets/{page.Cj5h09Zo.js → page.Ch647dVk.js} +1 -1
  294. package/public/assets/{page.DVIHRbxB.js → page.CpvXDkQF.js} +1 -1
  295. package/public/assets/{page.i4KDuWcM.js → page.CrBl7f8N.js} +1 -1
  296. package/public/assets/{page.BSLJ4tx5.js → page.CrP7niA2.js} +1 -1
  297. package/public/assets/{page.CnTop8Zt.js → page.CvUFZzXr.js} +1 -1
  298. package/public/assets/{page.O2ddJYoT.js → page.CyUqJPmx.js} +1 -1
  299. package/public/assets/{page.DBhu4Arl.js → page.D8Rp8fFR.js} +1 -1
  300. package/public/assets/{page.CPZav1_c.js → page.Df9qtrdG.js} +1 -1
  301. package/public/assets/{page.Qkkv8roc.js → page.DiL4Gwqe.js} +1 -1
  302. package/public/assets/{page.BdmJ3yY3.js → page.Dl1apZE2.js} +1 -1
  303. package/public/assets/{page.1qjqvrwX.js → page.HV0w1d5C.js} +1 -1
  304. package/public/assets/{page.ChX1NqmC.js → page.N1x4YL8_.js} +1 -1
  305. package/public/assets/{page.Dh5f0XJC.js → page.P2Ny5veR.js} +1 -1
  306. package/public/assets/{page.CSs3-gdt.js → page.fOOCr18J.js} +1 -1
  307. package/public/assets/{page.Ir7KvKcF.js → page.sUIPWIiF.js} +1 -1
  308. package/public/assets/{page.CzlQTyAL.js → page.tE7PpWYW.js} +1 -1
  309. package/public/assets/{page.DzZLqI5Q.js → page.uziaGZsT.js} +1 -1
  310. package/public/index.html +2 -2
  311. package/public/assets/EndpointPageClient.LyNNvZ4z.js +0 -6
  312. package/public/assets/index.BuPfZebu.css +0 -1
  313. package/public/assets/index.CShjRV_B.js +0 -89
  314. package/public/assets/page.DD_czjjP.js +0 -1
@@ -1,6 +1,21 @@
1
- import { execSync } from "child_process";
1
+ import { execFileSync, execSync } from "child_process";
2
2
  import path from "path";
3
3
 
4
+ // Extras that improve headroom compression quality. `proxy` is the base;
5
+ // `code` adds tree-sitter AST compression; `ml` adds Kompress-v2 HF model.
6
+ // Other `[all]` extras (image, voice, otel, reports, evals, ...) are not
7
+ // useful for the 9router proxy use case, so we don't track them here.
8
+ export const HEADROOM_COMPRESSION_EXTRAS = ["code", "ml"];
9
+
10
+ // Marker packages that each extra pulls in. Detected from `pip list --format=json`
11
+ // so one call can answer both the installed version and active extras.
12
+ export const EXTRA_MARKERS = {
13
+ code: ["tree-sitter", "tree-sitter-language-pack"],
14
+ ml: ["torch", "huggingface-hub"],
15
+ };
16
+
17
+ const HEADROOM_PIP_TIMEOUT_MS = 8000;
18
+
4
19
  const IS_WIN = process.platform === "win32";
5
20
  const WHICH_CMD = IS_WIN ? "where" : "which";
6
21
 
@@ -49,8 +64,33 @@ export function findHeadroomBinary() {
49
64
  }
50
65
 
51
66
  // Find a Python interpreter >= 3.10 (headroom-ai requires it). Returns null if none.
67
+ // `python3`, `python3.13`, `python` can point at different envs on any OS. Prefer
68
+ // the interpreter that can also see the installed `headroom-ai` package so the
69
+ // dashboard probes and install action operate on the same interpreter as the CLI.
70
+ // Falls back to the first version-eligible candidate when headroom-ai is not yet
71
+ // installed anywhere (needed for the initial install).
72
+ // Interpreters to probe, most specific first: the python next to the headroom
73
+ // binary (guaranteed to have headroom-ai), then full paths from EXTRA_BINS, then
74
+ // bare names resolved via PATH.
75
+ function pythonCandidates() {
76
+ const list = [];
77
+ const bin = findHeadroomBinary();
78
+ if (bin) {
79
+ const dir = path.dirname(bin);
80
+ const names = IS_WIN ? ["python.exe", "python3.exe"] : ["python3", "python3.13", "python"];
81
+ for (const n of names) list.push(path.join(dir, n));
82
+ }
83
+ for (const dir of EXTRA_BINS) {
84
+ if (!dir) continue;
85
+ for (const n of PYTHON_CANDIDATES) list.push(path.join(dir, IS_WIN ? `${n}.exe` : n));
86
+ }
87
+ list.push(...PYTHON_CANDIDATES);
88
+ return list;
89
+ }
90
+
52
91
  export function findPython310() {
53
- for (const candidate of PYTHON_CANDIDATES) {
92
+ let fallback = null;
93
+ for (const candidate of pythonCandidates()) {
54
94
  try {
55
95
  const ver = execSync(`${candidate} --version`, {
56
96
  stdio: ["ignore", "pipe", "ignore"],
@@ -60,14 +100,24 @@ export function findPython310() {
60
100
  const match = ver.match(/(\d+)\.(\d+)/);
61
101
  if (!match) continue;
62
102
  const [major, minor] = [parseInt(match[1], 10), parseInt(match[2], 10)];
63
- if (major > MIN_VERSION[0] || (major === MIN_VERSION[0] && minor >= MIN_VERSION[1])) {
103
+ if (!(major > MIN_VERSION[0] || (major === MIN_VERSION[0] && minor >= MIN_VERSION[1]))) continue;
104
+ if (!fallback) fallback = candidate;
105
+ try {
106
+ execFileSync(candidate, ["-m", "pip", "show", "headroom-ai"], {
107
+ stdio: ["ignore", "pipe", "ignore"],
108
+ windowsHide: true,
109
+ timeout: HEADROOM_PIP_TIMEOUT_MS,
110
+ env: { ...process.env, PATH: EXTENDED_PATH },
111
+ });
64
112
  return candidate;
113
+ } catch {
114
+ // Keep scanning until an interpreter that sees headroom-ai is found.
65
115
  }
66
116
  } catch {
67
117
  // candidate not present, try next
68
118
  }
69
119
  }
70
- return null;
120
+ return fallback;
71
121
  }
72
122
 
73
123
  // Probe whether a Headroom proxy is reachable at the given URL by hitting /health.
@@ -93,10 +143,50 @@ export function isLoopbackHeadroomUrl(url) {
93
143
 
94
144
  // Aggregate status for the dashboard: installed, running, python interpreter.
95
145
  export async function getHeadroomStatus(url) {
96
- const binPath = findHeadroomBinary();
146
+ const path = findHeadroomBinary();
97
147
  const python = findPython310();
98
- const installed = Boolean(binPath);
148
+ const installed = Boolean(path);
99
149
  const running = await probeProxyRunning(url);
100
150
  const localUrl = isLoopbackHeadroomUrl(url);
101
- return { installed, path: binPath, running, python, localUrl, canStart: installed && localUrl };
151
+ const extrasStatus = installed ? getInstalledHeadroomExtras(python) : { installed: false, version: null, extras: { code: false, ml: false } };
152
+ return {
153
+ installed,
154
+ path,
155
+ running,
156
+ python,
157
+ localUrl,
158
+ canStart: installed && localUrl,
159
+ version: extrasStatus.version,
160
+ extras: extrasStatus.extras,
161
+ };
162
+ }
163
+
164
+ // Parse installed headroom-ai version + which compression extras are
165
+ // actually installed (detected via marker package presence). One `pip list`
166
+ // call is enough to answer both questions.
167
+ //
168
+ // Returns: { installed: bool, version: string|null, extras: { code, ml } }
169
+ export function getInstalledHeadroomExtras(python) {
170
+ const py = python || findPython310();
171
+ if (!py) return { installed: false, version: null, extras: { code: false, ml: false } };
172
+ try {
173
+ const out = execFileSync(py, ["-m", "pip", "list", "--format=json", "--disable-pip-version-check"], {
174
+ stdio: ["ignore", "pipe", "ignore"],
175
+ windowsHide: true,
176
+ timeout: HEADROOM_PIP_TIMEOUT_MS,
177
+ env: { ...process.env, PATH: EXTENDED_PATH },
178
+ }).toString();
179
+ const packages = JSON.parse(out);
180
+ const names = new Set(packages.map((p) => String(p.name || "").toLowerCase()));
181
+ const installed = names.has("headroom-ai");
182
+ if (!installed) return { installed: false, version: null, extras: { code: false, ml: false } };
183
+ const version = packages.find((p) => p.name?.toLowerCase() === "headroom-ai")?.version || null;
184
+ const extras = {};
185
+ for (const extra of HEADROOM_COMPRESSION_EXTRAS) {
186
+ extras[extra] = EXTRA_MARKERS[extra].some((m) => names.has(m));
187
+ }
188
+ return { installed: true, version, extras };
189
+ } catch {
190
+ return { installed: false, version: null, extras: { code: false, ml: false } };
191
+ }
102
192
  }
@@ -1,12 +1,13 @@
1
1
  import fs from "fs";
2
2
  import path from "path";
3
3
  import { spawn } from "child_process";
4
- import { DATA_DIR } from "../dataDir.js";
5
- import { findHeadroomBinary } from "./detect.js";
4
+ import { DATA_DIR } from '../../lib/dataDir.js';
5
+ import { findHeadroomBinary, findPython310, HEADROOM_COMPRESSION_EXTRAS, EXTRA_MARKERS, getInstalledHeadroomExtras } from "./detect.js";
6
6
 
7
7
  const HEADROOM_DIR = path.join(DATA_DIR, "headroom");
8
8
  const PID_FILE = path.join(HEADROOM_DIR, "proxy.pid");
9
9
  const LOG_FILE = path.join(HEADROOM_DIR, "proxy.log");
10
+ const INSTALL_LOG_FILE = path.join(HEADROOM_DIR, "install.log");
10
11
  const DEFAULT_PORT = 8787;
11
12
  const STARTUP_TIMEOUT_MS = 8000;
12
13
 
@@ -41,7 +42,17 @@ export function getManagedPid() {
41
42
  return pid && isPidAlive(pid) ? pid : null;
42
43
  }
43
44
 
44
- export async function startHeadroomProxy({ port = DEFAULT_PORT } = {}) {
45
+ // Build proxy CLI flags for the active compression extras. `[code]` (AST
46
+ // compression) is off by default in headroom → pass --code-aware to turn it on;
47
+ // `[ml]` (Kompress) is on by default → pass --disable-kompress to turn it off.
48
+ function extrasProxyArgs({ codeAware, kompress } = {}) {
49
+ const args = [];
50
+ if (codeAware) args.push("--code-aware");
51
+ if (kompress === false) args.push("--disable-kompress");
52
+ return args;
53
+ }
54
+
55
+ export async function startHeadroomProxy({ port = DEFAULT_PORT, codeAware = false, kompress = true } = {}) {
45
56
  const safePort = Number(port) > 0 && Number(port) < 65536 ? Number(port) : DEFAULT_PORT;
46
57
  const binary = findHeadroomBinary();
47
58
  if (!binary) {
@@ -57,7 +68,8 @@ export async function startHeadroomProxy({ port = DEFAULT_PORT } = {}) {
57
68
  // spawn stdio requires fd numbers, not WriteStream objects.
58
69
  const outFd = fs.openSync(LOG_FILE, "a");
59
70
 
60
- const child = spawn(binary, ["proxy", "--port", String(safePort)], {
71
+ const args = ["proxy", "--port", String(safePort), ...extrasProxyArgs({ codeAware, kompress })];
72
+ const child = spawn(binary, args, {
61
73
  stdio: ["ignore", outFd, outFd],
62
74
  detached: true,
63
75
  windowsHide: true,
@@ -118,6 +130,25 @@ export function stopHeadroomProxy() {
118
130
  }
119
131
  }
120
132
 
133
+ // Stop the managed proxy (if any), wait for the pid to die, then start again
134
+ // with the given flags. Used when toggling active extras that require a restart.
135
+ export async function restartHeadroomProxy(opts = {}) {
136
+ const pid = getManagedPid();
137
+ if (pid) {
138
+ try { process.kill(pid, "SIGTERM"); } catch { /* already gone */ }
139
+ // Wait up to ~3s for graceful exit, force-kill if still alive.
140
+ for (let i = 0; i < 30 && isPidAlive(pid); i++) {
141
+ await new Promise((r) => setTimeout(r, 100));
142
+ }
143
+ if (isPidAlive(pid)) {
144
+ try { process.kill(pid, "SIGKILL"); } catch { /* already gone */ }
145
+ await new Promise((r) => setTimeout(r, 300));
146
+ }
147
+ clearPid();
148
+ }
149
+ return startHeadroomProxy(opts);
150
+ }
151
+
121
152
  export function getHeadroomLogTail(maxLines = 200) {
122
153
  try {
123
154
  if (!fs.existsSync(LOG_FILE)) return "";
@@ -126,3 +157,104 @@ export function getHeadroomLogTail(maxLines = 200) {
126
157
  return lines.slice(-maxLines).join("\n");
127
158
  } catch { return ""; }
128
159
  }
160
+
161
+ // Install (or upgrade) headroom-ai with the requested compression extras.
162
+ // `extras` is a whitelist from HEADROOM_COMPRESSION_EXTRAS — anything else
163
+ // is rejected to keep the install surface predictable. Always installs the
164
+ // `proxy` base + whatever extras the user picked, regardless of what is
165
+ // already present.
166
+ export async function installHeadroomExtras(extras = []) {
167
+ const requested = Array.isArray(extras) ? extras.filter((e) => HEADROOM_COMPRESSION_EXTRAS.includes(e)) : [];
168
+ const py = findPython310();
169
+ if (!py) {
170
+ const err = new Error("Python >= 3.10 not found");
171
+ err.code = "NO_PYTHON";
172
+ throw err;
173
+ }
174
+ if (!findHeadroomBinary()) {
175
+ const err = new Error("headroom-ai not installed (run `pip install headroom-ai[proxy]` first)");
176
+ err.code = "NOT_INSTALLED";
177
+ throw err;
178
+ }
179
+ // pip install string is built from a closed set (HEADROOM_COMPRESSION_EXTRAS),
180
+ // so it cannot be poisoned by caller input — the comma-list is a fixed
181
+ // ['proxy', ...requested]. No shell interpolation.
182
+ const extrasList = ["proxy", ...requested].join(",");
183
+ const spec = `headroom-ai[${extrasList}]`;
184
+ const args = ["-m", "pip", "install", "--upgrade", spec];
185
+
186
+ ensureDir();
187
+ // Truncate ("w") so the log reflects only the current install for live progress.
188
+ const outFd = fs.openSync(INSTALL_LOG_FILE, "w");
189
+ const child = spawn(py, args, {
190
+ stdio: ["ignore", outFd, outFd],
191
+ windowsHide: true,
192
+ env: { ...process.env },
193
+ });
194
+
195
+ return new Promise((resolve, reject) => {
196
+ child.once("error", (e) => { fs.closeSync(outFd); reject(e); });
197
+ child.once("exit", (code) => {
198
+ fs.closeSync(outFd);
199
+ if (code === 0) {
200
+ const status = getInstalledHeadroomExtras(py);
201
+ resolve({ success: true, code, spec, extras: requested, ...status });
202
+ } else {
203
+ const err = new Error(`pip install exited with code=${code} — see headroom/install.log`);
204
+ err.code = "INSTALL_FAILED";
205
+ reject(err);
206
+ }
207
+ });
208
+ });
209
+ }
210
+
211
+ // Uninstall the marker packages that back a single extra (e.g. `ml` → torch,
212
+ // huggingface-hub). `headroom-ai` base and the `proxy` extra are never removed.
213
+ export async function uninstallHeadroomExtras(extras = []) {
214
+ const requested = Array.isArray(extras) ? extras.filter((e) => HEADROOM_COMPRESSION_EXTRAS.includes(e)) : [];
215
+ const py = findPython310();
216
+ if (!py) {
217
+ const err = new Error("Python >= 3.10 not found");
218
+ err.code = "NO_PYTHON";
219
+ throw err;
220
+ }
221
+ const pkgs = [...new Set(requested.flatMap((e) => EXTRA_MARKERS[e] || []))];
222
+ if (pkgs.length === 0) {
223
+ const err = new Error("No valid extras to remove");
224
+ err.code = "INVALID_EXTRAS";
225
+ throw err;
226
+ }
227
+ const args = ["-m", "pip", "uninstall", "-y", ...pkgs];
228
+
229
+ ensureDir();
230
+ const outFd = fs.openSync(INSTALL_LOG_FILE, "w");
231
+ const child = spawn(py, args, {
232
+ stdio: ["ignore", outFd, outFd],
233
+ windowsHide: true,
234
+ env: { ...process.env },
235
+ });
236
+
237
+ return new Promise((resolve, reject) => {
238
+ child.once("error", (e) => { fs.closeSync(outFd); reject(e); });
239
+ child.once("exit", (code) => {
240
+ fs.closeSync(outFd);
241
+ if (code === 0) {
242
+ const status = getInstalledHeadroomExtras(py);
243
+ resolve({ success: true, code, removed: pkgs, extras: requested, ...status });
244
+ } else {
245
+ const err = new Error(`pip uninstall exited with code=${code} — see headroom/install.log`);
246
+ err.code = "UNINSTALL_FAILED";
247
+ reject(err);
248
+ }
249
+ });
250
+ });
251
+ }
252
+
253
+ // Read the tail of the install/uninstall log for live progress in the UI.
254
+ export function getInstallLogTail(maxLines = 15) {
255
+ try {
256
+ if (!fs.existsSync(INSTALL_LOG_FILE)) return "";
257
+ const lines = fs.readFileSync(INSTALL_LOG_FILE, "utf8").split(/\r?\n/).filter(Boolean);
258
+ return lines.slice(-maxLines).join("\n");
259
+ } catch { return ""; }
260
+ }
@@ -1,44 +1,10 @@
1
1
  import { platform, arch } from "os";
2
- import { proxyAwareFetch } from "../utils/proxyFetch.js";
3
-
4
- // === Kimchi CLI version (dynamic, cached from GitHub releases) ===
5
- const KIMCHI_FALLBACK_VERSION = "0.1.39";
6
- let _kimchiVersionCache = null;
7
- let _kimchiVersionFetching = null;
8
- const KIMCHI_VERSION_TTL_MS = 3600_000; // 1h
9
-
10
- async function fetchKimchiVersion() {
11
- try {
12
- const res = await proxyAwareFetch("https://api.github.com/repos/getkimchi/kimchi/releases/latest", {
13
- headers: { Accept: "application/vnd.github+json" },
14
- signal: AbortSignal.timeout(5000),
15
- });
16
- if (!res.ok) return KIMCHI_FALLBACK_VERSION;
17
- const body = await res.json();
18
- const tag = body?.tag_name || "";
19
- const ver = tag.replace(/^v/, "");
20
- return ver || KIMCHI_FALLBACK_VERSION;
21
- } catch {
22
- return KIMCHI_FALLBACK_VERSION;
23
- }
24
- }
25
-
26
- export async function getKimchiVersion() {
27
- if (_kimchiVersionCache && Date.now() - _kimchiVersionCache.ts < KIMCHI_VERSION_TTL_MS) return _kimchiVersionCache.ver;
28
- if (_kimchiVersionFetching) return _kimchiVersionFetching;
29
- _kimchiVersionFetching = fetchKimchiVersion().finally(() => { _kimchiVersionFetching = null; });
30
- const ver = await _kimchiVersionFetching;
31
- _kimchiVersionCache = { ver, ts: Date.now() };
32
- return ver;
33
- }
2
+ import { PROVIDERS, PROVIDER_OAUTH } from "./providers.js";
3
+ import { ANTIGRAVITY_IDE_USER_AGENT } from "../providers/shared.js";
34
4
 
35
- export function getKimchiVersionSync() {
36
- return _kimchiVersionCache?.ver || KIMCHI_FALLBACK_VERSION;
37
- }
38
-
39
- // === Gemini CLI ===
40
- export const GEMINI_CLI_VERSION = "0.34.0";
41
- export const GEMINI_CLI_API_CLIENT = "google-genai-sdk/1.41.0 gl-node/v22.19.0";
5
+ // === Gemini CLI === derive từ registry gemini-cli.transport
6
+ export const GEMINI_CLI_VERSION = PROVIDERS["gemini-cli"]?.cliVersion;
7
+ export const GEMINI_CLI_API_CLIENT = PROVIDERS["gemini-cli"]?.apiClient;
42
8
 
43
9
  // Map Node arch to Gemini CLI arch string (x64/x86/arm64/...)
44
10
  function geminiCLIArch() {
@@ -52,11 +18,13 @@ export function geminiCLIUserAgent(model = "unknown") {
52
18
  }
53
19
 
54
20
  // === GitHub Copilot ===
21
+ // Derive từ registry github.transport.copilot
22
+ const _ghCopilot = PROVIDERS.github?.copilot || {};
55
23
  export const GITHUB_COPILOT = {
56
- VSCODE_VERSION: "1.110.0",
57
- COPILOT_CHAT_VERSION: "0.38.0",
58
- USER_AGENT: "GitHubCopilotChat/0.38.0",
59
- API_VERSION: "2025-04-01",
24
+ VSCODE_VERSION: _ghCopilot.vscodeVersion,
25
+ COPILOT_CHAT_VERSION: _ghCopilot.chatVersion,
26
+ USER_AGENT: _ghCopilot.userAgent,
27
+ API_VERSION: _ghCopilot.apiVersion,
60
28
  };
61
29
 
62
30
  // === Antigravity enums ===
@@ -92,7 +60,7 @@ export function getPlatformEnum() {
92
60
  }
93
61
 
94
62
  export function getPlatformUserAgent() {
95
- return `antigravity/1.104.0 ${platform()}/${arch()}`;
63
+ return ANTIGRAVITY_IDE_USER_AGENT;
96
64
  }
97
65
 
98
66
  export const CLIENT_METADATA = {
@@ -162,7 +130,7 @@ export const AG_DEFAULT_TOOLS = new Set([
162
130
 
163
131
  // Antigravity chat/stream headers
164
132
  export const ANTIGRAVITY_HEADERS = {
165
- "User-Agent": `antigravity/1.107.0 ${platform()}/${arch()}`
133
+ "User-Agent": ANTIGRAVITY_IDE_USER_AGENT
166
134
  };
167
135
 
168
136
  // Cloud Code Assist API
@@ -188,43 +156,19 @@ export const LOAD_CODE_ASSIST_METADATA = {
188
156
  export const CLAUDE_SYSTEM_PROMPT = "You are Claude Code, Anthropic's official CLI for Claude.";
189
157
  export const ANTIGRAVITY_DEFAULT_SYSTEM = "You are Antigravity, a powerful agentic AI coding assistant designed by the Google Deepmind team working on Advanced Agentic Coding.You are pair programming with a USER to solve their coding task. The task may require creating a new codebase, modifying or debugging an existing codebase, or simply answering a question.**Absolute paths only****Proactiveness**";
190
158
 
191
- // Proactive token refresh lead times per provider (ms)
192
- export const REFRESH_LEAD_MS = {
193
- codex: 5 * 24 * 60 * 60 * 1000, // 5 days
194
- claude: 4 * 60 * 60 * 1000, // 4 hours
195
- iflow: 24 * 60 * 60 * 1000, // 24 hours
196
- qwen: 20 * 60 * 1000, // 20 minutes
197
- "kimi-coding": 5 * 60 * 1000, // 5 minutes
198
- antigravity: 5 * 60 * 1000, // 5 minutes
199
- };
159
+ // Derive từ registry oauth.refreshLeadMs
160
+ export const REFRESH_LEAD_MS = Object.fromEntries(
161
+ Object.entries(PROVIDER_OAUTH).filter(([, o]) => o.refreshLeadMs).map(([id, o]) => [id, o.refreshLeadMs])
162
+ );
200
163
 
201
164
  // OAuth endpoints
202
165
  export const OAUTH_ENDPOINTS = {
203
- google: {
204
- token: "https://oauth2.googleapis.com/token",
205
- auth: "https://accounts.google.com/o/oauth2/auth"
206
- },
207
- openai: {
208
- token: "https://auth.openai.com/oauth/token",
209
- auth: "https://auth.openai.com/oauth/authorize"
210
- },
211
- anthropic: {
212
- token: "https://api.anthropic.com/v1/oauth/token",
213
- auth: "https://api.anthropic.com/v1/oauth/authorize"
214
- },
215
- qwen: {
216
- token: "https://qwen.ai/api/v1/oauth2/token",
217
- auth: "https://qwen.ai/api/v1/oauth2/device/code"
218
- },
219
- iflow: {
220
- token: "https://iflow.cn/oauth/token",
221
- auth: "https://iflow.cn/oauth"
222
- },
223
- github: {
224
- token: "https://github.com/login/oauth/access_token",
225
- auth: "https://github.com/login/oauth/authorize",
226
- deviceCode: "https://github.com/login/device/code"
227
- }
166
+ google: { token: "https://oauth2.googleapis.com/token", auth: "https://accounts.google.com/o/oauth2/auth" },
167
+ openai: { token: PROVIDER_OAUTH["codex"]?.tokenUrl, auth: PROVIDER_OAUTH["codex"]?.authorizeUrl },
168
+ anthropic: { token: PROVIDER_OAUTH["claude"]?.tokenUrl, auth: "https://api.anthropic.com/v1/oauth/authorize" }, // ≠ claude.authorizeUrl (claude.ai login) — keep
169
+ qwen: { token: PROVIDER_OAUTH["qwen"]?.tokenUrl, auth: PROVIDER_OAUTH["qwen"]?.deviceCodeUrl },
170
+ iflow: { token: PROVIDER_OAUTH["iflow"]?.tokenUrl, auth: PROVIDER_OAUTH["iflow"]?.authorizeUrl },
171
+ github: { token: PROVIDER_OAUTH["github"]?.tokenUrl, auth: PROVIDER_OAUTH["github"]?.authorizeUrl, deviceCode: PROVIDER_OAUTH["github"]?.deviceCodeUrl },
228
172
  };
229
173
 
230
174
  // Generate Kimi OAuth custom headers
@@ -4,7 +4,7 @@ import {
4
4
  GITHUB_COPILOT_CHAT_USER_AGENT,
5
5
  getQwenOauthHeaders
6
6
  } from "./providerHeaderProfiles.ts";
7
- import { normalizeCliCompatProviderId } from '../../../dist/shared/utils/cliCompat.js';
7
+ import { normalizeCliCompatProviderId } from '../../dist/shared/utils/cliCompat.js';
8
8
  const CLI_FINGERPRINTS = {
9
9
  codex: {
10
10
  headerOrder: [
@@ -45,7 +45,6 @@ export const MAX_RATE_LIMIT_COOLDOWN_MS = 30 * 60 * 1000;
45
45
  const COOLDOWN = {
46
46
  long: 2 * 60 * 1000,
47
47
  short: 5 * 1000,
48
- exhausted: 24 * 60 * 60 * 1000, // 24 hours
49
48
  };
50
49
 
51
50
  /**
@@ -59,16 +58,6 @@ const COOLDOWN = {
59
58
  */
60
59
  export const ERROR_RULES = [
61
60
  // --- Text-based rules (checked first, order = priority) ---
62
- { text: "exhausted", cooldownMs: COOLDOWN.exhausted },
63
- { text: "insufficient credits", cooldownMs: COOLDOWN.exhausted },
64
- { text: "1076", cooldownMs: COOLDOWN.exhausted },
65
- { text: "only available on paid plans", cooldownMs: COOLDOWN.exhausted },
66
- { text: "failed to capture weavy firebase id token", cooldownMs: COOLDOWN.exhausted },
67
- { text: "trial version is not yet", cooldownMs: COOLDOWN.exhausted },
68
- { text: "neurons", cooldownMs: COOLDOWN.exhausted }, // CF Workers AI daily quota
69
- { text: "daily free allocation", cooldownMs: COOLDOWN.exhausted }, // CF Workers AI daily quota
70
- { text: "upgrade to cloudflare", cooldownMs: COOLDOWN.exhausted }, // CF Workers AI paid plan prompt
71
- { text: "4006", cooldownMs: COOLDOWN.exhausted }, // CF Workers AI error code
72
61
  { text: "no credentials", cooldownMs: COOLDOWN.long },
73
62
  { text: "request not allowed", cooldownMs: COOLDOWN.short },
74
63
  { text: "improperly formed request", cooldownMs: COOLDOWN.long },
@@ -0,0 +1,10 @@
1
+ export const GROK_CLI_VERSION = "0.2.99";
2
+ export const GROK_CLI_MODEL = "grok-build";
3
+ export const GROK_CLI_BASE_URL = "https://cli-chat-proxy.grok.com/v1";
4
+ export const GROK_CLI_CLIENT_IDENTIFIER = "grok-shell";
5
+ export const GROK_CLI_USER_AGENT = `grok-shell/${GROK_CLI_VERSION} (linux; x86_64)`;
6
+
7
+ export function supportsGrokCliReasoningEffort(model) {
8
+ // ponytail: unknown models omit effort until live metadata reaches dispatch.
9
+ return /^grok-4\.5(?:$|-)/.test(String(model || ""));
10
+ }