9router 0.3.51 → 0.3.52

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 (319) hide show
  1. package/app/.next/BUILD_ID +1 -1
  2. package/app/.next/app-path-routes-manifest.json +35 -35
  3. package/app/.next/build-manifest.json +2 -2
  4. package/app/.next/prerender-manifest.json +3 -3
  5. package/app/.next/server/app/(dashboard)/dashboard/cli-tools/page_client-reference-manifest.js +1 -1
  6. package/app/.next/server/app/(dashboard)/dashboard/combos/page_client-reference-manifest.js +1 -1
  7. package/app/.next/server/app/(dashboard)/dashboard/console-log/page_client-reference-manifest.js +1 -1
  8. package/app/.next/server/app/(dashboard)/dashboard/endpoint/page_client-reference-manifest.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 +3 -3
  31. package/app/.next/server/app/_not-found.segments/_full.segment.rsc +3 -3
  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 +3 -3
  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 +1 -1
  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.js +2 -2
  40. package/app/.next/server/app/api/cli-tools/antigravity-mitm/alias/route_client-reference-manifest.js +1 -1
  41. package/app/.next/server/app/api/cli-tools/antigravity-mitm/route.js +1 -1
  42. package/app/.next/server/app/api/cli-tools/antigravity-mitm/route_client-reference-manifest.js +1 -1
  43. package/app/.next/server/app/api/cli-tools/claude-settings/route.js +2 -2
  44. package/app/.next/server/app/api/cli-tools/claude-settings/route_client-reference-manifest.js +1 -1
  45. package/app/.next/server/app/api/cli-tools/codex-settings/route.js +1 -1
  46. package/app/.next/server/app/api/cli-tools/codex-settings/route_client-reference-manifest.js +1 -1
  47. package/app/.next/server/app/api/cli-tools/copilot-settings/route.js +2 -2
  48. package/app/.next/server/app/api/cli-tools/copilot-settings/route_client-reference-manifest.js +1 -1
  49. package/app/.next/server/app/api/cli-tools/droid-settings/route.js +2 -2
  50. package/app/.next/server/app/api/cli-tools/droid-settings/route_client-reference-manifest.js +1 -1
  51. package/app/.next/server/app/api/cli-tools/openclaw-settings/route.js +2 -2
  52. package/app/.next/server/app/api/cli-tools/openclaw-settings/route_client-reference-manifest.js +1 -1
  53. package/app/.next/server/app/api/cli-tools/opencode-settings/route.js +1 -1
  54. package/app/.next/server/app/api/cli-tools/opencode-settings/route_client-reference-manifest.js +1 -1
  55. package/app/.next/server/app/api/cloud/auth/route_client-reference-manifest.js +1 -1
  56. package/app/.next/server/app/api/cloud/credentials/update/route_client-reference-manifest.js +1 -1
  57. package/app/.next/server/app/api/cloud/model/resolve/route_client-reference-manifest.js +1 -1
  58. package/app/.next/server/app/api/cloud/models/alias/route_client-reference-manifest.js +1 -1
  59. package/app/.next/server/app/api/combos/[id]/route_client-reference-manifest.js +1 -1
  60. package/app/.next/server/app/api/combos/route_client-reference-manifest.js +1 -1
  61. package/app/.next/server/app/api/init/route_client-reference-manifest.js +1 -1
  62. package/app/.next/server/app/api/keys/[id]/route_client-reference-manifest.js +1 -1
  63. package/app/.next/server/app/api/keys/route_client-reference-manifest.js +1 -1
  64. package/app/.next/server/app/api/locale/route_client-reference-manifest.js +1 -1
  65. package/app/.next/server/app/api/models/alias/route_client-reference-manifest.js +1 -1
  66. package/app/.next/server/app/api/models/route.js +1 -1
  67. package/app/.next/server/app/api/models/route_client-reference-manifest.js +1 -1
  68. package/app/.next/server/app/api/models/test/route_client-reference-manifest.js +1 -1
  69. package/app/.next/server/app/api/oauth/[provider]/[action]/route_client-reference-manifest.js +1 -1
  70. package/app/.next/server/app/api/oauth/cursor/auto-import/route_client-reference-manifest.js +1 -1
  71. package/app/.next/server/app/api/oauth/cursor/import/route_client-reference-manifest.js +1 -1
  72. package/app/.next/server/app/api/oauth/iflow/cookie/route_client-reference-manifest.js +1 -1
  73. package/app/.next/server/app/api/oauth/kiro/auto-import/route_client-reference-manifest.js +1 -1
  74. package/app/.next/server/app/api/oauth/kiro/import/route_client-reference-manifest.js +1 -1
  75. package/app/.next/server/app/api/oauth/kiro/social-authorize/route_client-reference-manifest.js +1 -1
  76. package/app/.next/server/app/api/oauth/kiro/social-exchange/route_client-reference-manifest.js +1 -1
  77. package/app/.next/server/app/api/pricing/route_client-reference-manifest.js +1 -1
  78. package/app/.next/server/app/api/provider-nodes/[id]/route_client-reference-manifest.js +1 -1
  79. package/app/.next/server/app/api/provider-nodes/route_client-reference-manifest.js +1 -1
  80. package/app/.next/server/app/api/provider-nodes/validate/route_client-reference-manifest.js +1 -1
  81. package/app/.next/server/app/api/providers/[id]/models/route_client-reference-manifest.js +1 -1
  82. package/app/.next/server/app/api/providers/[id]/route_client-reference-manifest.js +1 -1
  83. package/app/.next/server/app/api/providers/[id]/test/route_client-reference-manifest.js +1 -1
  84. package/app/.next/server/app/api/providers/[id]/test-models/route_client-reference-manifest.js +1 -1
  85. package/app/.next/server/app/api/providers/client/route_client-reference-manifest.js +1 -1
  86. package/app/.next/server/app/api/providers/route.js +1 -1
  87. package/app/.next/server/app/api/providers/route_client-reference-manifest.js +1 -1
  88. package/app/.next/server/app/api/providers/test-batch/route_client-reference-manifest.js +1 -1
  89. package/app/.next/server/app/api/providers/validate/route_client-reference-manifest.js +1 -1
  90. package/app/.next/server/app/api/proxy-pools/[id]/route_client-reference-manifest.js +1 -1
  91. package/app/.next/server/app/api/proxy-pools/[id]/test/route_client-reference-manifest.js +1 -1
  92. package/app/.next/server/app/api/proxy-pools/route_client-reference-manifest.js +1 -1
  93. package/app/.next/server/app/api/settings/database/route_client-reference-manifest.js +1 -1
  94. package/app/.next/server/app/api/settings/proxy-test/route_client-reference-manifest.js +1 -1
  95. package/app/.next/server/app/api/settings/require-login/route_client-reference-manifest.js +1 -1
  96. package/app/.next/server/app/api/settings/route_client-reference-manifest.js +1 -1
  97. package/app/.next/server/app/api/shutdown/route_client-reference-manifest.js +1 -1
  98. package/app/.next/server/app/api/tags/route_client-reference-manifest.js +1 -1
  99. package/app/.next/server/app/api/translator/console-logs/route.js +1 -1
  100. package/app/.next/server/app/api/translator/console-logs/route_client-reference-manifest.js +1 -1
  101. package/app/.next/server/app/api/translator/console-logs/stream/route.js +1 -1
  102. package/app/.next/server/app/api/translator/console-logs/stream/route_client-reference-manifest.js +1 -1
  103. package/app/.next/server/app/api/translator/load/route_client-reference-manifest.js +1 -1
  104. package/app/.next/server/app/api/translator/save/route_client-reference-manifest.js +1 -1
  105. package/app/.next/server/app/api/translator/send/route_client-reference-manifest.js +1 -1
  106. package/app/.next/server/app/api/translator/translate/route_client-reference-manifest.js +1 -1
  107. package/app/.next/server/app/api/tunnel/disable/route_client-reference-manifest.js +1 -1
  108. package/app/.next/server/app/api/tunnel/enable/route_client-reference-manifest.js +1 -1
  109. package/app/.next/server/app/api/tunnel/status/route_client-reference-manifest.js +1 -1
  110. package/app/.next/server/app/api/usage/[connectionId]/route_client-reference-manifest.js +1 -1
  111. package/app/.next/server/app/api/usage/chart/route_client-reference-manifest.js +1 -1
  112. package/app/.next/server/app/api/usage/history/route_client-reference-manifest.js +1 -1
  113. package/app/.next/server/app/api/usage/providers/route.js +1 -1
  114. package/app/.next/server/app/api/usage/providers/route_client-reference-manifest.js +1 -1
  115. package/app/.next/server/app/api/usage/request-details/route_client-reference-manifest.js +1 -1
  116. package/app/.next/server/app/api/usage/request-logs/route_client-reference-manifest.js +1 -1
  117. package/app/.next/server/app/api/usage/stats/route_client-reference-manifest.js +1 -1
  118. package/app/.next/server/app/api/usage/stream/route_client-reference-manifest.js +1 -1
  119. package/app/.next/server/app/api/v1/api/chat/route_client-reference-manifest.js +1 -1
  120. package/app/.next/server/app/api/v1/chat/completions/route_client-reference-manifest.js +1 -1
  121. package/app/.next/server/app/api/v1/embeddings/route_client-reference-manifest.js +1 -1
  122. package/app/.next/server/app/api/v1/messages/count_tokens/route_client-reference-manifest.js +1 -1
  123. package/app/.next/server/app/api/v1/messages/route_client-reference-manifest.js +1 -1
  124. package/app/.next/server/app/api/v1/models/route_client-reference-manifest.js +1 -1
  125. package/app/.next/server/app/api/v1/responses/route_client-reference-manifest.js +1 -1
  126. package/app/.next/server/app/api/v1/route_client-reference-manifest.js +1 -1
  127. package/app/.next/server/app/api/v1beta/models/[...path]/route_client-reference-manifest.js +1 -1
  128. package/app/.next/server/app/api/v1beta/models/route_client-reference-manifest.js +1 -1
  129. package/app/.next/server/app/api/version/route.js +1 -1
  130. package/app/.next/server/app/api/version/route_client-reference-manifest.js +1 -1
  131. package/app/.next/server/app/callback/page_client-reference-manifest.js +1 -1
  132. package/app/.next/server/app/callback.html +1 -1
  133. package/app/.next/server/app/callback.rsc +3 -3
  134. package/app/.next/server/app/callback.segments/_full.segment.rsc +3 -3
  135. package/app/.next/server/app/callback.segments/_head.segment.rsc +1 -1
  136. package/app/.next/server/app/callback.segments/_index.segment.rsc +3 -3
  137. package/app/.next/server/app/callback.segments/_tree.segment.rsc +1 -1
  138. package/app/.next/server/app/callback.segments/callback/__PAGE__.segment.rsc +1 -1
  139. package/app/.next/server/app/callback.segments/callback.segment.rsc +1 -1
  140. package/app/.next/server/app/dashboard/cli-tools.html +1 -1
  141. package/app/.next/server/app/dashboard/cli-tools.rsc +5 -5
  142. package/app/.next/server/app/dashboard/cli-tools.segments/!KGRhc2hib2FyZCk/dashboard/cli-tools/__PAGE__.segment.rsc +2 -2
  143. package/app/.next/server/app/dashboard/cli-tools.segments/!KGRhc2hib2FyZCk/dashboard/cli-tools.segment.rsc +1 -1
  144. package/app/.next/server/app/dashboard/cli-tools.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
  145. package/app/.next/server/app/dashboard/cli-tools.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
  146. package/app/.next/server/app/dashboard/cli-tools.segments/_full.segment.rsc +5 -5
  147. package/app/.next/server/app/dashboard/cli-tools.segments/_head.segment.rsc +1 -1
  148. package/app/.next/server/app/dashboard/cli-tools.segments/_index.segment.rsc +3 -3
  149. package/app/.next/server/app/dashboard/cli-tools.segments/_tree.segment.rsc +1 -1
  150. package/app/.next/server/app/dashboard/combos.html +1 -1
  151. package/app/.next/server/app/dashboard/combos.rsc +5 -5
  152. package/app/.next/server/app/dashboard/combos.segments/!KGRhc2hib2FyZCk/dashboard/combos/__PAGE__.segment.rsc +2 -2
  153. package/app/.next/server/app/dashboard/combos.segments/!KGRhc2hib2FyZCk/dashboard/combos.segment.rsc +1 -1
  154. package/app/.next/server/app/dashboard/combos.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
  155. package/app/.next/server/app/dashboard/combos.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
  156. package/app/.next/server/app/dashboard/combos.segments/_full.segment.rsc +5 -5
  157. package/app/.next/server/app/dashboard/combos.segments/_head.segment.rsc +1 -1
  158. package/app/.next/server/app/dashboard/combos.segments/_index.segment.rsc +3 -3
  159. package/app/.next/server/app/dashboard/combos.segments/_tree.segment.rsc +1 -1
  160. package/app/.next/server/app/dashboard/endpoint.html +1 -1
  161. package/app/.next/server/app/dashboard/endpoint.rsc +5 -5
  162. package/app/.next/server/app/dashboard/endpoint.segments/!KGRhc2hib2FyZCk/dashboard/endpoint/__PAGE__.segment.rsc +2 -2
  163. package/app/.next/server/app/dashboard/endpoint.segments/!KGRhc2hib2FyZCk/dashboard/endpoint.segment.rsc +1 -1
  164. package/app/.next/server/app/dashboard/endpoint.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
  165. package/app/.next/server/app/dashboard/endpoint.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
  166. package/app/.next/server/app/dashboard/endpoint.segments/_full.segment.rsc +5 -5
  167. package/app/.next/server/app/dashboard/endpoint.segments/_head.segment.rsc +1 -1
  168. package/app/.next/server/app/dashboard/endpoint.segments/_index.segment.rsc +3 -3
  169. package/app/.next/server/app/dashboard/endpoint.segments/_tree.segment.rsc +1 -1
  170. package/app/.next/server/app/dashboard/mitm.html +1 -1
  171. package/app/.next/server/app/dashboard/mitm.rsc +5 -5
  172. package/app/.next/server/app/dashboard/mitm.segments/!KGRhc2hib2FyZCk/dashboard/mitm/__PAGE__.segment.rsc +2 -2
  173. package/app/.next/server/app/dashboard/mitm.segments/!KGRhc2hib2FyZCk/dashboard/mitm.segment.rsc +1 -1
  174. package/app/.next/server/app/dashboard/mitm.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
  175. package/app/.next/server/app/dashboard/mitm.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
  176. package/app/.next/server/app/dashboard/mitm.segments/_full.segment.rsc +5 -5
  177. package/app/.next/server/app/dashboard/mitm.segments/_head.segment.rsc +1 -1
  178. package/app/.next/server/app/dashboard/mitm.segments/_index.segment.rsc +3 -3
  179. package/app/.next/server/app/dashboard/mitm.segments/_tree.segment.rsc +1 -1
  180. package/app/.next/server/app/dashboard/profile.html +1 -1
  181. package/app/.next/server/app/dashboard/profile.rsc +5 -5
  182. package/app/.next/server/app/dashboard/profile.segments/!KGRhc2hib2FyZCk/dashboard/profile/__PAGE__.segment.rsc +2 -2
  183. package/app/.next/server/app/dashboard/profile.segments/!KGRhc2hib2FyZCk/dashboard/profile.segment.rsc +1 -1
  184. package/app/.next/server/app/dashboard/profile.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
  185. package/app/.next/server/app/dashboard/profile.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
  186. package/app/.next/server/app/dashboard/profile.segments/_full.segment.rsc +5 -5
  187. package/app/.next/server/app/dashboard/profile.segments/_head.segment.rsc +1 -1
  188. package/app/.next/server/app/dashboard/profile.segments/_index.segment.rsc +3 -3
  189. package/app/.next/server/app/dashboard/profile.segments/_tree.segment.rsc +1 -1
  190. package/app/.next/server/app/dashboard/providers/new.html +1 -1
  191. package/app/.next/server/app/dashboard/providers/new.rsc +5 -5
  192. package/app/.next/server/app/dashboard/providers/new.segments/!KGRhc2hib2FyZCk/dashboard/providers/new/__PAGE__.segment.rsc +2 -2
  193. package/app/.next/server/app/dashboard/providers/new.segments/!KGRhc2hib2FyZCk/dashboard/providers/new.segment.rsc +1 -1
  194. package/app/.next/server/app/dashboard/providers/new.segments/!KGRhc2hib2FyZCk/dashboard/providers.segment.rsc +1 -1
  195. package/app/.next/server/app/dashboard/providers/new.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
  196. package/app/.next/server/app/dashboard/providers/new.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
  197. package/app/.next/server/app/dashboard/providers/new.segments/_full.segment.rsc +5 -5
  198. package/app/.next/server/app/dashboard/providers/new.segments/_head.segment.rsc +1 -1
  199. package/app/.next/server/app/dashboard/providers/new.segments/_index.segment.rsc +3 -3
  200. package/app/.next/server/app/dashboard/providers/new.segments/_tree.segment.rsc +1 -1
  201. package/app/.next/server/app/dashboard/providers.html +1 -1
  202. package/app/.next/server/app/dashboard/providers.rsc +5 -5
  203. package/app/.next/server/app/dashboard/providers.segments/!KGRhc2hib2FyZCk/dashboard/providers/__PAGE__.segment.rsc +2 -2
  204. package/app/.next/server/app/dashboard/providers.segments/!KGRhc2hib2FyZCk/dashboard/providers.segment.rsc +1 -1
  205. package/app/.next/server/app/dashboard/providers.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
  206. package/app/.next/server/app/dashboard/providers.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
  207. package/app/.next/server/app/dashboard/providers.segments/_full.segment.rsc +5 -5
  208. package/app/.next/server/app/dashboard/providers.segments/_head.segment.rsc +1 -1
  209. package/app/.next/server/app/dashboard/providers.segments/_index.segment.rsc +3 -3
  210. package/app/.next/server/app/dashboard/providers.segments/_tree.segment.rsc +1 -1
  211. package/app/.next/server/app/dashboard/proxy-pools.html +1 -1
  212. package/app/.next/server/app/dashboard/proxy-pools.rsc +5 -5
  213. package/app/.next/server/app/dashboard/proxy-pools.segments/!KGRhc2hib2FyZCk/dashboard/proxy-pools/__PAGE__.segment.rsc +2 -2
  214. package/app/.next/server/app/dashboard/proxy-pools.segments/!KGRhc2hib2FyZCk/dashboard/proxy-pools.segment.rsc +1 -1
  215. package/app/.next/server/app/dashboard/proxy-pools.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
  216. package/app/.next/server/app/dashboard/proxy-pools.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
  217. package/app/.next/server/app/dashboard/proxy-pools.segments/_full.segment.rsc +5 -5
  218. package/app/.next/server/app/dashboard/proxy-pools.segments/_head.segment.rsc +1 -1
  219. package/app/.next/server/app/dashboard/proxy-pools.segments/_index.segment.rsc +3 -3
  220. package/app/.next/server/app/dashboard/proxy-pools.segments/_tree.segment.rsc +1 -1
  221. package/app/.next/server/app/dashboard/quota.html +2 -2
  222. package/app/.next/server/app/dashboard/quota.rsc +4 -4
  223. package/app/.next/server/app/dashboard/quota.segments/!KGRhc2hib2FyZCk/dashboard/quota/__PAGE__.segment.rsc +1 -1
  224. package/app/.next/server/app/dashboard/quota.segments/!KGRhc2hib2FyZCk/dashboard/quota.segment.rsc +1 -1
  225. package/app/.next/server/app/dashboard/quota.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
  226. package/app/.next/server/app/dashboard/quota.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
  227. package/app/.next/server/app/dashboard/quota.segments/_full.segment.rsc +4 -4
  228. package/app/.next/server/app/dashboard/quota.segments/_head.segment.rsc +1 -1
  229. package/app/.next/server/app/dashboard/quota.segments/_index.segment.rsc +3 -3
  230. package/app/.next/server/app/dashboard/quota.segments/_tree.segment.rsc +1 -1
  231. package/app/.next/server/app/dashboard/settings/pricing/page_client-reference-manifest.js +1 -1
  232. package/app/.next/server/app/dashboard/settings/pricing.html +1 -1
  233. package/app/.next/server/app/dashboard/settings/pricing.rsc +3 -3
  234. package/app/.next/server/app/dashboard/settings/pricing.segments/_full.segment.rsc +3 -3
  235. package/app/.next/server/app/dashboard/settings/pricing.segments/_head.segment.rsc +1 -1
  236. package/app/.next/server/app/dashboard/settings/pricing.segments/_index.segment.rsc +3 -3
  237. package/app/.next/server/app/dashboard/settings/pricing.segments/_tree.segment.rsc +1 -1
  238. package/app/.next/server/app/dashboard/settings/pricing.segments/dashboard/settings/pricing/__PAGE__.segment.rsc +1 -1
  239. package/app/.next/server/app/dashboard/settings/pricing.segments/dashboard/settings/pricing.segment.rsc +1 -1
  240. package/app/.next/server/app/dashboard/settings/pricing.segments/dashboard/settings.segment.rsc +1 -1
  241. package/app/.next/server/app/dashboard/settings/pricing.segments/dashboard.segment.rsc +1 -1
  242. package/app/.next/server/app/dashboard/translator.html +1 -1
  243. package/app/.next/server/app/dashboard/translator.rsc +5 -5
  244. package/app/.next/server/app/dashboard/translator.segments/!KGRhc2hib2FyZCk/dashboard/translator/__PAGE__.segment.rsc +2 -2
  245. package/app/.next/server/app/dashboard/translator.segments/!KGRhc2hib2FyZCk/dashboard/translator.segment.rsc +1 -1
  246. package/app/.next/server/app/dashboard/translator.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
  247. package/app/.next/server/app/dashboard/translator.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
  248. package/app/.next/server/app/dashboard/translator.segments/_full.segment.rsc +5 -5
  249. package/app/.next/server/app/dashboard/translator.segments/_head.segment.rsc +1 -1
  250. package/app/.next/server/app/dashboard/translator.segments/_index.segment.rsc +3 -3
  251. package/app/.next/server/app/dashboard/translator.segments/_tree.segment.rsc +1 -1
  252. package/app/.next/server/app/dashboard/usage.html +1 -1
  253. package/app/.next/server/app/dashboard/usage.rsc +5 -5
  254. package/app/.next/server/app/dashboard/usage.segments/!KGRhc2hib2FyZCk/dashboard/usage/__PAGE__.segment.rsc +2 -2
  255. package/app/.next/server/app/dashboard/usage.segments/!KGRhc2hib2FyZCk/dashboard/usage.segment.rsc +1 -1
  256. package/app/.next/server/app/dashboard/usage.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
  257. package/app/.next/server/app/dashboard/usage.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
  258. package/app/.next/server/app/dashboard/usage.segments/_full.segment.rsc +5 -5
  259. package/app/.next/server/app/dashboard/usage.segments/_head.segment.rsc +1 -1
  260. package/app/.next/server/app/dashboard/usage.segments/_index.segment.rsc +3 -3
  261. package/app/.next/server/app/dashboard/usage.segments/_tree.segment.rsc +1 -1
  262. package/app/.next/server/app/dashboard.html +1 -1
  263. package/app/.next/server/app/dashboard.rsc +5 -5
  264. package/app/.next/server/app/dashboard.segments/!KGRhc2hib2FyZCk/dashboard/__PAGE__.segment.rsc +2 -2
  265. package/app/.next/server/app/dashboard.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
  266. package/app/.next/server/app/dashboard.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
  267. package/app/.next/server/app/dashboard.segments/_full.segment.rsc +5 -5
  268. package/app/.next/server/app/dashboard.segments/_head.segment.rsc +1 -1
  269. package/app/.next/server/app/dashboard.segments/_index.segment.rsc +3 -3
  270. package/app/.next/server/app/dashboard.segments/_tree.segment.rsc +1 -1
  271. package/app/.next/server/app/index.html +1 -1
  272. package/app/.next/server/app/index.rsc +3 -3
  273. package/app/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  274. package/app/.next/server/app/index.segments/_full.segment.rsc +3 -3
  275. package/app/.next/server/app/index.segments/_head.segment.rsc +1 -1
  276. package/app/.next/server/app/index.segments/_index.segment.rsc +3 -3
  277. package/app/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  278. package/app/.next/server/app/landing/page_client-reference-manifest.js +1 -1
  279. package/app/.next/server/app/landing.html +1 -1
  280. package/app/.next/server/app/landing.rsc +3 -3
  281. package/app/.next/server/app/landing.segments/_full.segment.rsc +3 -3
  282. package/app/.next/server/app/landing.segments/_head.segment.rsc +1 -1
  283. package/app/.next/server/app/landing.segments/_index.segment.rsc +3 -3
  284. package/app/.next/server/app/landing.segments/_tree.segment.rsc +1 -1
  285. package/app/.next/server/app/landing.segments/landing/__PAGE__.segment.rsc +1 -1
  286. package/app/.next/server/app/landing.segments/landing.segment.rsc +1 -1
  287. package/app/.next/server/app/login/page_client-reference-manifest.js +1 -1
  288. package/app/.next/server/app/login.html +1 -1
  289. package/app/.next/server/app/login.rsc +4 -4
  290. package/app/.next/server/app/login.segments/_full.segment.rsc +4 -4
  291. package/app/.next/server/app/login.segments/_head.segment.rsc +1 -1
  292. package/app/.next/server/app/login.segments/_index.segment.rsc +3 -3
  293. package/app/.next/server/app/login.segments/_tree.segment.rsc +1 -1
  294. package/app/.next/server/app/login.segments/login/__PAGE__.segment.rsc +2 -2
  295. package/app/.next/server/app/login.segments/login.segment.rsc +1 -1
  296. package/app/.next/server/app/manifest.webmanifest/route_client-reference-manifest.js +1 -1
  297. package/app/.next/server/app/page_client-reference-manifest.js +1 -1
  298. package/app/.next/server/app-paths-manifest.json +35 -35
  299. package/app/.next/server/chunks/1114.js +1 -1
  300. package/app/.next/server/chunks/1424.js +1 -1
  301. package/app/.next/server/chunks/318.js +1 -1
  302. package/app/.next/server/chunks/4989.js +1 -1
  303. package/app/.next/server/chunks/6182.js +1 -1
  304. package/app/.next/server/chunks/649.js +1 -1
  305. package/app/.next/server/chunks/9201.js +1 -1
  306. package/app/.next/server/pages/404.html +1 -1
  307. package/app/.next/server/pages/500.html +2 -2
  308. package/app/.next/server/server-reference-manifest.js +1 -1
  309. package/app/.next/server/server-reference-manifest.json +1 -1
  310. package/app/.next/static/chunks/{5497-2ffdc00508844dd5.js → 5497-d8f3c314a3499978.js} +1 -1
  311. package/app/.next/static/chunks/{9242-911fd2719103a7fa.js → 9242-3fb6423adcc6e277.js} +1 -1
  312. package/app/.next/static/chunks/app/{layout-f3021d4efcb79499.js → layout-de7fd6e41a79bed7.js} +1 -1
  313. package/app/package.json +1 -1
  314. package/app/src/mitm/cert/install.js +4 -2
  315. package/app/src/mitm/server.js +40 -23
  316. package/app/src/mitm/server2.js +266 -57
  317. package/package.json +1 -1
  318. /package/app/.next/static/{T7L0jvobZfRknPKh4v85- → I0MjnG4BJTOdnQP-tVU65}/_buildManifest.js +0 -0
  319. /package/app/.next/static/{T7L0jvobZfRknPKh4v85- → I0MjnG4BJTOdnQP-tVU65}/_ssgManifest.js +0 -0
@@ -74,9 +74,11 @@ async function installCert(sudoPassword, certPath) {
74
74
  }
75
75
 
76
76
  async function installCertMac(sudoPassword, certPath) {
77
- const command = `security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain "${certPath}"`;
77
+ // Remove all old certs with same name first to avoid duplicate/stale cert conflict
78
+ const deleteOld = `security delete-certificate -c "9Router MITM Root CA" /Library/Keychains/System.keychain 2>/dev/null || true`;
79
+ const install = `security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain "${certPath}"`;
78
80
  try {
79
- await execWithPassword(command, sudoPassword);
81
+ await execWithPassword(`${deleteOld} && ${install}`, sudoPassword);
80
82
  console.log(`✅ Installed certificate to system keychain: ${certPath}`);
81
83
  } catch (error) {
82
84
  const msg = error.message?.includes("canceled") ? "User canceled authorization" : "Certificate install failed";
@@ -4,6 +4,9 @@ const path = require("path");
4
4
  const dns = require("dns");
5
5
  const { promisify } = require("util");
6
6
 
7
+ // Allow self-signed certs from MITM root CA when fetching external hosts
8
+
9
+
7
10
  const INTERNAL_REQUEST_HEADER = { name: "x-request-source", value: "local" };
8
11
 
9
12
  // All intercepted domains across all tools
@@ -198,6 +201,13 @@ async function intercept(req, res, bodyBuffer, mappedModel) {
198
201
  if (ct.includes("text/event-stream")) resHeaders["X-Accel-Buffering"] = "no";
199
202
  res.writeHead(200, resHeaders);
200
203
 
204
+ // Guard: some responses have no body (e.g. errors, empty replies)
205
+ if (!response.body) {
206
+ const text = await response.text().catch(() => "");
207
+ res.end(text);
208
+ return;
209
+ }
210
+
201
211
  const reader = response.body.getReader();
202
212
  const decoder = new TextDecoder();
203
213
  while (true) {
@@ -213,37 +223,44 @@ async function intercept(req, res, bodyBuffer, mappedModel) {
213
223
  }
214
224
 
215
225
  const server = https.createServer(sslOptions, async (req, res) => {
216
- if (req.url === "/_mitm_health") {
217
- res.writeHead(200, { "Content-Type": "application/json" });
218
- res.end(JSON.stringify({ ok: true, pid: process.pid }));
219
- return;
220
- }
226
+ // Top-level catch to prevent uncaughtException from crashing the server
227
+ try {
228
+ if (req.url === "/_mitm_health") {
229
+ res.writeHead(200, { "Content-Type": "application/json" });
230
+ res.end(JSON.stringify({ ok: true, pid: process.pid }));
231
+ return;
232
+ }
221
233
 
222
- const bodyBuffer = await collectBodyRaw(req);
223
- if (bodyBuffer.length > 0) saveRequestLog(req.url, bodyBuffer);
234
+ const bodyBuffer = await collectBodyRaw(req);
235
+ if (bodyBuffer.length > 0) saveRequestLog(req.url, bodyBuffer);
224
236
 
225
- // Anti-loop: requests originating from 9Router bypass interception
226
- if (req.headers[INTERNAL_REQUEST_HEADER.name] === INTERNAL_REQUEST_HEADER.value) {
227
- return passthrough(req, res, bodyBuffer);
228
- }
237
+ // Anti-loop: requests originating from 9Router bypass interception
238
+ if (req.headers[INTERNAL_REQUEST_HEADER.name] === INTERNAL_REQUEST_HEADER.value) {
239
+ return passthrough(req, res, bodyBuffer);
240
+ }
229
241
 
230
- const tool = getToolForHost(req.headers.host);
231
- if (!tool) return passthrough(req, res, bodyBuffer);
242
+ const tool = getToolForHost(req.headers.host);
243
+ if (!tool) return passthrough(req, res, bodyBuffer);
232
244
 
233
- // Check if this URL should be intercepted based on tool
234
- const isChat = tool === "antigravity"
235
- ? ANTIGRAVITY_URL_PATTERNS.some(p => req.url.includes(p))
236
- : COPILOT_URL_PATTERNS.some(p => req.url.includes(p));
245
+ // Check if this URL should be intercepted based on tool
246
+ const isChat = tool === "antigravity"
247
+ ? ANTIGRAVITY_URL_PATTERNS.some(p => req.url.includes(p))
248
+ : COPILOT_URL_PATTERNS.some(p => req.url.includes(p));
237
249
 
238
- if (!isChat) return passthrough(req, res, bodyBuffer);
250
+ if (!isChat) return passthrough(req, res, bodyBuffer);
239
251
 
240
- const model = extractModel(req.url, bodyBuffer);
241
- console.log("Extracted model:", model)
242
- const mappedModel = getMappedModel(tool, model);
252
+ const model = extractModel(req.url, bodyBuffer);
253
+ console.log("Extracted model:", model);
254
+ const mappedModel = getMappedModel(tool, model);
243
255
 
244
- if (!mappedModel) return passthrough(req, res, bodyBuffer);
256
+ if (!mappedModel) return passthrough(req, res, bodyBuffer);
245
257
 
246
- return intercept(req, res, bodyBuffer, mappedModel);
258
+ return intercept(req, res, bodyBuffer, mappedModel);
259
+ } catch (err) {
260
+ console.error(`❌ Unhandled request error: ${err.message}`);
261
+ if (!res.headersSent) res.writeHead(500, { "Content-Type": "application/json" });
262
+ res.end(JSON.stringify({ error: { message: err.message, type: "mitm_error" } }));
263
+ }
247
264
  });
248
265
 
249
266
  server.listen(LOCAL_PORT, () => {
@@ -75,6 +75,14 @@ const CURSOR_ENDPOINTS = [
75
75
  "/agent.v1.AgentService/RunSSE",
76
76
  ];
77
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
+
78
86
  /**
79
87
  * Decode Connect-RPC frame: [1 byte flags][4 bytes length][protobuf body]
80
88
  * Then walk raw protobuf fields and extract readable strings/numbers.
@@ -561,75 +569,57 @@ function decodeConversationState(buf) {
561
569
  }
562
570
 
563
571
  // ── Save per-chat JSON file ────────────────────────────────────
572
+ // Only logs AgentRunRequest and ExecClientMessage — skips noise (RunPoll, KvClientMessage, ClientHeartbeat...)
564
573
  function saveCursorLogFull(url, headers, buf) {
565
574
  try {
566
575
  if (buf.length < 5) return;
576
+ if (!url.includes("BidiAppend")) return;
567
577
 
568
- const isBidiAppend = url.includes("BidiAppend");
569
- const isRunPoll = url.includes("RunPoll");
570
- if (!isBidiAppend && !isRunPoll) return;
571
-
572
- // Decompress if gzip, otherwise use raw
573
- let raw;
574
578
  const isGzip = buf[0] === 0x1f && buf[1] === 0x8b;
575
- if (isGzip) {
576
- raw = zlib.gunzipSync(buf);
577
- } else {
578
- // Try strip Connect-RPC envelope if present (flag byte + 4-byte length)
579
- raw = (buf[0] === 0x00 || buf[0] === 0x01) ? buf.slice(5) : buf;
580
- }
579
+ const raw = isGzip ? zlib.gunzipSync(buf) : (buf[0] === 0x00 || buf[0] === 0x01 ? buf.slice(5) : buf);
581
580
 
582
- const endpoint = isBidiAppend ? "BidiAppend" : "RunPoll";
583
- let decoded = {};
584
- let userMessage = null;
581
+ const decoded = decodeBidiAppend(raw);
582
+ const msgType = decoded?.agentMsg?.type;
585
583
 
586
- if (isBidiAppend) {
587
- decoded = decodeBidiAppend(raw);
588
- const action = decoded?.agentMsg?.action || {};
589
- userMessage = action.textFull || action.text || null;
590
- } else {
591
- // RunPoll: BidiPollRequest — f1=requestId{f1=uuid}, f2=startRequest
592
- const fields = protoWalkFields(raw);
593
- for (const f of fields) {
594
- if (f.field === 1 && f.data) {
595
- const inner = protoWalkFields(f.data);
596
- const id = inner.find(x => x.field === 1 && x.data);
597
- decoded.requestId = id ? protoStr(id.data) : null;
598
- }
599
- if (f.field === 2) decoded.startRequest = f.value === 1;
600
- }
601
- }
584
+ // Only log meaningful message types
585
+ if (msgType !== "AgentRunRequest" && msgType !== "ExecClientMessage") return;
602
586
 
603
- // Fetch conversation history from local Cursor DB when AgentRunRequest detected
587
+ const action = decoded?.agentMsg?.action || {};
588
+ const userMessage = action.textFull || action.text || null;
589
+
590
+ // Fetch full conversation from DB for AgentRunRequest
604
591
  const conversationId = decoded?.agentMsg?.conversationId || null;
605
592
  let conversation = null;
606
- if (conversationId && decoded?.agentMsg?.type === "AgentRunRequest") {
593
+ if (conversationId && msgType === "AgentRunRequest") {
607
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
+ }
608
605
  }
609
606
 
610
607
  const ts = new Date().toISOString().replace(/[:.]/g, "-");
611
- const base = path.join(CURSOR_LOG_DIR, `${ts}_${endpoint}`);
612
-
613
- // _chat.json — structured decoded
614
- fs.writeFileSync(`${base}_chat.json`, JSON.stringify({
615
- ts: new Date().toISOString(),
616
- endpoint,
617
- version: headers["x-cursor-client-version"] || null,
618
- encoding: isGzip ? "gzip" : "raw",
619
- sizeIn: buf.length,
620
- sizeRaw: raw.length,
621
- userMessage,
622
- decoded,
623
- conversation,
624
- }, null, 2));
625
-
626
- // _decoded.json — full proto tree, no filtering
627
- const tree = protoTreeToObj(raw);
628
- fs.writeFileSync(`${base}_decoded.json`, JSON.stringify(tree, null, 2));
629
-
630
- const agentType = decoded?.agentMsg?.type || decoded?.requestId || "(none)";
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
+
631
621
  const convName = conversation?.name ? ` | conv="${conversation.name}" (${conversation.totalMessages} msgs)` : "";
632
- console.log(`[CURSOR] ${endpoint} | type=${agentType} | msg=${userMessage || "(none)"}${convName} | ${isGzip ? "gzip" : "raw"} ${buf.length}B`);
622
+ console.log(`[CURSOR] ${msgType} | msg=${userMessage || "(none)"}${convName} | ${buf.length}B`);
633
623
  } catch (e) {
634
624
  console.error(`[CURSOR] decode error: ${e.message}`);
635
625
  }
@@ -761,7 +751,93 @@ function getToolForHost(host) {
761
751
  return null;
762
752
  }
763
753
 
764
- async function passthrough(req, res, bodyBuffer) {
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) {
765
841
  const targetHost = (req.headers.host || TARGET_HOSTS[0]).split(":")[0];
766
842
  const targetIP = await resolveTargetIP(targetHost);
767
843
 
@@ -774,8 +850,121 @@ async function passthrough(req, res, bodyBuffer) {
774
850
  servername: targetHost,
775
851
  rejectUnauthorized: false
776
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
+ }
777
867
  res.writeHead(forwardRes.statusCode, forwardRes.headers);
778
- forwardRes.pipe(res);
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
+ });
779
968
  });
780
969
 
781
970
  forwardReq.on("error", (err) => {
@@ -838,11 +1027,31 @@ const server = https.createServer(sslOptions, async (req, res) => {
838
1027
  const bodyBuffer = await collectBodyRaw(req);
839
1028
  if (bodyBuffer.length > 0) saveRequestLog(req.url, bodyBuffer);
840
1029
 
841
- // Decode and log Cursor protobuf endpoints
1030
+ // Decode and log Cursor protobuf request endpoints
842
1031
  if (CURSOR_ENDPOINTS.some(e => req.url.includes(e))) {
843
1032
  saveCursorLogFull(req.url, req.headers, bodyBuffer);
844
1033
  }
845
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
+
846
1055
  // Anti-loop: requests originating from 9Router bypass interception
847
1056
  if (req.headers[INTERNAL_REQUEST_HEADER.name] === INTERNAL_REQUEST_HEADER.value) {
848
1057
  return passthrough(req, res, bodyBuffer);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "9router",
3
- "version": "0.3.51",
3
+ "version": "0.3.52",
4
4
  "description": "9Router CLI - Start and manage 9Router server",
5
5
  "bin": {
6
6
  "9router": "./cli.js"