9router 0.3.55 → 0.3.57

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (375) hide show
  1. package/app/.next/BUILD_ID +1 -1
  2. package/app/.next/app-path-routes-manifest.json +40 -40
  3. package/app/.next/build-manifest.json +5 -5
  4. package/app/.next/server/app/(dashboard)/dashboard/cli-tools/page_client-reference-manifest.js +1 -1
  5. package/app/.next/server/app/(dashboard)/dashboard/combos/page_client-reference-manifest.js +1 -1
  6. package/app/.next/server/app/(dashboard)/dashboard/console-log/page_client-reference-manifest.js +1 -1
  7. package/app/.next/server/app/(dashboard)/dashboard/endpoint/page_client-reference-manifest.js +1 -1
  8. package/app/.next/server/app/(dashboard)/dashboard/mitm/page.js +1 -1
  9. package/app/.next/server/app/(dashboard)/dashboard/mitm/page_client-reference-manifest.js +1 -1
  10. package/app/.next/server/app/(dashboard)/dashboard/page_client-reference-manifest.js +1 -1
  11. package/app/.next/server/app/(dashboard)/dashboard/profile/page_client-reference-manifest.js +1 -1
  12. package/app/.next/server/app/(dashboard)/dashboard/providers/[id]/page_client-reference-manifest.js +1 -1
  13. package/app/.next/server/app/(dashboard)/dashboard/providers/new/page_client-reference-manifest.js +1 -1
  14. package/app/.next/server/app/(dashboard)/dashboard/providers/page_client-reference-manifest.js +1 -1
  15. package/app/.next/server/app/(dashboard)/dashboard/proxy-pools/page_client-reference-manifest.js +1 -1
  16. package/app/.next/server/app/(dashboard)/dashboard/quota/page_client-reference-manifest.js +1 -1
  17. package/app/.next/server/app/(dashboard)/dashboard/translator/page_client-reference-manifest.js +1 -1
  18. package/app/.next/server/app/(dashboard)/dashboard/usage/page_client-reference-manifest.js +1 -1
  19. package/app/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  20. package/app/.next/server/app/_global-error.html +2 -2
  21. package/app/.next/server/app/_global-error.rsc +1 -1
  22. package/app/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  23. package/app/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  24. package/app/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  25. package/app/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  26. package/app/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  27. package/app/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  28. package/app/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  29. package/app/.next/server/app/_not-found.html +1 -1
  30. package/app/.next/server/app/_not-found.rsc +4 -4
  31. package/app/.next/server/app/_not-found.segments/_full.segment.rsc +4 -4
  32. package/app/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  33. package/app/.next/server/app/_not-found.segments/_index.segment.rsc +4 -4
  34. package/app/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  35. package/app/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  36. package/app/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  37. package/app/.next/server/app/api/auth/login/route_client-reference-manifest.js +1 -1
  38. package/app/.next/server/app/api/auth/logout/route_client-reference-manifest.js +1 -1
  39. package/app/.next/server/app/api/cli-tools/antigravity-mitm/alias/route_client-reference-manifest.js +1 -1
  40. package/app/.next/server/app/api/cli-tools/antigravity-mitm/route_client-reference-manifest.js +1 -1
  41. package/app/.next/server/app/api/cli-tools/claude-settings/route_client-reference-manifest.js +1 -1
  42. package/app/.next/server/app/api/cli-tools/codex-settings/route_client-reference-manifest.js +1 -1
  43. package/app/.next/server/app/api/cli-tools/copilot-settings/route_client-reference-manifest.js +1 -1
  44. package/app/.next/server/app/api/cli-tools/droid-settings/route_client-reference-manifest.js +1 -1
  45. package/app/.next/server/app/api/cli-tools/openclaw-settings/route_client-reference-manifest.js +1 -1
  46. package/app/.next/server/app/api/cli-tools/opencode-settings/route_client-reference-manifest.js +1 -1
  47. package/app/.next/server/app/api/cloud/auth/route_client-reference-manifest.js +1 -1
  48. package/app/.next/server/app/api/cloud/credentials/update/route_client-reference-manifest.js +1 -1
  49. package/app/.next/server/app/api/cloud/model/resolve/route_client-reference-manifest.js +1 -1
  50. package/app/.next/server/app/api/cloud/models/alias/route_client-reference-manifest.js +1 -1
  51. package/app/.next/server/app/api/combos/[id]/route_client-reference-manifest.js +1 -1
  52. package/app/.next/server/app/api/combos/route_client-reference-manifest.js +1 -1
  53. package/app/.next/server/app/api/init/route_client-reference-manifest.js +1 -1
  54. package/app/.next/server/app/api/keys/[id]/route_client-reference-manifest.js +1 -1
  55. package/app/.next/server/app/api/keys/route_client-reference-manifest.js +1 -1
  56. package/app/.next/server/app/api/locale/route.js +1 -1
  57. package/app/.next/server/app/api/locale/route_client-reference-manifest.js +1 -1
  58. package/app/.next/server/app/api/models/alias/route_client-reference-manifest.js +1 -1
  59. package/app/.next/server/app/api/models/route.js +1 -1
  60. package/app/.next/server/app/api/models/route_client-reference-manifest.js +1 -1
  61. package/app/.next/server/app/api/models/test/route_client-reference-manifest.js +1 -1
  62. package/app/.next/server/app/api/oauth/[provider]/[action]/route_client-reference-manifest.js +1 -1
  63. package/app/.next/server/app/api/oauth/cursor/auto-import/route_client-reference-manifest.js +1 -1
  64. package/app/.next/server/app/api/oauth/cursor/import/route_client-reference-manifest.js +1 -1
  65. package/app/.next/server/app/api/oauth/iflow/cookie/route_client-reference-manifest.js +1 -1
  66. package/app/.next/server/app/api/oauth/kiro/auto-import/route_client-reference-manifest.js +1 -1
  67. package/app/.next/server/app/api/oauth/kiro/import/route_client-reference-manifest.js +1 -1
  68. package/app/.next/server/app/api/oauth/kiro/social-authorize/route_client-reference-manifest.js +1 -1
  69. package/app/.next/server/app/api/oauth/kiro/social-exchange/route_client-reference-manifest.js +1 -1
  70. package/app/.next/server/app/api/pricing/route_client-reference-manifest.js +1 -1
  71. package/app/.next/server/app/api/provider-nodes/[id]/route_client-reference-manifest.js +1 -1
  72. package/app/.next/server/app/api/provider-nodes/route_client-reference-manifest.js +1 -1
  73. package/app/.next/server/app/api/provider-nodes/validate/route_client-reference-manifest.js +1 -1
  74. package/app/.next/server/app/api/providers/[id]/models/route.js +1 -1
  75. package/app/.next/server/app/api/providers/[id]/models/route_client-reference-manifest.js +1 -1
  76. package/app/.next/server/app/api/providers/[id]/route_client-reference-manifest.js +1 -1
  77. package/app/.next/server/app/api/providers/[id]/test/route_client-reference-manifest.js +1 -1
  78. package/app/.next/server/app/api/providers/[id]/test-models/route_client-reference-manifest.js +1 -1
  79. package/app/.next/server/app/api/providers/client/route_client-reference-manifest.js +1 -1
  80. package/app/.next/server/app/api/providers/route.js +1 -1
  81. package/app/.next/server/app/api/providers/route_client-reference-manifest.js +1 -1
  82. package/app/.next/server/app/api/providers/test-batch/route_client-reference-manifest.js +1 -1
  83. package/app/.next/server/app/api/providers/validate/route_client-reference-manifest.js +1 -1
  84. package/app/.next/server/app/api/proxy-pools/[id]/route_client-reference-manifest.js +1 -1
  85. package/app/.next/server/app/api/proxy-pools/[id]/test/route_client-reference-manifest.js +1 -1
  86. package/app/.next/server/app/api/proxy-pools/route_client-reference-manifest.js +1 -1
  87. package/app/.next/server/app/api/settings/database/route_client-reference-manifest.js +1 -1
  88. package/app/.next/server/app/api/settings/proxy-test/route_client-reference-manifest.js +1 -1
  89. package/app/.next/server/app/api/settings/require-login/route_client-reference-manifest.js +1 -1
  90. package/app/.next/server/app/api/settings/route_client-reference-manifest.js +1 -1
  91. package/app/.next/server/app/api/shutdown/route_client-reference-manifest.js +1 -1
  92. package/app/.next/server/app/api/tags/route_client-reference-manifest.js +1 -1
  93. package/app/.next/server/app/api/translator/console-logs/route.js +1 -1
  94. package/app/.next/server/app/api/translator/console-logs/route_client-reference-manifest.js +1 -1
  95. package/app/.next/server/app/api/translator/console-logs/stream/route.js +1 -1
  96. package/app/.next/server/app/api/translator/console-logs/stream/route_client-reference-manifest.js +1 -1
  97. package/app/.next/server/app/api/translator/load/route.js.nft.json +1 -1
  98. package/app/.next/server/app/api/translator/load/route_client-reference-manifest.js +1 -1
  99. package/app/.next/server/app/api/translator/save/route.js.nft.json +1 -1
  100. package/app/.next/server/app/api/translator/save/route_client-reference-manifest.js +1 -1
  101. package/app/.next/server/app/api/translator/send/route_client-reference-manifest.js +1 -1
  102. package/app/.next/server/app/api/translator/translate/route.js +1 -1
  103. package/app/.next/server/app/api/translator/translate/route_client-reference-manifest.js +1 -1
  104. package/app/.next/server/app/api/tunnel/disable/route_client-reference-manifest.js +1 -1
  105. package/app/.next/server/app/api/tunnel/enable/route_client-reference-manifest.js +1 -1
  106. package/app/.next/server/app/api/tunnel/status/route_client-reference-manifest.js +1 -1
  107. package/app/.next/server/app/api/usage/[connectionId]/route_client-reference-manifest.js +1 -1
  108. package/app/.next/server/app/api/usage/chart/route_client-reference-manifest.js +1 -1
  109. package/app/.next/server/app/api/usage/history/route_client-reference-manifest.js +1 -1
  110. package/app/.next/server/app/api/usage/providers/route_client-reference-manifest.js +1 -1
  111. package/app/.next/server/app/api/usage/request-details/route_client-reference-manifest.js +1 -1
  112. package/app/.next/server/app/api/usage/request-logs/route_client-reference-manifest.js +1 -1
  113. package/app/.next/server/app/api/usage/stats/route_client-reference-manifest.js +1 -1
  114. package/app/.next/server/app/api/usage/stream/route_client-reference-manifest.js +1 -1
  115. package/app/.next/server/app/api/v1/api/chat/route_client-reference-manifest.js +1 -1
  116. package/app/.next/server/app/api/v1/chat/completions/route_client-reference-manifest.js +1 -1
  117. package/app/.next/server/app/api/v1/embeddings/route_client-reference-manifest.js +1 -1
  118. package/app/.next/server/app/api/v1/messages/count_tokens/route_client-reference-manifest.js +1 -1
  119. package/app/.next/server/app/api/v1/messages/route_client-reference-manifest.js +1 -1
  120. package/app/.next/server/app/api/v1/models/route_client-reference-manifest.js +1 -1
  121. package/app/.next/server/app/api/v1/responses/route_client-reference-manifest.js +1 -1
  122. package/app/.next/server/app/api/v1/route_client-reference-manifest.js +1 -1
  123. package/app/.next/server/app/api/v1beta/models/[...path]/route_client-reference-manifest.js +1 -1
  124. package/app/.next/server/app/api/v1beta/models/route_client-reference-manifest.js +1 -1
  125. package/app/.next/server/app/api/version/route.js +1 -1
  126. package/app/.next/server/app/api/version/route_client-reference-manifest.js +1 -1
  127. package/app/.next/server/app/callback/page_client-reference-manifest.js +1 -1
  128. package/app/.next/server/app/callback.html +1 -1
  129. package/app/.next/server/app/callback.rsc +4 -4
  130. package/app/.next/server/app/callback.segments/_full.segment.rsc +4 -4
  131. package/app/.next/server/app/callback.segments/_head.segment.rsc +1 -1
  132. package/app/.next/server/app/callback.segments/_index.segment.rsc +4 -4
  133. package/app/.next/server/app/callback.segments/_tree.segment.rsc +2 -2
  134. package/app/.next/server/app/callback.segments/callback/__PAGE__.segment.rsc +1 -1
  135. package/app/.next/server/app/callback.segments/callback.segment.rsc +1 -1
  136. package/app/.next/server/app/dashboard/cli-tools.html +1 -1
  137. package/app/.next/server/app/dashboard/cli-tools.rsc +6 -6
  138. package/app/.next/server/app/dashboard/cli-tools.segments/!KGRhc2hib2FyZCk/dashboard/cli-tools/__PAGE__.segment.rsc +2 -2
  139. package/app/.next/server/app/dashboard/cli-tools.segments/!KGRhc2hib2FyZCk/dashboard/cli-tools.segment.rsc +1 -1
  140. package/app/.next/server/app/dashboard/cli-tools.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
  141. package/app/.next/server/app/dashboard/cli-tools.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
  142. package/app/.next/server/app/dashboard/cli-tools.segments/_full.segment.rsc +6 -6
  143. package/app/.next/server/app/dashboard/cli-tools.segments/_head.segment.rsc +1 -1
  144. package/app/.next/server/app/dashboard/cli-tools.segments/_index.segment.rsc +4 -4
  145. package/app/.next/server/app/dashboard/cli-tools.segments/_tree.segment.rsc +2 -2
  146. package/app/.next/server/app/dashboard/combos.html +1 -1
  147. package/app/.next/server/app/dashboard/combos.rsc +6 -6
  148. package/app/.next/server/app/dashboard/combos.segments/!KGRhc2hib2FyZCk/dashboard/combos/__PAGE__.segment.rsc +2 -2
  149. package/app/.next/server/app/dashboard/combos.segments/!KGRhc2hib2FyZCk/dashboard/combos.segment.rsc +1 -1
  150. package/app/.next/server/app/dashboard/combos.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
  151. package/app/.next/server/app/dashboard/combos.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
  152. package/app/.next/server/app/dashboard/combos.segments/_full.segment.rsc +6 -6
  153. package/app/.next/server/app/dashboard/combos.segments/_head.segment.rsc +1 -1
  154. package/app/.next/server/app/dashboard/combos.segments/_index.segment.rsc +4 -4
  155. package/app/.next/server/app/dashboard/combos.segments/_tree.segment.rsc +2 -2
  156. package/app/.next/server/app/dashboard/endpoint.html +1 -1
  157. package/app/.next/server/app/dashboard/endpoint.rsc +6 -6
  158. package/app/.next/server/app/dashboard/endpoint.segments/!KGRhc2hib2FyZCk/dashboard/endpoint/__PAGE__.segment.rsc +2 -2
  159. package/app/.next/server/app/dashboard/endpoint.segments/!KGRhc2hib2FyZCk/dashboard/endpoint.segment.rsc +1 -1
  160. package/app/.next/server/app/dashboard/endpoint.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
  161. package/app/.next/server/app/dashboard/endpoint.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
  162. package/app/.next/server/app/dashboard/endpoint.segments/_full.segment.rsc +6 -6
  163. package/app/.next/server/app/dashboard/endpoint.segments/_head.segment.rsc +1 -1
  164. package/app/.next/server/app/dashboard/endpoint.segments/_index.segment.rsc +4 -4
  165. package/app/.next/server/app/dashboard/endpoint.segments/_tree.segment.rsc +2 -2
  166. package/app/.next/server/app/dashboard/mitm.html +1 -1
  167. package/app/.next/server/app/dashboard/mitm.rsc +6 -6
  168. package/app/.next/server/app/dashboard/mitm.segments/!KGRhc2hib2FyZCk/dashboard/mitm/__PAGE__.segment.rsc +2 -2
  169. package/app/.next/server/app/dashboard/mitm.segments/!KGRhc2hib2FyZCk/dashboard/mitm.segment.rsc +1 -1
  170. package/app/.next/server/app/dashboard/mitm.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
  171. package/app/.next/server/app/dashboard/mitm.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
  172. package/app/.next/server/app/dashboard/mitm.segments/_full.segment.rsc +6 -6
  173. package/app/.next/server/app/dashboard/mitm.segments/_head.segment.rsc +1 -1
  174. package/app/.next/server/app/dashboard/mitm.segments/_index.segment.rsc +4 -4
  175. package/app/.next/server/app/dashboard/mitm.segments/_tree.segment.rsc +2 -2
  176. package/app/.next/server/app/dashboard/profile.html +1 -1
  177. package/app/.next/server/app/dashboard/profile.rsc +6 -6
  178. package/app/.next/server/app/dashboard/profile.segments/!KGRhc2hib2FyZCk/dashboard/profile/__PAGE__.segment.rsc +2 -2
  179. package/app/.next/server/app/dashboard/profile.segments/!KGRhc2hib2FyZCk/dashboard/profile.segment.rsc +1 -1
  180. package/app/.next/server/app/dashboard/profile.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
  181. package/app/.next/server/app/dashboard/profile.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
  182. package/app/.next/server/app/dashboard/profile.segments/_full.segment.rsc +6 -6
  183. package/app/.next/server/app/dashboard/profile.segments/_head.segment.rsc +1 -1
  184. package/app/.next/server/app/dashboard/profile.segments/_index.segment.rsc +4 -4
  185. package/app/.next/server/app/dashboard/profile.segments/_tree.segment.rsc +2 -2
  186. package/app/.next/server/app/dashboard/providers/new.html +1 -1
  187. package/app/.next/server/app/dashboard/providers/new.rsc +6 -6
  188. package/app/.next/server/app/dashboard/providers/new.segments/!KGRhc2hib2FyZCk/dashboard/providers/new/__PAGE__.segment.rsc +2 -2
  189. package/app/.next/server/app/dashboard/providers/new.segments/!KGRhc2hib2FyZCk/dashboard/providers/new.segment.rsc +1 -1
  190. package/app/.next/server/app/dashboard/providers/new.segments/!KGRhc2hib2FyZCk/dashboard/providers.segment.rsc +1 -1
  191. package/app/.next/server/app/dashboard/providers/new.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
  192. package/app/.next/server/app/dashboard/providers/new.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
  193. package/app/.next/server/app/dashboard/providers/new.segments/_full.segment.rsc +6 -6
  194. package/app/.next/server/app/dashboard/providers/new.segments/_head.segment.rsc +1 -1
  195. package/app/.next/server/app/dashboard/providers/new.segments/_index.segment.rsc +4 -4
  196. package/app/.next/server/app/dashboard/providers/new.segments/_tree.segment.rsc +2 -2
  197. package/app/.next/server/app/dashboard/providers.html +1 -1
  198. package/app/.next/server/app/dashboard/providers.rsc +6 -6
  199. package/app/.next/server/app/dashboard/providers.segments/!KGRhc2hib2FyZCk/dashboard/providers/__PAGE__.segment.rsc +2 -2
  200. package/app/.next/server/app/dashboard/providers.segments/!KGRhc2hib2FyZCk/dashboard/providers.segment.rsc +1 -1
  201. package/app/.next/server/app/dashboard/providers.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
  202. package/app/.next/server/app/dashboard/providers.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
  203. package/app/.next/server/app/dashboard/providers.segments/_full.segment.rsc +6 -6
  204. package/app/.next/server/app/dashboard/providers.segments/_head.segment.rsc +1 -1
  205. package/app/.next/server/app/dashboard/providers.segments/_index.segment.rsc +4 -4
  206. package/app/.next/server/app/dashboard/providers.segments/_tree.segment.rsc +2 -2
  207. package/app/.next/server/app/dashboard/proxy-pools.html +1 -1
  208. package/app/.next/server/app/dashboard/proxy-pools.rsc +6 -6
  209. package/app/.next/server/app/dashboard/proxy-pools.segments/!KGRhc2hib2FyZCk/dashboard/proxy-pools/__PAGE__.segment.rsc +2 -2
  210. package/app/.next/server/app/dashboard/proxy-pools.segments/!KGRhc2hib2FyZCk/dashboard/proxy-pools.segment.rsc +1 -1
  211. package/app/.next/server/app/dashboard/proxy-pools.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
  212. package/app/.next/server/app/dashboard/proxy-pools.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
  213. package/app/.next/server/app/dashboard/proxy-pools.segments/_full.segment.rsc +6 -6
  214. package/app/.next/server/app/dashboard/proxy-pools.segments/_head.segment.rsc +1 -1
  215. package/app/.next/server/app/dashboard/proxy-pools.segments/_index.segment.rsc +4 -4
  216. package/app/.next/server/app/dashboard/proxy-pools.segments/_tree.segment.rsc +2 -2
  217. package/app/.next/server/app/dashboard/quota.html +2 -2
  218. package/app/.next/server/app/dashboard/quota.rsc +7 -7
  219. package/app/.next/server/app/dashboard/quota.segments/!KGRhc2hib2FyZCk/dashboard/quota/__PAGE__.segment.rsc +3 -3
  220. package/app/.next/server/app/dashboard/quota.segments/!KGRhc2hib2FyZCk/dashboard/quota.segment.rsc +1 -1
  221. package/app/.next/server/app/dashboard/quota.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
  222. package/app/.next/server/app/dashboard/quota.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
  223. package/app/.next/server/app/dashboard/quota.segments/_full.segment.rsc +7 -7
  224. package/app/.next/server/app/dashboard/quota.segments/_head.segment.rsc +1 -1
  225. package/app/.next/server/app/dashboard/quota.segments/_index.segment.rsc +4 -4
  226. package/app/.next/server/app/dashboard/quota.segments/_tree.segment.rsc +2 -2
  227. package/app/.next/server/app/dashboard/settings/pricing/page.js +1 -1
  228. package/app/.next/server/app/dashboard/settings/pricing/page_client-reference-manifest.js +1 -1
  229. package/app/.next/server/app/dashboard/settings/pricing.html +1 -1
  230. package/app/.next/server/app/dashboard/settings/pricing.rsc +5 -5
  231. package/app/.next/server/app/dashboard/settings/pricing.segments/_full.segment.rsc +5 -5
  232. package/app/.next/server/app/dashboard/settings/pricing.segments/_head.segment.rsc +1 -1
  233. package/app/.next/server/app/dashboard/settings/pricing.segments/_index.segment.rsc +4 -4
  234. package/app/.next/server/app/dashboard/settings/pricing.segments/_tree.segment.rsc +2 -2
  235. package/app/.next/server/app/dashboard/settings/pricing.segments/dashboard/settings/pricing/__PAGE__.segment.rsc +2 -2
  236. package/app/.next/server/app/dashboard/settings/pricing.segments/dashboard/settings/pricing.segment.rsc +1 -1
  237. package/app/.next/server/app/dashboard/settings/pricing.segments/dashboard/settings.segment.rsc +1 -1
  238. package/app/.next/server/app/dashboard/settings/pricing.segments/dashboard.segment.rsc +1 -1
  239. package/app/.next/server/app/dashboard/translator.html +1 -1
  240. package/app/.next/server/app/dashboard/translator.rsc +6 -6
  241. package/app/.next/server/app/dashboard/translator.segments/!KGRhc2hib2FyZCk/dashboard/translator/__PAGE__.segment.rsc +2 -2
  242. package/app/.next/server/app/dashboard/translator.segments/!KGRhc2hib2FyZCk/dashboard/translator.segment.rsc +1 -1
  243. package/app/.next/server/app/dashboard/translator.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
  244. package/app/.next/server/app/dashboard/translator.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
  245. package/app/.next/server/app/dashboard/translator.segments/_full.segment.rsc +6 -6
  246. package/app/.next/server/app/dashboard/translator.segments/_head.segment.rsc +1 -1
  247. package/app/.next/server/app/dashboard/translator.segments/_index.segment.rsc +4 -4
  248. package/app/.next/server/app/dashboard/translator.segments/_tree.segment.rsc +2 -2
  249. package/app/.next/server/app/dashboard/usage.html +1 -1
  250. package/app/.next/server/app/dashboard/usage.rsc +6 -6
  251. package/app/.next/server/app/dashboard/usage.segments/!KGRhc2hib2FyZCk/dashboard/usage/__PAGE__.segment.rsc +2 -2
  252. package/app/.next/server/app/dashboard/usage.segments/!KGRhc2hib2FyZCk/dashboard/usage.segment.rsc +1 -1
  253. package/app/.next/server/app/dashboard/usage.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
  254. package/app/.next/server/app/dashboard/usage.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
  255. package/app/.next/server/app/dashboard/usage.segments/_full.segment.rsc +6 -6
  256. package/app/.next/server/app/dashboard/usage.segments/_head.segment.rsc +1 -1
  257. package/app/.next/server/app/dashboard/usage.segments/_index.segment.rsc +4 -4
  258. package/app/.next/server/app/dashboard/usage.segments/_tree.segment.rsc +2 -2
  259. package/app/.next/server/app/dashboard.html +1 -1
  260. package/app/.next/server/app/dashboard.rsc +6 -6
  261. package/app/.next/server/app/dashboard.segments/!KGRhc2hib2FyZCk/dashboard/__PAGE__.segment.rsc +2 -2
  262. package/app/.next/server/app/dashboard.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
  263. package/app/.next/server/app/dashboard.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
  264. package/app/.next/server/app/dashboard.segments/_full.segment.rsc +6 -6
  265. package/app/.next/server/app/dashboard.segments/_head.segment.rsc +1 -1
  266. package/app/.next/server/app/dashboard.segments/_index.segment.rsc +4 -4
  267. package/app/.next/server/app/dashboard.segments/_tree.segment.rsc +2 -2
  268. package/app/.next/server/app/index.html +1 -1
  269. package/app/.next/server/app/index.rsc +4 -4
  270. package/app/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  271. package/app/.next/server/app/index.segments/_full.segment.rsc +4 -4
  272. package/app/.next/server/app/index.segments/_head.segment.rsc +1 -1
  273. package/app/.next/server/app/index.segments/_index.segment.rsc +4 -4
  274. package/app/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  275. package/app/.next/server/app/landing/page_client-reference-manifest.js +1 -1
  276. package/app/.next/server/app/landing.html +1 -1
  277. package/app/.next/server/app/landing.rsc +5 -5
  278. package/app/.next/server/app/landing.segments/_full.segment.rsc +5 -5
  279. package/app/.next/server/app/landing.segments/_head.segment.rsc +1 -1
  280. package/app/.next/server/app/landing.segments/_index.segment.rsc +4 -4
  281. package/app/.next/server/app/landing.segments/_tree.segment.rsc +2 -2
  282. package/app/.next/server/app/landing.segments/landing/__PAGE__.segment.rsc +2 -2
  283. package/app/.next/server/app/landing.segments/landing.segment.rsc +1 -1
  284. package/app/.next/server/app/login/page_client-reference-manifest.js +1 -1
  285. package/app/.next/server/app/login.html +1 -1
  286. package/app/.next/server/app/login.rsc +5 -5
  287. package/app/.next/server/app/login.segments/_full.segment.rsc +5 -5
  288. package/app/.next/server/app/login.segments/_head.segment.rsc +1 -1
  289. package/app/.next/server/app/login.segments/_index.segment.rsc +4 -4
  290. package/app/.next/server/app/login.segments/_tree.segment.rsc +2 -2
  291. package/app/.next/server/app/login.segments/login/__PAGE__.segment.rsc +2 -2
  292. package/app/.next/server/app/login.segments/login.segment.rsc +1 -1
  293. package/app/.next/server/app/manifest.webmanifest/route.js.nft.json +1 -1
  294. package/app/.next/server/app/manifest.webmanifest/route_client-reference-manifest.js +1 -1
  295. package/app/.next/server/app/page_client-reference-manifest.js +1 -1
  296. package/app/.next/server/app-paths-manifest.json +40 -40
  297. package/app/.next/server/chunks/1114.js +1 -1
  298. package/app/.next/server/chunks/1424.js +1 -1
  299. package/app/.next/server/chunks/318.js +1 -1
  300. package/app/.next/server/chunks/3832.js +1 -1
  301. package/app/.next/server/chunks/412.js +1 -1
  302. package/app/.next/server/chunks/6182.js +1 -1
  303. package/app/.next/server/chunks/649.js +1 -1
  304. package/app/.next/server/chunks/7341.js +1 -1
  305. package/app/.next/server/chunks/8590.js +1 -1
  306. package/app/.next/server/chunks/9201.js +1 -1
  307. package/app/.next/server/chunks/9718.js +1 -1
  308. package/app/.next/server/middleware-build-manifest.js +1 -1
  309. package/app/.next/server/pages/404.html +1 -1
  310. package/app/.next/server/pages/500.html +2 -2
  311. package/app/.next/server/server-reference-manifest.js +1 -1
  312. package/app/.next/server/server-reference-manifest.json +1 -1
  313. package/app/.next/static/chunks/2652-51aca5cd32bd186f.js +1 -0
  314. package/app/.next/static/chunks/3794-23858078d298f399.js +2 -0
  315. package/app/.next/static/chunks/{4bd1b696-e5d7c65570c947b7.js → 4bd1b696-84e33c69f320f6a0.js} +1 -1
  316. package/app/.next/static/chunks/{5497-9933573cfe960e0c.js → 5497-ea854c092fddeb4d.js} +3 -3
  317. package/app/.next/static/chunks/{619-c4c101a6a78feeb4.js → 619-bfe7e89fff6eb942.js} +1 -1
  318. package/app/.next/static/chunks/{9242-3e0fdad972d9b35d.js → 9242-a85bb5812b359227.js} +3 -3
  319. package/app/.next/static/chunks/app/(dashboard)/dashboard/cli-tools/{page-d973cbda9e65d6ae.js → page-15fc16f73981b9be.js} +1 -1
  320. package/app/.next/static/chunks/app/(dashboard)/dashboard/mitm/page-fb6736d76c7a3b6a.js +1 -0
  321. package/app/.next/static/chunks/app/dashboard/settings/pricing/{page-4b7305b3e5d6e57b.js → page-e097c892258ad1fd.js} +1 -1
  322. package/app/.next/static/chunks/app/landing/{page-106f74afc6f71a31.js → page-cb9f1320605eaafc.js} +1 -1
  323. package/app/.next/static/chunks/app/{layout-08e56eacc7acf9e1.js → layout-095f249fd620f9cf.js} +1 -1
  324. package/app/.next/static/chunks/{framework-9f63a52f5ba18ac8.js → framework-6854168261815bb6.js} +1 -1
  325. package/app/.next/static/chunks/{main-aab9e1b069a77e0f.js → main-5b78d3de83609121.js} +2 -2
  326. package/app/.next/static/chunks/webpack-9bef9bba7ebc0551.js +1 -0
  327. package/app/.next/static/css/9dff3edaebe94c91.css +3 -0
  328. package/app/package.json +3 -1
  329. package/app/public/i18n/literals/ar.json +196 -0
  330. package/app/public/i18n/literals/bn.json +196 -0
  331. package/app/public/i18n/literals/cs.json +196 -0
  332. package/app/public/i18n/literals/da.json +196 -0
  333. package/app/public/i18n/literals/de.json +196 -0
  334. package/app/public/i18n/literals/el.json +196 -0
  335. package/app/public/i18n/literals/es.json +196 -0
  336. package/app/public/i18n/literals/fi.json +196 -0
  337. package/app/public/i18n/literals/fr.json +196 -0
  338. package/app/public/i18n/literals/he.json +196 -0
  339. package/app/public/i18n/literals/hi.json +196 -0
  340. package/app/public/i18n/literals/hu.json +196 -0
  341. package/app/public/i18n/literals/id.json +196 -0
  342. package/app/public/i18n/literals/it.json +196 -0
  343. package/app/public/i18n/literals/ja.json +196 -0
  344. package/app/public/i18n/literals/ko.json +196 -0
  345. package/app/public/i18n/literals/nl.json +196 -0
  346. package/app/public/i18n/literals/no.json +196 -0
  347. package/app/public/i18n/literals/pl.json +196 -0
  348. package/app/public/i18n/literals/pt-BR.json +196 -0
  349. package/app/public/i18n/literals/pt-PT.json +196 -0
  350. package/app/public/i18n/literals/ro.json +196 -0
  351. package/app/public/i18n/literals/ru.json +196 -0
  352. package/app/public/i18n/literals/sv.json +196 -0
  353. package/app/public/i18n/literals/th.json +196 -0
  354. package/app/public/i18n/literals/tl.json +196 -0
  355. package/app/public/i18n/literals/tr.json +196 -0
  356. package/app/public/i18n/literals/uk.json +196 -0
  357. package/app/public/i18n/literals/ur.json +196 -0
  358. package/app/public/i18n/literals/zh-TW.json +196 -0
  359. package/app/src/mitm/server.js +1 -297
  360. package/package.json +1 -1
  361. package/app/.next/static/chunks/2652-378fd4fa14847021.js +0 -1
  362. package/app/.next/static/chunks/3794-c67589461d449d62.js +0 -2
  363. package/app/.next/static/chunks/app/(dashboard)/dashboard/mitm/page-bf88929b2cc595ab.js +0 -1
  364. package/app/.next/static/chunks/webpack-25c43999146c934e.js +0 -1
  365. package/app/.next/static/css/4016074f63f34af9.css +0 -3
  366. package/app/src/mitm/cert/generate.js +0 -32
  367. package/app/src/mitm/cert/install.js +0 -176
  368. package/app/src/mitm/cert/rootCA.js +0 -173
  369. package/app/src/mitm/dns/dnsConfig.js +0 -216
  370. package/app/src/mitm/logger.js +0 -8
  371. package/app/src/mitm/manager.js +0 -602
  372. package/app/src/mitm/paths.js +0 -16
  373. package/app/src/mitm/server2.js +0 -1099
  374. /package/app/.next/static/{lSUZX6G8rzoxhxgvfuJ7I → k34dymG0FFBnm_nPA74jH}/_buildManifest.js +0 -0
  375. /package/app/.next/static/{lSUZX6G8rzoxhxgvfuJ7I → k34dymG0FFBnm_nPA74jH}/_ssgManifest.js +0 -0
@@ -1,1099 +0,0 @@
1
- const https = require("https");
2
- const fs = require("fs");
3
- const path = require("path");
4
- const dns = require("dns");
5
- const { promisify } = require("util");
6
- const Database = require("better-sqlite3");
7
-
8
- const CURSOR_GLOBAL_DB = path.join(
9
- process.env.HOME,
10
- "Library/Application Support/Cursor/User/globalStorage/state.vscdb"
11
- );
12
-
13
- // Read full conversation from Cursor global DB
14
- function readConversationFromDb(conversationId) {
15
- try {
16
- const db = new Database(CURSOR_GLOBAL_DB, { readonly: true, fileMustExist: true });
17
- const stmt = db.prepare("SELECT value FROM cursorDiskKV WHERE key=?");
18
-
19
- const row = stmt.get(`composerData:${conversationId}`);
20
- if (!row) { db.close(); return null; }
21
-
22
- const composer = JSON.parse(row.value);
23
- const headers = composer.fullConversationHeadersOnly || [];
24
- const name = composer.name || "";
25
-
26
- const messages = [];
27
- for (const h of headers) {
28
- const brow = stmt.get(`bubbleId:${conversationId}:${h.bubbleId}`);
29
- if (!brow) continue;
30
- const bubble = JSON.parse(brow.value);
31
- const role = h.type === 1 ? "user" : "assistant";
32
- const text = (bubble.text || "").trim();
33
- const ts = bubble.createdAt || null;
34
-
35
- // Tool call bubble (no text but has toolFormerData)
36
- const tool = bubble.toolFormerData && bubble.toolFormerData.name
37
- ? { name: bubble.toolFormerData.name, args: bubble.toolFormerData.rawArgs || null, status: bubble.toolFormerData.status || null }
38
- : null;
39
-
40
- if (!text && !tool) continue;
41
- messages.push({ role, text: text || null, tool, ts });
42
- }
43
-
44
- db.close();
45
- return { name, totalMessages: headers.length, messages };
46
- } catch (e) {
47
- return { error: e.message };
48
- }
49
- }
50
-
51
- const INTERNAL_REQUEST_HEADER = { name: "x-request-source", value: "local" };
52
-
53
- // All intercepted domains across all tools
54
- const TARGET_HOSTS = [
55
- "daily-cloudcode-pa.googleapis.com",
56
- "cloudcode-pa.googleapis.com",
57
- "api.individual.githubcopilot.com",
58
- ];
59
-
60
- const LOCAL_PORT = 443;
61
- const ROUTER_URL = "http://localhost:20128/v1/chat/completions";
62
- const API_KEY = process.env.ROUTER_API_KEY;
63
- const { DATA_DIR, MITM_DIR } = require("./paths");
64
- const DB_FILE = path.join(DATA_DIR, "db.json");
65
-
66
- const ENABLE_FILE_LOG = false;
67
- const CURSOR_LOG_DIR = path.join(__dirname, "../../logs/cursor");
68
- if (!fs.existsSync(CURSOR_LOG_DIR)) fs.mkdirSync(CURSOR_LOG_DIR, { recursive: true });
69
- const CURSOR_JSONL = path.join(CURSOR_LOG_DIR, "cursor_messages.jsonl");
70
-
71
- const CURSOR_ENDPOINTS = [
72
- "/agent.v1.AgentService/RunPoll",
73
- "/aiserver.v1.BidiService/BidiAppend",
74
- "/agent.v1.AgentService/Run",
75
- "/agent.v1.AgentService/RunSSE",
76
- ];
77
-
78
- // Mock rules: if last user message contains key → reply with value
79
- const MOCK_RULES = {
80
- "aaa": "bbb",
81
- };
82
-
83
- // conversationId → mock reply (set when AgentRunRequest matches a rule)
84
- const mockPending = new Map();
85
-
86
- /**
87
- * Decode Connect-RPC frame: [1 byte flags][4 bytes length][protobuf body]
88
- * Then walk raw protobuf fields and extract readable strings/numbers.
89
- */
90
- function decodeConnectFrame(buf) {
91
- if (!buf || buf.length < 5) return null;
92
- const msgLen = buf.readUInt32BE(1);
93
- if (buf.length < 5 + msgLen) return null;
94
- return decodeProtoRaw(buf.slice(5, 5 + msgLen));
95
- }
96
-
97
- function decodeProtoRaw(buf, depth = 0) {
98
- if (depth > 6) return {};
99
- const result = {};
100
- let offset = 0;
101
- try {
102
- while (offset < buf.length) {
103
- const tag = readVarint(buf, offset);
104
- if (!tag) break;
105
- offset += tag.bytes;
106
- const fieldNum = tag.value >> 3;
107
- const wireType = tag.value & 0x7;
108
-
109
- if (wireType === 0) {
110
- // varint
111
- const v = readVarint(buf, offset);
112
- if (!v) break;
113
- offset += v.bytes;
114
- result[`f${fieldNum}`] = v.value;
115
- } else if (wireType === 2) {
116
- // length-delimited: string, bytes, or nested message
117
- const lenV = readVarint(buf, offset);
118
- if (!lenV) break;
119
- offset += lenV.bytes;
120
- const data = buf.slice(offset, offset + lenV.value);
121
- offset += lenV.value;
122
- // Try as UTF-8 string first
123
- const str = data.toString("utf8");
124
- const isPrintable = /^[\x20-\x7E\n\r\t]*$/.test(str) && str.length > 0;
125
- if (isPrintable) {
126
- result[`f${fieldNum}`] = str;
127
- } else if (data.length > 0 && data.length < 4096) {
128
- // Try nested decode
129
- const nested = decodeProtoRaw(data, depth + 1);
130
- result[`f${fieldNum}`] = Object.keys(nested).length ? nested : data.toString("hex").substring(0, 64);
131
- }
132
- } else if (wireType === 5) {
133
- offset += 4;
134
- } else if (wireType === 1) {
135
- offset += 8;
136
- } else {
137
- break;
138
- }
139
- }
140
- } catch { /* best effort */ }
141
- return result;
142
- }
143
-
144
- function readVarint(buf, offset) {
145
- let value = 0, shift = 0, bytes = 0;
146
- while (offset + bytes < buf.length) {
147
- const b = buf[offset + bytes++];
148
- value |= (b & 0x7f) << shift;
149
- shift += 7;
150
- if (!(b & 0x80)) return { value, bytes };
151
- if (shift >= 28) break;
152
- }
153
- return null;
154
- }
155
-
156
- const zlib = require("zlib");
157
-
158
- /**
159
- * Deep decode protobuf buffer — returns structured object.
160
- * Tries to interpret each length-delimited field as:
161
- * 1. UTF-8 string (if fully printable)
162
- * 2. Nested proto message (recursive)
163
- * 3. Hex string fallback
164
- */
165
- function deepDecodeProto(buf, depth = 0) {
166
- if (depth > 10 || buf.length === 0) return null;
167
- const result = {};
168
- let off = 0;
169
- try {
170
- while (off < buf.length) {
171
- // Read varint tag
172
- let tag = 0, shift = 0;
173
- while (off < buf.length) {
174
- const b = buf[off++];
175
- tag |= (b & 0x7f) << shift;
176
- shift += 7;
177
- if (!(b & 0x80)) break;
178
- if (shift > 28) break;
179
- }
180
- if (tag === 0) break;
181
- const field = tag >> 3;
182
- const wire = tag & 7;
183
- const key = `f${field}`;
184
-
185
- if (wire === 0) {
186
- // varint
187
- let v = 0, s = 0;
188
- while (off < buf.length) {
189
- const b = buf[off++];
190
- v |= (b & 0x7f) << s;
191
- s += 7;
192
- if (!(b & 0x80)) break;
193
- }
194
- result[key] = v;
195
- } else if (wire === 2) {
196
- // length-delimited
197
- let len = 0, s = 0;
198
- while (off < buf.length) {
199
- const b = buf[off++];
200
- len |= (b & 0x7f) << s;
201
- s += 7;
202
- if (!(b & 0x80)) break;
203
- }
204
- if (off + len > buf.length || len < 0) break;
205
- const data = buf.slice(off, off + len);
206
- off += len;
207
-
208
- if (len === 0) {
209
- result[key] = "";
210
- continue;
211
- }
212
-
213
- // Try UTF-8 string
214
- const str = data.toString("utf8");
215
- const isPrintable = str.length > 0 && !/[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]/.test(str);
216
- if (isPrintable) {
217
- // Accumulate repeated fields as array
218
- if (key in result) {
219
- result[key] = [].concat(result[key], str);
220
- } else {
221
- result[key] = str;
222
- }
223
- continue;
224
- }
225
-
226
- // Try nested proto
227
- if (len >= 2 && len <= 500000) {
228
- const nested = deepDecodeProto(data, depth + 1);
229
- if (nested && Object.keys(nested).length > 0) {
230
- if (key in result) {
231
- result[key] = [].concat(result[key], [nested]);
232
- } else {
233
- result[key] = nested;
234
- }
235
- continue;
236
- }
237
- }
238
-
239
- // Fallback: hex (truncate at 64 bytes)
240
- result[key] = data.slice(0, 64).toString("hex");
241
- } else if (wire === 5) {
242
- off += 4;
243
- } else if (wire === 1) {
244
- off += 8;
245
- } else {
246
- break;
247
- }
248
- }
249
- } catch { /* best effort */ }
250
- return result;
251
- }
252
-
253
- // ── Proto helpers ──────────────────────────────────────────────
254
- function protoReadVarint(buf, off) {
255
- let v = 0, shift = 0;
256
- while (off < buf.length) {
257
- const b = buf[off++];
258
- v |= (b & 0x7f) << shift;
259
- shift += 7;
260
- if (!(b & 0x80)) return { v, off };
261
- if (shift > 49) break;
262
- }
263
- return null;
264
- }
265
-
266
- function protoWalkFields(buf) {
267
- const fields = [];
268
- let off = 0;
269
- while (off < buf.length) {
270
- const t = protoReadVarint(buf, off);
271
- if (!t || t.v === 0) break;
272
- off = t.off;
273
- const field = t.v >> 3, wire = t.v & 7;
274
- if (wire === 0) {
275
- const r = protoReadVarint(buf, off);
276
- if (!r) break;
277
- off = r.off;
278
- fields.push({ field, wire, value: r.v });
279
- } else if (wire === 2) {
280
- const r = protoReadVarint(buf, off);
281
- if (!r) break;
282
- off = r.off;
283
- if (off + r.v > buf.length) break;
284
- fields.push({ field, wire, data: buf.slice(off, off + r.v) });
285
- off += r.v;
286
- } else if (wire === 5) { off += 4; }
287
- else if (wire === 1) { off += 8; }
288
- else break;
289
- }
290
- return fields;
291
- }
292
-
293
- function protoStr(buf) {
294
- if (!buf || buf.length === 0) return null;
295
- const s = buf.toString("utf8");
296
- return /[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]/.test(s) ? null : s;
297
- }
298
-
299
- // ── Schema-aware decoders ──────────────────────────────────────
300
-
301
- // BidiAppendRequest: f1=data(hex-encoded AgentClientMessage), f2=requestId{f1=uuid}, f3=seqno
302
- function decodeBidiAppend(buf) {
303
- const fields = protoWalkFields(buf);
304
- const result = {};
305
- for (const f of fields) {
306
- if (f.field === 1 && f.data) {
307
- // f1.data is ASCII hex string → decode to actual proto bytes
308
- try {
309
- const hexStr = f.data.toString("utf8");
310
- const protoBytes = Buffer.from(hexStr, "hex");
311
- result.agentMsg = decodeAgentClientMsg(protoBytes);
312
- } catch { result.agentMsg = { type: "hex_decode_error" }; }
313
- } else if (f.field === 2 && f.data) {
314
- const inner = protoWalkFields(f.data);
315
- const id = inner.find(x => x.field === 1 && x.data);
316
- result.requestId = id ? protoStr(id.data) : null;
317
- } else if (f.field === 3) result.seqno = f.value;
318
- }
319
- return result;
320
- }
321
-
322
- // AgentClientMessage oneof: f1=AgentRunRequest, f2=ExecClientMessage, f3=KvClientMessage, f4=ConversationAction, f5=ExecClientControlMessage, f6=InteractionResponse, f7=ClientHeartbeat
323
- function decodeAgentClientMsg(buf) {
324
- const fields = protoWalkFields(buf);
325
- for (const f of fields) {
326
- // f7=ClientHeartbeat: wire-type 2 but empty (len=0), data is Buffer(0)
327
- if (f.field === 7) return { type: "ClientHeartbeat" };
328
- if (f.data === undefined || f.data === null) continue;
329
- if (f.field === 1 && f.data.length > 0) return { type: "AgentRunRequest", ...decodeAgentRunRequest(f.data) };
330
- if (f.field === 2 && f.data.length > 0) return { type: "ExecClientMessage", ...decodeExecClientMessage(f.data) };
331
- if (f.field === 3) return { type: "KvClientMessage" };
332
- if (f.field === 4 && f.data.length > 0) return { type: "ConversationAction", ...decodeConversationAction(f.data) };
333
- if (f.field === 5) return { type: "ExecClientControlMessage" };
334
- if (f.field === 6) return { type: "InteractionResponse" };
335
- }
336
- return { type: "unknown" };
337
- }
338
-
339
- // AgentRunRequest: f1=conversation_state, f2=action, f3=model_details, f4=mcp_tools, f5=conversation_id, f6=mcp_file_system_options, f7=skill_options
340
- function decodeAgentRunRequest(buf) {
341
- const fields = protoWalkFields(buf);
342
- const result = {};
343
-
344
- for (const f of fields) {
345
- if (f.field === 1 && f.data) result.state = decodeConversationState(f.data);
346
- if (f.field === 2 && f.data) result.action = decodeConversationAction(f.data);
347
- if (f.field === 3 && f.data) result.model = decodeModelDetails(f.data);
348
- if (f.field === 4 && f.data) result.mcpTools = decodeMcpTools(f.data);
349
- if (f.field === 5 && f.data) result.conversationId = protoStr(f.data);
350
- }
351
- return result;
352
- }
353
-
354
- // McpTools: f1=repeated McpDescriptor (f1=serverName, f2=repeated tools)
355
- function decodeMcpTools(buf) {
356
- const fields = protoWalkFields(buf);
357
- const descriptors = [];
358
- for (const f of fields) {
359
- if (f.field === 1 && f.data) {
360
- const inner = protoWalkFields(f.data);
361
- const name = inner.find(x => x.field === 1 && x.data);
362
- const tools = inner.filter(x => x.field === 2 && x.data).map(t => {
363
- const tf = protoWalkFields(t.data);
364
- const tname = tf.find(x => x.field === 1 && x.data);
365
- return tname ? protoStr(tname.data) : null;
366
- }).filter(Boolean);
367
- descriptors.push({ server: name ? protoStr(name.data) : null, tools });
368
- }
369
- }
370
- return descriptors;
371
- }
372
-
373
- // ExecClientMessage: f1=id(uint32), f2=shellResult, f3=writeResult, etc.
374
- function decodeExecClientMessage(buf) {
375
- const fields = protoWalkFields(buf);
376
- const result = { id: null, execId: null, resultType: "unknown" };
377
- for (const f of fields) {
378
- if (f.field === 1 && f.value !== undefined) result.id = f.value;
379
- if (f.field === 15 && f.data) result.execId = protoStr(f.data);
380
- // Detect result type by field number (oneof)
381
- const resultTypes = { 2: "shellResult", 3: "writeResult", 4: "deleteResult", 5: "grepResult", 7: "readResult", 8: "lsResult", 9: "diagnosticsResult", 10: "requestContextResult", 11: "mcpResult", 14: "shellStream", 16: "backgroundShellSpawnResult" };
382
- if (f.data && resultTypes[f.field]) result.resultType = resultTypes[f.field];
383
- }
384
- return result;
385
- }
386
-
387
- // ModelDetails — scan all string fields
388
- function decodeModelDetails(buf) {
389
- const fields = protoWalkFields(buf);
390
- const result = {};
391
- for (const f of fields) {
392
- if (f.data) {
393
- const s = protoStr(f.data);
394
- if (s && s.length > 0) result[`f${f.field}`] = s;
395
- } else if (f.value !== undefined) {
396
- result[`f${f.field}`] = f.value;
397
- }
398
- }
399
- return result;
400
- }
401
-
402
- // ConversationAction: f1=StartChatAction → f1=userMsg{f1=text,f2=uuid,f8=lexical}, f2=history{f2=contextFiles,f7=tools}
403
- function decodeConversationAction(buf) {
404
- const result = {};
405
- const topFields = protoWalkFields(buf);
406
-
407
- // action.f1 = StartChatAction wrapper
408
- const f1 = topFields.find(f => f.field === 1 && f.data && f.data.length > 0);
409
- if (!f1) {
410
- // No StartChatAction — show which fields are present for debugging
411
- const presentFields = topFields.map(f => `f${f.field}`);
412
- if (presentFields.length > 0) result._fields = presentFields;
413
- return result;
414
- }
415
- const f1Fields = protoWalkFields(f1.data);
416
-
417
- // ── User message: action.f1.f1 ──────────────────────────────
418
- const f1f1 = f1Fields.find(f => f.field === 1 && f.data);
419
- if (f1f1) {
420
- for (const f of protoWalkFields(f1f1.data)) {
421
- if (!f.data) continue;
422
- const s = protoStr(f.data);
423
- if (f.field === 1 && s) result.text = s;
424
- if (f.field === 2 && s) result.messageId = s;
425
- if (f.field === 8 && s) {
426
- try {
427
- const lex = JSON.parse(s);
428
- const texts = [];
429
- function extractLexText(node) {
430
- if (node?.text) texts.push(node.text);
431
- (node?.children || []).forEach(extractLexText);
432
- }
433
- extractLexText(lex?.root);
434
- result.textFull = texts.join("");
435
- } catch { result.lexical = s.substring(0, 300); }
436
- }
437
- }
438
- }
439
-
440
- // ── Conversation history: action.f1.f2 ──────────────────────
441
- const f1f2 = f1Fields.find(f => f.field === 2 && f.data);
442
- if (f1f2) {
443
- const histFields = protoWalkFields(f1f2.data);
444
-
445
- // f2 repeated = context files (rules, open files...)
446
- result.contextFiles = histFields
447
- .filter(f => f.field === 2 && f.data)
448
- .map(t => {
449
- const tf = protoWalkFields(t.data);
450
- const name = tf.find(f => f.field === 1 && f.data);
451
- const content = tf.find(f => f.field === 2 && f.data);
452
- return {
453
- path: name ? protoStr(name.data) : null,
454
- content: content ? protoStr(content.data)?.substring(0, 500) : null,
455
- };
456
- })
457
- .filter(x => x.path);
458
-
459
- // f7 repeated = MCP tools
460
- result.tools = histFields
461
- .filter(f => f.field === 7 && f.data)
462
- .map(t => {
463
- const tf = protoWalkFields(t.data);
464
- const name = tf.find(f => f.field === 1 && f.data);
465
- const desc = tf.find(f => f.field === 2 && f.data);
466
- return {
467
- name: name ? protoStr(name.data) : null,
468
- description: desc ? protoStr(desc.data) : null,
469
- };
470
- })
471
- .filter(x => x.name);
472
-
473
- }
474
-
475
- return result;
476
- }
477
-
478
- /**
479
- * Recursively decode any proto buffer into a plain JS object for debugging.
480
- * Each field: try UTF-8 string → nested proto → hex fallback.
481
- * Repeated fields become arrays.
482
- */
483
- function protoTreeToObj(buf, depth = 0) {
484
- if (depth > 12 || !buf || buf.length === 0) return null;
485
- const result = {};
486
- const fields = protoWalkFields(buf);
487
- for (const f of fields) {
488
- const key = `f${f.field}`;
489
- let val;
490
- if (f.data !== undefined) {
491
- const s = protoStr(f.data);
492
- if (s !== null) {
493
- // Detect hex-encoded proto (BidiAppend.data field)
494
- if (/^[0-9a-f]{20,}$/i.test(s)) {
495
- try {
496
- const dec = protoTreeToObj(Buffer.from(s, "hex"), depth + 1);
497
- val = (dec && Object.keys(dec).length > 0) ? dec : s;
498
- } catch { val = s; }
499
- } else {
500
- try { val = JSON.parse(s); } catch { val = s; }
501
- }
502
- } else if (f.data.length > 0) {
503
- const nested = protoTreeToObj(f.data, depth + 1);
504
- val = (nested && Object.keys(nested).length > 0)
505
- ? nested
506
- : f.data.toString("hex");
507
- } else {
508
- val = "";
509
- }
510
- } else {
511
- val = f.value;
512
- }
513
- // Accumulate repeated fields as array
514
- if (key in result) {
515
- result[key] = [].concat(result[key], [val]);
516
- } else {
517
- result[key] = val;
518
- }
519
- }
520
- return result;
521
- }
522
-
523
- // ConversationStateStructure: f1=root_prompt_messages_json(encrypted bytes), f3=todos, f8=turns, f10=mode
524
- function decodeConversationState(buf) {
525
- const fields = protoWalkFields(buf);
526
- const turns = [], todos = [];
527
- let mode = null, messageCount = 0;
528
- for (const f of fields) {
529
- if (f.field === 10 && f.value !== undefined) {
530
- const modes = ["unspecified", "agent", "ask", "plan", "debug", "triage"];
531
- mode = modes[f.value] || `mode_${f.value}`;
532
- }
533
- if (!f.data) continue;
534
- if (f.field === 1) {
535
- // Encrypted bytes — just count, cannot decode
536
- messageCount++;
537
- } else if (f.field === 8) {
538
- // f8 = repeated bytes (ConversationTurn OR encrypted blob)
539
- // Encrypted turns: binary blobs that don't parse as valid proto strings
540
- if (f.data.length === 32) continue; // 32-byte encrypted blob
541
- const inner = protoWalkFields(f.data);
542
- const strs = inner.filter(x => x.data).map(x => protoStr(x.data)).filter(s => s && s.length > 3);
543
- if (strs.length) turns.push(strs.slice(0, 3));
544
- } else if (f.field === 3) {
545
- // f3 = repeated bytes (TodoItem OR encrypted blob)
546
- // Encrypted: 32-byte binary (shows as 64-char hex in protoStr-reject path)
547
- // TodoItem: f1=id(str), f2=content(str), f3=status(varint)
548
- if (f.data.length === 32) {
549
- // 32 bytes = encrypted blob, skip
550
- continue;
551
- }
552
- const inner = protoWalkFields(f.data);
553
- const id = inner.find(x => x.field === 1 && x.data);
554
- const content = inner.find(x => x.field === 2 && x.data);
555
- const status = inner.find(x => x.field === 3 && x.value !== undefined);
556
- const idStr = id ? protoStr(id.data) : null;
557
- const contentStr = content ? protoStr(content.data) : null;
558
- // If neither id nor content is readable string, it's encrypted
559
- if (!idStr && !contentStr) continue;
560
- const statusMap = ["unspecified", "pending", "in_progress", "completed", "cancelled"];
561
- todos.push({
562
- id: idStr,
563
- content: contentStr,
564
- status: status ? (statusMap[status.value] || `status_${status.value}`) : null,
565
- });
566
- }
567
- }
568
- return { mode, messageCount, turns: turns.slice(0, 5), todos: todos.slice(0, 20) };
569
- }
570
-
571
- // ── Save per-chat JSON file ────────────────────────────────────
572
- // Only logs AgentRunRequest and ExecClientMessage — skips noise (RunPoll, KvClientMessage, ClientHeartbeat...)
573
- function saveCursorLogFull(url, headers, buf) {
574
- try {
575
- if (buf.length < 5) return;
576
- if (!url.includes("BidiAppend")) return;
577
-
578
- const isGzip = buf[0] === 0x1f && buf[1] === 0x8b;
579
- const raw = isGzip ? zlib.gunzipSync(buf) : (buf[0] === 0x00 || buf[0] === 0x01 ? buf.slice(5) : buf);
580
-
581
- const decoded = decodeBidiAppend(raw);
582
- const msgType = decoded?.agentMsg?.type;
583
-
584
- // Only log meaningful message types
585
- if (msgType !== "AgentRunRequest" && msgType !== "ExecClientMessage") return;
586
-
587
- const action = decoded?.agentMsg?.action || {};
588
- const userMessage = action.textFull || action.text || null;
589
-
590
- // Fetch full conversation from DB for AgentRunRequest
591
- const conversationId = decoded?.agentMsg?.conversationId || null;
592
- let conversation = null;
593
- if (conversationId && msgType === "AgentRunRequest") {
594
- conversation = readConversationFromDb(conversationId);
595
-
596
- // Check MOCK_RULES against last user message
597
- const lastMsg = userMessage || "";
598
- for (const [keyword, reply] of Object.entries(MOCK_RULES)) {
599
- if (lastMsg.toLowerCase().includes(keyword.toLowerCase())) {
600
- mockPending.set(conversationId, reply);
601
- console.log(`[MOCK] Triggered rule "${keyword}" → "${reply}" for conv=${conversationId}`);
602
- break;
603
- }
604
- }
605
- }
606
-
607
- const ts = new Date().toISOString().replace(/[:.]/g, "-");
608
- fs.writeFileSync(
609
- path.join(CURSOR_LOG_DIR, `${ts}_${msgType}_chat.json`),
610
- JSON.stringify({
611
- ts: new Date().toISOString(),
612
- type: msgType,
613
- version: headers["x-cursor-client-version"] || null,
614
- sizeIn: buf.length,
615
- userMessage,
616
- decoded,
617
- conversation,
618
- }, null, 2)
619
- );
620
-
621
- const convName = conversation?.name ? ` | conv="${conversation.name}" (${conversation.totalMessages} msgs)` : "";
622
- console.log(`[CURSOR] ${msgType} | msg=${userMessage || "(none)"}${convName} | ${buf.length}B`);
623
- } catch (e) {
624
- console.error(`[CURSOR] decode error: ${e.message}`);
625
- }
626
- }
627
-
628
- if (!API_KEY) {
629
- console.error("❌ ROUTER_API_KEY required");
630
- process.exit(1);
631
- }
632
-
633
- const { getCertForDomain } = require("./cert/generate");
634
-
635
- // Certificate cache for performance
636
- const certCache = new Map();
637
-
638
- // SNI callback for dynamic certificate generation
639
- function sniCallback(servername, cb) {
640
- try {
641
- // Check cache first
642
- if (certCache.has(servername)) {
643
- const cached = certCache.get(servername);
644
- return cb(null, cached);
645
- }
646
-
647
- // Generate new cert for this domain
648
- const certData = getCertForDomain(servername);
649
- if (!certData) {
650
- return cb(new Error(`Failed to generate cert for ${servername}`));
651
- }
652
-
653
- // Create secure context
654
- const ctx = require("tls").createSecureContext({
655
- key: certData.key,
656
- cert: certData.cert
657
- });
658
-
659
- // Cache it
660
- certCache.set(servername, ctx);
661
- console.log(`✅ Generated cert for: ${servername}`);
662
-
663
- cb(null, ctx);
664
- } catch (error) {
665
- console.error(`❌ SNI error for ${servername}:`, error.message);
666
- cb(error);
667
- }
668
- }
669
-
670
- // Load Root CA for default context
671
- const certDir = MITM_DIR;
672
- const rootCAKeyPath = path.join(certDir, "rootCA.key");
673
- const rootCACertPath = path.join(certDir, "rootCA.crt");
674
-
675
- let sslOptions;
676
- try {
677
- sslOptions = {
678
- key: fs.readFileSync(rootCAKeyPath),
679
- cert: fs.readFileSync(rootCACertPath),
680
- SNICallback: sniCallback
681
- };
682
- } catch (e) {
683
- console.error(`❌ Root CA not found in ${certDir}: ${e.message}`);
684
- process.exit(1);
685
- }
686
-
687
- // Antigravity: Gemini generateContent endpoints
688
- const ANTIGRAVITY_URL_PATTERNS = [":generateContent", ":streamGenerateContent"];
689
- // Copilot: OpenAI-compatible + Anthropic endpoints
690
- const COPILOT_URL_PATTERNS = ["/chat/completions", "/v1/messages", "/responses"];
691
-
692
- const LOG_DIR = path.join(__dirname, "../../logs/mitm");
693
- if (ENABLE_FILE_LOG && !fs.existsSync(LOG_DIR)) fs.mkdirSync(LOG_DIR, { recursive: true });
694
-
695
- function saveRequestLog(url, bodyBuffer) {
696
- if (!ENABLE_FILE_LOG) return;
697
- try {
698
- const ts = new Date().toISOString().replace(/[:.]/g, "-");
699
- const urlSlug = url.replace(/[^a-zA-Z0-9]/g, "_").substring(0, 60);
700
- const filePath = path.join(LOG_DIR, `${ts}_${urlSlug}.json`);
701
- const body = JSON.parse(bodyBuffer.toString());
702
- fs.writeFileSync(filePath, JSON.stringify(body, null, 2));
703
- } catch { /* ignore */ }
704
- }
705
-
706
- const cachedTargetIPs = {};
707
- async function resolveTargetIP(hostname) {
708
- if (cachedTargetIPs[hostname]) return cachedTargetIPs[hostname];
709
- const resolver = new dns.Resolver();
710
- resolver.setServers(["8.8.8.8"]);
711
- const resolve4 = promisify(resolver.resolve4.bind(resolver));
712
- const addresses = await resolve4(hostname);
713
- cachedTargetIPs[hostname] = addresses[0];
714
- return cachedTargetIPs[hostname];
715
- }
716
-
717
- function collectBodyRaw(req) {
718
- return new Promise((resolve, reject) => {
719
- const chunks = [];
720
- req.on("data", chunk => chunks.push(chunk));
721
- req.on("end", () => resolve(Buffer.concat(chunks)));
722
- req.on("error", reject);
723
- });
724
- }
725
-
726
- // Extract model from URL path (Gemini) or body (OpenAI/Anthropic)
727
- function extractModel(url, body) {
728
- const urlMatch = url.match(/\/models\/([^/:]+)/);
729
- if (urlMatch) return urlMatch[1];
730
- try { return JSON.parse(body.toString()).model || null; } catch { return null; }
731
- }
732
-
733
- function getMappedModel(tool, model) {
734
- if (!model) return null;
735
- try {
736
- if (!fs.existsSync(DB_FILE)) return null;
737
- const db = JSON.parse(fs.readFileSync(DB_FILE, "utf-8"));
738
- return db.mitmAlias?.[tool]?.[model] || null;
739
- } catch {
740
- return null;
741
- }
742
- }
743
-
744
- /**
745
- * Determine which tool this request belongs to based on hostname
746
- */
747
- function getToolForHost(host) {
748
- const h = (host || "").split(":")[0];
749
- if (h === "api.individual.githubcopilot.com") return "copilot";
750
- if (h === "daily-cloudcode-pa.googleapis.com" || h === "cloudcode-pa.googleapis.com") return "antigravity";
751
- return null;
752
- }
753
-
754
- /**
755
- * Encode a single protobuf length-delimited field: (fieldNum << 3 | wireType) + varint(len) + bytes
756
- * wireType 2 = length-delimited, wireType 0 = varint
757
- */
758
- function protoEncodeField(fieldNum, wireType, data) {
759
- const tag = (fieldNum << 3) | wireType;
760
- const tagBuf = encodeVarint(tag);
761
- if (wireType === 2) {
762
- const lenBuf = encodeVarint(data.length);
763
- return Buffer.concat([tagBuf, lenBuf, data]);
764
- }
765
- // wireType 0: data is already a varint buffer
766
- return Buffer.concat([tagBuf, data]);
767
- }
768
-
769
- function encodeVarint(n) {
770
- const bufs = [];
771
- while (n > 0x7f) {
772
- bufs.push((n & 0x7f) | 0x80);
773
- n >>>= 7;
774
- }
775
- bufs.push(n & 0x7f);
776
- return Buffer.from(bufs);
777
- }
778
-
779
- /**
780
- * Build a Connect-RPC streaming frame: [flags=0][4-byte big-endian length][body]
781
- */
782
- function buildConnectFrame(body) {
783
- const lenBuf = Buffer.alloc(4);
784
- lenBuf.writeUInt32BE(body.length, 0);
785
- return Buffer.concat([Buffer.from([0x00]), lenBuf, body]);
786
- }
787
-
788
- /**
789
- * Build one gzip-compressed Connect-RPC data frame containing a BidiPollResponse.
790
- * BidiPollResponse: f1=seqno(varint), f2=data(hex string of AgentServerMessage)
791
- * AgentServerMessage.f1 = InteractionUpdate.f1 = TextDeltaUpdate.f1 = text
792
- */
793
- function buildFakePollFrame(text, seqno) {
794
- const zlib = require("zlib");
795
-
796
- // TextDeltaUpdate { f1: text }
797
- const textDelta = protoEncodeField(1, 2, Buffer.from(text, "utf8"));
798
- // InteractionUpdate { f1: TextDeltaUpdate }
799
- const interactionUpdate = protoEncodeField(1, 2, textDelta);
800
- // AgentServerMessage { f1: InteractionUpdate }
801
- const agentMsg = protoEncodeField(1, 2, interactionUpdate);
802
-
803
- // BidiPollResponse { f1: seqno, f2: hex(agentMsg) }
804
- let pollResp = protoEncodeField(1, 0, encodeVarint(seqno));
805
- pollResp = Buffer.concat([pollResp, protoEncodeField(2, 2, Buffer.from(agentMsg.toString("hex"), "utf8"))]);
806
-
807
- // Gzip compress (flags=1)
808
- const compressed = zlib.gzipSync(pollResp);
809
- const lenBuf = Buffer.alloc(4);
810
- lenBuf.writeUInt32BE(compressed.length, 0);
811
- return Buffer.concat([Buffer.from([0x01]), lenBuf, compressed]);
812
- }
813
-
814
- /**
815
- * Build Connect-RPC end-of-stream trailer frame: flags=0x02, body={}
816
- */
817
- function buildTrailerFrame() {
818
- const body = Buffer.from("{}", "utf8");
819
- const lenBuf = Buffer.alloc(4);
820
- lenBuf.writeUInt32BE(body.length, 0);
821
- return Buffer.concat([Buffer.from([0x02]), lenBuf, body]);
822
- }
823
-
824
- /**
825
- * Send fake RunPoll response matching real Cursor server format
826
- */
827
- function sendMockResponse(res, replyText) {
828
- res.writeHead(200, {
829
- "content-type": "application/connect+proto",
830
- "transfer-encoding": "chunked",
831
- });
832
-
833
- // Send text as single frame + trailer
834
- res.write(buildFakePollFrame(replyText, 1));
835
- res.write(buildTrailerFrame());
836
- res.end();
837
- console.log(`[MOCK] RunPoll → "${replyText}"`);
838
- }
839
-
840
- async function passthrough(req, res, bodyBuffer, captureFile = null) {
841
- const targetHost = (req.headers.host || TARGET_HOSTS[0]).split(":")[0];
842
- const targetIP = await resolveTargetIP(targetHost);
843
-
844
- const forwardReq = https.request({
845
- hostname: targetIP,
846
- port: 443,
847
- path: req.url,
848
- method: req.method,
849
- headers: { ...req.headers, host: targetHost },
850
- servername: targetHost,
851
- rejectUnauthorized: false
852
- }, (forwardRes) => {
853
- // Log headers + first frame raw bytes of first RunPoll response for mock calibration
854
- if (req.url.includes("RunPoll") && !passthrough._loggedRunPollHeaders) {
855
- passthrough._loggedRunPollHeaders = true;
856
- console.log("[DBG] RunPoll headers:", JSON.stringify(forwardRes.headers));
857
- const origWrite = res.write.bind(res);
858
- let logged = false;
859
- res.write = function(chunk) {
860
- if (!logged) {
861
- logged = true;
862
- console.log("[DBG] RunPoll first chunk hex:", Buffer.isBuffer(chunk) ? chunk.slice(0, 80).toString("hex") : Buffer.from(chunk).slice(0, 80).toString("hex"));
863
- }
864
- return origWrite(chunk);
865
- };
866
- }
867
- res.writeHead(forwardRes.statusCode, forwardRes.headers);
868
-
869
- if (!captureFile) {
870
- forwardRes.pipe(res);
871
- return;
872
- }
873
-
874
- // Tee response: forward to client AND decode+save to file
875
- const chunks = [];
876
- forwardRes.on("data", chunk => {
877
- chunks.push(chunk);
878
- res.write(chunk);
879
- });
880
- forwardRes.on("end", () => {
881
- res.end();
882
- try {
883
- const raw = Buffer.concat(chunks);
884
- // Save first RunPoll raw that has text (frames > 20)
885
- if (req.url.includes("RunPoll") && !passthrough._savedTextRaw && frameCount > 20) {
886
- passthrough._savedTextRaw = true;
887
- fs.writeFileSync(path.join(CURSOR_LOG_DIR, "_runpoll_text_raw.hex"), raw.toString("hex"));
888
- console.log("[DBG] RunPoll TEXT raw saved, len=", raw.length, "frames=", frameCount);
889
- }
890
- // Decode Connect-RPC streaming frames: each frame = [1B flags][4B len][proto body]
891
- const textChunks = [];
892
- const toolCalls = [];
893
- let frameCount = 0;
894
- let offset = 0;
895
-
896
- while (offset + 5 <= raw.length) {
897
- const flags = raw[offset];
898
- const msgLen = raw.readUInt32BE(offset + 1);
899
- if (offset + 5 + msgLen > raw.length) break;
900
- let body = raw.slice(offset + 5, offset + 5 + msgLen);
901
- offset += 5 + msgLen;
902
- frameCount++;
903
-
904
- // Decompress gzip frame (flags=1)
905
- if (flags === 1) {
906
- try { body = zlib.gunzipSync(body); } catch { continue; }
907
- }
908
-
909
- // BidiPollResponse: f1=seqno(varint), f2=data(hex-encoded AgentServerMessage)
910
- const pollFields = protoWalkFields(body);
911
- const dataField = pollFields.find(f => f.field === 2 && f.data);
912
- if (!dataField) continue;
913
-
914
- // f2.data is ASCII hex string → decode to actual AgentServerMessage bytes
915
- const hexStr = dataField.data.toString("utf8");
916
- if (!/^[0-9a-f]+$/i.test(hexStr)) continue;
917
- const agentMsg = Buffer.from(hexStr, "hex");
918
-
919
- // AgentServerMessage: f1=InteractionUpdate, f2=ExecServerMessage
920
- const agentFields = protoWalkFields(agentMsg);
921
-
922
- // f1 = InteractionUpdate → f1=TextDeltaUpdate.f1=text
923
- const interactionUpdate = agentFields.find(f => f.field === 1 && f.data);
924
- if (interactionUpdate) {
925
- const iuFields = protoWalkFields(interactionUpdate.data);
926
- const textDelta = iuFields.find(f => f.field === 1 && f.data);
927
- if (textDelta) {
928
- const tdFields = protoWalkFields(textDelta.data);
929
- const textField = tdFields.find(f => f.field === 1 && f.data);
930
- if (textField) {
931
- const text = textField.data.toString("utf8");
932
- if (text.length > 0) textChunks.push(text);
933
- }
934
- }
935
- }
936
-
937
- // f2 = ExecServerMessage → decode tool call
938
- // ExecServerMessage: f1=id(varint), f15=exec_id(str), f2=shell, f3=write, f4=delete, f5=grep, f7=read, f8=ls
939
- const execMsg = agentFields.find(f => f.field === 2 && f.data);
940
- if (execMsg) {
941
- const execFields = protoWalkFields(execMsg.data);
942
- const toolFieldMap = { 2: "shell", 3: "write", 4: "delete", 5: "grep", 7: "read", 8: "ls", 11: "mcp", 14: "shell_stream", 20: "fetch" };
943
- const toolField = execFields.find(f => toolFieldMap[f.field] && f.data);
944
- if (toolField) {
945
- const toolName = toolFieldMap[toolField.field];
946
- // Extract first string field as main arg (command/path)
947
- const argFields = protoWalkFields(toolField.data);
948
- const mainArg = argFields.find(f => f.field === 1 && f.data);
949
- const arg = mainArg ? mainArg.data.toString("utf8") : null;
950
- toolCalls.push({ tool: toolName, arg });
951
- }
952
- }
953
- }
954
-
955
- const assembled = textChunks.length > 0 ? textChunks.join("") : null;
956
- // Only save file if there's actual content
957
- if (assembled || toolCalls.length > 0) {
958
- const entry = { ts: new Date().toISOString(), frames: frameCount };
959
- if (assembled) entry.text = assembled;
960
- if (toolCalls.length > 0) entry.tools = toolCalls;
961
- fs.writeFileSync(captureFile, JSON.stringify(entry, null, 2));
962
- const toolSummary = toolCalls.map(t => `${t.tool}(${(t.arg || "").slice(0, 40)})`).join(", ");
963
- const preview = assembled ? `"${assembled.slice(0, 80)}"` : "";
964
- console.log(`[CURSOR] RunPoll ← ${preview}${toolSummary ? ` [${toolSummary}]` : ""}`);
965
- }
966
- } catch { /* ignore */ }
967
- });
968
- });
969
-
970
- forwardReq.on("error", (err) => {
971
- console.error(`❌ Passthrough error: ${err.message}`);
972
- if (!res.headersSent) res.writeHead(502);
973
- res.end("Bad Gateway");
974
- });
975
-
976
- if (bodyBuffer.length > 0) forwardReq.write(bodyBuffer);
977
- forwardReq.end();
978
- }
979
-
980
- async function intercept(req, res, bodyBuffer, mappedModel) {
981
- try {
982
- const body = JSON.parse(bodyBuffer.toString());
983
- body.model = mappedModel;
984
-
985
- const response = await fetch(ROUTER_URL, {
986
- method: "POST",
987
- headers: {
988
- "Content-Type": "application/json",
989
- "Authorization": `Bearer ${API_KEY}`
990
- },
991
- body: JSON.stringify(body)
992
- });
993
-
994
- if (!response.ok) {
995
- const errText = await response.text().catch(() => "");
996
- throw new Error(`9Router ${response.status}: ${errText}`);
997
- }
998
-
999
- const ct = response.headers.get("content-type") || "application/json";
1000
- const resHeaders = { "Content-Type": ct, "Cache-Control": "no-cache", "Connection": "keep-alive" };
1001
- if (ct.includes("text/event-stream")) resHeaders["X-Accel-Buffering"] = "no";
1002
- res.writeHead(200, resHeaders);
1003
-
1004
- const reader = response.body.getReader();
1005
- const decoder = new TextDecoder();
1006
- while (true) {
1007
- const { done, value } = await reader.read();
1008
- if (done) { res.end(); break; }
1009
- res.write(decoder.decode(value, { stream: true }));
1010
- }
1011
- } catch (error) {
1012
- console.error(`❌ ${error.message}`);
1013
- if (!res.headersSent) res.writeHead(500, { "Content-Type": "application/json" });
1014
- res.end(JSON.stringify({ error: { message: error.message, type: "mitm_error" } }));
1015
- }
1016
- }
1017
-
1018
- const server = https.createServer(sslOptions, async (req, res) => {
1019
- if (req.url === "/_mitm_health") {
1020
- res.writeHead(200, { "Content-Type": "application/json" });
1021
- res.end(JSON.stringify({ ok: true, pid: process.pid }));
1022
- return;
1023
- }
1024
-
1025
- console.log(`[MITM] ${req.method} https://${req.headers.host}${req.url}`);
1026
-
1027
- const bodyBuffer = await collectBodyRaw(req);
1028
- if (bodyBuffer.length > 0) saveRequestLog(req.url, bodyBuffer);
1029
-
1030
- // Decode and log Cursor protobuf request endpoints
1031
- if (CURSOR_ENDPOINTS.some(e => req.url.includes(e))) {
1032
- saveCursorLogFull(req.url, req.headers, bodyBuffer);
1033
- }
1034
-
1035
- // Capture response of RunPoll (server streams BidiPollResponse chunks back)
1036
- const isRunPoll = req.url.includes("RunPoll");
1037
- if (isRunPoll) {
1038
- // Check if there's a mock rule pending for this conversation
1039
- // Extract conversationId from BidiPollRequest.f1 (BidiRequestId) → need to check mockPending
1040
- // Simple approach: check all pending mocks and reply for any RunPoll within same session
1041
- // Since mockPending is keyed by conversationId and RunPoll doesn't carry it directly,
1042
- // we intercept the first RunPoll after a matching AgentRunRequest by checking pendingQueue
1043
- if (mockPending.size > 0) {
1044
- // Pick the first pending mock (FIFO) — matches the most recent matching conversation
1045
- const [convId, replyText] = mockPending.entries().next().value;
1046
- mockPending.delete(convId);
1047
- return sendMockResponse(res, replyText);
1048
- }
1049
-
1050
- const ts = new Date().toISOString().replace(/[:.]/g, "-");
1051
- const captureFile = path.join(CURSOR_LOG_DIR, `${ts}_RunPoll_response.json`);
1052
- return passthrough(req, res, bodyBuffer, captureFile);
1053
- }
1054
-
1055
- // Anti-loop: requests originating from 9Router bypass interception
1056
- if (req.headers[INTERNAL_REQUEST_HEADER.name] === INTERNAL_REQUEST_HEADER.value) {
1057
- return passthrough(req, res, bodyBuffer);
1058
- }
1059
-
1060
- const tool = getToolForHost(req.headers.host);
1061
- if (!tool) return passthrough(req, res, bodyBuffer);
1062
-
1063
- // Check if this URL should be intercepted based on tool
1064
- const isChat = tool === "antigravity"
1065
- ? ANTIGRAVITY_URL_PATTERNS.some(p => req.url.includes(p))
1066
- : COPILOT_URL_PATTERNS.some(p => req.url.includes(p));
1067
-
1068
- if (!isChat) return passthrough(req, res, bodyBuffer);
1069
-
1070
- const model = extractModel(req.url, bodyBuffer);
1071
- console.log("Extracted model:", model)
1072
- const mappedModel = getMappedModel(tool, model);
1073
-
1074
- if (!mappedModel) return passthrough(req, res, bodyBuffer);
1075
-
1076
- return intercept(req, res, bodyBuffer, mappedModel);
1077
- });
1078
-
1079
- server.listen(LOCAL_PORT, () => {
1080
- console.log(`🚀 MITM ready on :${LOCAL_PORT}`);
1081
- });
1082
-
1083
- server.on("error", (error) => {
1084
- if (error.code === "EADDRINUSE") {
1085
- console.error(`❌ Port ${LOCAL_PORT} already in use`);
1086
- } else if (error.code === "EACCES") {
1087
- console.error(`❌ Permission denied for port ${LOCAL_PORT}`);
1088
- } else {
1089
- console.error(`❌ ${error.message}`);
1090
- }
1091
- process.exit(1);
1092
- });
1093
-
1094
- const shutdown = () => { server.close(() => process.exit(0)); };
1095
- process.on("SIGTERM", shutdown);
1096
- process.on("SIGINT", shutdown);
1097
- if (process.platform === "win32") {
1098
- process.on("SIGBREAK", shutdown);
1099
- }