@fudrouter/fsrouter 0.6.61 → 0.6.63

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 (557) hide show
  1. package/bin/copyJs.js +13 -9
  2. package/open-sse/AGENTS.md +39 -0
  3. package/open-sse/config/anthropicHeaders.js +87 -0
  4. package/open-sse/config/appConstants.js +238 -0
  5. package/open-sse/config/audioRegistry.js +506 -0
  6. package/open-sse/config/cliFingerprints.js +304 -0
  7. package/open-sse/config/codexInstructions.js +119 -0
  8. package/open-sse/config/codexQuotaScopes.js +42 -0
  9. package/open-sse/config/constants.js +4 -0
  10. package/open-sse/config/contextEditing.js +68 -0
  11. package/open-sse/config/credentialLoader.js +83 -0
  12. package/open-sse/config/defaultThinkingSignature.js +12 -0
  13. package/open-sse/config/embeddingRegistry.js +264 -0
  14. package/open-sse/config/errorConfig.js +96 -0
  15. package/open-sse/config/freeModelCatalog.data.js +121 -0
  16. package/open-sse/config/freeModelCatalog.js +90 -0
  17. package/open-sse/config/freeTierCatalog.js +81 -0
  18. package/open-sse/config/googleTtsLanguages.js +62 -0
  19. package/open-sse/config/imageParamDefs.js +360 -0
  20. package/open-sse/config/imageRegistry.js +493 -0
  21. package/open-sse/config/kiroConstants.js +268 -0
  22. package/open-sse/config/mediaConfig.js +27 -0
  23. package/open-sse/config/mediaServiceKinds.js +71 -0
  24. package/open-sse/config/models.js +13 -0
  25. package/open-sse/config/moderationRegistry.js +71 -0
  26. package/open-sse/config/musicRegistry.js +99 -0
  27. package/open-sse/config/ocrRegistry.js +61 -0
  28. package/open-sse/config/ollamaModels.js +19 -0
  29. package/open-sse/config/providerErrorRules.js +114 -0
  30. package/open-sse/config/providerFieldStrips.js +35 -0
  31. package/open-sse/config/providerHeaderProfiles.js +191 -0
  32. package/open-sse/config/providerModels.js +106 -0
  33. package/open-sse/config/providerRegistry.js +16 -0
  34. package/open-sse/config/providers.js +19 -0
  35. package/open-sse/config/registryUtils.js +106 -0
  36. package/open-sse/config/rerankRegistry.js +177 -0
  37. package/open-sse/config/runtimeConfig.js +96 -0
  38. package/open-sse/config/runway.js +39 -0
  39. package/open-sse/config/searchRegistry.js +153 -0
  40. package/open-sse/config/toolCloaking.js +199 -0
  41. package/open-sse/config/ttsModels.js +129 -0
  42. package/open-sse/config/videoRegistry.js +207 -0
  43. package/open-sse/executors/adapta-web.js +435 -0
  44. package/open-sse/executors/antigravity.js +534 -0
  45. package/open-sse/executors/antigravityUpstreamError.js +13 -0
  46. package/open-sse/executors/auggie.js +437 -0
  47. package/open-sse/executors/azure-openai.js +32 -0
  48. package/open-sse/executors/azure.js +57 -0
  49. package/open-sse/executors/base.js +181 -0
  50. package/open-sse/executors/bedrock.js +633 -0
  51. package/open-sse/executors/blackbox-web.js +578 -0
  52. package/open-sse/executors/chatgpt-web.js +2042 -0
  53. package/open-sse/executors/chipotle.js +357 -0
  54. package/open-sse/executors/claude-web-with-auto-refresh.js +73 -0
  55. package/open-sse/executors/claude-web.js +586 -0
  56. package/open-sse/executors/cliproxyapi.js +296 -0
  57. package/open-sse/executors/cloudflare-ai.js +46 -0
  58. package/open-sse/executors/codebuddy-cn.js +40 -0
  59. package/open-sse/executors/codex.js +1324 -0
  60. package/open-sse/executors/commandCode.js +558 -0
  61. package/open-sse/executors/commandcode.js +88 -0
  62. package/open-sse/executors/copilot-m365-connection.js +176 -0
  63. package/open-sse/executors/copilot-m365-frames.js +192 -0
  64. package/open-sse/executors/copilot-m365-web.js +299 -0
  65. package/open-sse/executors/copilot-web.js +580 -0
  66. package/open-sse/executors/cursor.js +795 -0
  67. package/open-sse/executors/deepseek-web-with-auto-refresh.js +150 -0
  68. package/open-sse/executors/deepseek-web.js +875 -0
  69. package/open-sse/executors/default.js +430 -0
  70. package/open-sse/executors/devin-cli.js +351 -0
  71. package/open-sse/executors/doubao-web.js +550 -0
  72. package/open-sse/executors/duckduckgo-web.js +629 -0
  73. package/open-sse/executors/forceResponsesUpstream.js +33 -0
  74. package/open-sse/executors/gemini-business.js +320 -0
  75. package/open-sse/executors/gemini-cli.js +89 -0
  76. package/open-sse/executors/gemini-web.js +297 -0
  77. package/open-sse/executors/github.js +379 -0
  78. package/open-sse/executors/gitlab.js +569 -0
  79. package/open-sse/executors/glm.js +361 -0
  80. package/open-sse/executors/grok-cli.js +119 -0
  81. package/open-sse/executors/grok-web.js +345 -0
  82. package/open-sse/executors/huggingchat.js +467 -0
  83. package/open-sse/executors/iflow.js +108 -0
  84. package/open-sse/executors/index.js +78 -0
  85. package/open-sse/executors/inner-ai.js +527 -0
  86. package/open-sse/executors/kimchi.js +123 -0
  87. package/open-sse/executors/kimi-web.js +325 -0
  88. package/open-sse/executors/kimi.js +97 -0
  89. package/open-sse/executors/kiro.js +503 -0
  90. package/open-sse/executors/kiroThinking.js +44 -0
  91. package/open-sse/executors/lmarena.js +395 -0
  92. package/open-sse/executors/mimo-free.js +167 -0
  93. package/open-sse/executors/mimocode.js +392 -0
  94. package/open-sse/executors/ninerouter.js +155 -0
  95. package/open-sse/executors/nlpcloud.js +438 -0
  96. package/open-sse/executors/ollama-local.js +14 -0
  97. package/open-sse/executors/opencode-go.js +41 -0
  98. package/open-sse/executors/opencode.js +32 -0
  99. package/open-sse/executors/perplexity-web.js +581 -0
  100. package/open-sse/executors/poe-web.js +133 -0
  101. package/open-sse/executors/pollinations.js +95 -0
  102. package/open-sse/executors/puter.js +31 -0
  103. package/open-sse/executors/qoder.js +448 -0
  104. package/open-sse/executors/qwen-web.js +372 -0
  105. package/open-sse/executors/qwen.js +129 -0
  106. package/open-sse/executors/t3-chat-web.js +417 -0
  107. package/open-sse/executors/theoldllm.js +290 -0
  108. package/open-sse/executors/trae.js +418 -0
  109. package/open-sse/executors/v0-vercel-web.js +141 -0
  110. package/open-sse/executors/venice-web.js +142 -0
  111. package/open-sse/executors/vertex.js +131 -0
  112. package/open-sse/executors/vertexMedia.js +236 -0
  113. package/open-sse/executors/windsurf.js +560 -0
  114. package/open-sse/executors/xai.js +46 -0
  115. package/open-sse/executors/xiaomi-tokenplan.js +19 -0
  116. package/open-sse/executors/yuanbao-web.js +385 -0
  117. package/open-sse/executors/zed-hosted.js +281 -0
  118. package/open-sse/executors/zenmux-free.js +247 -0
  119. package/open-sse/handlers/audioSpeech.js +759 -0
  120. package/open-sse/handlers/audioTranscription.js +395 -0
  121. package/open-sse/handlers/audioTranslation.js +181 -0
  122. package/open-sse/handlers/chatCore/nonStreamingHandler.js +300 -0
  123. package/open-sse/handlers/chatCore/requestDetail.js +102 -0
  124. package/open-sse/handlers/chatCore/sseToJsonHandler.js +231 -0
  125. package/open-sse/handlers/chatCore/streamingHandler.js +95 -0
  126. package/open-sse/handlers/chatCore.js +404 -0
  127. package/open-sse/handlers/embeddingProviders/_base.js +4 -0
  128. package/open-sse/handlers/embeddingProviders/gemini.js +54 -0
  129. package/open-sse/handlers/embeddingProviders/index.js +23 -0
  130. package/open-sse/handlers/embeddingProviders/openai.js +39 -0
  131. package/open-sse/handlers/embeddingProviders/openaiCompatNode.js +13 -0
  132. package/open-sse/handlers/embeddingsCore.js +126 -0
  133. package/open-sse/handlers/fetch/index.js +237 -0
  134. package/open-sse/handlers/imageGenerationCore.js +230 -0
  135. package/open-sse/handlers/imageProviders/_base.js +31 -0
  136. package/open-sse/handlers/imageProviders/antigravity.js +73 -0
  137. package/open-sse/handlers/imageProviders/blackForestLabs.js +63 -0
  138. package/open-sse/handlers/imageProviders/cloudflareAi.js +207 -0
  139. package/open-sse/handlers/imageProviders/codex.js +217 -0
  140. package/open-sse/handlers/imageProviders/comfyui.js +25 -0
  141. package/open-sse/handlers/imageProviders/falAi.js +62 -0
  142. package/open-sse/handlers/imageProviders/gemini.js +40 -0
  143. package/open-sse/handlers/imageProviders/huggingface.js +38 -0
  144. package/open-sse/handlers/imageProviders/index.js +44 -0
  145. package/open-sse/handlers/imageProviders/leonardo.js +435 -0
  146. package/open-sse/handlers/imageProviders/nanobanana.js +79 -0
  147. package/open-sse/handlers/imageProviders/openai.js +61 -0
  148. package/open-sse/handlers/imageProviders/runwayml.js +72 -0
  149. package/open-sse/handlers/imageProviders/sdwebui.js +36 -0
  150. package/open-sse/handlers/imageProviders/stabilityAi.js +59 -0
  151. package/open-sse/handlers/imageProviders/weavy.js +222 -0
  152. package/open-sse/handlers/moderations.js +92 -0
  153. package/open-sse/handlers/ocr.js +89 -0
  154. package/open-sse/handlers/rerank.js +223 -0
  155. package/open-sse/handlers/responseSanitizer/reasoning.js +144 -0
  156. package/open-sse/handlers/responsesHandler.js +99 -0
  157. package/open-sse/handlers/search/callers.js +371 -0
  158. package/open-sse/handlers/search/chatSearch.js +409 -0
  159. package/open-sse/handlers/search/index.js +201 -0
  160. package/open-sse/handlers/search/normalizers.js +223 -0
  161. package/open-sse/handlers/search.js +1056 -0
  162. package/open-sse/handlers/sseParser.js +469 -0
  163. package/open-sse/handlers/sttCore.js +193 -0
  164. package/open-sse/handlers/ttsCore.js +74 -0
  165. package/open-sse/handlers/ttsProviders/_base.js +39 -0
  166. package/open-sse/handlers/ttsProviders/edgeTts.js +89 -0
  167. package/open-sse/handlers/ttsProviders/elevenlabs.js +48 -0
  168. package/open-sse/handlers/ttsProviders/gemini.js +117 -0
  169. package/open-sse/handlers/ttsProviders/genericFormats.js +169 -0
  170. package/open-sse/handlers/ttsProviders/googleTts.js +54 -0
  171. package/open-sse/handlers/ttsProviders/index.js +50 -0
  172. package/open-sse/handlers/ttsProviders/localDevice.js +87 -0
  173. package/open-sse/handlers/ttsProviders/minimax.js +59 -0
  174. package/open-sse/handlers/ttsProviders/openai.js +30 -0
  175. package/open-sse/handlers/ttsProviders/openrouter.js +70 -0
  176. package/open-sse/handlers/usageExtractor.js +93 -0
  177. package/open-sse/handlers/videoGenerationCore.js +119 -0
  178. package/open-sse/handlers/videoProviders/index.js +22 -0
  179. package/open-sse/handlers/videoProviders/leonardo.js +511 -0
  180. package/open-sse/handlers/videoProviders/weavy.js +198 -0
  181. package/open-sse/handlers/webFetch.js +200 -0
  182. package/open-sse/index.js +79 -0
  183. package/open-sse/mcp-server/audit.js +283 -0
  184. package/open-sse/mcp-server/catalog.js +184 -0
  185. package/open-sse/mcp-server/descriptionCompressor.js +175 -0
  186. package/open-sse/mcp-server/httpAuthContext.js +32 -0
  187. package/open-sse/mcp-server/httpTransport.js +229 -0
  188. package/open-sse/mcp-server/index.js +33 -0
  189. package/open-sse/mcp-server/mcpCallerIdentity.js +21 -0
  190. package/open-sse/mcp-server/runtimeHeartbeat.js +110 -0
  191. package/open-sse/mcp-server/schemas/a2a.js +153 -0
  192. package/open-sse/mcp-server/schemas/audit.js +17 -0
  193. package/open-sse/mcp-server/schemas/index.js +166 -0
  194. package/open-sse/mcp-server/schemas/pickFastestModel.js +90 -0
  195. package/open-sse/mcp-server/schemas/toolDefinition.js +0 -0
  196. package/open-sse/mcp-server/schemas/toolSearch.js +32 -0
  197. package/open-sse/mcp-server/schemas/tools.js +1219 -0
  198. package/open-sse/mcp-server/scopeEnforcement.js +80 -0
  199. package/open-sse/mcp-server/server.js +1168 -0
  200. package/open-sse/mcp-server/toolCardinality.js +78 -0
  201. package/open-sse/mcp-server/toolSearch/catalog.js +66 -0
  202. package/open-sse/mcp-server/toolSearch/handler.js +20 -0
  203. package/open-sse/mcp-server/toolSearch/index.js +10 -0
  204. package/open-sse/mcp-server/toolSearch/register.js +21 -0
  205. package/open-sse/mcp-server/toolSearch/search.js +55 -0
  206. package/open-sse/mcp-server/toolSearch/signature.js +67 -0
  207. package/open-sse/mcp-server/tools/advancedTools.js +893 -0
  208. package/open-sse/mcp-server/tools/agentSkillTools.js +69 -0
  209. package/open-sse/mcp-server/tools/compressionTools.js +309 -0
  210. package/open-sse/mcp-server/tools/gamificationTools.js +134 -0
  211. package/open-sse/mcp-server/tools/githubSkillTools.js +102 -0
  212. package/open-sse/mcp-server/tools/memoryTools.js +118 -0
  213. package/open-sse/mcp-server/tools/notionTools.js +101 -0
  214. package/open-sse/mcp-server/tools/obsidianTools.js +307 -0
  215. package/open-sse/mcp-server/tools/pickFastestModel.js +223 -0
  216. package/open-sse/mcp-server/tools/pluginTools.js +181 -0
  217. package/open-sse/mcp-server/tools/poolTools.js +139 -0
  218. package/open-sse/mcp-server/tools/skillTools.js +113 -0
  219. package/open-sse/package.json +10 -0
  220. package/open-sse/providers/REGISTRY_TEMPLATE.js +98 -0
  221. package/open-sse/providers/capabilities.js +293 -0
  222. package/open-sse/providers/index.js +51 -0
  223. package/open-sse/providers/models/helpers.js +20 -0
  224. package/open-sse/providers/models/namePatterns.js +33 -0
  225. package/open-sse/providers/models/schema.js +40 -0
  226. package/open-sse/providers/pricing.js +308 -0
  227. package/open-sse/providers/registry/alicode-intl.js +30 -0
  228. package/open-sse/providers/registry/alicode.js +31 -0
  229. package/open-sse/providers/registry/anthropic.js +37 -0
  230. package/open-sse/providers/registry/antigravity.js +81 -0
  231. package/open-sse/providers/registry/assemblyai.js +38 -0
  232. package/open-sse/providers/registry/aws-polly.js +45 -0
  233. package/open-sse/providers/registry/azure.js +21 -0
  234. package/open-sse/providers/registry/black-forest-labs.js +32 -0
  235. package/open-sse/providers/registry/blackbox.js +41 -0
  236. package/open-sse/providers/registry/brave-search.js +35 -0
  237. package/open-sse/providers/registry/byteplus.js +35 -0
  238. package/open-sse/providers/registry/cartesia.js +36 -0
  239. package/open-sse/providers/registry/cerebras.js +31 -0
  240. package/open-sse/providers/registry/chutes.js +24 -0
  241. package/open-sse/providers/registry/claude.js +87 -0
  242. package/open-sse/providers/registry/cline.js +51 -0
  243. package/open-sse/providers/registry/clinepass.js +57 -0
  244. package/open-sse/providers/registry/cloudflare-ai.js +55 -0
  245. package/open-sse/providers/registry/codebuddy-cn.js +77 -0
  246. package/open-sse/providers/registry/codex.js +100 -0
  247. package/open-sse/providers/registry/cohere.js +27 -0
  248. package/open-sse/providers/registry/comfyui.js +20 -0
  249. package/open-sse/providers/registry/commandcode.js +43 -0
  250. package/open-sse/providers/registry/coqui.js +30 -0
  251. package/open-sse/providers/registry/cursor.js +58 -0
  252. package/open-sse/providers/registry/deepgram.js +33 -0
  253. package/open-sse/providers/registry/deepseek.js +51 -0
  254. package/open-sse/providers/registry/digitalocean.js +92 -0
  255. package/open-sse/providers/registry/edge-tts.js +24 -0
  256. package/open-sse/providers/registry/elevenlabs.js +35 -0
  257. package/open-sse/providers/registry/exa.js +50 -0
  258. package/open-sse/providers/registry/fal-ai.js +34 -0
  259. package/open-sse/providers/registry/featherless.js +34 -0
  260. package/open-sse/providers/registry/firecrawl.js +34 -0
  261. package/open-sse/providers/registry/fireworks.js +29 -0
  262. package/open-sse/providers/registry/gemini-cli.js +58 -0
  263. package/open-sse/providers/registry/gemini.js +83 -0
  264. package/open-sse/providers/registry/github.js +88 -0
  265. package/open-sse/providers/registry/gitlab.js +32 -0
  266. package/open-sse/providers/registry/glm-cn.js +35 -0
  267. package/open-sse/providers/registry/glm.js +58 -0
  268. package/open-sse/providers/registry/google-pse.js +35 -0
  269. package/open-sse/providers/registry/google-tts.js +24 -0
  270. package/open-sse/providers/registry/grok-cli.js +86 -0
  271. package/open-sse/providers/registry/grok-web.js +39 -0
  272. package/open-sse/providers/registry/groq.js +37 -0
  273. package/open-sse/providers/registry/huggingface.js +34 -0
  274. package/open-sse/providers/registry/hyperbolic.js +35 -0
  275. package/open-sse/providers/registry/ibm-bob.js +27 -0
  276. package/open-sse/providers/registry/iflow.js +52 -0
  277. package/open-sse/providers/registry/index.js +210 -0
  278. package/open-sse/providers/registry/inworld.js +36 -0
  279. package/open-sse/providers/registry/jina-ai.js +42 -0
  280. package/open-sse/providers/registry/jina-reader.js +34 -0
  281. package/open-sse/providers/registry/kilocode.js +51 -0
  282. package/open-sse/providers/registry/kimchi.js +49 -0
  283. package/open-sse/providers/registry/kimi-coding.js +65 -0
  284. package/open-sse/providers/registry/kimi.js +56 -0
  285. package/open-sse/providers/registry/kiro.js +115 -0
  286. package/open-sse/providers/registry/linkup.js +34 -0
  287. package/open-sse/providers/registry/local-device.js +24 -0
  288. package/open-sse/providers/registry/mimo-free.js +24 -0
  289. package/open-sse/providers/registry/minimax-cn.js +76 -0
  290. package/open-sse/providers/registry/minimax.js +83 -0
  291. package/open-sse/providers/registry/mistral.js +34 -0
  292. package/open-sse/providers/registry/mmf.js +19 -0
  293. package/open-sse/providers/registry/nanobanana.js +35 -0
  294. package/open-sse/providers/registry/nebius.js +27 -0
  295. package/open-sse/providers/registry/nvidia.js +43 -0
  296. package/open-sse/providers/registry/ollama-local.js +19 -0
  297. package/open-sse/providers/registry/ollama.js +36 -0
  298. package/open-sse/providers/registry/openai.js +84 -0
  299. package/open-sse/providers/registry/opencode-go.js +41 -0
  300. package/open-sse/providers/registry/opencode.js +25 -0
  301. package/open-sse/providers/registry/openrouter.js +60 -0
  302. package/open-sse/providers/registry/perplexity-agent.js +49 -0
  303. package/open-sse/providers/registry/perplexity-web.js +33 -0
  304. package/open-sse/providers/registry/perplexity.js +37 -0
  305. package/open-sse/providers/registry/playht.js +36 -0
  306. package/open-sse/providers/registry/qoder.js +54 -0
  307. package/open-sse/providers/registry/qwen.js +33 -0
  308. package/open-sse/providers/registry/recraft.js +24 -0
  309. package/open-sse/providers/registry/runwayml.js +30 -0
  310. package/open-sse/providers/registry/sdwebui.js +20 -0
  311. package/open-sse/providers/registry/searchapi.js +35 -0
  312. package/open-sse/providers/registry/searxng.js +35 -0
  313. package/open-sse/providers/registry/serper.js +35 -0
  314. package/open-sse/providers/registry/siliconflow.js +39 -0
  315. package/open-sse/providers/registry/stability-ai.js +31 -0
  316. package/open-sse/providers/registry/tavily.js +50 -0
  317. package/open-sse/providers/registry/together.js +31 -0
  318. package/open-sse/providers/registry/topaz.js +19 -0
  319. package/open-sse/providers/registry/tortoise.js +30 -0
  320. package/open-sse/providers/registry/venice.js +56 -0
  321. package/open-sse/providers/registry/vercel-ai-gateway.js +41 -0
  322. package/open-sse/providers/registry/vertex-partner.js +29 -0
  323. package/open-sse/providers/registry/vertex.js +32 -0
  324. package/open-sse/providers/registry/volcengine-ark.js +35 -0
  325. package/open-sse/providers/registry/voyage-ai.js +30 -0
  326. package/open-sse/providers/registry/xai.js +45 -0
  327. package/open-sse/providers/registry/xiaomi-mimo.js +46 -0
  328. package/open-sse/providers/registry/xiaomi-tokenplan.js +63 -0
  329. package/open-sse/providers/registry/youcom.js +35 -0
  330. package/open-sse/providers/schema.js +76 -0
  331. package/open-sse/providers/shared.js +74 -0
  332. package/open-sse/providers/thinkingLevels.js +48 -0
  333. package/open-sse/rtk/applyFilter.js +15 -0
  334. package/open-sse/rtk/autodetect.js +111 -0
  335. package/open-sse/rtk/caveman.js +100 -0
  336. package/open-sse/rtk/cavemanPrompts.js +78 -0
  337. package/open-sse/rtk/constants.js +55 -0
  338. package/open-sse/rtk/filters/buildOutput.js +127 -0
  339. package/open-sse/rtk/filters/dedupLog.js +44 -0
  340. package/open-sse/rtk/filters/find.js +50 -0
  341. package/open-sse/rtk/filters/gitDiff.js +92 -0
  342. package/open-sse/rtk/filters/gitLog.js +99 -0
  343. package/open-sse/rtk/filters/gitStatus.js +117 -0
  344. package/open-sse/rtk/filters/grep.js +48 -0
  345. package/open-sse/rtk/filters/ls.js +79 -0
  346. package/open-sse/rtk/filters/readNumbered.js +27 -0
  347. package/open-sse/rtk/filters/searchList.js +52 -0
  348. package/open-sse/rtk/filters/smartTruncate.js +15 -0
  349. package/open-sse/rtk/filters/tree.js +32 -0
  350. package/open-sse/rtk/headroom.js +215 -0
  351. package/open-sse/rtk/index.js +155 -0
  352. package/open-sse/rtk/paleo.js +47 -0
  353. package/open-sse/rtk/ponytail.js +9 -0
  354. package/open-sse/rtk/ponytailPrompt.js +52 -0
  355. package/open-sse/rtk/ponytailPrompts.js +76 -0
  356. package/open-sse/rtk/pxpipe.js +104 -0
  357. package/open-sse/rtk/registry.js +38 -0
  358. package/open-sse/rtk/systemInject.js +98 -0
  359. package/open-sse/services/accountFallback.js +323 -0
  360. package/open-sse/services/antigravityHeaders.js +91 -0
  361. package/open-sse/services/antigravityVersion.js +154 -0
  362. package/open-sse/services/clinepassModels.js +63 -0
  363. package/open-sse/services/codexQuotaFetcher.js +312 -0
  364. package/open-sse/services/codexVerbosity.js +30 -0
  365. package/open-sse/services/combo/context.js +12 -0
  366. package/open-sse/services/combo/fingerprintExpansion.js +51 -0
  367. package/open-sse/services/combo/headroomRanking.js +28 -0
  368. package/open-sse/services/combo/quotaExhaustionCutoff.js +87 -0
  369. package/open-sse/services/combo/quotaScoring.js +226 -0
  370. package/open-sse/services/combo/quotaShareConcurrency.js +25 -0
  371. package/open-sse/services/combo/quotaShareInflight.js +50 -0
  372. package/open-sse/services/combo/quotaShareStrategy.js +130 -0
  373. package/open-sse/services/combo/resolveAutoStrategy.js +231 -0
  374. package/open-sse/services/combo/responseValidation.js +140 -0
  375. package/open-sse/services/combo/runtimeUnits.js +195 -0
  376. package/open-sse/services/combo/sessionStickiness.js +128 -0
  377. package/open-sse/services/combo/shadowRouting.js +131 -0
  378. package/open-sse/services/combo/targetExhaustion.js +75 -0
  379. package/open-sse/services/combo/targetSorters.js +126 -0
  380. package/open-sse/services/combo/targetTimeoutRunner.js +65 -0
  381. package/open-sse/services/combo/validateQuality.js +271 -0
  382. package/open-sse/services/combo.js +571 -0
  383. package/open-sse/services/comboAgentMiddleware.js +91 -0
  384. package/open-sse/services/comboConfig.js +153 -0
  385. package/open-sse/services/comboManifestMetrics.js +10 -0
  386. package/open-sse/services/comboMetrics.js +278 -0
  387. package/open-sse/services/compact.js +71 -0
  388. package/open-sse/services/copilotModels.js +155 -0
  389. package/open-sse/services/emergencyFallback.js +109 -0
  390. package/open-sse/services/errorClassifier.js +190 -0
  391. package/open-sse/services/evalRouting.js +201 -0
  392. package/open-sse/services/freeWebSearch.js +4 -0
  393. package/open-sse/services/fusion.js +223 -0
  394. package/open-sse/services/intentClassifier.js +631 -0
  395. package/open-sse/services/kimchiModels.js +176 -0
  396. package/open-sse/services/kiroModels.js +332 -0
  397. package/open-sse/services/model.js +136 -0
  398. package/open-sse/services/modelCapabilities.js +5 -0
  399. package/open-sse/services/modelDeprecation.js +101 -0
  400. package/open-sse/services/modelFamilyFallback.js +166 -0
  401. package/open-sse/services/oauthCredentialManager.js +156 -0
  402. package/open-sse/services/pipeline.js +107 -0
  403. package/open-sse/services/projectId.js +306 -0
  404. package/open-sse/services/provider.js +169 -0
  405. package/open-sse/services/providerCooldownTracker.js +94 -0
  406. package/open-sse/services/providerDefaultRateLimit.js +11 -0
  407. package/open-sse/services/proxyAutoSelector.js +24 -0
  408. package/open-sse/services/qoderModels.js +214 -0
  409. package/open-sse/services/quotaFetchThrottle.js +103 -0
  410. package/open-sse/services/quotaMonitor.js +310 -0
  411. package/open-sse/services/quotaPreflight.js +266 -0
  412. package/open-sse/services/rateLimitManager/headers.js +56 -0
  413. package/open-sse/services/rateLimitManager.js +616 -0
  414. package/open-sse/services/rateLimitSemaphore.js +112 -0
  415. package/open-sse/services/responsesInputSanitizer.js +99 -0
  416. package/open-sse/services/slidingWindowLimiter.js +44 -0
  417. package/open-sse/services/streamRecovery.js +355 -0
  418. package/open-sse/services/taskAwareRouter.js +227 -0
  419. package/open-sse/services/taskAwareRouting.js +332 -0
  420. package/open-sse/services/thinkingBudget.js +247 -0
  421. package/open-sse/services/tokenRefresh/dedup.js +31 -0
  422. package/open-sse/services/tokenRefresh/providers.js +624 -0
  423. package/open-sse/services/tokenRefresh.js +254 -0
  424. package/open-sse/services/usage/claude.js +147 -0
  425. package/open-sse/services/usage/codebuddy-cn.js +138 -0
  426. package/open-sse/services/usage/codex.js +267 -0
  427. package/open-sse/services/usage/github.js +100 -0
  428. package/open-sse/services/usage/google.js +241 -0
  429. package/open-sse/services/usage/grok-cli.js +274 -0
  430. package/open-sse/services/usage/kiro.js +188 -0
  431. package/open-sse/services/usage/minimax.js +234 -0
  432. package/open-sse/services/usage/misc.js +288 -0
  433. package/open-sse/services/usage/shared.js +70 -0
  434. package/open-sse/services/usage.js +62 -0
  435. package/open-sse/services/usageDb.js +2 -0
  436. package/open-sse/services/webSearchRouting.js +25 -0
  437. package/open-sse/services/wildcardRouter.js +59 -0
  438. package/open-sse/shared/clineAuth.js +37 -0
  439. package/open-sse/shared/machineId.js +19 -0
  440. package/open-sse/shared/qoder/constants.js +64 -0
  441. package/open-sse/shared/qoder/cosy.js +175 -0
  442. package/open-sse/shared/qoder/encoding.js +55 -0
  443. package/open-sse/transformer/responsesTransformer.js +439 -0
  444. package/open-sse/transformer/streamToJsonConverter.js +103 -0
  445. package/open-sse/translator/concerns/chunk.js +11 -0
  446. package/open-sse/translator/concerns/finishReason.js +63 -0
  447. package/open-sse/translator/concerns/image.js +124 -0
  448. package/open-sse/translator/concerns/json.js +5 -0
  449. package/open-sse/translator/concerns/message.js +7 -0
  450. package/open-sse/translator/concerns/modality.js +155 -0
  451. package/open-sse/translator/concerns/paramSupport.js +75 -0
  452. package/open-sse/translator/concerns/prefetch.js +96 -0
  453. package/open-sse/translator/concerns/reasoning.js +24 -0
  454. package/open-sse/translator/concerns/thinking.js +53 -0
  455. package/open-sse/translator/concerns/thinkingUnified.js +329 -0
  456. package/open-sse/translator/concerns/toolCall.js +153 -0
  457. package/open-sse/translator/concerns/usage.js +69 -0
  458. package/open-sse/translator/formats/claude.js +368 -0
  459. package/open-sse/translator/formats/gemini.js +380 -0
  460. package/open-sse/translator/formats/maxTokens.js +34 -0
  461. package/open-sse/translator/formats/openai.js +134 -0
  462. package/open-sse/translator/formats/responsesApi.js +141 -0
  463. package/open-sse/translator/formats.js +36 -0
  464. package/open-sse/translator/helpers/claudeHelper.js +216 -0
  465. package/open-sse/translator/helpers/geminiHelper.js +372 -0
  466. package/open-sse/translator/helpers/imageHelper.js +34 -0
  467. package/open-sse/translator/helpers/maxTokensHelper.js +27 -0
  468. package/open-sse/translator/helpers/openaiHelper.js +130 -0
  469. package/open-sse/translator/helpers/responsesApiHelper.js +139 -0
  470. package/open-sse/translator/helpers/toolCallHelper.js +148 -0
  471. package/open-sse/translator/index.js +252 -0
  472. package/open-sse/translator/request/antigravity-to-openai.js +242 -0
  473. package/open-sse/translator/request/claude-to-kiro.js +478 -0
  474. package/open-sse/translator/request/claude-to-openai.js +263 -0
  475. package/open-sse/translator/request/gemini-to-openai.js +152 -0
  476. package/open-sse/translator/request/openai-responses.js +385 -0
  477. package/open-sse/translator/request/openai-to-claude.js +383 -0
  478. package/open-sse/translator/request/openai-to-commandcode.js +176 -0
  479. package/open-sse/translator/request/openai-to-cursor.js +185 -0
  480. package/open-sse/translator/request/openai-to-gemini.js +442 -0
  481. package/open-sse/translator/request/openai-to-kiro.js +607 -0
  482. package/open-sse/translator/request/openai-to-kiro.old.js +278 -0
  483. package/open-sse/translator/request/openai-to-ollama.js +195 -0
  484. package/open-sse/translator/request/openai-to-vertex.js +42 -0
  485. package/open-sse/translator/response/claude-to-openai.js +195 -0
  486. package/open-sse/translator/response/commandcode-to-openai.js +188 -0
  487. package/open-sse/translator/response/cursor-to-openai.js +30 -0
  488. package/open-sse/translator/response/gemini-to-openai.js +147 -0
  489. package/open-sse/translator/response/kiro-to-claude.js +261 -0
  490. package/open-sse/translator/response/kiro-to-openai.js +160 -0
  491. package/open-sse/translator/response/ollama-to-openai.js +134 -0
  492. package/open-sse/translator/response/openai-responses.js +535 -0
  493. package/open-sse/translator/response/openai-to-antigravity.js +123 -0
  494. package/open-sse/translator/response/openai-to-claude.js +265 -0
  495. package/open-sse/translator/schema/blocks.js +43 -0
  496. package/open-sse/translator/schema/defaults.js +7 -0
  497. package/open-sse/translator/schema/finishReasons.js +27 -0
  498. package/open-sse/translator/schema/index.js +8 -0
  499. package/open-sse/translator/schema/roles.js +16 -0
  500. package/open-sse/utils/agentGoalPolicy.js +85 -0
  501. package/open-sse/utils/aiSdkCompat.js +75 -0
  502. package/open-sse/utils/bypassHandler.js +298 -0
  503. package/open-sse/utils/cacheControlPolicy.js +189 -0
  504. package/open-sse/utils/claudeCloaking.js +155 -0
  505. package/open-sse/utils/claudeHeaderCache.js +70 -0
  506. package/open-sse/utils/claudeSignature.js +41 -0
  507. package/open-sse/utils/clientDetector.js +63 -0
  508. package/open-sse/utils/codebuddySanitizer.js +96 -0
  509. package/open-sse/utils/composerToolCalls.js +158 -0
  510. package/open-sse/utils/cors.js +13 -0
  511. package/open-sse/utils/cursorChecksum.js +149 -0
  512. package/open-sse/utils/cursorImages.js +224 -0
  513. package/open-sse/utils/cursorProtobuf.js +904 -0
  514. package/open-sse/utils/cursorVersionDetector.js +55 -0
  515. package/open-sse/utils/debugLog.js +14 -0
  516. package/open-sse/utils/diagnostics.js +143 -0
  517. package/open-sse/utils/error.js +164 -0
  518. package/open-sse/utils/estimateSize.js +33 -0
  519. package/open-sse/utils/finishReason.js +32 -0
  520. package/open-sse/utils/flattenToolHistory.js +68 -0
  521. package/open-sse/utils/headers.js +36 -0
  522. package/open-sse/utils/heapPressure.js +35 -0
  523. package/open-sse/utils/jsonToSse.js +125 -0
  524. package/open-sse/utils/keepaliveThreshold.js +40 -0
  525. package/open-sse/utils/logger.js +104 -0
  526. package/open-sse/utils/noThinkingAlias.js +74 -0
  527. package/open-sse/utils/number.js +7 -0
  528. package/open-sse/utils/ollamaTransform.js +85 -0
  529. package/open-sse/utils/opencodeHeaders.js +47 -0
  530. package/open-sse/utils/progressTracker.js +81 -0
  531. package/open-sse/utils/providerRequestLogging.js +219 -0
  532. package/open-sse/utils/proxyFetch.js +369 -0
  533. package/open-sse/utils/reasoningContentInjector.js +79 -0
  534. package/open-sse/utils/reasoningFields.js +70 -0
  535. package/open-sse/utils/requestLogger.js +260 -0
  536. package/open-sse/utils/responsesInputNormalization.js +92 -0
  537. package/open-sse/utils/responsesStatePolicy.js +52 -0
  538. package/open-sse/utils/responsesStreamHelpers.js +49 -0
  539. package/open-sse/utils/sessionManager.js +240 -0
  540. package/open-sse/utils/sleep.js +6 -0
  541. package/open-sse/utils/sse.js +14 -0
  542. package/open-sse/utils/sseConstants.js +23 -0
  543. package/open-sse/utils/sseHeartbeat.js +104 -0
  544. package/open-sse/utils/stream.js +517 -0
  545. package/open-sse/utils/streamFailureFinalization.js +134 -0
  546. package/open-sse/utils/streamHandler.js +250 -0
  547. package/open-sse/utils/streamHelpers.js +137 -0
  548. package/open-sse/utils/textualToolCall.js +104 -0
  549. package/open-sse/utils/thinkCloseMarker.js +72 -0
  550. package/open-sse/utils/thinkTagParser.js +146 -0
  551. package/open-sse/utils/toolCallArguments.js +12 -0
  552. package/open-sse/utils/toolDeduper.js +49 -0
  553. package/open-sse/utils/toolSources.js +31 -0
  554. package/open-sse/utils/upstreamResponseHeaders.js +25 -0
  555. package/open-sse/utils/urlSanitize.js +15 -0
  556. package/open-sse/utils/usageTracking.js +347 -0
  557. package/package.json +1 -1
@@ -0,0 +1,99 @@
1
+ // JS-native git-log filter
2
+ // Compresses `git log` output: keeps commit headers, subjects, Author/Date;
3
+ // drops body padding, decoration, embedded diff lines.
4
+ import { GIT_LOG_MAX_LINES } from "../constants.js";
5
+
6
+ export function gitLog(text, maxLines = GIT_LOG_MAX_LINES) {
7
+ if (!text) return "";
8
+
9
+ const input = String(text);
10
+ const lines = input.split("\n");
11
+ const out = [];
12
+ let skipped = 0;
13
+ let inCommit = false;
14
+ let subjectSeen = false;
15
+
16
+ function pushLine(l) {
17
+ if (out.length < maxLines) {
18
+ out.push(l);
19
+ return true;
20
+ }
21
+ skipped++;
22
+ return false;
23
+ }
24
+
25
+ for (let i = 0; i < lines.length; i++) {
26
+ const raw = lines[i];
27
+ const line = raw.trimEnd();
28
+ const trimmed = line.trim();
29
+
30
+ // commit <sha> header — starts new commit entry
31
+ // Also matched with leading graph decoration (`* commit abc1234...` — --graph without --oneline)
32
+ if (/^commit [0-9a-f]{7,40}$/i.test(trimmed) || /^[*|/\\ ]+commit [0-9a-f]{7,40}/i.test(trimmed)) {
33
+ inCommit = true;
34
+ subjectSeen = false;
35
+ pushLine(line);
36
+ continue;
37
+ }
38
+
39
+ if (inCommit) {
40
+ // Author / Date — keep as-is (already column 0 in raw, or graph-prefix stripped by commit-header match)
41
+ if (/^[*|/\\ ]*(Author|Date):/i.test(trimmed)) {
42
+ pushLine(trimmed);
43
+ continue;
44
+ }
45
+ // blank — skip
46
+ if (trimmed === "") continue;
47
+ // indented subject (4 spaces, optionally preceded by graph decoration) — first one is subject
48
+ if (!subjectSeen && /^[*|/\\ ]* \S/.test(line)) {
49
+ pushLine(" Subject: " + trimmed);
50
+ subjectSeen = true;
51
+ continue;
52
+ }
53
+ // stat summary: "N file(s) changed, N insertions(+), N deletions(-)"
54
+ if (/^\d+ file\w* changed/.test(trimmed)) {
55
+ pushLine(" " + trimmed);
56
+ continue;
57
+ }
58
+ // embedded diff header — one-line marker
59
+ if (/^diff --git /.test(trimmed)) {
60
+ pushLine(" ... diff body omitted");
61
+ continue;
62
+ }
63
+ // everything else in commit body — drop
64
+ continue;
65
+ }
66
+
67
+ // Not in a commit block (--oneline / --graph modes):
68
+
69
+ // Graph decoration + sha + subject: "*|/\\ <sha7> <subject>"
70
+ const graphMatch = trimmed.match(/^[*|/\\ ]+([0-9a-f]{7,40}\s+.+)/i);
71
+ if (graphMatch) {
72
+ pushLine(graphMatch[1]);
73
+ continue;
74
+ }
75
+
76
+ // Plain oneline: "<sha7> <subject>"
77
+ if (/^[0-9a-f]{7,40}\s+/.test(trimmed)) {
78
+ pushLine(trimmed);
79
+ continue;
80
+ }
81
+
82
+ // Pure graph decoration (no sha) — drop
83
+ if (/^[*|/\\ ]+$/.test(trimmed) && /[*|/\\]/.test(trimmed)) {
84
+ continue;
85
+ }
86
+
87
+ // catch-all pass-through
88
+ pushLine(trimmed);
89
+ }
90
+
91
+ if (skipped > 0) out.push(`... (${skipped} more lines)`);
92
+
93
+ const result = out.join("\n");
94
+ if (!result && input) return input;
95
+ if (result.length > input.length) return input;
96
+ return result;
97
+ }
98
+
99
+ gitLog.filterName = "git-log";
@@ -0,0 +1,117 @@
1
+ // Port of git::format_status_output (rtk/src/cmds/git/git.rs:619-730)
2
+ // Output format:
3
+ // * <branch>
4
+ // + Staged: N files
5
+ // path1
6
+ // ... +K more
7
+ // ~ Modified: N files
8
+ // ? Untracked: N files
9
+ // conflicts: N files
10
+ // clean — nothing to commit
11
+ import { STATUS_MAX_FILES, STATUS_MAX_UNTRACKED } from "../constants.js";
12
+
13
+ export function gitStatus(input) {
14
+ const lines = input.split("\n");
15
+ if (lines.length === 0 || (lines.length === 1 && !lines[0].trim())) {
16
+ return "Clean working tree";
17
+ }
18
+
19
+ let branch = "";
20
+ const stagedFiles = [];
21
+ const modifiedFiles = [];
22
+ const untrackedFiles = [];
23
+ let staged = 0;
24
+ let modified = 0;
25
+ let untracked = 0;
26
+ let conflicts = 0;
27
+
28
+ for (const raw of lines) {
29
+ if (!raw.trim()) continue;
30
+
31
+ // Long-form branch detection (LLM usually sends this, not porcelain)
32
+ const longBranch = raw.match(/^On branch (\S+)/);
33
+ if (longBranch) { branch = longBranch[1]; continue; }
34
+
35
+ // Porcelain branch header: "## main...origin/main"
36
+ if (raw.startsWith("##")) { branch = raw.replace(/^##\s*/, ""); continue; }
37
+
38
+ // Porcelain status (2 chars + space + path)
39
+ if (raw.length >= 3 && /^[ MADRCU?!][ MADRCU?!] /.test(raw)) {
40
+ const x = raw[0];
41
+ const y = raw[1];
42
+ const file = raw.slice(3);
43
+
44
+ if (raw.slice(0, 2) === "??") {
45
+ untracked++;
46
+ untrackedFiles.push(file);
47
+ continue;
48
+ }
49
+
50
+ if ("MADRC".includes(x)) {
51
+ staged++;
52
+ stagedFiles.push(file);
53
+ } else if (x === "U") {
54
+ conflicts++;
55
+ }
56
+
57
+ if (y === "M" || y === "D") {
58
+ modified++;
59
+ modifiedFiles.push(file);
60
+ }
61
+ continue;
62
+ }
63
+
64
+ // Long form fallback ("modified: path", "new file: path", ...)
65
+ const longMatch = raw.match(/^\s*(modified|new file|deleted|renamed|both modified):\s+(.+)$/);
66
+ if (longMatch) {
67
+ const kind = longMatch[1];
68
+ const path = longMatch[2].trim();
69
+ if (kind === "both modified") { conflicts++; }
70
+ else if (kind === "modified" || kind === "deleted") { modified++; modifiedFiles.push(path); }
71
+ else if (kind === "new file" || kind === "renamed") { staged++; stagedFiles.push(path); }
72
+ continue;
73
+ }
74
+
75
+ // "Untracked files:" section — gather bare paths after this marker
76
+ // Handled implicitly: plain paths without markers are skipped (safer).
77
+ }
78
+
79
+ let out = "";
80
+ if (branch) out += `* ${branch}\n`;
81
+
82
+ if (staged > 0) {
83
+ out += `+ Staged: ${staged} files\n`;
84
+ for (const f of stagedFiles.slice(0, STATUS_MAX_FILES)) out += ` ${f}\n`;
85
+ if (stagedFiles.length > STATUS_MAX_FILES) {
86
+ out += ` ... +${stagedFiles.length - STATUS_MAX_FILES} more\n`;
87
+ }
88
+ }
89
+
90
+ if (modified > 0) {
91
+ out += `~ Modified: ${modified} files\n`;
92
+ for (const f of modifiedFiles.slice(0, STATUS_MAX_FILES)) out += ` ${f}\n`;
93
+ if (modifiedFiles.length > STATUS_MAX_FILES) {
94
+ out += ` ... +${modifiedFiles.length - STATUS_MAX_FILES} more\n`;
95
+ }
96
+ }
97
+
98
+ if (untracked > 0) {
99
+ out += `? Untracked: ${untracked} files\n`;
100
+ for (const f of untrackedFiles.slice(0, STATUS_MAX_UNTRACKED)) out += ` ${f}\n`;
101
+ if (untrackedFiles.length > STATUS_MAX_UNTRACKED) {
102
+ out += ` ... +${untrackedFiles.length - STATUS_MAX_UNTRACKED} more\n`;
103
+ }
104
+ }
105
+
106
+ if (conflicts > 0) {
107
+ out += `conflicts: ${conflicts} files\n`;
108
+ }
109
+
110
+ if (staged === 0 && modified === 0 && untracked === 0 && conflicts === 0) {
111
+ out += "clean — nothing to commit\n";
112
+ }
113
+
114
+ return out.replace(/\n+$/, "");
115
+ }
116
+
117
+ gitStatus.filterName = "git-status";
@@ -0,0 +1,48 @@
1
+ // Port of grep_wrapper (rtk/src/cmds/system/pipe_cmd.rs:50-86)
2
+ // Input format: "file:lineno:content" — splitn(3, ':') in Rust
3
+ import { GREP_PER_FILE_MAX } from "../constants.js";
4
+
5
+ export function grep(input) {
6
+ const byFile = new Map();
7
+ let total = 0;
8
+
9
+ for (const line of input.split("\n")) {
10
+ // splitn(3, ':') — only split on first 2 colons
11
+ const first = line.indexOf(":");
12
+ if (first === -1) continue;
13
+ const second = line.indexOf(":", first + 1);
14
+ if (second === -1) continue;
15
+ const file = line.slice(0, first);
16
+ const lineNumStr = line.slice(first + 1, second);
17
+ const content = line.slice(second + 1);
18
+ // Rust: parts[1].parse::<usize>().is_ok()
19
+ if (!/^\d+$/.test(lineNumStr)) continue;
20
+ total++;
21
+ if (!byFile.has(file)) byFile.set(file, []);
22
+ byFile.get(file).push([lineNumStr, content]);
23
+ }
24
+
25
+ if (total === 0) return input;
26
+
27
+ // Rust: files.sort_by_key(|(f, _)| *f)
28
+ const files = Array.from(byFile.keys()).sort();
29
+ let out = `${total} matches in ${files.length}F:\n\n`;
30
+
31
+ for (const file of files) {
32
+ const matches = byFile.get(file);
33
+ out += `[file] ${file} (${matches.length}):\n`;
34
+ const show = matches.slice(0, GREP_PER_FILE_MAX);
35
+ for (const [lineNum, content] of show) {
36
+ // Rust: format!(" {:>4}: {}", line_num, content.trim())
37
+ out += ` ${lineNum.padStart(4)}: ${content.trim()}\n`;
38
+ }
39
+ if (matches.length > GREP_PER_FILE_MAX) {
40
+ out += ` +${matches.length - GREP_PER_FILE_MAX}\n`;
41
+ }
42
+ out += "\n";
43
+ }
44
+
45
+ return out;
46
+ }
47
+
48
+ grep.filterName = "grep";
@@ -0,0 +1,79 @@
1
+ // Port of compact_ls (rtk/src/cmds/system/ls.rs:154-232)
2
+ // Input: `ls -la` style output. Output: compact "name/ (dirs)\nname size"
3
+ import { LS_EXT_SUMMARY_TOP, LS_NOISE_DIRS } from "../constants.js";
4
+
5
+ // Rust LS_DATE_RE: month + day + (year|HH:MM)
6
+ const LS_DATE_RE = /\s+(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s+\d{1,2}\s+(\d{4}|\d{2}:\d{2})\s+/;
7
+
8
+ function humanSize(bytes) {
9
+ if (bytes >= 1_048_576) return `${(bytes / 1_048_576).toFixed(1)}M`;
10
+ if (bytes >= 1024) return `${(bytes / 1024).toFixed(1)}K`;
11
+ return `${bytes}B`;
12
+ }
13
+
14
+ function parseLsLine(line) {
15
+ const m = LS_DATE_RE.exec(line);
16
+ if (!m) return null;
17
+ const name = line.slice(m.index + m[0].length);
18
+ const beforeDate = line.slice(0, m.index);
19
+ const beforeParts = beforeDate.split(/\s+/).filter(Boolean);
20
+ if (beforeParts.length < 4) return null;
21
+
22
+ const perms = beforeParts[0];
23
+ const fileType = perms.charAt(0);
24
+
25
+ // size = rightmost parseable number before the date
26
+ let size = 0;
27
+ for (let i = beforeParts.length - 1; i >= 0; i--) {
28
+ const n = Number(beforeParts[i]);
29
+ if (Number.isInteger(n) && String(n) === beforeParts[i]) { size = n; break; }
30
+ }
31
+ return { fileType, size, name };
32
+ }
33
+
34
+ export function ls(input) {
35
+ const dirs = [];
36
+ const files = []; // [name, sizeStr]
37
+ const byExt = new Map();
38
+
39
+ for (const line of input.split("\n")) {
40
+ if (line.startsWith("total ") || line.length === 0) continue;
41
+ const parsed = parseLsLine(line);
42
+ if (!parsed) continue;
43
+ if (parsed.name === "." || parsed.name === "..") continue;
44
+
45
+ // Rust ls.rs: show_all flag respected — for LLM context always skip noise
46
+ if (LS_NOISE_DIRS.includes(parsed.name)) continue;
47
+
48
+ if (parsed.fileType === "d") {
49
+ dirs.push(parsed.name);
50
+ } else if (parsed.fileType === "-" || parsed.fileType === "l") {
51
+ const dot = parsed.name.lastIndexOf(".");
52
+ const ext = dot > 0 ? parsed.name.slice(dot) : "no ext";
53
+ byExt.set(ext, (byExt.get(ext) || 0) + 1);
54
+ files.push([parsed.name, humanSize(parsed.size)]);
55
+ }
56
+ }
57
+
58
+ if (dirs.length === 0 && files.length === 0) return input;
59
+
60
+ let out = "";
61
+ for (const d of dirs) out += `${d}/\n`;
62
+ for (const [name, size] of files) out += `${name} ${size}\n`;
63
+
64
+ // Summary line (Rust port)
65
+ let summary = `\nSummary: ${files.length} files, ${dirs.length} dirs`;
66
+ if (byExt.size > 0) {
67
+ const ext = Array.from(byExt.entries()).sort((a, b) => b[1] - a[1]);
68
+ const parts = ext.slice(0, LS_EXT_SUMMARY_TOP).map(([e, c]) => `${c} ${e}`);
69
+ summary += ` (${parts.join(", ")}`;
70
+ if (ext.length > LS_EXT_SUMMARY_TOP) {
71
+ summary += `, +${ext.length - LS_EXT_SUMMARY_TOP} more`;
72
+ }
73
+ summary += ")";
74
+ }
75
+
76
+ return out + summary;
77
+ }
78
+
79
+ ls.filterName = "ls";
@@ -0,0 +1,27 @@
1
+ // Handles Cursor/Codex read_file output: " 1|content\n 2|content".
2
+ // Strategy mirrors Rust filter::smart_truncate (filter.rs): keep head+tail, drop middle.
3
+ import { SMART_TRUNCATE_HEAD, SMART_TRUNCATE_TAIL, SMART_TRUNCATE_MIN_LINES } from "../constants.js";
4
+
5
+ const LINE_RE = /^\s*\d+\|/;
6
+
7
+ export function readNumbered(input) {
8
+ const lines = input.split("\n");
9
+ if (lines.length < SMART_TRUNCATE_MIN_LINES) return input;
10
+
11
+ // Count how many lines match "N|content" to verify shape (hit ratio check
12
+ // already done by autodetect; here we just truncate).
13
+ const head = lines.slice(0, SMART_TRUNCATE_HEAD);
14
+ const tail = lines.slice(lines.length - SMART_TRUNCATE_TAIL);
15
+ const cut = lines.length - head.length - tail.length;
16
+
17
+ return [
18
+ ...head,
19
+ `... +${cut} lines truncated (file continues)`,
20
+ ...tail
21
+ ].join("\n");
22
+ }
23
+
24
+ readNumbered.filterName = "read-numbered";
25
+
26
+ // Exposed for autodetect
27
+ export const READ_NUMBERED_LINE_RE = LINE_RE;
@@ -0,0 +1,52 @@
1
+ // Compact "Result of search in '...' (total N files):\n- path\n- path" output
2
+ // (Cursor Glob tool). Groups by parent dir like find, shows basenames.
3
+ import { SEARCH_LIST_PER_DIR_MAX, SEARCH_LIST_TOTAL_DIR_MAX } from "../constants.js";
4
+
5
+ const HEADER_RE = /^Result of search in '[^']*' \(total (\d+) files?\):/;
6
+
7
+ export function searchList(input) {
8
+ const lines = input.split("\n");
9
+ if (lines.length === 0) return input;
10
+
11
+ // First line must be the header (validated by autodetect too)
12
+ const header = lines[0] || "";
13
+ const rest = lines.slice(1);
14
+
15
+ const paths = [];
16
+ for (const raw of rest) {
17
+ const t = raw.trim();
18
+ if (!t.startsWith("- ")) continue;
19
+ paths.push(t.slice(2));
20
+ }
21
+ if (paths.length === 0) return input;
22
+
23
+ const byDir = new Map();
24
+ for (const p of paths) {
25
+ const slash = p.lastIndexOf("/");
26
+ const dir = slash === -1 ? "." : (p.slice(0, slash) || "/");
27
+ const name = slash === -1 ? p : p.slice(slash + 1);
28
+ if (!byDir.has(dir)) byDir.set(dir, []);
29
+ byDir.get(dir).push(name);
30
+ }
31
+
32
+ const dirs = Array.from(byDir.keys()).sort();
33
+ let out = `${header}\n${paths.length} files in ${dirs.length} dirs:\n\n`;
34
+
35
+ for (const dir of dirs.slice(0, SEARCH_LIST_TOTAL_DIR_MAX)) {
36
+ const names = byDir.get(dir);
37
+ out += `${dir}/ (${names.length}):\n`;
38
+ for (const n of names.slice(0, SEARCH_LIST_PER_DIR_MAX)) out += ` ${n}\n`;
39
+ if (names.length > SEARCH_LIST_PER_DIR_MAX) {
40
+ out += ` +${names.length - SEARCH_LIST_PER_DIR_MAX}\n`;
41
+ }
42
+ out += "\n";
43
+ }
44
+ if (dirs.length > SEARCH_LIST_TOTAL_DIR_MAX) {
45
+ out += `+${dirs.length - SEARCH_LIST_TOTAL_DIR_MAX} more dirs\n`;
46
+ }
47
+
48
+ return out.replace(/\n+$/, "");
49
+ }
50
+
51
+ searchList.filterName = "search-list";
52
+ export const SEARCH_LIST_HEADER_RE = HEADER_RE;
@@ -0,0 +1,15 @@
1
+ // Port concept of filter::smart_truncate (rtk/src/core/filter.rs).
2
+ // Keep HEAD + TAIL lines, replace middle with "... +N lines truncated".
3
+ import { SMART_TRUNCATE_HEAD, SMART_TRUNCATE_TAIL, SMART_TRUNCATE_MIN_LINES } from "../constants.js";
4
+
5
+ export function smartTruncate(input) {
6
+ const lines = input.split("\n");
7
+ if (lines.length < SMART_TRUNCATE_MIN_LINES) return input;
8
+
9
+ const head = lines.slice(0, SMART_TRUNCATE_HEAD);
10
+ const tail = lines.slice(lines.length - SMART_TRUNCATE_TAIL);
11
+ const cut = lines.length - head.length - tail.length;
12
+ return [...head, `... +${cut} lines truncated`, ...tail].join("\n");
13
+ }
14
+
15
+ smartTruncate.filterName = "smart-truncate";
@@ -0,0 +1,32 @@
1
+ // Port of filter_tree_output (rtk/src/cmds/system/tree.rs:65-94)
2
+ // Removes summary line (e.g. "5 directories, 23 files") and trailing blanks.
3
+ import { TREE_MAX_LINES } from "../constants.js";
4
+
5
+ export function tree(input) {
6
+ const lines = input.split("\n");
7
+ if (lines.length === 0) return input;
8
+
9
+ const filtered = [];
10
+ for (const line of lines) {
11
+ // Drop "X directories, Y files" summary
12
+ if (line.includes("director") && line.includes("file")) continue;
13
+ // Drop leading blanks
14
+ if (line.trim() === "" && filtered.length === 0) continue;
15
+ filtered.push(line);
16
+ }
17
+
18
+ // Drop trailing blanks
19
+ while (filtered.length > 0 && filtered[filtered.length - 1].trim() === "") {
20
+ filtered.pop();
21
+ }
22
+
23
+ // Cap overly long trees (JS-only safeguard; Rust has no cap)
24
+ if (filtered.length > TREE_MAX_LINES) {
25
+ const cut = filtered.length - TREE_MAX_LINES;
26
+ return filtered.slice(0, TREE_MAX_LINES).join("\n") + `\n... +${cut} more lines`;
27
+ }
28
+
29
+ return filtered.join("\n");
30
+ }
31
+
32
+ tree.filterName = "tree";
@@ -0,0 +1,215 @@
1
+ import { claudeToOpenAIRequest } from "../translator/request/claude-to-openai.js";
2
+ import { openaiToClaudeRequest } from "../translator/request/openai-to-claude.js";
3
+ import {
4
+ openaiResponsesToOpenAIRequest,
5
+ openaiToOpenAIResponsesRequest,
6
+ } from "../translator/request/openai-responses.js";
7
+
8
+ const DEFAULT_TIMEOUT_MS = 3000;
9
+
10
+ function jsonBytes(value) {
11
+ try {
12
+ return new TextEncoder().encode(JSON.stringify(value) || "").length;
13
+ } catch {
14
+ return 0;
15
+ }
16
+ }
17
+
18
+ function messagePayload(body) {
19
+ if (Array.isArray(body?.messages)) return body.messages;
20
+ if (Array.isArray(body?.input)) return body.input;
21
+ return null;
22
+ }
23
+
24
+ function captureSizeSnapshot(body) {
25
+ const messages = messagePayload(body);
26
+ return {
27
+ bodyBytes: jsonBytes(body),
28
+ messageBytes: messages ? jsonBytes(messages) : 0,
29
+ };
30
+ }
31
+
32
+ function setDiagnostic(diagnostics, reason) {
33
+ if (diagnostics && !diagnostics.reason) diagnostics.reason = reason;
34
+ }
35
+
36
+ function scrubSensitiveUrlText(text) {
37
+ return String(text)
38
+ .replace(/\/\/[^/@\s]+@/g, "//")
39
+ .replace(/(https?:\/\/[^\s?#]+)[?#][^\s)]*/g, "$1");
40
+ }
41
+
42
+ function describeFetchError(error) {
43
+ const cause = error?.cause;
44
+ const code = cause?.code || error?.code;
45
+ const message = scrubSensitiveUrlText(cause?.message || error?.message || String(error));
46
+ return code ? `${code}: ${message}` : message;
47
+ }
48
+
49
+ function buildCompressEndpoint(url) {
50
+ try {
51
+ const parsed = new URL(url);
52
+ parsed.pathname = `${parsed.pathname.replace(/\/$/, "")}/v1/compress`;
53
+ parsed.hash = "";
54
+ return parsed.toString();
55
+ } catch {
56
+ const raw = String(url).replace(/#.*$/, "");
57
+ const [base, query = ""] = raw.split("?", 2);
58
+ const endpoint = `${base.replace(/\/$/, "")}/v1/compress`;
59
+ return query ? `${endpoint}?${query}` : endpoint;
60
+ }
61
+ }
62
+
63
+ function maskEndpoint(endpoint) {
64
+ try {
65
+ const parsed = new URL(endpoint);
66
+ parsed.username = "";
67
+ parsed.password = "";
68
+ parsed.search = "";
69
+ parsed.hash = "";
70
+ return parsed.toString();
71
+ } catch {
72
+ return String(endpoint).replace(/\/\/[^/@\s]+@/, "//").replace(/[?#].*$/, "");
73
+ }
74
+ }
75
+
76
+ function hasUnsafeResponsesInputForCompression(body) {
77
+ if (!Array.isArray(body?.input)) return false;
78
+ return body.input.some((item) => {
79
+ if (!item || typeof item !== "object" || Array.isArray(item)) return false;
80
+ return typeof item.type === "string" && item.type !== "message";
81
+ });
82
+ }
83
+
84
+ // POST messages to Headroom /v1/compress; returns compressed messages + stats or null.
85
+ async function callCompress(url, messages, model, timeoutMs, compressUserMessages, diagnostics) {
86
+ const endpoint = buildCompressEndpoint(url);
87
+ diagnostics.endpoint = maskEndpoint(endpoint);
88
+ const payload = { messages, model };
89
+ if (compressUserMessages) payload.config = { compress_user_messages: true };
90
+ let res;
91
+ try {
92
+ res = await fetch(endpoint, {
93
+ method: "POST",
94
+ headers: { "Content-Type": "application/json" },
95
+ body: JSON.stringify(payload),
96
+ signal: AbortSignal.timeout(timeoutMs),
97
+ });
98
+ } catch (error) {
99
+ setDiagnostic(diagnostics, `request failed: ${describeFetchError(error)}`);
100
+ return null;
101
+ }
102
+ if (!res.ok) {
103
+ setDiagnostic(diagnostics, `proxy returned HTTP ${res.status}`);
104
+ return null;
105
+ }
106
+ const data = await res.json();
107
+ if (!Array.isArray(data?.messages)) {
108
+ setDiagnostic(diagnostics, "proxy response missing messages[]");
109
+ return null;
110
+ }
111
+ return data;
112
+ }
113
+
114
+ // Compress request body via Headroom proxy. Fail-open: returns null on any error.
115
+ // /v1/compress only understands OpenAI shape, so Claude bodies are translated
116
+ // to OpenAI, compressed, then translated back using 9Router's own translators.
117
+ export async function compressWithHeadroom(body, { enabled, url, model, format, compressUserMessages, timeoutMs = DEFAULT_TIMEOUT_MS, diagnostics = null } = {}) {
118
+ if (!enabled) {
119
+ setDiagnostic(diagnostics, "disabled");
120
+ return null;
121
+ }
122
+ if (!url) {
123
+ setDiagnostic(diagnostics, "missing proxy URL");
124
+ return null;
125
+ }
126
+ if (!body) {
127
+ setDiagnostic(diagnostics, "missing request body");
128
+ return null;
129
+ }
130
+
131
+ try {
132
+ if (diagnostics) diagnostics.before = captureSizeSnapshot(body);
133
+
134
+ // Claude shape: translate → OpenAI → compress → translate back.
135
+ if (format === "claude") {
136
+ const oai = claudeToOpenAIRequest(model, body, false);
137
+ if (!Array.isArray(oai?.messages)) {
138
+ setDiagnostic(diagnostics, "Claude request did not translate to messages[]");
139
+ return null;
140
+ }
141
+ const data = await callCompress(url, oai.messages, model, timeoutMs, compressUserMessages, diagnostics || {});
142
+ if (!data) return null;
143
+ const claudeBody = openaiToClaudeRequest(model, { ...oai, messages: data.messages }, false);
144
+ if (Array.isArray(claudeBody?.messages)) body.messages = claudeBody.messages;
145
+ if (claudeBody?.system !== undefined) body.system = claudeBody.system;
146
+ if (diagnostics) diagnostics.after = captureSizeSnapshot(body);
147
+ return data;
148
+ }
149
+
150
+ // OpenAI Responses shape (Codex): body.input holds Responses items, NOT OpenAI
151
+ // messages. Translate input -> OpenAI -> compress -> translate back to input so
152
+ // body.input keeps the Responses contract (the proxy only understands OpenAI). (#1998)
153
+ if (format === "openai-responses") {
154
+ if (hasUnsafeResponsesInputForCompression(body)) {
155
+ setDiagnostic(diagnostics, "skipped: openai-responses tool/reasoning input is not safe to compress");
156
+ return null;
157
+ }
158
+ const oai = openaiResponsesToOpenAIRequest(model, body, false);
159
+ if (!Array.isArray(oai?.messages)) return null;
160
+ const data = await callCompress(url, oai.messages, model, timeoutMs, compressUserMessages, diagnostics || {});
161
+ if (!data) return null;
162
+ // input: undefined so the translator rebuilds input from the compressed
163
+ // messages instead of returning the original input unchanged.
164
+ const responsesBody = openaiToOpenAIResponsesRequest(
165
+ model,
166
+ { ...oai, input: undefined, messages: data.messages },
167
+ false
168
+ );
169
+ if (Array.isArray(responsesBody?.input)) body.input = responsesBody.input;
170
+ if (diagnostics) diagnostics.after = captureSizeSnapshot(body);
171
+ return data;
172
+ }
173
+
174
+ // OpenAI shape: messages/input go straight to the proxy.
175
+ const key = Array.isArray(body.messages) ? "messages"
176
+ : Array.isArray(body.input) ? "input"
177
+ : null;
178
+ if (!key) {
179
+ setDiagnostic(diagnostics, `unsupported ${format || "unknown"} request shape`);
180
+ return null;
181
+ }
182
+ const data = await callCompress(url, body[key], model, timeoutMs, compressUserMessages, diagnostics || {});
183
+ if (!data) return null;
184
+ body[key] = data.messages;
185
+ if (diagnostics) diagnostics.after = captureSizeSnapshot(body);
186
+ return data;
187
+ } catch (error) {
188
+ setDiagnostic(diagnostics, `unexpected error: ${error?.message || String(error)}`);
189
+ return null;
190
+ }
191
+ }
192
+
193
+ export function formatHeadroomLog(stats) {
194
+ if (!stats) return null;
195
+ const before = stats.tokens_before || 0;
196
+ const after = stats.tokens_after || 0;
197
+ const delta = stats.tokens_saved || 0;
198
+ const pct = before > 0 ? ((delta / before) * 100).toFixed(1) : "0";
199
+ return `reported token delta=${delta} before=${before}${after ? ` after=${after}` : ""} (${pct}%)`.trim();
200
+ }
201
+
202
+ export function formatHeadroomSizeLog(diagnostics) {
203
+ const before = diagnostics?.before;
204
+ const after = diagnostics?.after;
205
+ if (!before || !after) return "";
206
+ return `body=${before.bodyBytes}B→${after.bodyBytes}B messages=${before.messageBytes}B→${after.messageBytes}B`;
207
+ }
208
+
209
+ export function isHeadroomPhantomSavings(stats, diagnostics, minShrinkRatio = 0.05) {
210
+ if (!stats?.tokens_saved || stats.tokens_saved <= 0) return false;
211
+ const before = diagnostics?.before?.bodyBytes || 0;
212
+ const after = diagnostics?.after?.bodyBytes || 0;
213
+ if (before <= 0 || after <= 0) return false;
214
+ return after >= before * (1 - minShrinkRatio);
215
+ }