miawrouter 1.2.3 → 1.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (640) hide show
  1. package/README.md +7 -0
  2. package/app/.next-cli-build/BUILD_ID +1 -1
  3. package/app/.next-cli-build/app-path-routes-manifest.json +9 -9
  4. package/app/.next-cli-build/build-manifest.json +2 -2
  5. package/app/.next-cli-build/prerender-manifest.json +3 -3
  6. package/app/.next-cli-build/server/app/(dashboard)/dashboard/a2a/page.js.nft.json +1 -1
  7. package/app/.next-cli-build/server/app/(dashboard)/dashboard/a2a/page_client-reference-manifest.js +1 -1
  8. package/app/.next-cli-build/server/app/(dashboard)/dashboard/activity/page.js.nft.json +1 -1
  9. package/app/.next-cli-build/server/app/(dashboard)/dashboard/activity/page_client-reference-manifest.js +1 -1
  10. package/app/.next-cli-build/server/app/(dashboard)/dashboard/agent-skills/page.js.nft.json +1 -1
  11. package/app/.next-cli-build/server/app/(dashboard)/dashboard/agent-skills/page_client-reference-manifest.js +1 -1
  12. package/app/.next-cli-build/server/app/(dashboard)/dashboard/api-endpoints/page.js.nft.json +1 -1
  13. package/app/.next-cli-build/server/app/(dashboard)/dashboard/api-endpoints/page_client-reference-manifest.js +1 -1
  14. package/app/.next-cli-build/server/app/(dashboard)/dashboard/basic-chat/page.js.nft.json +1 -1
  15. package/app/.next-cli-build/server/app/(dashboard)/dashboard/basic-chat/page_client-reference-manifest.js +1 -1
  16. package/app/.next-cli-build/server/app/(dashboard)/dashboard/batch/page.js.nft.json +1 -1
  17. package/app/.next-cli-build/server/app/(dashboard)/dashboard/batch/page_client-reference-manifest.js +1 -1
  18. package/app/.next-cli-build/server/app/(dashboard)/dashboard/cache/page.js.nft.json +1 -1
  19. package/app/.next-cli-build/server/app/(dashboard)/dashboard/cache/page_client-reference-manifest.js +1 -1
  20. package/app/.next-cli-build/server/app/(dashboard)/dashboard/cli-tools/[toolId]/page.js.nft.json +1 -1
  21. package/app/.next-cli-build/server/app/(dashboard)/dashboard/cli-tools/[toolId]/page_client-reference-manifest.js +1 -1
  22. package/app/.next-cli-build/server/app/(dashboard)/dashboard/cli-tools/page.js +1 -1
  23. package/app/.next-cli-build/server/app/(dashboard)/dashboard/cli-tools/page.js.nft.json +1 -1
  24. package/app/.next-cli-build/server/app/(dashboard)/dashboard/cli-tools/page_client-reference-manifest.js +1 -1
  25. package/app/.next-cli-build/server/app/(dashboard)/dashboard/cloud-agents/page.js.nft.json +1 -1
  26. package/app/.next-cli-build/server/app/(dashboard)/dashboard/cloud-agents/page_client-reference-manifest.js +1 -1
  27. package/app/.next-cli-build/server/app/(dashboard)/dashboard/combos/page.js.nft.json +1 -1
  28. package/app/.next-cli-build/server/app/(dashboard)/dashboard/combos/page_client-reference-manifest.js +1 -1
  29. package/app/.next-cli-build/server/app/(dashboard)/dashboard/console-log/page.js.nft.json +1 -1
  30. package/app/.next-cli-build/server/app/(dashboard)/dashboard/console-log/page_client-reference-manifest.js +1 -1
  31. package/app/.next-cli-build/server/app/(dashboard)/dashboard/costs/page.js.nft.json +1 -1
  32. package/app/.next-cli-build/server/app/(dashboard)/dashboard/costs/page_client-reference-manifest.js +1 -1
  33. package/app/.next-cli-build/server/app/(dashboard)/dashboard/discovery/page.js.nft.json +1 -1
  34. package/app/.next-cli-build/server/app/(dashboard)/dashboard/discovery/page_client-reference-manifest.js +1 -1
  35. package/app/.next-cli-build/server/app/(dashboard)/dashboard/endpoint/page.js.nft.json +1 -1
  36. package/app/.next-cli-build/server/app/(dashboard)/dashboard/endpoint/page_client-reference-manifest.js +1 -1
  37. package/app/.next-cli-build/server/app/(dashboard)/dashboard/free-provider-rankings/page.js.nft.json +1 -1
  38. package/app/.next-cli-build/server/app/(dashboard)/dashboard/free-provider-rankings/page_client-reference-manifest.js +1 -1
  39. package/app/.next-cli-build/server/app/(dashboard)/dashboard/free-tiers/page.js.nft.json +1 -1
  40. package/app/.next-cli-build/server/app/(dashboard)/dashboard/free-tiers/page_client-reference-manifest.js +1 -1
  41. package/app/.next-cli-build/server/app/(dashboard)/dashboard/guardrails/page.js.nft.json +1 -1
  42. package/app/.next-cli-build/server/app/(dashboard)/dashboard/guardrails/page_client-reference-manifest.js +1 -1
  43. package/app/.next-cli-build/server/app/(dashboard)/dashboard/health/page.js.nft.json +1 -1
  44. package/app/.next-cli-build/server/app/(dashboard)/dashboard/health/page_client-reference-manifest.js +1 -1
  45. package/app/.next-cli-build/server/app/(dashboard)/dashboard/logs/page.js.nft.json +1 -1
  46. package/app/.next-cli-build/server/app/(dashboard)/dashboard/logs/page_client-reference-manifest.js +1 -1
  47. package/app/.next-cli-build/server/app/(dashboard)/dashboard/mcp/page.js.nft.json +1 -1
  48. package/app/.next-cli-build/server/app/(dashboard)/dashboard/mcp/page_client-reference-manifest.js +1 -1
  49. package/app/.next-cli-build/server/app/(dashboard)/dashboard/media-providers/[kind]/[id]/page.js.nft.json +1 -1
  50. package/app/.next-cli-build/server/app/(dashboard)/dashboard/media-providers/[kind]/[id]/page_client-reference-manifest.js +1 -1
  51. package/app/.next-cli-build/server/app/(dashboard)/dashboard/media-providers/[kind]/page.js.nft.json +1 -1
  52. package/app/.next-cli-build/server/app/(dashboard)/dashboard/media-providers/[kind]/page_client-reference-manifest.js +1 -1
  53. package/app/.next-cli-build/server/app/(dashboard)/dashboard/media-providers/combo/[id]/page.js.nft.json +1 -1
  54. package/app/.next-cli-build/server/app/(dashboard)/dashboard/media-providers/combo/[id]/page_client-reference-manifest.js +1 -1
  55. package/app/.next-cli-build/server/app/(dashboard)/dashboard/media-providers/web/page.js.nft.json +1 -1
  56. package/app/.next-cli-build/server/app/(dashboard)/dashboard/media-providers/web/page_client-reference-manifest.js +1 -1
  57. package/app/.next-cli-build/server/app/(dashboard)/dashboard/memory/page.js.nft.json +1 -1
  58. package/app/.next-cli-build/server/app/(dashboard)/dashboard/memory/page_client-reference-manifest.js +1 -1
  59. package/app/.next-cli-build/server/app/(dashboard)/dashboard/mitm/page.js.nft.json +1 -1
  60. package/app/.next-cli-build/server/app/(dashboard)/dashboard/mitm/page_client-reference-manifest.js +1 -1
  61. package/app/.next-cli-build/server/app/(dashboard)/dashboard/page.js.nft.json +1 -1
  62. package/app/.next-cli-build/server/app/(dashboard)/dashboard/page_client-reference-manifest.js +1 -1
  63. package/app/.next-cli-build/server/app/(dashboard)/dashboard/playground/page.js.nft.json +1 -1
  64. package/app/.next-cli-build/server/app/(dashboard)/dashboard/playground/page_client-reference-manifest.js +1 -1
  65. package/app/.next-cli-build/server/app/(dashboard)/dashboard/privacy/page.js.nft.json +1 -1
  66. package/app/.next-cli-build/server/app/(dashboard)/dashboard/privacy/page_client-reference-manifest.js +1 -1
  67. package/app/.next-cli-build/server/app/(dashboard)/dashboard/profile/page.js.nft.json +1 -1
  68. package/app/.next-cli-build/server/app/(dashboard)/dashboard/profile/page_client-reference-manifest.js +1 -1
  69. package/app/.next-cli-build/server/app/(dashboard)/dashboard/provider-stats/page.js.nft.json +1 -1
  70. package/app/.next-cli-build/server/app/(dashboard)/dashboard/provider-stats/page_client-reference-manifest.js +1 -1
  71. package/app/.next-cli-build/server/app/(dashboard)/dashboard/providers/[id]/page.js.nft.json +1 -1
  72. package/app/.next-cli-build/server/app/(dashboard)/dashboard/providers/[id]/page_client-reference-manifest.js +1 -1
  73. package/app/.next-cli-build/server/app/(dashboard)/dashboard/providers/new/page.js.nft.json +1 -1
  74. package/app/.next-cli-build/server/app/(dashboard)/dashboard/providers/new/page_client-reference-manifest.js +1 -1
  75. package/app/.next-cli-build/server/app/(dashboard)/dashboard/providers/page.js.nft.json +1 -1
  76. package/app/.next-cli-build/server/app/(dashboard)/dashboard/providers/page_client-reference-manifest.js +1 -1
  77. package/app/.next-cli-build/server/app/(dashboard)/dashboard/proxy-pools/page.js.nft.json +1 -1
  78. package/app/.next-cli-build/server/app/(dashboard)/dashboard/proxy-pools/page_client-reference-manifest.js +1 -1
  79. package/app/.next-cli-build/server/app/(dashboard)/dashboard/pxpipe/page.js.nft.json +1 -1
  80. package/app/.next-cli-build/server/app/(dashboard)/dashboard/pxpipe/page_client-reference-manifest.js +1 -1
  81. package/app/.next-cli-build/server/app/(dashboard)/dashboard/quota/page.js.nft.json +1 -1
  82. package/app/.next-cli-build/server/app/(dashboard)/dashboard/quota/page_client-reference-manifest.js +1 -1
  83. package/app/.next-cli-build/server/app/(dashboard)/dashboard/runtime/page.js.nft.json +1 -1
  84. package/app/.next-cli-build/server/app/(dashboard)/dashboard/runtime/page_client-reference-manifest.js +1 -1
  85. package/app/.next-cli-build/server/app/(dashboard)/dashboard/settings/feature-flags/page.js.nft.json +1 -1
  86. package/app/.next-cli-build/server/app/(dashboard)/dashboard/settings/feature-flags/page_client-reference-manifest.js +1 -1
  87. package/app/.next-cli-build/server/app/(dashboard)/dashboard/settings/pricing/page.js.nft.json +1 -1
  88. package/app/.next-cli-build/server/app/(dashboard)/dashboard/settings/pricing/page_client-reference-manifest.js +1 -1
  89. package/app/.next-cli-build/server/app/(dashboard)/dashboard/skill-discovery/page.js.nft.json +1 -1
  90. package/app/.next-cli-build/server/app/(dashboard)/dashboard/skill-discovery/page_client-reference-manifest.js +1 -1
  91. package/app/.next-cli-build/server/app/(dashboard)/dashboard/skills/page.js.nft.json +1 -1
  92. package/app/.next-cli-build/server/app/(dashboard)/dashboard/skills/page_client-reference-manifest.js +1 -1
  93. package/app/.next-cli-build/server/app/(dashboard)/dashboard/token-saver/page.js.nft.json +1 -1
  94. package/app/.next-cli-build/server/app/(dashboard)/dashboard/token-saver/page_client-reference-manifest.js +1 -1
  95. package/app/.next-cli-build/server/app/(dashboard)/dashboard/translator/page.js.nft.json +1 -1
  96. package/app/.next-cli-build/server/app/(dashboard)/dashboard/translator/page_client-reference-manifest.js +1 -1
  97. package/app/.next-cli-build/server/app/(dashboard)/dashboard/usage/page.js.nft.json +1 -1
  98. package/app/.next-cli-build/server/app/(dashboard)/dashboard/usage/page_client-reference-manifest.js +1 -1
  99. package/app/.next-cli-build/server/app/(dashboard)/dashboard/webhooks/page.js.nft.json +1 -1
  100. package/app/.next-cli-build/server/app/(dashboard)/dashboard/webhooks/page_client-reference-manifest.js +1 -1
  101. package/app/.next-cli-build/server/app/.well-known/agent.json/route.js.nft.json +1 -1
  102. package/app/.next-cli-build/server/app/_global-error/page.js.nft.json +1 -1
  103. package/app/.next-cli-build/server/app/_global-error/page_client-reference-manifest.js +1 -1
  104. package/app/.next-cli-build/server/app/_global-error.html +1 -1
  105. package/app/.next-cli-build/server/app/_global-error.rsc +1 -1
  106. package/app/.next-cli-build/server/app/_global-error.segments/_full.segment.rsc +1 -1
  107. package/app/.next-cli-build/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  108. package/app/.next-cli-build/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  109. package/app/.next-cli-build/server/app/_not-found/page.js.nft.json +1 -1
  110. package/app/.next-cli-build/server/app/_not-found/page_client-reference-manifest.js +1 -1
  111. package/app/.next-cli-build/server/app/_not-found.html +1 -1
  112. package/app/.next-cli-build/server/app/_not-found.rsc +5 -5
  113. package/app/.next-cli-build/server/app/_not-found.segments/_full.segment.rsc +5 -5
  114. package/app/.next-cli-build/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +5 -5
  115. package/app/.next-cli-build/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  116. package/app/.next-cli-build/server/app/api/a2a/route.js.nft.json +1 -1
  117. package/app/.next-cli-build/server/app/api/a2a/status/route.js.nft.json +1 -1
  118. package/app/.next-cli-build/server/app/api/agents/[id]/actions/route.js +1 -1
  119. package/app/.next-cli-build/server/app/api/agents/[id]/actions/route.js.nft.json +1 -1
  120. package/app/.next-cli-build/server/app/api/agents/route.js +1 -1
  121. package/app/.next-cli-build/server/app/api/agents/route.js.nft.json +1 -1
  122. package/app/.next-cli-build/server/app/api/auth/login/route.js.nft.json +1 -1
  123. package/app/.next-cli-build/server/app/api/auth/logout/route.js.nft.json +1 -1
  124. package/app/.next-cli-build/server/app/api/auth/oidc/callback/route.js.nft.json +1 -1
  125. package/app/.next-cli-build/server/app/api/auth/oidc/start/route.js.nft.json +1 -1
  126. package/app/.next-cli-build/server/app/api/auth/oidc/test/route.js.nft.json +1 -1
  127. package/app/.next-cli-build/server/app/api/auth/reset-password/route.js.nft.json +1 -1
  128. package/app/.next-cli-build/server/app/api/auth/status/route.js.nft.json +1 -1
  129. package/app/.next-cli-build/server/app/api/batch/[id]/route.js.nft.json +1 -1
  130. package/app/.next-cli-build/server/app/api/batch/route.js.nft.json +1 -1
  131. package/app/.next-cli-build/server/app/api/batches/[id]/cancel/route.js.nft.json +1 -1
  132. package/app/.next-cli-build/server/app/api/batches/[id]/errors/route.js.nft.json +1 -1
  133. package/app/.next-cli-build/server/app/api/batches/[id]/results/route.js.nft.json +1 -1
  134. package/app/.next-cli-build/server/app/api/batches/[id]/retry/route.js.nft.json +1 -1
  135. package/app/.next-cli-build/server/app/api/batches/[id]/route.js.nft.json +1 -1
  136. package/app/.next-cli-build/server/app/api/batches/route.js.nft.json +1 -1
  137. package/app/.next-cli-build/server/app/api/cache/clear/route.js.nft.json +1 -1
  138. package/app/.next-cli-build/server/app/api/cache/stats/route.js.nft.json +1 -1
  139. package/app/.next-cli-build/server/app/api/catalog/opencode/route.js.nft.json +1 -1
  140. package/app/.next-cli-build/server/app/api/cli-tools/all-statuses/route.js +5 -5
  141. package/app/.next-cli-build/server/app/api/cli-tools/all-statuses/route.js.nft.json +1 -1
  142. package/app/.next-cli-build/server/app/api/cli-tools/antigravity-mitm/alias/route.js +2 -2
  143. package/app/.next-cli-build/server/app/api/cli-tools/antigravity-mitm/alias/route.js.nft.json +1 -1
  144. package/app/.next-cli-build/server/app/api/cli-tools/antigravity-mitm/route.js.nft.json +1 -1
  145. package/app/.next-cli-build/server/app/api/cli-tools/claude-settings/route.js +1 -1
  146. package/app/.next-cli-build/server/app/api/cli-tools/claude-settings/route.js.nft.json +1 -1
  147. package/app/.next-cli-build/server/app/api/cli-tools/cline-settings/route.js +2 -2
  148. package/app/.next-cli-build/server/app/api/cli-tools/cline-settings/route.js.nft.json +1 -1
  149. package/app/.next-cli-build/server/app/api/cli-tools/codex-settings/route.js +1 -1
  150. package/app/.next-cli-build/server/app/api/cli-tools/codex-settings/route.js.nft.json +1 -1
  151. package/app/.next-cli-build/server/app/api/cli-tools/copilot-settings/route.js +2 -2
  152. package/app/.next-cli-build/server/app/api/cli-tools/copilot-settings/route.js.nft.json +1 -1
  153. package/app/.next-cli-build/server/app/api/cli-tools/cowork-mcp-registry/route.js +2 -2
  154. package/app/.next-cli-build/server/app/api/cli-tools/cowork-mcp-registry/route.js.nft.json +1 -1
  155. package/app/.next-cli-build/server/app/api/cli-tools/cowork-mcp-tools/route.js +1 -1
  156. package/app/.next-cli-build/server/app/api/cli-tools/cowork-mcp-tools/route.js.nft.json +1 -1
  157. package/app/.next-cli-build/server/app/api/cli-tools/cowork-settings/route.js +1 -1
  158. package/app/.next-cli-build/server/app/api/cli-tools/cowork-settings/route.js.nft.json +1 -1
  159. package/app/.next-cli-build/server/app/api/cli-tools/deepseek-tui-settings/route.js +3 -3
  160. package/app/.next-cli-build/server/app/api/cli-tools/deepseek-tui-settings/route.js.nft.json +1 -1
  161. package/app/.next-cli-build/server/app/api/cli-tools/devin-settings/route.js +1 -1
  162. package/app/.next-cli-build/server/app/api/cli-tools/devin-settings/route.js.nft.json +1 -1
  163. package/app/.next-cli-build/server/app/api/cli-tools/droid-settings/route.js +1 -1
  164. package/app/.next-cli-build/server/app/api/cli-tools/droid-settings/route.js.nft.json +1 -1
  165. package/app/.next-cli-build/server/app/api/cli-tools/grok-build-settings/route.js +2 -2
  166. package/app/.next-cli-build/server/app/api/cli-tools/grok-build-settings/route.js.nft.json +1 -1
  167. package/app/.next-cli-build/server/app/api/cli-tools/hermes-settings/route.js +2 -2
  168. package/app/.next-cli-build/server/app/api/cli-tools/hermes-settings/route.js.nft.json +1 -1
  169. package/app/.next-cli-build/server/app/api/cli-tools/jcode-settings/route.js +2 -2
  170. package/app/.next-cli-build/server/app/api/cli-tools/jcode-settings/route.js.nft.json +1 -1
  171. package/app/.next-cli-build/server/app/api/cli-tools/kilo-settings/route.js +2 -2
  172. package/app/.next-cli-build/server/app/api/cli-tools/kilo-settings/route.js.nft.json +1 -1
  173. package/app/.next-cli-build/server/app/api/cli-tools/oh-my-pi-settings/route.js +2 -2
  174. package/app/.next-cli-build/server/app/api/cli-tools/oh-my-pi-settings/route.js.nft.json +1 -1
  175. package/app/.next-cli-build/server/app/api/cli-tools/openclaw-settings/route.js +2 -2
  176. package/app/.next-cli-build/server/app/api/cli-tools/openclaw-settings/route.js.nft.json +1 -1
  177. package/app/.next-cli-build/server/app/api/cli-tools/opencode-settings/route.js +2 -2
  178. package/app/.next-cli-build/server/app/api/cli-tools/opencode-settings/route.js.nft.json +1 -1
  179. package/app/.next-cli-build/server/app/api/cli-tools/subagents/route.js +1 -1
  180. package/app/.next-cli-build/server/app/api/cli-tools/subagents/route.js.nft.json +1 -1
  181. package/app/.next-cli-build/server/app/api/cloud-agents/status/route.js +1 -1
  182. package/app/.next-cli-build/server/app/api/cloud-agents/status/route.js.nft.json +1 -1
  183. package/app/.next-cli-build/server/app/api/combos/[id]/route.js.nft.json +1 -1
  184. package/app/.next-cli-build/server/app/api/combos/route.js.nft.json +1 -1
  185. package/app/.next-cli-build/server/app/api/dashboard/chat/completions/route.js.nft.json +1 -1
  186. package/app/.next-cli-build/server/app/api/discovery/endpoints/route.js +1 -1
  187. package/app/.next-cli-build/server/app/api/discovery/endpoints/route.js.nft.json +1 -1
  188. package/app/.next-cli-build/server/app/api/discovery/route.js +1 -1
  189. package/app/.next-cli-build/server/app/api/discovery/route.js.nft.json +1 -1
  190. package/app/.next-cli-build/server/app/api/discovery/skills/route.js +1 -1
  191. package/app/.next-cli-build/server/app/api/discovery/skills/route.js.nft.json +1 -1
  192. package/app/.next-cli-build/server/app/api/events/route.js.nft.json +1 -1
  193. package/app/.next-cli-build/server/app/api/headroom/extras/route.js.nft.json +1 -1
  194. package/app/.next-cli-build/server/app/api/headroom/proxy/[...path]/route.js.nft.json +1 -1
  195. package/app/.next-cli-build/server/app/api/headroom/restart/route.js.nft.json +1 -1
  196. package/app/.next-cli-build/server/app/api/headroom/start/route.js.nft.json +1 -1
  197. package/app/.next-cli-build/server/app/api/headroom/status/route.js.nft.json +1 -1
  198. package/app/.next-cli-build/server/app/api/headroom/stop/route.js.nft.json +1 -1
  199. package/app/.next-cli-build/server/app/api/health/route.js.nft.json +1 -1
  200. package/app/.next-cli-build/server/app/api/hermes/autonomy/route.js.nft.json +1 -1
  201. package/app/.next-cli-build/server/app/api/init/route.js.nft.json +1 -1
  202. package/app/.next-cli-build/server/app/api/keys/[id]/route.js.nft.json +1 -1
  203. package/app/.next-cli-build/server/app/api/keys/route.js.nft.json +1 -1
  204. package/app/.next-cli-build/server/app/api/locale/route.js.nft.json +1 -1
  205. package/app/.next-cli-build/server/app/api/mcp/[plugin]/message/route.js.nft.json +1 -1
  206. package/app/.next-cli-build/server/app/api/mcp/[plugin]/sse/route.js.nft.json +1 -1
  207. package/app/.next-cli-build/server/app/api/mcp/route.js +1 -1
  208. package/app/.next-cli-build/server/app/api/mcp/route.js.nft.json +1 -1
  209. package/app/.next-cli-build/server/app/api/mcp/status/route.js.nft.json +1 -1
  210. package/app/.next-cli-build/server/app/api/media-providers/tts/deepgram/voices/route.js.nft.json +1 -1
  211. package/app/.next-cli-build/server/app/api/media-providers/tts/elevenlabs/voices/route.js.nft.json +1 -1
  212. package/app/.next-cli-build/server/app/api/media-providers/tts/inworld/voices/route.js.nft.json +1 -1
  213. package/app/.next-cli-build/server/app/api/media-providers/tts/minimax/voices/route.js.nft.json +1 -1
  214. package/app/.next-cli-build/server/app/api/media-providers/tts/voices/route.js.nft.json +1 -1
  215. package/app/.next-cli-build/server/app/api/memory/[id]/route.js.nft.json +1 -1
  216. package/app/.next-cli-build/server/app/api/memory/health/route.js.nft.json +1 -1
  217. package/app/.next-cli-build/server/app/api/memory/reindex/route.js.nft.json +1 -1
  218. package/app/.next-cli-build/server/app/api/memory/route.js.nft.json +1 -1
  219. package/app/.next-cli-build/server/app/api/memory/search/route.js.nft.json +1 -1
  220. package/app/.next-cli-build/server/app/api/metrics/route.js.nft.json +1 -1
  221. package/app/.next-cli-build/server/app/api/models/alias/route.js.nft.json +1 -1
  222. package/app/.next-cli-build/server/app/api/models/availability/route.js.nft.json +1 -1
  223. package/app/.next-cli-build/server/app/api/models/custom/route.js.nft.json +1 -1
  224. package/app/.next-cli-build/server/app/api/models/disabled/route.js.nft.json +1 -1
  225. package/app/.next-cli-build/server/app/api/models/route.js.nft.json +1 -1
  226. package/app/.next-cli-build/server/app/api/models/test/route.js.nft.json +1 -1
  227. package/app/.next-cli-build/server/app/api/oauth/[provider]/[action]/route.js +1 -1
  228. package/app/.next-cli-build/server/app/api/oauth/[provider]/[action]/route.js.nft.json +1 -1
  229. package/app/.next-cli-build/server/app/api/oauth/codex/bulk-import/route.js +1 -1
  230. package/app/.next-cli-build/server/app/api/oauth/codex/bulk-import/route.js.nft.json +1 -1
  231. package/app/.next-cli-build/server/app/api/oauth/codex/import-token/route.js +1 -1
  232. package/app/.next-cli-build/server/app/api/oauth/codex/import-token/route.js.nft.json +1 -1
  233. package/app/.next-cli-build/server/app/api/oauth/cursor/auto-import/route.js.nft.json +1 -1
  234. package/app/.next-cli-build/server/app/api/oauth/cursor/import/route.js.nft.json +1 -1
  235. package/app/.next-cli-build/server/app/api/oauth/gitlab/pat/route.js.nft.json +1 -1
  236. package/app/.next-cli-build/server/app/api/oauth/iflow/cookie/route.js.nft.json +1 -1
  237. package/app/.next-cli-build/server/app/api/oauth/kiro/api-key/route.js.nft.json +1 -1
  238. package/app/.next-cli-build/server/app/api/oauth/kiro/auto-import/route.js.nft.json +1 -1
  239. package/app/.next-cli-build/server/app/api/oauth/kiro/import/route.js.nft.json +1 -1
  240. package/app/.next-cli-build/server/app/api/oauth/kiro/import-cli-proxy/route.js.nft.json +1 -1
  241. package/app/.next-cli-build/server/app/api/oauth/kiro/social-authorize/route.js.nft.json +1 -1
  242. package/app/.next-cli-build/server/app/api/oauth/kiro/social-exchange/route.js.nft.json +1 -1
  243. package/app/.next-cli-build/server/app/api/pricing/route.js.nft.json +1 -1
  244. package/app/.next-cli-build/server/app/api/provider-nodes/[id]/route.js.nft.json +1 -1
  245. package/app/.next-cli-build/server/app/api/provider-nodes/route.js.nft.json +1 -1
  246. package/app/.next-cli-build/server/app/api/provider-nodes/validate/route.js.nft.json +1 -1
  247. package/app/.next-cli-build/server/app/api/providers/[id]/export/route.js.nft.json +1 -1
  248. package/app/.next-cli-build/server/app/api/providers/[id]/models/route.js.nft.json +1 -1
  249. package/app/.next-cli-build/server/app/api/providers/[id]/onboard/route.js +1 -1
  250. package/app/.next-cli-build/server/app/api/providers/[id]/onboard/route.js.nft.json +1 -1
  251. package/app/.next-cli-build/server/app/api/providers/[id]/route.js.nft.json +1 -1
  252. package/app/.next-cli-build/server/app/api/providers/[id]/test/route.js.nft.json +1 -1
  253. package/app/.next-cli-build/server/app/api/providers/[id]/test-models/route.js.nft.json +1 -1
  254. package/app/.next-cli-build/server/app/api/providers/client/route.js +1 -1
  255. package/app/.next-cli-build/server/app/api/providers/client/route.js.nft.json +1 -1
  256. package/app/.next-cli-build/server/app/api/providers/kilo/free-models/route.js.nft.json +1 -1
  257. package/app/.next-cli-build/server/app/api/providers/route.js.nft.json +1 -1
  258. package/app/.next-cli-build/server/app/api/providers/suggested-models/route.js.nft.json +1 -1
  259. package/app/.next-cli-build/server/app/api/providers/test-batch/route.js.nft.json +1 -1
  260. package/app/.next-cli-build/server/app/api/providers/validate/route.js.nft.json +1 -1
  261. package/app/.next-cli-build/server/app/api/proxy-pools/[id]/route.js.nft.json +1 -1
  262. package/app/.next-cli-build/server/app/api/proxy-pools/[id]/test/route.js.nft.json +1 -1
  263. package/app/.next-cli-build/server/app/api/proxy-pools/cloudflare-deploy/route.js.nft.json +1 -1
  264. package/app/.next-cli-build/server/app/api/proxy-pools/deno-deploy/route.js.nft.json +1 -1
  265. package/app/.next-cli-build/server/app/api/proxy-pools/route.js.nft.json +1 -1
  266. package/app/.next-cli-build/server/app/api/proxy-pools/vercel-deploy/route.js +1 -1
  267. package/app/.next-cli-build/server/app/api/proxy-pools/vercel-deploy/route.js.nft.json +1 -1
  268. package/app/.next-cli-build/server/app/api/pxpipe/health/route.js.nft.json +1 -1
  269. package/app/.next-cli-build/server/app/api/pxpipe/install/route.js.nft.json +1 -1
  270. package/app/.next-cli-build/server/app/api/pxpipe/logs/route.js.nft.json +1 -1
  271. package/app/.next-cli-build/server/app/api/pxpipe/restart/route.js.nft.json +1 -1
  272. package/app/.next-cli-build/server/app/api/pxpipe/start/route.js.nft.json +1 -1
  273. package/app/.next-cli-build/server/app/api/pxpipe/stats/route.js.nft.json +1 -1
  274. package/app/.next-cli-build/server/app/api/pxpipe/status/route.js.nft.json +1 -1
  275. package/app/.next-cli-build/server/app/api/pxpipe/stop/route.js.nft.json +1 -1
  276. package/app/.next-cli-build/server/app/api/saver/stats/route.js.nft.json +1 -1
  277. package/app/.next-cli-build/server/app/api/settings/database/route.js.nft.json +1 -1
  278. package/app/.next-cli-build/server/app/api/settings/proxy-test/route.js.nft.json +1 -1
  279. package/app/.next-cli-build/server/app/api/settings/require-login/route.js.nft.json +1 -1
  280. package/app/.next-cli-build/server/app/api/settings/route.js.nft.json +1 -1
  281. package/app/.next-cli-build/server/app/api/shutdown/route.js.nft.json +1 -1
  282. package/app/.next-cli-build/server/app/api/skill-discovery/[id]/install/route.js.nft.json +1 -1
  283. package/app/.next-cli-build/server/app/api/skill-discovery/[id]/route.js.nft.json +1 -1
  284. package/app/.next-cli-build/server/app/api/skill-discovery/[id]/uninstall/route.js.nft.json +1 -1
  285. package/app/.next-cli-build/server/app/api/skill-discovery/route.js.nft.json +1 -1
  286. package/app/.next-cli-build/server/app/api/skill-discovery/sync/route.js.nft.json +1 -1
  287. package/app/.next-cli-build/server/app/api/tags/route.js.nft.json +1 -1
  288. package/app/.next-cli-build/server/app/api/translator/console-logs/route.js.nft.json +1 -1
  289. package/app/.next-cli-build/server/app/api/translator/console-logs/stream/route.js.nft.json +1 -1
  290. package/app/.next-cli-build/server/app/api/translator/load/route.js.nft.json +1 -1
  291. package/app/.next-cli-build/server/app/api/translator/save/route.js.nft.json +1 -1
  292. package/app/.next-cli-build/server/app/api/translator/send/route.js +1 -1
  293. package/app/.next-cli-build/server/app/api/translator/send/route.js.nft.json +1 -1
  294. package/app/.next-cli-build/server/app/api/translator/translate/route.js +1 -1
  295. package/app/.next-cli-build/server/app/api/translator/translate/route.js.nft.json +1 -1
  296. package/app/.next-cli-build/server/app/api/tunnel/disable/route.js.nft.json +1 -1
  297. package/app/.next-cli-build/server/app/api/tunnel/enable/route.js.nft.json +1 -1
  298. package/app/.next-cli-build/server/app/api/tunnel/status/route.js.nft.json +1 -1
  299. package/app/.next-cli-build/server/app/api/tunnel/tailscale-check/route.js.nft.json +1 -1
  300. package/app/.next-cli-build/server/app/api/tunnel/tailscale-disable/route.js.nft.json +1 -1
  301. package/app/.next-cli-build/server/app/api/tunnel/tailscale-enable/route.js.nft.json +1 -1
  302. package/app/.next-cli-build/server/app/api/tunnel/tailscale-install/route.js +2 -2
  303. package/app/.next-cli-build/server/app/api/tunnel/tailscale-install/route.js.nft.json +1 -1
  304. package/app/.next-cli-build/server/app/api/usage/[connectionId]/codex-reset-credits/route.js +1 -1
  305. package/app/.next-cli-build/server/app/api/usage/[connectionId]/codex-reset-credits/route.js.nft.json +1 -1
  306. package/app/.next-cli-build/server/app/api/usage/[connectionId]/route.js +1 -1
  307. package/app/.next-cli-build/server/app/api/usage/[connectionId]/route.js.nft.json +1 -1
  308. package/app/.next-cli-build/server/app/api/usage/chart/route.js.nft.json +1 -1
  309. package/app/.next-cli-build/server/app/api/usage/history/route.js.nft.json +1 -1
  310. package/app/.next-cli-build/server/app/api/usage/local-snapshot/route.js +1 -1
  311. package/app/.next-cli-build/server/app/api/usage/local-snapshot/route.js.nft.json +1 -1
  312. package/app/.next-cli-build/server/app/api/usage/logs/route.js.nft.json +1 -1
  313. package/app/.next-cli-build/server/app/api/usage/providers/route.js.nft.json +1 -1
  314. package/app/.next-cli-build/server/app/api/usage/request-details/route.js.nft.json +1 -1
  315. package/app/.next-cli-build/server/app/api/usage/request-logs/route.js.nft.json +1 -1
  316. package/app/.next-cli-build/server/app/api/usage/stats/route.js.nft.json +1 -1
  317. package/app/.next-cli-build/server/app/api/usage/stream/route.js.nft.json +1 -1
  318. package/app/.next-cli-build/server/app/api/v1/api/chat/route.js.nft.json +1 -1
  319. package/app/.next-cli-build/server/app/api/v1/audio/speech/route.js.nft.json +1 -1
  320. package/app/.next-cli-build/server/app/api/v1/audio/transcriptions/route.js.nft.json +1 -1
  321. package/app/.next-cli-build/server/app/api/v1/audio/voices/route.js.nft.json +1 -1
  322. package/app/.next-cli-build/server/app/api/v1/chat/completions/route.js.nft.json +1 -1
  323. package/app/.next-cli-build/server/app/api/v1/embeddings/route.js +1 -1
  324. package/app/.next-cli-build/server/app/api/v1/embeddings/route.js.nft.json +1 -1
  325. package/app/.next-cli-build/server/app/api/v1/images/generations/route.js +1 -1
  326. package/app/.next-cli-build/server/app/api/v1/images/generations/route.js.nft.json +1 -1
  327. package/app/.next-cli-build/server/app/api/v1/messages/count_tokens/route.js.nft.json +1 -1
  328. package/app/.next-cli-build/server/app/api/v1/messages/route.js.nft.json +1 -1
  329. package/app/.next-cli-build/server/app/api/v1/models/[kind]/route.js.nft.json +1 -1
  330. package/app/.next-cli-build/server/app/api/v1/models/info/route.js.nft.json +1 -1
  331. package/app/.next-cli-build/server/app/api/v1/models/route.js.nft.json +1 -1
  332. package/app/.next-cli-build/server/app/api/v1/responses/compact/route.js.nft.json +1 -1
  333. package/app/.next-cli-build/server/app/api/v1/responses/route.js.nft.json +1 -1
  334. package/app/.next-cli-build/server/app/api/v1/route.js.nft.json +1 -1
  335. package/app/.next-cli-build/server/app/api/v1/search/route.js +1 -1
  336. package/app/.next-cli-build/server/app/api/v1/search/route.js.nft.json +1 -1
  337. package/app/.next-cli-build/server/app/api/v1/videos/[id]/route.js.nft.json +1 -1
  338. package/app/.next-cli-build/server/app/api/v1/videos/edits/route.js.nft.json +1 -1
  339. package/app/.next-cli-build/server/app/api/v1/videos/extensions/route.js.nft.json +1 -1
  340. package/app/.next-cli-build/server/app/api/v1/videos/generations/route.js.nft.json +1 -1
  341. package/app/.next-cli-build/server/app/api/v1/web/fetch/route.js +1 -1
  342. package/app/.next-cli-build/server/app/api/v1/web/fetch/route.js.nft.json +1 -1
  343. package/app/.next-cli-build/server/app/api/v1beta/models/[...path]/route.js.nft.json +1 -1
  344. package/app/.next-cli-build/server/app/api/v1beta/models/route.js.nft.json +1 -1
  345. package/app/.next-cli-build/server/app/api/version/route.js +1 -1
  346. package/app/.next-cli-build/server/app/api/version/route.js.nft.json +1 -1
  347. package/app/.next-cli-build/server/app/api/version/shutdown/route.js.nft.json +1 -1
  348. package/app/.next-cli-build/server/app/api/version/update/route.js.nft.json +1 -1
  349. package/app/.next-cli-build/server/app/api/webhooks/[id]/route.js.nft.json +1 -1
  350. package/app/.next-cli-build/server/app/api/webhooks/events/route.js.nft.json +1 -1
  351. package/app/.next-cli-build/server/app/api/webhooks/route.js.nft.json +1 -1
  352. package/app/.next-cli-build/server/app/callback/page.js.nft.json +1 -1
  353. package/app/.next-cli-build/server/app/callback/page_client-reference-manifest.js +1 -1
  354. package/app/.next-cli-build/server/app/callback.html +1 -1
  355. package/app/.next-cli-build/server/app/callback.rsc +5 -5
  356. package/app/.next-cli-build/server/app/callback.segments/_full.segment.rsc +5 -5
  357. package/app/.next-cli-build/server/app/callback.segments/_tree.segment.rsc +2 -2
  358. package/app/.next-cli-build/server/app/callback.segments/callback/__PAGE__.segment.rsc +5 -5
  359. package/app/.next-cli-build/server/app/dashboard/a2a.html +1 -1
  360. package/app/.next-cli-build/server/app/dashboard/a2a.rsc +7 -7
  361. package/app/.next-cli-build/server/app/dashboard/a2a.segments/!KGRhc2hib2FyZCk/dashboard/a2a/__PAGE__.segment.rsc +7 -7
  362. package/app/.next-cli-build/server/app/dashboard/a2a.segments/_full.segment.rsc +7 -7
  363. package/app/.next-cli-build/server/app/dashboard/a2a.segments/_tree.segment.rsc +2 -2
  364. package/app/.next-cli-build/server/app/dashboard/activity.html +1 -1
  365. package/app/.next-cli-build/server/app/dashboard/activity.rsc +7 -7
  366. package/app/.next-cli-build/server/app/dashboard/activity.segments/!KGRhc2hib2FyZCk/dashboard/activity/__PAGE__.segment.rsc +7 -7
  367. package/app/.next-cli-build/server/app/dashboard/activity.segments/_full.segment.rsc +7 -7
  368. package/app/.next-cli-build/server/app/dashboard/activity.segments/_tree.segment.rsc +2 -2
  369. package/app/.next-cli-build/server/app/dashboard/agent-skills.html +1 -1
  370. package/app/.next-cli-build/server/app/dashboard/agent-skills.rsc +7 -7
  371. package/app/.next-cli-build/server/app/dashboard/agent-skills.segments/!KGRhc2hib2FyZCk/dashboard/agent-skills/__PAGE__.segment.rsc +7 -7
  372. package/app/.next-cli-build/server/app/dashboard/agent-skills.segments/_full.segment.rsc +7 -7
  373. package/app/.next-cli-build/server/app/dashboard/agent-skills.segments/_tree.segment.rsc +2 -2
  374. package/app/.next-cli-build/server/app/dashboard/api-endpoints.html +1 -1
  375. package/app/.next-cli-build/server/app/dashboard/api-endpoints.rsc +7 -7
  376. package/app/.next-cli-build/server/app/dashboard/api-endpoints.segments/!KGRhc2hib2FyZCk/dashboard/api-endpoints/__PAGE__.segment.rsc +7 -7
  377. package/app/.next-cli-build/server/app/dashboard/api-endpoints.segments/_full.segment.rsc +7 -7
  378. package/app/.next-cli-build/server/app/dashboard/api-endpoints.segments/_tree.segment.rsc +2 -2
  379. package/app/.next-cli-build/server/app/dashboard/basic-chat.html +1 -1
  380. package/app/.next-cli-build/server/app/dashboard/basic-chat.rsc +7 -7
  381. package/app/.next-cli-build/server/app/dashboard/basic-chat.segments/!KGRhc2hib2FyZCk/dashboard/basic-chat/__PAGE__.segment.rsc +7 -7
  382. package/app/.next-cli-build/server/app/dashboard/basic-chat.segments/_full.segment.rsc +7 -7
  383. package/app/.next-cli-build/server/app/dashboard/basic-chat.segments/_tree.segment.rsc +2 -2
  384. package/app/.next-cli-build/server/app/dashboard/batch.html +1 -1
  385. package/app/.next-cli-build/server/app/dashboard/batch.rsc +7 -7
  386. package/app/.next-cli-build/server/app/dashboard/batch.segments/!KGRhc2hib2FyZCk/dashboard/batch/__PAGE__.segment.rsc +7 -7
  387. package/app/.next-cli-build/server/app/dashboard/batch.segments/_full.segment.rsc +7 -7
  388. package/app/.next-cli-build/server/app/dashboard/batch.segments/_tree.segment.rsc +2 -2
  389. package/app/.next-cli-build/server/app/dashboard/cache.html +1 -1
  390. package/app/.next-cli-build/server/app/dashboard/cache.rsc +7 -7
  391. package/app/.next-cli-build/server/app/dashboard/cache.segments/!KGRhc2hib2FyZCk/dashboard/cache/__PAGE__.segment.rsc +7 -7
  392. package/app/.next-cli-build/server/app/dashboard/cache.segments/_full.segment.rsc +7 -7
  393. package/app/.next-cli-build/server/app/dashboard/cache.segments/_tree.segment.rsc +2 -2
  394. package/app/.next-cli-build/server/app/dashboard/cli-tools.html +1 -1
  395. package/app/.next-cli-build/server/app/dashboard/cli-tools.rsc +7 -7
  396. package/app/.next-cli-build/server/app/dashboard/cli-tools.segments/!KGRhc2hib2FyZCk/dashboard/cli-tools/__PAGE__.segment.rsc +7 -7
  397. package/app/.next-cli-build/server/app/dashboard/cli-tools.segments/_full.segment.rsc +7 -7
  398. package/app/.next-cli-build/server/app/dashboard/cli-tools.segments/_tree.segment.rsc +2 -2
  399. package/app/.next-cli-build/server/app/dashboard/cloud-agents.html +1 -1
  400. package/app/.next-cli-build/server/app/dashboard/cloud-agents.rsc +7 -7
  401. package/app/.next-cli-build/server/app/dashboard/cloud-agents.segments/!KGRhc2hib2FyZCk/dashboard/cloud-agents/__PAGE__.segment.rsc +7 -7
  402. package/app/.next-cli-build/server/app/dashboard/cloud-agents.segments/_full.segment.rsc +7 -7
  403. package/app/.next-cli-build/server/app/dashboard/cloud-agents.segments/_tree.segment.rsc +2 -2
  404. package/app/.next-cli-build/server/app/dashboard/combos.html +1 -1
  405. package/app/.next-cli-build/server/app/dashboard/combos.rsc +7 -7
  406. package/app/.next-cli-build/server/app/dashboard/combos.segments/!KGRhc2hib2FyZCk/dashboard/combos/__PAGE__.segment.rsc +7 -7
  407. package/app/.next-cli-build/server/app/dashboard/combos.segments/_full.segment.rsc +7 -7
  408. package/app/.next-cli-build/server/app/dashboard/combos.segments/_tree.segment.rsc +2 -2
  409. package/app/.next-cli-build/server/app/dashboard/costs.html +1 -1
  410. package/app/.next-cli-build/server/app/dashboard/costs.rsc +7 -7
  411. package/app/.next-cli-build/server/app/dashboard/costs.segments/!KGRhc2hib2FyZCk/dashboard/costs/__PAGE__.segment.rsc +7 -7
  412. package/app/.next-cli-build/server/app/dashboard/costs.segments/_full.segment.rsc +7 -7
  413. package/app/.next-cli-build/server/app/dashboard/costs.segments/_tree.segment.rsc +2 -2
  414. package/app/.next-cli-build/server/app/dashboard/discovery.html +1 -1
  415. package/app/.next-cli-build/server/app/dashboard/discovery.rsc +7 -7
  416. package/app/.next-cli-build/server/app/dashboard/discovery.segments/!KGRhc2hib2FyZCk/dashboard/discovery/__PAGE__.segment.rsc +7 -7
  417. package/app/.next-cli-build/server/app/dashboard/discovery.segments/_full.segment.rsc +7 -7
  418. package/app/.next-cli-build/server/app/dashboard/discovery.segments/_tree.segment.rsc +2 -2
  419. package/app/.next-cli-build/server/app/dashboard/endpoint.html +1 -1
  420. package/app/.next-cli-build/server/app/dashboard/endpoint.rsc +7 -7
  421. package/app/.next-cli-build/server/app/dashboard/endpoint.segments/!KGRhc2hib2FyZCk/dashboard/endpoint/__PAGE__.segment.rsc +7 -7
  422. package/app/.next-cli-build/server/app/dashboard/endpoint.segments/_full.segment.rsc +7 -7
  423. package/app/.next-cli-build/server/app/dashboard/endpoint.segments/_tree.segment.rsc +2 -2
  424. package/app/.next-cli-build/server/app/dashboard/free-provider-rankings.html +1 -1
  425. package/app/.next-cli-build/server/app/dashboard/free-provider-rankings.rsc +7 -7
  426. package/app/.next-cli-build/server/app/dashboard/free-provider-rankings.segments/!KGRhc2hib2FyZCk/dashboard/free-provider-rankings/__PAGE__.segment.rsc +7 -7
  427. package/app/.next-cli-build/server/app/dashboard/free-provider-rankings.segments/_full.segment.rsc +7 -7
  428. package/app/.next-cli-build/server/app/dashboard/free-provider-rankings.segments/_tree.segment.rsc +2 -2
  429. package/app/.next-cli-build/server/app/dashboard/free-tiers.html +1 -1
  430. package/app/.next-cli-build/server/app/dashboard/free-tiers.rsc +7 -7
  431. package/app/.next-cli-build/server/app/dashboard/free-tiers.segments/!KGRhc2hib2FyZCk/dashboard/free-tiers/__PAGE__.segment.rsc +7 -7
  432. package/app/.next-cli-build/server/app/dashboard/free-tiers.segments/_full.segment.rsc +7 -7
  433. package/app/.next-cli-build/server/app/dashboard/free-tiers.segments/_tree.segment.rsc +2 -2
  434. package/app/.next-cli-build/server/app/dashboard/guardrails.html +1 -1
  435. package/app/.next-cli-build/server/app/dashboard/guardrails.rsc +7 -7
  436. package/app/.next-cli-build/server/app/dashboard/guardrails.segments/!KGRhc2hib2FyZCk/dashboard/guardrails/__PAGE__.segment.rsc +7 -7
  437. package/app/.next-cli-build/server/app/dashboard/guardrails.segments/_full.segment.rsc +7 -7
  438. package/app/.next-cli-build/server/app/dashboard/guardrails.segments/_tree.segment.rsc +2 -2
  439. package/app/.next-cli-build/server/app/dashboard/health.html +1 -1
  440. package/app/.next-cli-build/server/app/dashboard/health.rsc +7 -7
  441. package/app/.next-cli-build/server/app/dashboard/health.segments/!KGRhc2hib2FyZCk/dashboard/health/__PAGE__.segment.rsc +7 -7
  442. package/app/.next-cli-build/server/app/dashboard/health.segments/_full.segment.rsc +7 -7
  443. package/app/.next-cli-build/server/app/dashboard/health.segments/_tree.segment.rsc +2 -2
  444. package/app/.next-cli-build/server/app/dashboard/logs.html +1 -1
  445. package/app/.next-cli-build/server/app/dashboard/logs.rsc +7 -7
  446. package/app/.next-cli-build/server/app/dashboard/logs.segments/!KGRhc2hib2FyZCk/dashboard/logs/__PAGE__.segment.rsc +7 -7
  447. package/app/.next-cli-build/server/app/dashboard/logs.segments/_full.segment.rsc +7 -7
  448. package/app/.next-cli-build/server/app/dashboard/logs.segments/_tree.segment.rsc +2 -2
  449. package/app/.next-cli-build/server/app/dashboard/mcp.html +1 -1
  450. package/app/.next-cli-build/server/app/dashboard/mcp.rsc +7 -7
  451. package/app/.next-cli-build/server/app/dashboard/mcp.segments/!KGRhc2hib2FyZCk/dashboard/mcp/__PAGE__.segment.rsc +7 -7
  452. package/app/.next-cli-build/server/app/dashboard/mcp.segments/_full.segment.rsc +7 -7
  453. package/app/.next-cli-build/server/app/dashboard/mcp.segments/_tree.segment.rsc +2 -2
  454. package/app/.next-cli-build/server/app/dashboard/media-providers/web.html +1 -1
  455. package/app/.next-cli-build/server/app/dashboard/media-providers/web.rsc +7 -7
  456. package/app/.next-cli-build/server/app/dashboard/media-providers/web.segments/!KGRhc2hib2FyZCk/dashboard/media-providers/web/__PAGE__.segment.rsc +7 -7
  457. package/app/.next-cli-build/server/app/dashboard/media-providers/web.segments/_full.segment.rsc +7 -7
  458. package/app/.next-cli-build/server/app/dashboard/media-providers/web.segments/_tree.segment.rsc +2 -2
  459. package/app/.next-cli-build/server/app/dashboard/memory.html +1 -1
  460. package/app/.next-cli-build/server/app/dashboard/memory.rsc +7 -7
  461. package/app/.next-cli-build/server/app/dashboard/memory.segments/!KGRhc2hib2FyZCk/dashboard/memory/__PAGE__.segment.rsc +7 -7
  462. package/app/.next-cli-build/server/app/dashboard/memory.segments/_full.segment.rsc +7 -7
  463. package/app/.next-cli-build/server/app/dashboard/memory.segments/_tree.segment.rsc +2 -2
  464. package/app/.next-cli-build/server/app/dashboard/mitm.html +1 -1
  465. package/app/.next-cli-build/server/app/dashboard/mitm.rsc +7 -7
  466. package/app/.next-cli-build/server/app/dashboard/mitm.segments/!KGRhc2hib2FyZCk/dashboard/mitm/__PAGE__.segment.rsc +7 -7
  467. package/app/.next-cli-build/server/app/dashboard/mitm.segments/_full.segment.rsc +7 -7
  468. package/app/.next-cli-build/server/app/dashboard/mitm.segments/_tree.segment.rsc +2 -2
  469. package/app/.next-cli-build/server/app/dashboard/playground.html +1 -1
  470. package/app/.next-cli-build/server/app/dashboard/playground.rsc +7 -7
  471. package/app/.next-cli-build/server/app/dashboard/playground.segments/!KGRhc2hib2FyZCk/dashboard/playground/__PAGE__.segment.rsc +7 -7
  472. package/app/.next-cli-build/server/app/dashboard/playground.segments/_full.segment.rsc +7 -7
  473. package/app/.next-cli-build/server/app/dashboard/playground.segments/_tree.segment.rsc +2 -2
  474. package/app/.next-cli-build/server/app/dashboard/privacy.html +1 -1
  475. package/app/.next-cli-build/server/app/dashboard/privacy.rsc +7 -7
  476. package/app/.next-cli-build/server/app/dashboard/privacy.segments/!KGRhc2hib2FyZCk/dashboard/privacy/__PAGE__.segment.rsc +7 -7
  477. package/app/.next-cli-build/server/app/dashboard/privacy.segments/_full.segment.rsc +7 -7
  478. package/app/.next-cli-build/server/app/dashboard/privacy.segments/_tree.segment.rsc +2 -2
  479. package/app/.next-cli-build/server/app/dashboard/profile.html +1 -1
  480. package/app/.next-cli-build/server/app/dashboard/profile.rsc +7 -7
  481. package/app/.next-cli-build/server/app/dashboard/profile.segments/!KGRhc2hib2FyZCk/dashboard/profile/__PAGE__.segment.rsc +7 -7
  482. package/app/.next-cli-build/server/app/dashboard/profile.segments/_full.segment.rsc +7 -7
  483. package/app/.next-cli-build/server/app/dashboard/profile.segments/_tree.segment.rsc +2 -2
  484. package/app/.next-cli-build/server/app/dashboard/provider-stats.html +1 -1
  485. package/app/.next-cli-build/server/app/dashboard/provider-stats.rsc +7 -7
  486. package/app/.next-cli-build/server/app/dashboard/provider-stats.segments/!KGRhc2hib2FyZCk/dashboard/provider-stats/__PAGE__.segment.rsc +7 -7
  487. package/app/.next-cli-build/server/app/dashboard/provider-stats.segments/_full.segment.rsc +7 -7
  488. package/app/.next-cli-build/server/app/dashboard/provider-stats.segments/_tree.segment.rsc +2 -2
  489. package/app/.next-cli-build/server/app/dashboard/providers/new.html +1 -1
  490. package/app/.next-cli-build/server/app/dashboard/providers/new.rsc +7 -7
  491. package/app/.next-cli-build/server/app/dashboard/providers/new.segments/!KGRhc2hib2FyZCk/dashboard/providers/new/__PAGE__.segment.rsc +7 -7
  492. package/app/.next-cli-build/server/app/dashboard/providers/new.segments/_full.segment.rsc +7 -7
  493. package/app/.next-cli-build/server/app/dashboard/providers/new.segments/_tree.segment.rsc +2 -2
  494. package/app/.next-cli-build/server/app/dashboard/providers.html +1 -1
  495. package/app/.next-cli-build/server/app/dashboard/providers.rsc +7 -7
  496. package/app/.next-cli-build/server/app/dashboard/providers.segments/!KGRhc2hib2FyZCk/dashboard/providers/__PAGE__.segment.rsc +7 -7
  497. package/app/.next-cli-build/server/app/dashboard/providers.segments/_full.segment.rsc +7 -7
  498. package/app/.next-cli-build/server/app/dashboard/providers.segments/_tree.segment.rsc +2 -2
  499. package/app/.next-cli-build/server/app/dashboard/proxy-pools.html +1 -1
  500. package/app/.next-cli-build/server/app/dashboard/proxy-pools.rsc +7 -7
  501. package/app/.next-cli-build/server/app/dashboard/proxy-pools.segments/!KGRhc2hib2FyZCk/dashboard/proxy-pools/__PAGE__.segment.rsc +7 -7
  502. package/app/.next-cli-build/server/app/dashboard/proxy-pools.segments/_full.segment.rsc +7 -7
  503. package/app/.next-cli-build/server/app/dashboard/proxy-pools.segments/_tree.segment.rsc +2 -2
  504. package/app/.next-cli-build/server/app/dashboard/pxpipe.html +1 -1
  505. package/app/.next-cli-build/server/app/dashboard/pxpipe.rsc +7 -7
  506. package/app/.next-cli-build/server/app/dashboard/pxpipe.segments/!KGRhc2hib2FyZCk/dashboard/pxpipe/__PAGE__.segment.rsc +7 -7
  507. package/app/.next-cli-build/server/app/dashboard/pxpipe.segments/_full.segment.rsc +7 -7
  508. package/app/.next-cli-build/server/app/dashboard/pxpipe.segments/_tree.segment.rsc +2 -2
  509. package/app/.next-cli-build/server/app/dashboard/quota.html +2 -2
  510. package/app/.next-cli-build/server/app/dashboard/quota.rsc +8 -8
  511. package/app/.next-cli-build/server/app/dashboard/quota.segments/!KGRhc2hib2FyZCk/dashboard/quota/__PAGE__.segment.rsc +8 -8
  512. package/app/.next-cli-build/server/app/dashboard/quota.segments/_full.segment.rsc +8 -8
  513. package/app/.next-cli-build/server/app/dashboard/quota.segments/_tree.segment.rsc +2 -2
  514. package/app/.next-cli-build/server/app/dashboard/runtime.html +1 -1
  515. package/app/.next-cli-build/server/app/dashboard/runtime.rsc +7 -7
  516. package/app/.next-cli-build/server/app/dashboard/runtime.segments/!KGRhc2hib2FyZCk/dashboard/runtime/__PAGE__.segment.rsc +7 -7
  517. package/app/.next-cli-build/server/app/dashboard/runtime.segments/_full.segment.rsc +7 -7
  518. package/app/.next-cli-build/server/app/dashboard/runtime.segments/_tree.segment.rsc +2 -2
  519. package/app/.next-cli-build/server/app/dashboard/settings/feature-flags.html +1 -1
  520. package/app/.next-cli-build/server/app/dashboard/settings/feature-flags.rsc +7 -7
  521. package/app/.next-cli-build/server/app/dashboard/settings/feature-flags.segments/!KGRhc2hib2FyZCk/dashboard/settings/feature-flags/__PAGE__.segment.rsc +7 -7
  522. package/app/.next-cli-build/server/app/dashboard/settings/feature-flags.segments/_full.segment.rsc +7 -7
  523. package/app/.next-cli-build/server/app/dashboard/settings/feature-flags.segments/_tree.segment.rsc +2 -2
  524. package/app/.next-cli-build/server/app/dashboard/settings/pricing.html +1 -1
  525. package/app/.next-cli-build/server/app/dashboard/settings/pricing.rsc +7 -7
  526. package/app/.next-cli-build/server/app/dashboard/settings/pricing.segments/!KGRhc2hib2FyZCk/dashboard/settings/pricing/__PAGE__.segment.rsc +7 -7
  527. package/app/.next-cli-build/server/app/dashboard/settings/pricing.segments/_full.segment.rsc +7 -7
  528. package/app/.next-cli-build/server/app/dashboard/settings/pricing.segments/_tree.segment.rsc +2 -2
  529. package/app/.next-cli-build/server/app/dashboard/skill-discovery.html +1 -1
  530. package/app/.next-cli-build/server/app/dashboard/skill-discovery.rsc +7 -7
  531. package/app/.next-cli-build/server/app/dashboard/skill-discovery.segments/!KGRhc2hib2FyZCk/dashboard/skill-discovery/__PAGE__.segment.rsc +7 -7
  532. package/app/.next-cli-build/server/app/dashboard/skill-discovery.segments/_full.segment.rsc +7 -7
  533. package/app/.next-cli-build/server/app/dashboard/skill-discovery.segments/_tree.segment.rsc +2 -2
  534. package/app/.next-cli-build/server/app/dashboard/skills.html +1 -1
  535. package/app/.next-cli-build/server/app/dashboard/skills.rsc +7 -7
  536. package/app/.next-cli-build/server/app/dashboard/skills.segments/!KGRhc2hib2FyZCk/dashboard/skills/__PAGE__.segment.rsc +7 -7
  537. package/app/.next-cli-build/server/app/dashboard/skills.segments/_full.segment.rsc +7 -7
  538. package/app/.next-cli-build/server/app/dashboard/skills.segments/_tree.segment.rsc +2 -2
  539. package/app/.next-cli-build/server/app/dashboard/token-saver.html +1 -1
  540. package/app/.next-cli-build/server/app/dashboard/token-saver.rsc +8 -8
  541. package/app/.next-cli-build/server/app/dashboard/token-saver.segments/!KGRhc2hib2FyZCk/dashboard/token-saver/__PAGE__.segment.rsc +8 -8
  542. package/app/.next-cli-build/server/app/dashboard/token-saver.segments/_full.segment.rsc +8 -8
  543. package/app/.next-cli-build/server/app/dashboard/token-saver.segments/_tree.segment.rsc +2 -2
  544. package/app/.next-cli-build/server/app/dashboard/translator.html +1 -1
  545. package/app/.next-cli-build/server/app/dashboard/translator.rsc +7 -7
  546. package/app/.next-cli-build/server/app/dashboard/translator.segments/!KGRhc2hib2FyZCk/dashboard/translator/__PAGE__.segment.rsc +7 -7
  547. package/app/.next-cli-build/server/app/dashboard/translator.segments/_full.segment.rsc +7 -7
  548. package/app/.next-cli-build/server/app/dashboard/translator.segments/_tree.segment.rsc +2 -2
  549. package/app/.next-cli-build/server/app/dashboard/usage.html +1 -1
  550. package/app/.next-cli-build/server/app/dashboard/usage.rsc +7 -7
  551. package/app/.next-cli-build/server/app/dashboard/usage.segments/!KGRhc2hib2FyZCk/dashboard/usage/__PAGE__.segment.rsc +7 -7
  552. package/app/.next-cli-build/server/app/dashboard/usage.segments/_full.segment.rsc +7 -7
  553. package/app/.next-cli-build/server/app/dashboard/usage.segments/_tree.segment.rsc +2 -2
  554. package/app/.next-cli-build/server/app/dashboard/webhooks.html +1 -1
  555. package/app/.next-cli-build/server/app/dashboard/webhooks.rsc +7 -7
  556. package/app/.next-cli-build/server/app/dashboard/webhooks.segments/!KGRhc2hib2FyZCk/dashboard/webhooks/__PAGE__.segment.rsc +7 -7
  557. package/app/.next-cli-build/server/app/dashboard/webhooks.segments/_full.segment.rsc +7 -7
  558. package/app/.next-cli-build/server/app/dashboard/webhooks.segments/_tree.segment.rsc +2 -2
  559. package/app/.next-cli-build/server/app/dashboard.html +1 -1
  560. package/app/.next-cli-build/server/app/dashboard.rsc +7 -7
  561. package/app/.next-cli-build/server/app/dashboard.segments/!KGRhc2hib2FyZCk/dashboard/__PAGE__.segment.rsc +7 -7
  562. package/app/.next-cli-build/server/app/dashboard.segments/_full.segment.rsc +7 -7
  563. package/app/.next-cli-build/server/app/dashboard.segments/_tree.segment.rsc +2 -2
  564. package/app/.next-cli-build/server/app/favicon.ico/route.js.nft.json +1 -1
  565. package/app/.next-cli-build/server/app/index.html +1 -1
  566. package/app/.next-cli-build/server/app/index.rsc +5 -5
  567. package/app/.next-cli-build/server/app/index.segments/__PAGE__.segment.rsc +5 -5
  568. package/app/.next-cli-build/server/app/index.segments/_full.segment.rsc +5 -5
  569. package/app/.next-cli-build/server/app/index.segments/_tree.segment.rsc +2 -2
  570. package/app/.next-cli-build/server/app/landing/page.js.nft.json +1 -1
  571. package/app/.next-cli-build/server/app/landing/page_client-reference-manifest.js +1 -1
  572. package/app/.next-cli-build/server/app/landing.html +1 -1
  573. package/app/.next-cli-build/server/app/landing.rsc +5 -5
  574. package/app/.next-cli-build/server/app/landing.segments/_full.segment.rsc +5 -5
  575. package/app/.next-cli-build/server/app/landing.segments/_tree.segment.rsc +2 -2
  576. package/app/.next-cli-build/server/app/landing.segments/landing/__PAGE__.segment.rsc +5 -5
  577. package/app/.next-cli-build/server/app/login/page.js.nft.json +1 -1
  578. package/app/.next-cli-build/server/app/login/page_client-reference-manifest.js +1 -1
  579. package/app/.next-cli-build/server/app/login.html +1 -1
  580. package/app/.next-cli-build/server/app/login.rsc +6 -6
  581. package/app/.next-cli-build/server/app/login.segments/_full.segment.rsc +6 -6
  582. package/app/.next-cli-build/server/app/login.segments/_tree.segment.rsc +2 -2
  583. package/app/.next-cli-build/server/app/login.segments/login/__PAGE__.segment.rsc +6 -6
  584. package/app/.next-cli-build/server/app/manifest.webmanifest/route.js.nft.json +1 -1
  585. package/app/.next-cli-build/server/app/page.js.nft.json +1 -1
  586. package/app/.next-cli-build/server/app/page_client-reference-manifest.js +1 -1
  587. package/app/.next-cli-build/server/app-paths-manifest.json +9 -9
  588. package/app/.next-cli-build/server/chunks/112.js +1 -1
  589. package/app/.next-cli-build/server/chunks/2638.js +1 -1
  590. package/app/.next-cli-build/server/chunks/2813.js +1 -1
  591. package/app/.next-cli-build/server/chunks/2974.js +1 -1
  592. package/app/.next-cli-build/server/chunks/318.js +1 -1
  593. package/app/.next-cli-build/server/chunks/3755.js +1 -1
  594. package/app/.next-cli-build/server/chunks/4037.js +1 -1
  595. package/app/.next-cli-build/server/chunks/4303.js +1 -1
  596. package/app/.next-cli-build/server/chunks/5243.js +1 -1
  597. package/app/.next-cli-build/server/chunks/5731.js +1 -1
  598. package/app/.next-cli-build/server/chunks/6270.js +1 -1
  599. package/app/.next-cli-build/server/chunks/6664.js +1 -1
  600. package/app/.next-cli-build/server/chunks/7403.js +1 -1
  601. package/app/.next-cli-build/server/chunks/772.js +1 -1
  602. package/app/.next-cli-build/server/chunks/{4018.js → 7937.js} +5 -5
  603. package/app/.next-cli-build/server/chunks/8499.js +1 -1
  604. package/app/.next-cli-build/server/chunks/8537.js +1 -1
  605. package/app/.next-cli-build/server/chunks/862.js +1 -1
  606. package/app/.next-cli-build/server/chunks/869.js +1 -1
  607. package/app/.next-cli-build/server/chunks/8750.js +1 -1
  608. package/app/.next-cli-build/server/instrumentation.js.nft.json +1 -1
  609. package/app/.next-cli-build/server/middleware-build-manifest.js +1 -1
  610. package/app/.next-cli-build/server/middleware.js +4 -4
  611. package/app/.next-cli-build/server/middleware.js.nft.json +1 -1
  612. package/app/.next-cli-build/server/pages/404.html +1 -1
  613. package/app/.next-cli-build/server/pages/500.html +1 -1
  614. package/app/.next-cli-build/server/server-reference-manifest.js +1 -1
  615. package/app/.next-cli-build/server/server-reference-manifest.json +1 -1
  616. package/app/.next-cli-build/static/chunks/{1321-b974e2c6d758f2eb.js → 1321-6b997794bb843da8.js} +1 -1
  617. package/app/.next-cli-build/static/chunks/{7780-8fef40eb7ea5a323.js → 7780-f3508723257e47c1.js} +1 -1
  618. package/app/.next-cli-build/static/chunks/app/(dashboard)/dashboard/cli-tools/{page-8f34a6d3a99ebd37.js → page-f7cbd07558c7b42e.js} +1 -1
  619. package/app/.next-cli-build/static/css/01b1ec05918332c3.css +1 -0
  620. package/app/package.json +79 -78
  621. package/app/src/mitm/server.js +40 -42
  622. package/cli.js +10 -0
  623. package/hooks/opencodeBridgeRuntime.js +77 -0
  624. package/hooks/sqliteRuntime.js +156 -156
  625. package/hooks/trayRuntime.js +107 -107
  626. package/package.json +49 -49
  627. package/vendor/opencode-free-bridge/LICENSE +21 -0
  628. package/vendor/opencode-free-bridge/README.md +762 -0
  629. package/vendor/opencode-free-bridge/THIRD_PARTY_NOTICES.md +33 -0
  630. package/vendor/opencode-free-bridge/UPSTREAM_COMMIT +1 -0
  631. package/vendor/opencode-free-bridge/identity.js +2624 -0
  632. package/vendor/opencode-free-bridge/package.json +54 -0
  633. package/vendor/opencode-free-bridge/panel.js +515 -0
  634. package/vendor/opencode-free-bridge/proxy.js +980 -0
  635. package/vendor/opencode-free-bridge/server.js +3357 -0
  636. package/vendor/opencode-free-bridge/token-budget.js +107 -0
  637. package/vendor/opencode-free-bridge/transport-baseline.json +39 -0
  638. package/app/.next-cli-build/static/css/8ba5c8dbc4e30aa0.css +0 -1
  639. /package/app/.next-cli-build/static/{X4uxXfKI78mMCnlqFsTAr → DryEkcB2pIbzN1YYgNcUS}/_buildManifest.js +0 -0
  640. /package/app/.next-cli-build/static/{X4uxXfKI78mMCnlqFsTAr → DryEkcB2pIbzN1YYgNcUS}/_ssgManifest.js +0 -0
@@ -0,0 +1,762 @@
1
+ # opencode-free-bridge
2
+
3
+ OpenAI-compatible local API bridge for [OpenCode](https://opencode.ai) free-tier models. No account and no API key required.
4
+
5
+ It runs a local server on `http://127.0.0.1:20129/v1` that any OpenAI-compatible client (9Router, Cursor, Continue, LiteLLM, Open WebUI, or the OpenAI SDK) can call directly.
6
+
7
+ ## What's New in v2.0.0
8
+
9
+ - **Bun TLS transport parity:** The official OpenCode CLI ships as a compiled Bun binary, and upstream's free-tier gate inspects the TLS `ClientHello` fingerprint (17 cipher suites and 12 TLS extensions in exact order). The bridge runs on Bun (`bun server.js`), blocks accidental Node.js startups unless `ALLOW_NODE=1` is set for offline tests, and ships `transport-fingerprint.js` to verify TLS parity against `transport-baseline.json`.
10
+ - **Full source & catalog derivation:** All hardcoded model tables (`MODEL_MAP`) and model-name substring heuristics have been removed. Client version, commit SHA, session ID recipe (`ses_` + 12 hex + 14 base62), 7 gate headers, 13 tool plugins (parsed from upstream's Effect Schema AST in GitHub source, 12 active per model after `patch` vs `edit`/`write` swap), inference endpoints (`chatUrl` and `responsesUrl`), active free models, shorthand family aliases, and reasoning token limits are derived directly from OpenCode's update API, GitHub repository, and `models.opencode.ai/api.json`.
11
+ - **On-disk catalog cache for instant cold starts:** Caches `models.opencode.ai/api.json` at `~/.opencode-free-bridge/cache/catalog.json` and loads it at startup (`OPENCODE_CACHE_DIR=off` disables disk caching). Shorthand aliases (`mimo`, `longcat`, `beam`), deprecated/paid model checks, and reasoning token budgets work on the very first request and when offline.
12
+ - **Multi-layer reactive self-healing with IP-cooldown protection:** On `403 FreeTierError`, `426 UpgradeRequired`, or `404` on a migrated endpoint path, the bridge refreshes its recipe and catalog, evicts stale session IDs, mints a fresh session ID, escalates to the full tool profile, and retries once transparently. If a full-shape retry still returns `403 FreeTierError` (indicating a per-IP upstream cooldown rather than a stale request shape), subsequent requests within the 30s cooldown window (`GATE_RETRY_COOLDOWN_MS`, `GATE_REFRESH_COOLDOWN_MS`) skip redundant GitHub fetches and duplicate retries so the bridge never amplifies an IP penalty. **Exception:** the gateway's explicit IP-level abuse block (*"detected abusive traffic from this IP address"* / `Detect Abuse Traffic`) is terminal — the bridge answers it verbatim with `X-OpenCode-Gate: ip-abuse` and performs no refresh, session re-mint, or retry, because no client-side change can clear a flag keyed to the egress network.
13
+ - **Gate anchors, so a shape bug can never masquerade as an IP block:** Upstream returns one `403 FreeTierError` — *"OpenCode's free tier can only be used from within OpenCode"* — for at least four unrelated causes: a refused egress IP, a request without a tool named `read`, a User-Agent that is not `opencode/<channel>/<semver>/<name>`, and a request without a session header. Measured by replaying byte-identical requests from a refused egress and a clean one, varying one field at a time: `read` + 11 fabricated tools → `200`, the real `read` renamed → `403`, a fabricated tool *named* `read` → `200`. The bridge therefore pins those anchors (`GATE_ANCHOR_TOOL_NAMES`, `GATE_ANCHOR_HEADER_NAMES`) independently of what the derived recipe and tool profile contain, audits the outgoing request when a `403` arrives, and reports `X-OpenCode-Gate: shape-rejected` plus the missing anchors instead of blaming the network. A second, unambiguous message (*"detected abusive traffic from this IP address"* or `Detect Abuse Traffic`) identifies a network-level block and is answered immediately as `ip-abuse`; only the ambiguous free-tier message goes through the shape audit at all. Upstream's `x-opencode-log-id` is recorded and exposed at `/health` (`identity.gate.lastRejection`) for correlation.
14
+ - **Zero-dead-end universal installer:** `install.sh` finds or installs Bun (and `unzip` when missing on minimal Linux), stages and validates every file before touching a running bridge, retires legacy `opencode-bridge.service` units, rewrites `node` units to `bun`, configures `systemd` (Linux) or `launchd` (macOS), and verifies `/health` and the TLS fingerprint baseline before succeeding.
15
+
16
+ ## Features
17
+
18
+ - **Self-healing client identity:** Derives the OpenCode CLI wire identity at the current release commit SHA and updates automatically when upstream tightens the gate.
19
+ - **Live catalog discovery:** Reads `models.opencode.ai/api.json` (and `/v1/models`) to expose only active free-tier models (`cost.input === 0`, non-deprecated) and reject retired or paid model IDs locally with a clear error.
20
+ - **Dual-protocol support:** Routes requests to `/inference/openai/v1/chat/completions` or `/inference/openai/v1/responses` based on catalog metadata and automatic protocol-mismatch detection.
21
+ - **Reasoning-aware token budgeting:** Applies an additive token floor (`max(requested, 1024) + 4096`) for reasoning models (determined from catalog `reasoning: true` metadata) so short prompts do not return empty content with `finish_reason: "length"`.
22
+ - **Reasoning stream normalization:** Emits thinking tokens under `reasoning_content` for both streaming SSE and non-streaming JSON responses, and forwards client tool calls with automatic name de-collision (`read` -> `read_client` upstream, restored to `read` on return).
23
+ - **Zero dependencies:** Uses only built-in runtime modules (`http`, `crypto`, `fs`, `path`, `net`, `tls`). No `npm install` step.
24
+ - **Container deployment:** Ships a `Dockerfile` and `docker-compose.yaml` (contributed in PR #1 by @rustam76, completed in v2.1.0). The image pins `oven/bun:1.4.3-slim` — the Bun version is pinned because the free-tier gate inspects the TLS `ClientHello` — runs as the non-root `bun` user, and publishes the port on loopback only.
25
+
26
+ ## Requirements: Bun >= 1.0
27
+
28
+ Bun is required to talk to the live OpenCode gateway. Node.js 18+ can run the offline unit test suite, but upstream rejects Node.js requests with `403 FreeTierError` because Node's OpenSSL TLS `ClientHello` differs from the compiled OpenCode CLI (which is built on Bun/BoringSSL). The installer installs Bun for you when it is missing.
29
+
30
+ Supported: Linux (systemd) and macOS (launchd). Windows is not supported; use WSL if you need it there.
31
+
32
+ Measured against a raw TCP listener and the live gateway from the same IP within one minute, using identical headers and payload:
33
+
34
+ | Property | OpenCode CLI v2.0.32 | Bridge on Bun | Bridge on Node.js |
35
+ |---|---|---|---|
36
+ | TLS cipher suites offered | 17 | **17 (identical)** | 52 |
37
+ | TLS extensions offered | 12 | **12 (identical order)** | 11 (different order) |
38
+ | Default `Accept-Encoding` | `gzip, deflate, br, zstd` | **identical** | `gzip, deflate` |
39
+ | Live gateway result | `200 OK` | **`200 OK` (6/6)** | `403 FreeTierError` (0/6) |
40
+
41
+ Starting the server with `node server.js` exits immediately with an explanation so a broken Node deployment cannot fail silently in the background:
42
+
43
+ ```bash
44
+ bun server.js # required for live traffic
45
+ node server.js # exits with code 1 and instructions
46
+ ALLOW_NODE=1 node server.js # starts for offline tests and mocked upstreams only
47
+ ```
48
+
49
+ You can verify that your local Bun binary matches the recorded OpenCode CLI TLS baseline at any time:
50
+
51
+ ```bash
52
+ bun transport-fingerprint.js --check # exits 0 if ciphers and extensions match
53
+ bun transport-fingerprint.js # prints current TLS ClientHello JSON
54
+ bun transport-fingerprint.js --write-baseline # updates transport-baseline.json
55
+ ```
56
+
57
+ ## Install & Update
58
+
59
+ ### One-line installer (Linux & macOS)
60
+
61
+ ```bash
62
+ curl -fsSL https://raw.githubusercontent.com/azrinaldi/opencode-free-bridge/main/install.sh | bash
63
+ ```
64
+
65
+ What `install.sh` does:
66
+ 1. Finds `bun` across `PATH`, `$BUN_INSTALL/bin`, `~/.bun/bin`, `~/.local/bin`, `/usr/local/bin`, and `/opt/bun/bin`, or installs it via `https://bun.sh/install` (installing `unzip` first on minimal Linux images when needed).
67
+ 2. Downloads every file into a staging directory and validates it (in-process JS syntax compilation, JSON parsing, and `bash -n` for `tunnel-doctor.sh`) before touching anything that is already running.
68
+ 3. Checks port availability (`ss` or `lsof`), retires a pre-2.0 `opencode-bridge.service` that would hold port 20129, and stops its own running bridge when upgrading in place.
69
+ 4. Backs up the previous install under `~/.opencode-free-bridge/.backup-*`, then moves the staged files into place.
70
+ 5. Registers and starts the background service (`systemd` system or `--user` unit on Linux, `launchd` agent with `~/Library/Logs/opencode-free-bridge.log` on macOS).
71
+ 6. Waits up to 20 seconds for `/health`, runs the quick self-check, and checks the Bun TLS fingerprint against `transport-baseline.json`.
72
+
73
+ If the bridge does not answer after 20 seconds, the installer exits with code `1` and prints the exact log inspection command. It only prints `Done.` when the bridge is answering.
74
+
75
+ Installer options:
76
+
77
+ ```bash
78
+ PORT=3000 BINDIR=/opt/opencode-free-bridge bash install.sh
79
+ NO_SERVICE=1 bash install.sh # install files only, skip systemd/launchd setup
80
+ ```
81
+
82
+ An occupied port aborts the install before anything is changed. To install alongside an existing service, choose a free port:
83
+
84
+ ```bash
85
+ PORT=20130 bash install.sh
86
+ ```
87
+
88
+ To update an existing installation, re-run the `curl ... | bash` command above. Running instances outside a git checkout also check for new releases in this repository every 6 hours (`AUTO_UPDATE=0` disables self-update).
89
+
90
+ ### Run from a git clone
91
+
92
+ ```bash
93
+ git clone https://github.com/azrinaldi/opencode-free-bridge.git
94
+ cd opencode-free-bridge
95
+ bun server.js
96
+ ```
97
+
98
+ `bash install.sh` inside the clone installs that working tree (including
99
+ uncommitted or unpushed files) instead of downloading from GitHub. Force a
100
+ download with `SOURCE=remote bash install.sh`.
101
+
102
+ The server listens on `http://127.0.0.1:20129` by default.
103
+ Open `http://127.0.0.1:20129/` for the panel: it shows the live egress state and sets
104
+ an HTTP proxy for every outbound request. See [Egress proxy](#egress-proxy).
105
+
106
+ ### Docker
107
+
108
+ The repository ships a `Dockerfile` and a `docker-compose.yaml` for container
109
+ deployments (single host, no orchestrator needed):
110
+
111
+ ```bash
112
+ git clone https://github.com/azrinaldi/opencode-free-bridge.git
113
+ cd opencode-free-bridge
114
+ docker compose up -d
115
+ ```
116
+
117
+ The bridge is then reachable at `http://127.0.0.1:20129/v1` (API key `public`),
118
+ exactly like a native install, and the model catalog cache survives restarts in
119
+ the `bridge-cache` volume.
120
+
121
+ What the container setup does:
122
+
123
+ - Runs on `oven/bun:1.4.3-slim` as the non-root `bun` user. The Bun version is
124
+ pinned because the free-tier gate inspects the TLS ClientHello: the image
125
+ must produce the same fingerprint as the OpenCode CLI, which
126
+ `transport-baseline.json` records.
127
+ - Publishes the port on **loopback only**. The bridge has no authentication
128
+ (the API key is literally `public`), so publishing on `0.0.0.0` would expose
129
+ an open relay to the whole network. For remote access, put a reverse proxy
130
+ or an SSH tunnel in front of it.
131
+ - Persists the on-disk catalog cache in the `bridge-cache` volume
132
+ (`OPENCODE_CACHE_DIR=/data/cache`), so a restart does not re-fetch the
133
+ upstream model catalog.
134
+ - Persists the panel's egress-proxy setting in the `bridge-state` volume
135
+ (`OPENCODE_BRIDGE_STATE_DIR=/data/state`). Without it, the container
136
+ filesystem is thrown away on recreate and the proxy would silently revert.
137
+ - Runs with `no-new-privileges` and all Linux capabilities dropped.
138
+
139
+ The image is the unit of deployment, so `AUTO_UPDATE` defaults to `0` in the
140
+ compose file: an in-place self-update is reverted by the next
141
+ `docker compose build`. Upgrade with:
142
+
143
+ ```bash
144
+ docker compose build --pull && docker compose up -d
145
+ ```
146
+
147
+ Plain `docker run` works too — set `HOST=0.0.0.0` and publish the port
148
+ yourself:
149
+
150
+ ```bash
151
+ docker build -t opencode-free-bridge .
152
+ docker run -d --name opencode-free-bridge \
153
+ -p 127.0.0.1:20129:20129 \
154
+ -e OPENCODE_CACHE_DIR=/data/cache \
155
+ -e OPENCODE_BRIDGE_STATE_DIR=/data/state \
156
+ -v opencode-free-bridge-cache:/data/cache \
157
+ -v opencode-free-bridge-state:/data/state \
158
+ opencode-free-bridge
159
+ ```
160
+
161
+ ## Usage & Client Setup
162
+
163
+ | Setting | Value |
164
+ |---|---|
165
+ | Base URL | `http://127.0.0.1:20129/v1` |
166
+ | API Key | `public` (any non-empty string is accepted) |
167
+ | Model ID | Any ID returned by `GET http://127.0.0.1:20129/v1/models` |
168
+
169
+ ### 9Router
170
+
171
+ 1. Add a custom OpenAI-compatible provider:
172
+ - **Base URL:** `http://127.0.0.1:20129/v1`
173
+ - **API Key:** `public`
174
+ - **Prefix:** `zen`
175
+ - **Model IDs:** leave empty and click **Import from /models endpoint**
176
+ 2. Models are imported as `zen/big-pickle`, `zen/mimo-v2.6-flash-free`, `zen/nemotron-3-ultra-free`, etc.
177
+ 3. Optional: if you run the bridge on multiple hosts (for example, a laptop and a VPS), register each host as a separate connection in 9Router so per-IP rate limits fail over automatically.
178
+
179
+ ### LiteLLM, Open WebUI, Continue, Cursor
180
+
181
+ Use the same three settings: Base URL `http://127.0.0.1:20129/v1`, API key `public`, and model IDs from `/v1/models`.
182
+
183
+ ```yaml
184
+ # LiteLLM config.yaml example
185
+ model_list:
186
+ - model_name: zen-mimo
187
+ litellm_params:
188
+ model: openai/mimo-v2.6-flash-free
189
+ api_base: http://127.0.0.1:20129/v1
190
+ api_key: public
191
+ ```
192
+
193
+ ### Coding agents & CLI tools
194
+
195
+ ```bash
196
+ export OPENAI_BASE_URL="http://127.0.0.1:20129/v1"
197
+ export OPENAI_API_KEY="public"
198
+ export MODEL="mimo-v2.6-flash-free"
199
+ ```
200
+
201
+ ### Python (OpenAI SDK)
202
+
203
+ ```python
204
+ from openai import OpenAI
205
+
206
+ client = OpenAI(base_url="http://127.0.0.1:20129/v1", api_key="public")
207
+
208
+ response = client.chat.completions.create(
209
+ model="mimo-v2.6-flash-free",
210
+ messages=[{"role": "user", "content": "Write a Python palindrome checker."}],
211
+ )
212
+ print(response.choices[0].message.content)
213
+ ```
214
+
215
+ ### curl
216
+
217
+ ```bash
218
+ curl -s http://127.0.0.1:20129/v1/chat/completions \
219
+ -H 'Content-Type: application/json' \
220
+ -d '{"model":"mimo-v2.6-flash-free","messages":[{"role":"user","content":"Reply with OK"}]}'
221
+ ```
222
+
223
+ ## Available Free Models
224
+
225
+ The model list is derived dynamically from `models.opencode.ai/api.json` (`cost.input === 0` and `status !== "deprecated"`) and cached at `~/.opencode-free-bridge/cache/catalog.json`.
226
+
227
+ Current active free-tier models in the upstream catalog:
228
+
229
+ | Model ID | Family Shorthand | Reasoning | Max Output Tokens |
230
+ |---|---|---|---|
231
+ | `big-pickle` | `big-pickle` | Yes | 32,000 |
232
+ | `beam-free` | `beam` | Yes | 131,072 |
233
+ | `mimo-v2.6-flash-free` | `mimo` | Yes | 32,000 |
234
+ | `nemotron-3-ultra-free` | `nemotron-free` | Yes | 128,000 |
235
+ | `nemotron-3.5-lightning-free` | - | Yes | 262,144 |
236
+ | `nemotron-3.5-super-vl-free` | - | Yes | 131,072 |
237
+ | `longcat-2.5-preview-free` | `longcat` | Yes | 131,072 |
238
+ | `deepseek-v4.1-flash-free` | `deepseek-flash` | Yes | 32,000 |
239
+ | `glm-5.3-flash-free` | `glm-flash` | Yes | 32,000 |
240
+ | `space-bunny-free` | - | Yes | 524,288 |
241
+
242
+ Query the live list from your running bridge:
243
+
244
+ ```bash
245
+ curl -s http://127.0.0.1:20129/v1/models
246
+ ```
247
+
248
+ Requests for retired models (such as `cat-jam-free`, `muse-spark-1.3-contributor-free`, or `step-5-preview-free`) or paid models (such as `claude-sonnet-4-5` or `gpt-5.4`) are rejected locally with HTTP `404` and an explanation rather than being forwarded upstream to fail with `401 Missing API key`.
249
+
250
+ ## Reasoning Models & Token Budgets
251
+
252
+ Reasoning models spend tokens on chain-of-thought before emitting visible text, and both share the same `max_completion_tokens` ceiling. When a client sends a small `max_tokens` (such as `50` or `100` for a health probe or title generator), a reasoning model can exhaust the entire budget while thinking and return an empty string with `finish_reason: "length"`.
253
+
254
+ `token-budget.js` checks the model's `reasoning` flag from the catalog (`identity.getModelFacts(modelId)`) and applies an additive floor:
255
+
256
+ | Request Type | Effective `max_completion_tokens` Sent Upstream |
257
+ |---|---|
258
+ | Catalog `reasoning: true` model (or request with `reasoning_effort` set) | `min(max(requested, 1024) + 4096, modelMaxOutput)` |
259
+ | Non-reasoning model | `min(max(requested, 512), modelMaxOutput)` |
260
+
261
+ The client's requested value is never lowered (unless it exceeds the model's catalog `limit.output` or `131072`).
262
+
263
+ ## How Adaptive Identity & Self-Healing Work
264
+
265
+ ```
266
+ Client ──▶ Bridge (:20129, Bun) ──▶ https://opencode.ai/inference/openai/v1/...
267
+ │
268
+ ├─ 1. Handshake: opencode.ai/update/api/latest/cli/npm
269
+ │ -> resolves latest CLI version, minimum floor, and GitHub commit SHA
270
+ ├─ 2. Source AST parser: raw.githubusercontent.com/anomalyco/opencode/<sha>/...
271
+ │ -> extracts session ID recipe, UA template, 7 gate headers,
272
+ │ 13 tool plugins (Effect Schema AST), and model-conditional tool swaps
273
+ ├─ 3. Provider catalog: models.opencode.ai/api.json (cached on disk)
274
+ │ -> extracts inference endpoints, 10 free models, family aliases,
275
+ │ deprecated/paid verdicts, and per-model reasoning/output limits
276
+ └─ 4. On 403 / 426 / 404:
277
+ -> refreshes recipe + catalog, evicts stale session ID, mints fresh
278
+ ses_<12hex><14base62> ID, escalates to full tool profile, retries once
279
+ (throttled for 30s if full-shape retry is still refused by per-IP gate)
280
+ ```
281
+
282
+ ### What is derived dynamically vs. fixed
283
+
284
+ | Layer | Source | Fallback if unreachable |
285
+ |---|---|---|
286
+ | CLI version & minimum floor | `opencode.ai/update/api/latest/cli/npm` (fallback: GitHub `releases.atom`) | `DEFAULT_RECIPE.version` (`2.0.32`) |
287
+ | Session ID charset, length, multiplier | `packages/schema/src/identifier.ts` | 62-char base62, length 26, mult `4096` |
288
+ | Session ID prefix | `packages/schema/src/session-id.ts` | `ses_` |
289
+ | User-Agent template | `packages/core/src/app.ts` | `opencode/${channel}/${version}/${cli}` |
290
+ | Required & optional gate headers | `packages/core/src/session/model-request.ts` | 7 core OpenCode headers |
291
+ | Tool plugin list & wire allowlist | GitHub tree listing of `packages/core/src/tool/plugin/*.ts` + `codemode/tool.ts` | 13 known plugins (`read`, `shell`, `edit`, etc.) |
292
+ | Tool JSON schemas & descriptions | Effect Schema AST parser across plugin `.ts`, sibling `.txt`, and `@opencode/schema/*` | `DEFAULT_TOOLS` (`read`, `shell`) |
293
+ | Model-conditional tool swaps (`edit`/`write` vs `patch`) | `packages/core/src/tool/plugin/patch.ts` | `gpt-*` condition rule |
294
+ | Inference endpoints (`chatUrl`, `responsesUrl`) | `models.opencode.ai/api.json` (`opencode.api`, validated under `*.opencode.ai`) | `https://opencode.ai/inference/openai/v1/*` |
295
+ | Free model list, paid/retired verdicts, family aliases, token limits | `models.opencode.ai/api.json` | `~/.opencode-free-bridge/cache/catalog.json` |
296
+
297
+ ### Inspecting live bridge state
298
+
299
+ ```bash
300
+ curl -s http://127.0.0.1:20129/health
301
+ ```
302
+
303
+ ```json
304
+ {
305
+ "status": "ok",
306
+ "provider": "opencode-free-bridge",
307
+ "version": "2.0.0",
308
+ "runtime": "bun/1.4.2",
309
+ "discoveredModels": 10,
310
+ "identity": {
311
+ "userAgent": "opencode/latest/2.0.32/cli",
312
+ "updateMode": "reactive",
313
+ "sourceTag": "d4a6223d017e17f1beaa91d3e6ecc6511c5132ad",
314
+ "versionFloor": null,
315
+ "lastCheckAgeMs": 1240,
316
+ "ttlMs": 900000,
317
+ "lastError": null,
318
+ "release": {
319
+ "version": "2.0.32",
320
+ "sha": "d4a6223d017e17f1beaa91d3e6ecc6511c5132ad",
321
+ "minimum": false,
322
+ "active": true,
323
+ "channel": "latest",
324
+ "source": "update-api",
325
+ "resolvedAt": 1760740000000,
326
+ "stale": false
327
+ },
328
+ "available": null,
329
+ "headers": [
330
+ "x-opencode-session-id",
331
+ "x-session-affinity",
332
+ "X-Session-Id",
333
+ "User-Agent",
334
+ "x-opencode-project",
335
+ "x-opencode-session",
336
+ "x-opencode-client"
337
+ ],
338
+ "unsentHeaders": [],
339
+ "endpoints": {
340
+ "chatUrl": "https://opencode.ai/inference/openai/v1/chat/completions",
341
+ "responsesUrl": "https://opencode.ai/inference/openai/v1/responses",
342
+ "modelsUrl": "https://opencode.ai/inference/v1/models",
343
+ "catalogBase": "https://opencode.ai/inference/openai/v1"
344
+ },
345
+ "toolNames": [
346
+ "read", "shell", "edit", "write", "glob", "grep", "patch",
347
+ "question", "skill", "subagent", "webfetch", "websearch", "execute"
348
+ ],
349
+ "tools": {
350
+ "source": "source",
351
+ "version": "2.0.32",
352
+ "toolNames": [
353
+ "execute", "edit", "glob", "grep", "patch", "question",
354
+ "read", "shell", "skill", "subagent", "webfetch", "websearch", "write"
355
+ ]
356
+ }
357
+ }
358
+ }
359
+ ```
360
+
361
+ ## Testing, Verification & Gate Drills
362
+
363
+ ```bash
364
+ bun test # 165 offline unit, contract, and regression tests
365
+ bun run verify # live check: probes every discovered free model
366
+ bun run verify:quick # live check: stops at the first model that answers
367
+ bun run drill # runs live + offline self-healing gate drills
368
+ bun run fingerprint:check # checks Bun TLS ClientHello against transport-baseline.json
369
+ ```
370
+
371
+ `verify.js` exits `0` when a model answers, `2` when the bridge is healthy and its TLS fingerprint matches the baseline but upstream refuses this IP (free-tier allowance or an explicit abuse block), and `1` for a real failure (bridge unreachable, running on Node.js, or TLS fingerprint drift). The `2` case is what a throttled or flagged network looks like: the official OpenCode CLI gets the same `403 FreeTierError` from the same IP at the same moment, so it is not a reason to reinstall or edit headers. The bridge labels the refusal (`X-OpenCode-Gate: ip-throttled | ip-abuse | shape-rejected`), so `verify.js` no longer depends on upstream keeping identical wording.
372
+
373
+ `gate-drill.js` deliberately corrupts the bridge's state and verifies that a single client request triggers self-healing and still returns `HTTP 200`:
374
+
375
+ | Drill | Mode | What it corrupts / stages | What it verifies |
376
+ |---|---|---|---|
377
+ | `version-floor` | Live | User-Agent version below floor | `426 UpgradeRequired` -> floor learned -> identity refreshed -> retry succeeds |
378
+ | `empty-tools` | Live | Empty tool profile | Falls back to shipped tool definitions instead of sending `tools: []` |
379
+ | `session-shape` | Live | Unrecognized session ID prefix | `403 FreeTierError` -> recipe refreshed -> old ID evicted -> fresh `ses_...` ID minted |
380
+ | `legacy-shape` | Live | Pre-v1.5 request shape | Control check against live upstream |
381
+ | `routing` | Offline | `chatUrl` repointed after boot | Endpoints are resolved per request from recipe/catalog, not frozen at boot |
382
+ | `allowlist` | Offline | Upstream renames a tool (`shell` -> `run`) | Extracted tool name reaches the wire in `full` scope and retired name is dropped |
383
+ | `retry-endpoint` | Offline | `403` gate rejection + catalog URL change | The self-heal retry uses the newly refreshed endpoint URL |
384
+ | `endpoint-move` | Offline | `404` on retired endpoint path | Re-reads catalog on `404` and retries at the new path transparently |
385
+ | `gate-heal` | Offline | Stale prefix + minimal tool scope | Full heal order: `403` -> refresh -> re-mint session ID -> escalate to full tools -> `200` |
386
+ | `full-corrupt` | Offline | Version `0.9.9`, prefix `old_`, length `20`, hex charset, default tools | One client request heals all corrupted layers simultaneously from source and returns `200` |
387
+
388
+ Before running the 4 live drills, `gate-drill.js` sends a single CLI-shaped control probe. If the current IP is temporarily throttled by upstream (`403 FreeTierError` on the control probe), the 4 live drills report `SKIP` so they do not extend the IP cooldown, while the 6 offline drills still execute and determine the exit code.
389
+
390
+ ## Configuration
391
+
392
+ | Environment Variable | Default | Description |
393
+ |---|---|---|
394
+ | `PORT` | `20129` | HTTP listen port |
395
+ | `HOST` | `127.0.0.1` | Bind address (keep on `127.0.0.1` or behind a firewall; the server has no auth) |
396
+ | `CORS_ORIGIN` | `""` (localhost only) | Allowed CORS origin(s), comma-separated or `*` |
397
+ | `UPSTREAM_TIMEOUT_MS` | `120000` | Upstream fetch timeout in milliseconds |
398
+ | `MAX_BODY_BYTES` | `10485760` | Maximum request body size in bytes (10 MiB) |
399
+ | `IDENTITY_TTL_MS` | `900000` | Identity freshness TTL in milliseconds (15 minutes) |
400
+ | `UPDATE_MODE` | `reactive` | `reactive` adopts new CLI releases only on `403`/`426` or `minimum: true`; `always` adopts every release on TTL expiry |
401
+ | `GATE_RETRY_COOLDOWN_MS` | `30000` | Cooldown window (ms) after a failed full-shape `403` retry during which duplicate retries are suppressed until identity changes |
402
+ | `GATE_REFRESH_COOLDOWN_MS` | `30000` | Cooldown window (ms) between forced GitHub/catalog refreshes during a `403` burst |
403
+ | `DNS_RESULT_ORDER` | `ipv4first` | DNS resolution order passed to `dns.setDefaultResultOrder` (`ipv4first`, `ipv6first`, `verbatim`) |
404
+ | `TOOL_PROFILE_SCOPE` | `core` | `core` sends the minimal gate anchor (`read`, `shell`) on first attempt and escalates to `full` (all model-applicable tools) on retry; `full` sends the full tool profile on every request |
405
+ | `OPENCODE_CHANNEL` | `latest` | OpenCode release channel (`latest`, `beta`, `dev`) |
406
+ | `OPENCODE_MAJOR` | _(unset)_ | Pin a major version line (for example `2`) |
407
+ | `OPENCODE_USER_AGENT` | _(derived)_ | Override `User-Agent` and disable dynamic identity derivation |
408
+ | `OPENCODE_CATALOG_URL` | `https://models.opencode.ai/api.json` | Provider catalog URL |
409
+ | `OPENCODE_CACHE_DIR` | `~/.opencode-free-bridge/cache` | Directory for the on-disk `catalog.json` cache (`off` disables disk caching) |
410
+ | `OPENCODE_CHAT_URL` | _(derived)_ | Override the upstream Chat Completions endpoint URL |
411
+ | `OPENCODE_RESPONSES_URL` | _(derived)_ | Override the upstream Responses API endpoint URL |
412
+ | `UPSTREAM_RELAY_URL` | _(unset)_ | Route inference through an egress relay (`x-relay-target` / `x-relay-path` contract); empty = direct. See [Optional egress relay](#optional-egress-relay) |
413
+ | `UPSTREAM_PROXY_URL` | _(unset)_ | Operator-level default for the egress proxy (`http://[user:pass@]host:port`). When set it wins over the panel and locks runtime edits. See [Egress proxy](#egress-proxy) |
414
+ | `PANEL_ALLOWED_HOSTS` | _(unset)_ | Extra `Host` names the panel and `/api/proxy` accept (comma-separated), for a reverse proxy in front of the bridge. Loopback names and the configured `HOST` are always accepted |
415
+ | `AUTO_UPDATE` | `1` | Poll GitHub for bridge updates every 6 hours (automatically skipped inside a `.git` checkout; set `0` to disable) |
416
+ | `ALLOW_NODE` | _(unset)_ | Set `ALLOW_NODE=1` to bypass the startup Bun check for offline tests |
417
+
418
+ ### Optional egress relay
419
+
420
+ Set `UPSTREAM_RELAY_URL` to a relay that speaks the same contract as 9Router's
421
+ Cloudflare/Vercel/Deno/Netlify relays. The bridge POSTs to the relay with
422
+ `x-relay-target: <origin>` and `x-relay-path: <path>`, and the relay replays the
423
+ request at that origin; upstream therefore sees the relay's egress IP.
424
+
425
+ ```bash
426
+ UPSTREAM_RELAY_URL="https://relay.example.workers.dev" bun server.js
427
+ ```
428
+
429
+ The relay covers inference requests and their retries; model discovery and
430
+ identity synchronization stay direct. `/health` reports `egress.mode` (`direct`
431
+ or `relay`) and the relay's origin, without credentials or query strings. Use a
432
+ trusted HTTPS relay: it receives the request headers (including
433
+ `Authorization: Bearer public`) and the full prompt. Changing the variable
434
+ requires a restart.
435
+
436
+ ### Egress proxy
437
+
438
+ Open `http://127.0.0.1:20129/` and enter an HTTP proxy. Every outbound request
439
+ the bridge makes then tunnels through it (`CONNECT`), so upstream sees the
440
+ proxy's IP rather than this machine's. That covers inference, model discovery,
441
+ identity sync, and the self-updater.
442
+
443
+ - **Protocol:** `http://` and `https://` only. Bun's fetch accepts those and
444
+ tunnels TLS itself, so `transport-baseline.json` still matches. SOCKS5 is
445
+ refused by Bun (`UnsupportedProxyProtocol`) and rejected in the panel with
446
+ that reason.
447
+ - **Credentials:** `http://user:pass@host:port`, percent-encoded if they contain
448
+ `@`, `:`, or `/`. They are stored in `~/.opencode-free-bridge/proxy.json`
449
+ (mode `0600`) and never returned by the panel, `/api/proxy`, or `/health`;
450
+ those show `host:port` only.
451
+ - **Test before trusting it:** *Uji koneksi* fetches the models endpoint through
452
+ the candidate proxy and reports the exit IP from `cdn-cgi/trace`. A 403 there
453
+ means the proxy reaches upstream but its egress is refused.
454
+ - **No restart:** the setting is read on every request. *Matikan proxy* returns
455
+ to direct egress.
456
+ - **Operator override:** `UPSTREAM_PROXY_URL` beats the panel and locks runtime
457
+ edits to it.
458
+ - **Only from this machine:** the panel and `/api/proxy` accept `Host` names of
459
+ loopback (or the configured bind address) plus anything in
460
+ `PANEL_ALLOWED_HOSTS`, reject cross-site requests, and require
461
+ `Content-Type: application/json` for writes. That blocks a random website from
462
+ re-pointing your egress and blocks DNS rebinding. Put a reverse proxy in front
463
+ and add its name to `PANEL_ALLOWED_HOSTS` if you reach the panel that way.
464
+ - **Container:** the compose file mounts the `bridge-state` volume at
465
+ `/data/state` (`OPENCODE_BRIDGE_STATE_DIR`) so the setting survives a
466
+ recreate. Plain `docker run` needs that env var and volume too.
467
+
468
+ ### Egress pool
469
+
470
+ The free-tier allowance is per egress IP, not per account. Running one bridge
471
+ per host multiplies processes, service units and tunnels without giving anything
472
+ a pool does not: the pool rotates the egress while one process keeps the
473
+ identity, the catalog and the session cache in one place.
474
+
475
+ A pool is a list of egress entries. Each keeps its own health, so an entry that
476
+ upstream throttles is skipped until its cooldown ends instead of being retried
477
+ by every request.
478
+
479
+ ```bash
480
+ # in the panel under "Pool egress", one entry per line
481
+ med1=http://pool:token@127.0.0.1:20251
482
+ med2=http://pool:token@127.0.0.1:20252
483
+ ```
484
+
485
+ ```bash
486
+ # operator override: comma- or newline-separated, label=url optional
487
+ UPSTREAM_PROXY_POOL="med1=http://a:1,med2=http://b:2" \
488
+ UPSTREAM_PROXY_STRATEGY=failover \
489
+ bun server.js
490
+ ```
491
+
492
+ - **Entry shape:** a URL string, `{id,label,url,enabled,weight}`, or
493
+ `{direct: true}` for this machine's own address. `direct` is a first-class
494
+ entry, so the hosting IP can take part in the rotation instead of being the
495
+ fallback used only when every proxy is down.
496
+ - **Strategies:** `round-robin` (default; even spread across healthy entries),
497
+ `failover` (sticky on the first healthy entry, which keeps upstream prompt
498
+ caching on one IP), `random` (weighted).
499
+ - **Cooldown:** a refusal on a pooled egress is recorded against *that* entry.
500
+ The backoff doubles per consecutive failure from `cooldownMs` (default 120 s)
501
+ up to `maxCooldownMs` (default 30 min); a success resets it. A `429` earns four
502
+ times the base window because it is an unambiguous allowance answer.
503
+ - **Always sends:** when every entry is cooling, the one that recovers first is
504
+ used anyway. Refusing would turn a throttled pool into a dead bridge, and
505
+ upstream answers a throttled IP with a normal refusal the caller already
506
+ handles.
507
+ - **Failover on a gate rejection:** the bridge drops the entry that was refused
508
+ and retries through a different one, in the same request. An unreachable proxy
509
+ is also failed over, since nothing reached upstream.
510
+ - **One egress per request:** the protocol-lane, endpoint-migration, 5xx and
511
+ gate retries all reuse the entry the request started on, because upstream ties
512
+ a retry to the address that saw the first attempt. Only the two cases above
513
+ move it.
514
+ - **`/health`** reports `egress.mode: "pool"` and `egress.proxy.pool` with each
515
+ entry's host, state, remaining cooldown and failure count. Credentials are
516
+ never included.
517
+
518
+ #### Health across restarts
519
+
520
+ Cooldowns are written to `<state dir>/pool-health.json` (mode `0600`), so a
521
+ service restart or a host suspend/resume does not forget which IPs are spent and
522
+ re-burn all of them.
523
+
524
+ - A refusal is written immediately; a success is coalesced over one second,
525
+ because a success arrives with every request and a rewrite per request would
526
+ turn a memory update into disk churn.
527
+ - The file is written by rename, so a crash mid-write keeps the previous copy
528
+ instead of leaving a truncated one that would cost every cooldown.
529
+ - Records are keyed by a truncated SHA-256 of the egress identity, not by URL,
530
+ so the file is not a second copy of the proxy credentials. A `label` field
531
+ carries `host:port` (or `direct`), which `/health` already exposes.
532
+ - Saving the pool in the panel keeps existing cooldowns; only an entry that
533
+ leaves the pool loses its record.
534
+ - A corrupt or missing health file costs the cooldowns and nothing else: the
535
+ bridge starts, reports the pool from `proxy.json`, and treats every entry as
536
+ ready.
537
+
538
+ #### Turning a host into a pool member
539
+
540
+ `egress-proxy.js` is a dependency-free HTTP proxy for exactly this: it answers
541
+ `CONNECT` and absolute-URI HTTP, and forwards bytes without inspecting them.
542
+ Its TLS is tunneled end to end, so it never sees plaintext.
543
+
544
+ ```bash
545
+ # on the node
546
+ PORT=8888 EGRESS_PROXY_TOKEN=secret bun egress-proxy.js
547
+
548
+ # from the bridge host: put it on a loopback port, so the proxy itself is never
549
+ # exposed and the tunnel carries the authentication
550
+ ssh -L 127.0.0.1:20251:127.0.0.1:8888 node
551
+ ```
552
+
553
+ `/healthz` is unauthenticated on purpose: it reports a connection count and an
554
+ uptime, nothing about the target or the token, so a monitor does not need the
555
+ credential to ask whether the proxy is up.
556
+
557
+ `/health` reports `egress.mode` (`pool`, `proxy`, `relay`, or `direct`) plus
558
+ `egress.proxy` with the same credential-free description.
559
+
560
+ The proxy applies *in addition to* the relay: with both configured, the request
561
+ is still sent to `UPSTREAM_RELAY_URL`, and that connection is dialled through
562
+ the proxy.
563
+
564
+ ## Troubleshooting
565
+
566
+ ### `403` with "detected abusive traffic" / `Detect Abuse Traffic` (IP-level block)
567
+
568
+ This is not the shape gate and not a stale bridge. The gateway has flagged the
569
+ network's egress IP for abusive traffic; the message says it is unrelated to the
570
+ account. The bridge treats it as terminal: it does **not** refresh the identity,
571
+ re-mint the session id, or retry, and returns the refusal verbatim with
572
+ `X-OpenCode-Gate: ip-abuse`. `/health` reports `identity.gate.status:
573
+ "ip-blocked"` and `identity.gate.lastRejection.kind: "ip-abuse"`.
574
+
575
+ The official OpenCode CLI gets the same answer from the same network. Only
576
+ upstream can clear the flag (`help@anoma.ly`, with the time it started and the
577
+ `x-opencode-log-id` from the response). Until then, change egress (route through
578
+ another host or SSH tunnel), subscribe to OpenCode Go, or wait. Reinstalling the
579
+ bridge or editing headers will not help.
580
+
581
+ ### `403 FreeTierError` persists even after retry
582
+
583
+ When the bridge receives `403 FreeTierError`, it refreshes its recipe from OpenCode's update API and GitHub source tree, re-mints the session ID, escalates to the full tool profile, and retries once. If the message names an explicit IP-level abuse block (`abusive traffic` / `Detect Abuse Traffic`), this path is skipped entirely — see the section above.
584
+
585
+ If that retry also returns `403 FreeTierError` and `/health` shows `"lastError": null` with the current CLI version (for example `opencode/latest/2.0.32/cli`), **your current IP is in a temporary free-tier cooldown upstream**. To prevent extending the penalty, the bridge suppresses duplicate `403` retries and forced GitHub refreshes for `30s` (`GATE_RETRY_COOLDOWN_MS`). Running the official OpenCode CLI binary (`opencode run -m opencode/big-pickle "hi"`) from the same IP at the same moment returns the exact same `403 FreeTierError`. Wait for the per-IP window to reset or route through another host/SSH tunnel.
586
+
587
+ ### `429 RateLimitError` / `BUSY` in `verify.js`
588
+
589
+ Upstream is throttling the specific model or current IP due to capacity. Try another model ID from `/v1/models`.
590
+
591
+ ### `404 Model '<id>' has been retired upstream`
592
+
593
+ The model was marked `status: "deprecated"` in `models.opencode.ai/api.json` (for example `cat-jam-free`, `muse-spark-1.3-contributor-free`, or `step-5-preview-free`). Query `curl -s http://127.0.0.1:20129/v1/models` and switch your client to one of the active models.
594
+
595
+ ### `bun: command not found` in a fresh SSH session
596
+
597
+ The service runs fine, but `curl https://bun.sh/install | bash` only adds
598
+ `~/.bun/bin` to an *interactive* shell's PATH. A new non-login SSH session, or a
599
+ `sh -c` command, does not see it:
600
+
601
+ ```bash
602
+ export PATH="$HOME/.bun/bin:$PATH" # or use the absolute path
603
+ /root/.bun/bin/bun transport-fingerprint.js --check
604
+ ```
605
+
606
+ The installer prints the absolute path in its closing summary for this reason.
607
+ The service itself is unaffected: its unit file records the full path.
608
+
609
+ ### `remote port forwarding failed for listen port 20136`
610
+
611
+ The receiving host still has a **stale** listener from a tunnel whose sender rebooted or lost power. The TCP connection died without a FIN, so `sshd` keeps the forwarded port until keepalive notices — ten minutes with the default `ClientAliveInterval 300` × `ClientAliveCountMax 2`. The replacement tunnel then fails even though its own unit is healthy.
612
+
613
+ ```bash
614
+ ./tunnel-doctor.sh # which forwards are stale (listener with no SSH transport)
615
+ ./tunnel-doctor.sh --reap # kill only the stale sessions
616
+ ./tunnel-doctor.sh --check # is the keepalive window short enough?
617
+ ```
618
+
619
+ To close the window itself, on the **receiving** host:
620
+
621
+ ```bash
622
+ # /etc/ssh/sshd_config.d/00-keepalive.conf — the 00- prefix matters
623
+ ClientAliveInterval 30
624
+ ClientAliveCountMax 4 # dead peer detected in 120s
625
+ ```
626
+
627
+ OpenSSH uses the **first** value it reads, so a later-sorting file (for example `99-*.conf`) is silently ignored. Verify with `sshd -T | grep -i clientalive` and `systemctl reload ssh`.
628
+
629
+ ### `429 FreeUsageLimitError` — the quota, or a missing `<env>` block?
630
+
631
+ `429 FreeUsageLimitError` has **two** causes, and the gateway uses the same
632
+ message for both:
633
+
634
+ 1. the free-tier allowance is spent, or
635
+ 2. the request's system prompt is missing the harness environment block.
636
+
637
+ Cause 2 is the one that made the bridge look throttled while the CLI worked.
638
+ Reproduced by capturing the CLI's own request and replaying it byte-for-byte:
639
+ the captured body answers `200`, the same body with only its system prompt
640
+ replaced by a short one answers `429`. Same headers, same session id, same TLS
641
+ stack — the difference is the body.
642
+
643
+ The trigger is precise: an `<env>` block containing a `Working directory:` line.
644
+
645
+ | system prompt | result |
646
+ |---|---|
647
+ | `You are a helpful assistant.` | `429` |
648
+ | 12 KB of generic prompt text | `429` |
649
+ | `<env>Working directory: /tmp</env>` (65 bytes) | `200` |
650
+ | 12 KB generic prompt **plus** the env block | `200` |
651
+
652
+ Length is not the rule, and neither is the model — `big-pickle` and
653
+ `mimo-v2.6-flash-free` split the same way. Sending `tools: []` also produces
654
+ this `429`, which is why an empty tool profile looked like a quota error too.
655
+
656
+ The bridge has appended the block since the fix in this release: it derives the
657
+ working directory, workspace root, git-repo flag and platform from its own
658
+ process. A client that already forwards the CLI's prompt keeps its own block
659
+ and does not get a duplicate. If you still see `429` on an up-to-date bridge,
660
+ the allowance really is spent — check with the interleaving probe:
661
+
662
+ ```bash
663
+ for i in 1 2 3; do
664
+ opencode run -m opencode/glm-5.3-flash-free "probe $i" 2>&1 | tail -1
665
+ curl -s http://127.0.0.1:20129/v1/chat/completions \
666
+ -H 'Content-Type: application/json' \
667
+ -d '{"model":"glm-5.3-flash-free","messages":[{"role":"user","content":"probe"}],"max_tokens":8}' \
668
+ | head -c 120; echo
669
+ done
670
+ ```
671
+
672
+ If both refuse, the allowance is spent. If the CLI answers while the bridge
673
+ refuses **in the same minute** on a bridge older than this release, upgrade —
674
+ that is the shape bug, not a quota.
675
+
676
+ #### Why the bridge can be charged earlier than the CLI
677
+
678
+ The default `TOOL_PROFILE_SCOPE=core` sends two tools (`read`, `shell`) and a
679
+ short placeholder note, then escalates to `full` only after a rejection. The
680
+ real CLI always sends the full profile. Measured against a captured CLI request
681
+ (`opencode run`, v2.0.32) and this bridge on the same model:
682
+
683
+ | | CLI | bridge, `core` | bridge, `full` |
684
+ |---|---|---|---|
685
+ | tools | 12 | 2 | 13 |
686
+ | tool schema bytes | 13,991 | 2,522 | 13,972 |
687
+ | system prompt chars | 12,259 | ~470 | ~470 |
688
+ | `max_completion_tokens` | 32,000 | 5,120 | 5,120 |
689
+ | total body bytes | 26,296 | ~3,300 | ~14,500 |
690
+
691
+ `TOOL_PROFILE_SCOPE=full` closes the tool gap and is the safer default when a
692
+ deployment is being throttled ahead of the CLI.
693
+
694
+ The system-prompt gap is **not** cosmetic: before the `<env>` fix in this
695
+ release it was the whole `429` cause. What remains after the fix is the CLI's
696
+ harness prose (persona, communication rules, skill catalogue), which the bridge
697
+ does not ship. That part is accepted by the gateway — the env block is the only
698
+ anchor it checks — so the bridge no longer needs to reproduce the full prompt.
699
+
700
+ ```bash
701
+ # systemd drop-in for a service that runs as a dedicated user
702
+ sudo mkdir -p /etc/systemd/system/opencode-free-bridge.service.d
703
+ printf '[Service]\nEnvironment=TOOL_PROFILE_SCOPE=full\n' \
704
+ | sudo tee /etc/systemd/system/opencode-free-bridge.service.d/10-tool-profile.conf
705
+ sudo systemctl daemon-reload && sudo systemctl restart opencode-free-bridge.service
706
+ ```
707
+
708
+ ### Reverse tunnel dies while the process still looks healthy
709
+
710
+ A deployment that reaches the bridge over `ssh -R` can fail in a way systemd
711
+ cannot see: the `ssh` process stays `active`, the TCP connection stays `ESTAB`,
712
+ and the listener on the far end is gone. `Restart=always` never fires because
713
+ the process never exits. This cost two hours of downtime on a five-node
714
+ deployment before it was diagnosed.
715
+
716
+ The only reliable probe is the endpoint itself. Run it on the host that owns the
717
+ forwarded port, not on the node:
718
+
719
+ ```bash
720
+ #!/bin/bash
721
+ # /usr/local/bin/opencode-tunnel-watchdog.sh — run as root via a systemd timer
722
+ PORT=20136
723
+ LOG=/var/log/opencode-tunnel-watchdog.log
724
+ log() { printf '%s %s\n' "$(date -u +%FT%TZ)" "$*" >> "$LOG"; }
725
+
726
+ if ! curl -sf --max-time 5 http://127.0.0.1:20129/health >/dev/null; then
727
+ log "bridge DOWN - restarting"; systemctl restart opencode-bridge.service; sleep 4
728
+ fi
729
+ if ! pgrep -f "ssh .*-R 127.0.0.1:${PORT}:" >/dev/null; then
730
+ log "tunnel MISSING - restarting"; systemctl restart opencode-tunnel.service; sleep 6
731
+ fi
732
+ pgrep -f "ssh .*-R 127.0.0.1:${PORT}:" >/dev/null \
733
+ && log "SUMMARY ok" || log "SUMMARY FAILED - manual attention needed"
734
+ ```
735
+
736
+ Pair it with a `oneshot` service and a `OnUnitActiveSec=60` timer. The
737
+ `SUMMARY` line is deliberate: without a heartbeat, an empty log is
738
+ indistinguishable from a watchdog that never ran.
739
+
740
+ Restarting the tunnel from a remote host over SSH needs care. `Defaults use_pty`
741
+ in `/etc/sudoers` makes `sudo -n` fail with "a password is required" even when
742
+ `NOPASSWD` is granted, and a nested `ssh host "python3 -c \"...\""` mangles
743
+ quotes. Run the watchdog **as root on the node itself** through systemd instead
744
+ of driving it remotely.
745
+
746
+ ### Checking service logs
747
+
748
+ ```bash
749
+ # Linux (systemd user or system service)
750
+ journalctl --user -u opencode-free-bridge -n 50 --no-pager
751
+ journalctl -u opencode-free-bridge -n 50 --no-pager
752
+
753
+ # macOS (launchd)
754
+ tail -50 ~/Library/Logs/opencode-free-bridge.log
755
+
756
+ # Manual foreground run
757
+ bun ~/.opencode-free-bridge/server.js
758
+ ```
759
+
760
+ ## License and upstream data
761
+
762
+ This project is licensed under [MIT](./LICENSE). `identity.js` derives request identity and tool metadata from the [OpenCode source repository](https://github.com/anomalyco/opencode). Its offline fallback includes OpenCode `read` and `shell` tool descriptions and schema fields; related source-shaped fixtures appear in `test/identity.test.js`. See [`THIRD_PARTY_NOTICES.md`](./THIRD_PARTY_NOTICES.md) for the OpenCode MIT notice and contributor credit.