@jonathanleelx/meddle 0.0.1

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 (361) hide show
  1. package/CONFIG_STRUCTURE.md +315 -0
  2. package/LICENSE +21 -0
  3. package/README.md +298 -0
  4. package/bin/commands/mock/add.js +92 -0
  5. package/bin/commands/mock/delete.js +58 -0
  6. package/bin/commands/mock/index.js +50 -0
  7. package/bin/commands/mock/list.js +68 -0
  8. package/bin/commands/mock/toggle.js +64 -0
  9. package/bin/commands/mock/update.js +94 -0
  10. package/bin/commands/route/active.js +141 -0
  11. package/bin/commands/route/add.js +127 -0
  12. package/bin/commands/route/create.js +77 -0
  13. package/bin/commands/route/delete.js +120 -0
  14. package/bin/commands/route/index.js +59 -0
  15. package/bin/commands/route/list.js +67 -0
  16. package/bin/commands/route/preview.js +159 -0
  17. package/bin/commands/route/show.js +111 -0
  18. package/bin/commands/route/update.js +126 -0
  19. package/bin/commands/session/create.js +166 -0
  20. package/bin/commands/session/delete.js +69 -0
  21. package/bin/commands/session/index.js +61 -0
  22. package/bin/commands/session/list.js +42 -0
  23. package/bin/commands/session/prune.js +31 -0
  24. package/bin/commands/start.js +43 -0
  25. package/bin/commands/status.js +115 -0
  26. package/bin/commands/supervise.js +106 -0
  27. package/bin/commands/url.js +30 -0
  28. package/bin/doctor.js +356 -0
  29. package/bin/index +130 -0
  30. package/bin/lib/api-client.js +72 -0
  31. package/bin/lib/file-access.js +337 -0
  32. package/bin/lib/meddle-home.js +20 -0
  33. package/bin/lib/output.js +146 -0
  34. package/bin/lib/parsers.js +127 -0
  35. package/bin/lib/proxy-detect.js +105 -0
  36. package/bin/lib/route-preview.js +180 -0
  37. package/bin/lib/session-args.js +54 -0
  38. package/bin/lib/sessions.js +213 -0
  39. package/dist/cert.d.ts +10 -0
  40. package/dist/cert.d.ts.map +1 -0
  41. package/dist/cert.js +184 -0
  42. package/dist/cert.js.map +1 -0
  43. package/dist/core/application-identity.d.ts +55 -0
  44. package/dist/core/application-identity.d.ts.map +1 -0
  45. package/dist/core/application-identity.js +321 -0
  46. package/dist/core/application-identity.js.map +1 -0
  47. package/dist/core/body-utils.d.ts +2 -0
  48. package/dist/core/body-utils.d.ts.map +1 -0
  49. package/dist/core/body-utils.js +21 -0
  50. package/dist/core/body-utils.js.map +1 -0
  51. package/dist/core/browser.d.ts +2 -0
  52. package/dist/core/browser.d.ts.map +1 -0
  53. package/dist/core/browser.js +92 -0
  54. package/dist/core/browser.js.map +1 -0
  55. package/dist/core/client-identity.d.ts +27 -0
  56. package/dist/core/client-identity.d.ts.map +1 -0
  57. package/dist/core/client-identity.js +136 -0
  58. package/dist/core/client-identity.js.map +1 -0
  59. package/dist/core/config-diagnostics.d.ts +14 -0
  60. package/dist/core/config-diagnostics.d.ts.map +1 -0
  61. package/dist/core/config-diagnostics.js +137 -0
  62. package/dist/core/config-diagnostics.js.map +1 -0
  63. package/dist/core/connect-tunnel.d.ts +5 -0
  64. package/dist/core/connect-tunnel.d.ts.map +1 -0
  65. package/dist/core/connect-tunnel.js +45 -0
  66. package/dist/core/connect-tunnel.js.map +1 -0
  67. package/dist/core/content-encoding.d.ts +2 -0
  68. package/dist/core/content-encoding.d.ts.map +1 -0
  69. package/dist/core/content-encoding.js +77 -0
  70. package/dist/core/content-encoding.js.map +1 -0
  71. package/dist/core/custom-plugin-loader.d.ts +18 -0
  72. package/dist/core/custom-plugin-loader.d.ts.map +1 -0
  73. package/dist/core/custom-plugin-loader.js +178 -0
  74. package/dist/core/custom-plugin-loader.js.map +1 -0
  75. package/dist/core/h2-pool.d.ts +4 -0
  76. package/dist/core/h2-pool.d.ts.map +1 -0
  77. package/dist/core/h2-pool.js +180 -0
  78. package/dist/core/h2-pool.js.map +1 -0
  79. package/dist/core/inspection-dispatch.d.ts +5 -0
  80. package/dist/core/inspection-dispatch.d.ts.map +1 -0
  81. package/dist/core/inspection-dispatch.js +146 -0
  82. package/dist/core/inspection-dispatch.js.map +1 -0
  83. package/dist/core/log-rate-limit.d.ts +34 -0
  84. package/dist/core/log-rate-limit.d.ts.map +1 -0
  85. package/dist/core/log-rate-limit.js +52 -0
  86. package/dist/core/log-rate-limit.js.map +1 -0
  87. package/dist/core/map-local.d.ts +4 -0
  88. package/dist/core/map-local.d.ts.map +1 -0
  89. package/dist/core/map-local.js +195 -0
  90. package/dist/core/map-local.js.map +1 -0
  91. package/dist/core/meddle-home.d.ts +13 -0
  92. package/dist/core/meddle-home.d.ts.map +1 -0
  93. package/dist/core/meddle-home.js +56 -0
  94. package/dist/core/meddle-home.js.map +1 -0
  95. package/dist/core/mock-gate.d.ts +3 -0
  96. package/dist/core/mock-gate.d.ts.map +1 -0
  97. package/dist/core/mock-gate.js +20 -0
  98. package/dist/core/mock-gate.js.map +1 -0
  99. package/dist/core/mock-handler.d.ts +5 -0
  100. package/dist/core/mock-handler.d.ts.map +1 -0
  101. package/dist/core/mock-handler.js +339 -0
  102. package/dist/core/mock-handler.js.map +1 -0
  103. package/dist/core/on-mode-gate.d.ts +4 -0
  104. package/dist/core/on-mode-gate.d.ts.map +1 -0
  105. package/dist/core/on-mode-gate.js +64 -0
  106. package/dist/core/on-mode-gate.js.map +1 -0
  107. package/dist/core/pipeline-gate.d.ts +3 -0
  108. package/dist/core/pipeline-gate.d.ts.map +1 -0
  109. package/dist/core/pipeline-gate.js +34 -0
  110. package/dist/core/pipeline-gate.js.map +1 -0
  111. package/dist/core/pipeline.d.ts +6 -0
  112. package/dist/core/pipeline.d.ts.map +1 -0
  113. package/dist/core/pipeline.js +228 -0
  114. package/dist/core/pipeline.js.map +1 -0
  115. package/dist/core/plugin-bootstrap-runner.d.ts +6 -0
  116. package/dist/core/plugin-bootstrap-runner.d.ts.map +1 -0
  117. package/dist/core/plugin-bootstrap-runner.js +148 -0
  118. package/dist/core/plugin-bootstrap-runner.js.map +1 -0
  119. package/dist/core/plugin-bootstrap.d.ts +3 -0
  120. package/dist/core/plugin-bootstrap.d.ts.map +1 -0
  121. package/dist/core/plugin-bootstrap.js +15 -0
  122. package/dist/core/plugin-bootstrap.js.map +1 -0
  123. package/dist/core/plugin-compiler.d.ts +37 -0
  124. package/dist/core/plugin-compiler.d.ts.map +1 -0
  125. package/dist/core/plugin-compiler.js +172 -0
  126. package/dist/core/plugin-compiler.js.map +1 -0
  127. package/dist/core/plugin-context-factory.d.ts +29 -0
  128. package/dist/core/plugin-context-factory.d.ts.map +1 -0
  129. package/dist/core/plugin-context-factory.js +206 -0
  130. package/dist/core/plugin-context-factory.js.map +1 -0
  131. package/dist/core/plugin-generator.d.ts +47 -0
  132. package/dist/core/plugin-generator.d.ts.map +1 -0
  133. package/dist/core/plugin-generator.js +697 -0
  134. package/dist/core/plugin-generator.js.map +1 -0
  135. package/dist/core/plugin-health.d.ts +3 -0
  136. package/dist/core/plugin-health.d.ts.map +1 -0
  137. package/dist/core/plugin-health.js +54 -0
  138. package/dist/core/plugin-health.js.map +1 -0
  139. package/dist/core/plugin-intercept.d.ts +17 -0
  140. package/dist/core/plugin-intercept.d.ts.map +1 -0
  141. package/dist/core/plugin-intercept.js +133 -0
  142. package/dist/core/plugin-intercept.js.map +1 -0
  143. package/dist/core/plugin-runtime.d.ts +33 -0
  144. package/dist/core/plugin-runtime.d.ts.map +1 -0
  145. package/dist/core/plugin-runtime.js +254 -0
  146. package/dist/core/plugin-runtime.js.map +1 -0
  147. package/dist/core/proxy-context.d.ts +3 -0
  148. package/dist/core/proxy-context.d.ts.map +1 -0
  149. package/dist/core/proxy-context.js +129 -0
  150. package/dist/core/proxy-context.js.map +1 -0
  151. package/dist/core/proxy-record.d.ts +3 -0
  152. package/dist/core/proxy-record.d.ts.map +1 -0
  153. package/dist/core/proxy-record.js +32 -0
  154. package/dist/core/proxy-record.js.map +1 -0
  155. package/dist/core/refactor-config.d.ts +6 -0
  156. package/dist/core/refactor-config.d.ts.map +1 -0
  157. package/dist/core/refactor-config.js +45 -0
  158. package/dist/core/refactor-config.js.map +1 -0
  159. package/dist/core/refactor-status.d.ts +3 -0
  160. package/dist/core/refactor-status.d.ts.map +1 -0
  161. package/dist/core/refactor-status.js +19 -0
  162. package/dist/core/refactor-status.js.map +1 -0
  163. package/dist/core/remote-access.d.ts +40 -0
  164. package/dist/core/remote-access.d.ts.map +1 -0
  165. package/dist/core/remote-access.js +281 -0
  166. package/dist/core/remote-access.js.map +1 -0
  167. package/dist/core/route-decision.d.ts +3 -0
  168. package/dist/core/route-decision.d.ts.map +1 -0
  169. package/dist/core/route-decision.js +20 -0
  170. package/dist/core/route-decision.js.map +1 -0
  171. package/dist/core/route-loader.d.ts +14 -0
  172. package/dist/core/route-loader.d.ts.map +1 -0
  173. package/dist/core/route-loader.js +94 -0
  174. package/dist/core/route-loader.js.map +1 -0
  175. package/dist/core/route-preview.d.ts +15 -0
  176. package/dist/core/route-preview.d.ts.map +1 -0
  177. package/dist/core/route-preview.js +91 -0
  178. package/dist/core/route-preview.js.map +1 -0
  179. package/dist/core/runtime-health.d.ts +92 -0
  180. package/dist/core/runtime-health.d.ts.map +1 -0
  181. package/dist/core/runtime-health.js +205 -0
  182. package/dist/core/runtime-health.js.map +1 -0
  183. package/dist/core/sessions.d.ts +19 -0
  184. package/dist/core/sessions.d.ts.map +1 -0
  185. package/dist/core/sessions.js +93 -0
  186. package/dist/core/sessions.js.map +1 -0
  187. package/dist/core/shadow-compare.d.ts +8 -0
  188. package/dist/core/shadow-compare.d.ts.map +1 -0
  189. package/dist/core/shadow-compare.js +83 -0
  190. package/dist/core/shadow-compare.js.map +1 -0
  191. package/dist/core/shadow-readiness.d.ts +4 -0
  192. package/dist/core/shadow-readiness.d.ts.map +1 -0
  193. package/dist/core/shadow-readiness.js +118 -0
  194. package/dist/core/shadow-readiness.js.map +1 -0
  195. package/dist/core/short-response.d.ts +5 -0
  196. package/dist/core/short-response.d.ts.map +1 -0
  197. package/dist/core/short-response.js +18 -0
  198. package/dist/core/short-response.js.map +1 -0
  199. package/dist/core/static-server.d.ts +9 -0
  200. package/dist/core/static-server.d.ts.map +1 -0
  201. package/dist/core/static-server.js +136 -0
  202. package/dist/core/static-server.js.map +1 -0
  203. package/dist/core/types.d.ts +590 -0
  204. package/dist/core/types.d.ts.map +1 -0
  205. package/dist/core/types.js +4 -0
  206. package/dist/core/types.js.map +1 -0
  207. package/dist/helpers.d.ts +36 -0
  208. package/dist/helpers.d.ts.map +1 -0
  209. package/dist/helpers.js +290 -0
  210. package/dist/helpers.js.map +1 -0
  211. package/dist/plugins/builtin/index.d.ts +3 -0
  212. package/dist/plugins/builtin/index.d.ts.map +1 -0
  213. package/dist/plugins/builtin/index.js +23 -0
  214. package/dist/plugins/builtin/index.js.map +1 -0
  215. package/dist/plugins/builtin/logger-plugin.d.ts +8 -0
  216. package/dist/plugins/builtin/logger-plugin.d.ts.map +1 -0
  217. package/dist/plugins/builtin/logger-plugin.js +121 -0
  218. package/dist/plugins/builtin/logger-plugin.js.map +1 -0
  219. package/dist/plugins/builtin/mock-plugin.d.ts +3 -0
  220. package/dist/plugins/builtin/mock-plugin.d.ts.map +1 -0
  221. package/dist/plugins/builtin/mock-plugin.js +99 -0
  222. package/dist/plugins/builtin/mock-plugin.js.map +1 -0
  223. package/dist/plugins/builtin/router-plugin.d.ts +3 -0
  224. package/dist/plugins/builtin/router-plugin.d.ts.map +1 -0
  225. package/dist/plugins/builtin/router-plugin.js +36 -0
  226. package/dist/plugins/builtin/router-plugin.js.map +1 -0
  227. package/dist/server/agent/model.d.ts +30 -0
  228. package/dist/server/agent/model.d.ts.map +1 -0
  229. package/dist/server/agent/model.js +143 -0
  230. package/dist/server/agent/model.js.map +1 -0
  231. package/dist/server/agent/routes.d.ts +4 -0
  232. package/dist/server/agent/routes.d.ts.map +1 -0
  233. package/dist/server/agent/routes.js +188 -0
  234. package/dist/server/agent/routes.js.map +1 -0
  235. package/dist/server/agent/runtime.d.ts +12 -0
  236. package/dist/server/agent/runtime.d.ts.map +1 -0
  237. package/dist/server/agent/runtime.js +208 -0
  238. package/dist/server/agent/runtime.js.map +1 -0
  239. package/dist/server/agent/tools.d.ts +13 -0
  240. package/dist/server/agent/tools.d.ts.map +1 -0
  241. package/dist/server/agent/tools.js +1201 -0
  242. package/dist/server/agent/tools.js.map +1 -0
  243. package/dist/server/agent/types.d.ts +56 -0
  244. package/dist/server/agent/types.d.ts.map +1 -0
  245. package/dist/server/agent/types.js +3 -0
  246. package/dist/server/agent/types.js.map +1 -0
  247. package/dist/server/config.d.ts +9 -0
  248. package/dist/server/config.d.ts.map +1 -0
  249. package/dist/server/config.js +124 -0
  250. package/dist/server/config.js.map +1 -0
  251. package/dist/server/health.d.ts +4 -0
  252. package/dist/server/health.d.ts.map +1 -0
  253. package/dist/server/health.js +22 -0
  254. package/dist/server/health.js.map +1 -0
  255. package/dist/server/index.d.ts +239 -0
  256. package/dist/server/index.d.ts.map +1 -0
  257. package/dist/server/index.js +44 -0
  258. package/dist/server/index.js.map +1 -0
  259. package/dist/server/logs.d.ts +4 -0
  260. package/dist/server/logs.d.ts.map +1 -0
  261. package/dist/server/logs.js +40 -0
  262. package/dist/server/logs.js.map +1 -0
  263. package/dist/server/mocks.d.ts +9 -0
  264. package/dist/server/mocks.d.ts.map +1 -0
  265. package/dist/server/mocks.js +103 -0
  266. package/dist/server/mocks.js.map +1 -0
  267. package/dist/server/pipeline.d.ts +16 -0
  268. package/dist/server/pipeline.d.ts.map +1 -0
  269. package/dist/server/pipeline.js +159 -0
  270. package/dist/server/pipeline.js.map +1 -0
  271. package/dist/server/plugins.d.ts +32 -0
  272. package/dist/server/plugins.d.ts.map +1 -0
  273. package/dist/server/plugins.js +795 -0
  274. package/dist/server/plugins.js.map +1 -0
  275. package/dist/server/refactor.d.ts +4 -0
  276. package/dist/server/refactor.d.ts.map +1 -0
  277. package/dist/server/refactor.js +86 -0
  278. package/dist/server/refactor.js.map +1 -0
  279. package/dist/server/rule-files.d.ts +34 -0
  280. package/dist/server/rule-files.d.ts.map +1 -0
  281. package/dist/server/rule-files.js +389 -0
  282. package/dist/server/rule-files.js.map +1 -0
  283. package/dist/server/rules.d.ts +4 -0
  284. package/dist/server/rules.d.ts.map +1 -0
  285. package/dist/server/rules.js +40 -0
  286. package/dist/server/rules.js.map +1 -0
  287. package/dist/server/sessions.d.ts +4 -0
  288. package/dist/server/sessions.d.ts.map +1 -0
  289. package/dist/server/sessions.js +20 -0
  290. package/dist/server/sessions.js.map +1 -0
  291. package/index.js +950 -0
  292. package/mcp-server.js +794 -0
  293. package/package.json +92 -0
  294. package/plugins/builtin/index.ts +25 -0
  295. package/plugins/builtin/logger-plugin.ts +126 -0
  296. package/plugins/builtin/mock-plugin.ts +112 -0
  297. package/plugins/builtin/router-plugin.ts +35 -0
  298. package/web/README.md +111 -0
  299. package/web/dist/assets/ai-config-store-DQXVJVn_.js +1 -0
  300. package/web/dist/assets/alert-COF-DIAE.js +1 -0
  301. package/web/dist/assets/arrow-right-B4Mrlj2-.js +1 -0
  302. package/web/dist/assets/babel-DsprIpXZ.js +15 -0
  303. package/web/dist/assets/body-diff-view-D7dCWajG.js +6 -0
  304. package/web/dist/assets/button-BTToMaBW.js +1 -0
  305. package/web/dist/assets/checkbox-DIBarrJx.js +1 -0
  306. package/web/dist/assets/chevron-down-CPngAx4M.js +1 -0
  307. package/web/dist/assets/chevron-right-V1DGIDbL.js +1 -0
  308. package/web/dist/assets/circle-alert-Q8cZk9Rv.js +1 -0
  309. package/web/dist/assets/circle-x-C9USji_R.js +1 -0
  310. package/web/dist/assets/code-5_eJ_XpJ.js +1 -0
  311. package/web/dist/assets/code-fixer-fQtWZ5He.js +20 -0
  312. package/web/dist/assets/copy-BYjq1hdN.js +1 -0
  313. package/web/dist/assets/detail-panel-BX_hxeI0.js +3 -0
  314. package/web/dist/assets/dist-B8XUKgXe.js +1 -0
  315. package/web/dist/assets/dist-Bb9TeEub.js +1 -0
  316. package/web/dist/assets/dist-C5nMErq8.js +1 -0
  317. package/web/dist/assets/dist-C6eaYCUo.js +1 -0
  318. package/web/dist/assets/dist-Cn0y0IRn.js +1 -0
  319. package/web/dist/assets/dist-CxdY_A67.js +5 -0
  320. package/web/dist/assets/dist-D5Dj17P8.js +1 -0
  321. package/web/dist/assets/dist-DZJ9SMlJ.js +1 -0
  322. package/web/dist/assets/es2015-CfXu88Y7.js +41 -0
  323. package/web/dist/assets/estree-BP7k0NIt.js +44 -0
  324. package/web/dist/assets/file-system-access-CtcvBfj4.js +1 -0
  325. package/web/dist/assets/global-panel-shell-ChdO0dWd.js +6 -0
  326. package/web/dist/assets/health-panel-CQeCQ7gr.js +1 -0
  327. package/web/dist/assets/html-6FIWbqxX.js +25 -0
  328. package/web/dist/assets/index-CjqaTnE_.css +2 -0
  329. package/web/dist/assets/index-L7uWxTnp.js +18 -0
  330. package/web/dist/assets/mobile-proxy-panel-Dj1iLami.js +8 -0
  331. package/web/dist/assets/mock-config-BTTCw7RK.js +1 -0
  332. package/web/dist/assets/mock-editor-panel-C-aVfFme.js +1 -0
  333. package/web/dist/assets/monaco-editor-B3brLg8j.js +11 -0
  334. package/web/dist/assets/pencil-line-Cqe41E4h.js +1 -0
  335. package/web/dist/assets/plugin-code-editor-CPjCbJ9g.js +2 -0
  336. package/web/dist/assets/plugin-config-BzmCkvz3.js +1 -0
  337. package/web/dist/assets/plugin-generator-BnEafDF9.js +2 -0
  338. package/web/dist/assets/plugin-test-dialog-BWoWsWV4.js +7 -0
  339. package/web/dist/assets/plus-tVxSydJ8.js +1 -0
  340. package/web/dist/assets/postcss-Dnf30fQU.js +61 -0
  341. package/web/dist/assets/refresh-cw-CG3HaiQT.js +1 -0
  342. package/web/dist/assets/rotate-ccw-CAYM6Vv0.js +1 -0
  343. package/web/dist/assets/route-preview-BX7sfY0O.js +1 -0
  344. package/web/dist/assets/rule-ai-assistant-panel-WBiOOUw5.js +47 -0
  345. package/web/dist/assets/rule-config-CHpVij2M.css +1 -0
  346. package/web/dist/assets/rule-config-fTIZVwg1.js +15 -0
  347. package/web/dist/assets/select-CkFOB61l.js +1 -0
  348. package/web/dist/assets/server-Cpj4KNwN.js +1 -0
  349. package/web/dist/assets/settings-panel-COCYiIUg.js +1 -0
  350. package/web/dist/assets/shield-check-OqUmVLQt.js +1 -0
  351. package/web/dist/assets/smartphone-DKeDuJTU.js +1 -0
  352. package/web/dist/assets/standalone-CjxtLKw-.js +29 -0
  353. package/web/dist/assets/switch-C-Xk56TK.js +1 -0
  354. package/web/dist/assets/syntax-highlight-DVhPdkuV.js +5 -0
  355. package/web/dist/assets/table-CT97lAYq.js +1 -0
  356. package/web/dist/assets/textarea-C6NooVK1.js +1 -0
  357. package/web/dist/assets/wand-sparkles-wkul5vje.js +1 -0
  358. package/web/dist/assets/wifi-D9M35Ajj.js +1 -0
  359. package/web/dist/assets/zap-Djo4cgux.js +1 -0
  360. package/web/dist/index.html +24 -0
  361. package/web/dist/vite.svg +1 -0
@@ -0,0 +1,105 @@
1
+ /**
2
+ * Proxy detection utilities
3
+ * Detect if proxy is running and get proxy URL
4
+ *
5
+ * On module load, applies any --session context from argv. This makes
6
+ * every CLI command session-aware without individual changes: when
7
+ * --session <id> is set, MEDDLE_HOME is pinned to the session's data dir
8
+ * and getProxyUrl() returns that session's port.
9
+ */
10
+
11
+ const fs = require('fs')
12
+ const path = require('path')
13
+ const { resolveMeddleHome } = require('./meddle-home')
14
+ const { applySessionContext, GLOBAL_DEFAULT_PORT } = require('./session-args')
15
+
16
+ // Apply --session / MEDDLE_HOME precedence before computing paths.
17
+ applySessionContext()
18
+
19
+ const meddleDir = resolveMeddleHome()
20
+ const mcpFile = path.join(meddleDir, 'mcp-proxy-url.json')
21
+ const DEFAULT_PROXY_BASE = `http://127.0.0.1:${GLOBAL_DEFAULT_PORT}`
22
+
23
+ /**
24
+ * Get proxy URL.
25
+ *
26
+ * Priority:
27
+ * 1. MEDDLE_SESSION_PORT env (set by --session resolution)
28
+ * 2. mcp-proxy-url.json (written by proxy on startup)
29
+ * 3. DEFAULT_PROXY_BASE (http://127.0.0.1:8989)
30
+ */
31
+ function getProxyUrl() {
32
+ if (process.env.MEDDLE_SESSION_PORT) {
33
+ return `http://127.0.0.1:${process.env.MEDDLE_SESSION_PORT}`
34
+ }
35
+ try {
36
+ if (fs.existsSync(mcpFile)) {
37
+ const data = JSON.parse(fs.readFileSync(mcpFile, 'utf8'))
38
+ if (data.proxyUrl) return data.proxyUrl
39
+ }
40
+ } catch (_) {}
41
+ return DEFAULT_PROXY_BASE
42
+ }
43
+
44
+ /**
45
+ * Check if proxy is running by attempting to connect
46
+ * @param {number} timeoutMs - Timeout in milliseconds (default 2000)
47
+ */
48
+ async function isProxyRunning(timeoutMs = 2000) {
49
+ const url = getProxyUrl()
50
+ try {
51
+ const response = await fetch(url + '/api/mocks', {
52
+ method: 'GET',
53
+ signal: AbortSignal.timeout(timeoutMs)
54
+ })
55
+ return response.ok
56
+ } catch (_) {
57
+ return false
58
+ }
59
+ }
60
+
61
+ /**
62
+ * Wait for proxy to start
63
+ * @param {number} timeoutMs - Timeout in milliseconds (default 5000)
64
+ */
65
+ function waitForProxyUrl(timeoutMs = 5000) {
66
+ return new Promise((resolve, reject) => {
67
+ const start = Date.now()
68
+ const interval = 50
69
+ const check = () => {
70
+ try {
71
+ if (process.env.MEDDLE_SESSION_PORT) {
72
+ // For --session mode, poll the HTTP endpoint directly.
73
+ const port = process.env.MEDDLE_SESSION_PORT
74
+ fetch(`http://127.0.0.1:${port}/api/mocks`, { method: 'GET', signal: AbortSignal.timeout(500) })
75
+ .then((r) => { if (r.ok) resolve(`http://127.0.0.1:${port}`); else retry() })
76
+ .catch(() => retry())
77
+ return
78
+ }
79
+ if (fs.existsSync(mcpFile)) {
80
+ const data = JSON.parse(fs.readFileSync(mcpFile, 'utf8'))
81
+ if (data.proxyUrl) {
82
+ return resolve(data.proxyUrl)
83
+ }
84
+ }
85
+ } catch (_) {}
86
+ retry()
87
+ }
88
+ function retry() {
89
+ if (Date.now() - start > timeoutMs) {
90
+ return reject(new Error('等待代理启动超时'))
91
+ }
92
+ setTimeout(check, interval)
93
+ }
94
+ check()
95
+ })
96
+ }
97
+
98
+ module.exports = {
99
+ meddleDir,
100
+ mcpFile,
101
+ DEFAULT_PROXY_BASE,
102
+ getProxyUrl,
103
+ isProxyRunning,
104
+ waitForProxyUrl
105
+ }
@@ -0,0 +1,180 @@
1
+ /**
2
+ * Local route preview logic (for CLI when proxy is not running)
3
+ * Ported from core/route-preview.ts
4
+ */
5
+
6
+ const { parseEprcWithExclusions } = require('./parsers')
7
+
8
+ function getTargetKind(target) {
9
+ const trimmed = target.trim()
10
+ if (!trimmed) return 'empty'
11
+ if (/^file:\/\//i.test(trimmed) || /^[A-Za-z]:\\|^\//.test(trimmed)) return 'file'
12
+ if (/^(https?|wss?):\/\//i.test(trimmed)) return 'absolute-url'
13
+ return 'host'
14
+ }
15
+
16
+ function buildNotes(kind, target, resolvedUrl, inputUrl) {
17
+ const notes = []
18
+
19
+ if (resolvedUrl === inputUrl) {
20
+ notes.push('未命中规则,保持原 URL')
21
+ return notes
22
+ }
23
+
24
+ switch (kind) {
25
+ case 'file':
26
+ notes.push('命中本地文件目标')
27
+ break
28
+ case 'absolute-url':
29
+ notes.push('使用完整目标地址')
30
+ break
31
+ case 'host':
32
+ notes.push('继承原请求协议、路径和 query')
33
+ break
34
+ case 'empty':
35
+ notes.push('规则目标为空')
36
+ break
37
+ }
38
+
39
+ if (/\[[^\]]+\]/.test(target)) {
40
+ notes.push('保留 marker 尾缀')
41
+ }
42
+
43
+ return notes
44
+ }
45
+
46
+ function testRulePattern(pattern, input) {
47
+ function looksLikeWildcardPattern(p) {
48
+ if (!p.includes('*')) return false
49
+ return !/[\\^$+?()[\]{}|]/.test(p)
50
+ }
51
+
52
+ function isSimplePattern(p) {
53
+ return !/[\\^$+?()[\]{}|]/.test(p) && !p.includes('*')
54
+ }
55
+
56
+ function escapeRegexLiteral(value) {
57
+ return value.replace(/[|\\{}()[\]^$+?.*]/g, '\\$&')
58
+ }
59
+
60
+ function wildcardPatternToRegex(p) {
61
+ const escaped = escapeRegexLiteral(p)
62
+ const withOptionalSubdomain = p.startsWith('*.')
63
+ ? escaped.replace(/^\\\*\\\./, '(?:[^/:?#]+\\.)*')
64
+ : escaped
65
+ const regexSource = withOptionalSubdomain.replace(/\\\*/g, '.*')
66
+ return new RegExp(regexSource)
67
+ }
68
+
69
+ if (looksLikeWildcardPattern(pattern)) {
70
+ return wildcardPatternToRegex(pattern).test(input)
71
+ }
72
+ if (isSimplePattern(pattern)) {
73
+ const escaped = escapeRegexLiteral(pattern)
74
+ return new RegExp(escaped).test(input)
75
+ }
76
+ return new RegExp(pattern).test(input)
77
+ }
78
+
79
+ function applyRuleTarget(url, urlSegment) {
80
+ const originUrlObj = new URL(url)
81
+
82
+ const bracketMatch = urlSegment.match(/\[([^\]]+)\]/)
83
+ if (bracketMatch) {
84
+ const marker = bracketMatch[1]
85
+ const markerIdx = url.indexOf(marker)
86
+ const before = urlSegment.substring(0, bracketMatch.index)
87
+ const after = urlSegment.substring(bracketMatch.index + bracketMatch[0].length)
88
+ if (markerIdx !== -1) {
89
+ const tail = url.substring(markerIdx + marker.length)
90
+ urlSegment = (before + tail + after).replace(/([^:])\/\//g, '$1/')
91
+ } else {
92
+ urlSegment = before + after
93
+ }
94
+ }
95
+
96
+ if (!urlSegment.startsWith('http') && !urlSegment.startsWith('ws') && !urlSegment.startsWith('file')) {
97
+ urlSegment = originUrlObj.protocol + urlSegment
98
+ }
99
+
100
+ if (urlSegment.startsWith('file://')) {
101
+ return urlSegment
102
+ }
103
+
104
+ const targetURLObj = new URL(urlSegment)
105
+
106
+ if (!targetURLObj.port && originUrlObj.port) {
107
+ targetURLObj.port = originUrlObj.port
108
+ }
109
+
110
+ if (targetURLObj.pathname === '/' && originUrlObj.pathname !== '/') {
111
+ targetURLObj.pathname = originUrlObj.pathname
112
+ }
113
+
114
+ if (targetURLObj.search === '' && originUrlObj.search) {
115
+ targetURLObj.search = originUrlObj.search
116
+ }
117
+
118
+ const originIsWs = /^wss?:\/\//.test(url)
119
+ const targetIsHttp = /^https?:\/\//.test(targetURLObj.toString())
120
+ if (originIsWs && targetIsHttp) {
121
+ targetURLObj.protocol = originUrlObj.protocol
122
+ }
123
+
124
+ return targetURLObj.toString()
125
+ }
126
+
127
+ function findMatchedRouteRule(url, rules) {
128
+ for (const entry of rules) {
129
+ if (!testRulePattern(entry.pattern, url)) continue
130
+ if (entry.exclusions.some((exc) => testRulePattern(exc, url))) continue
131
+ const resolvedUrl = applyRuleTarget(url, entry.target)
132
+ if (resolvedUrl) {
133
+ return { entry, resolvedUrl }
134
+ }
135
+ }
136
+ return null
137
+ }
138
+
139
+ function previewRouteTargetLocal(inputUrl, rulesText) {
140
+ let parsedUrl
141
+ try {
142
+ parsedUrl = new URL(inputUrl)
143
+ } catch {
144
+ throw new Error('请输入合法的 URL')
145
+ }
146
+
147
+ const { rules } = parseEprcWithExclusions(rulesText)
148
+ const matched = findMatchedRouteRule(parsedUrl.toString(), rules)
149
+
150
+ if (!matched) {
151
+ return {
152
+ inputUrl: parsedUrl.toString(),
153
+ matched: false,
154
+ resolvedUrl: parsedUrl.toString(),
155
+ notes: ['未命中规则,保持原 URL'],
156
+ }
157
+ }
158
+
159
+ const { entry, resolvedUrl } = matched
160
+ const kind = getTargetKind(entry.target)
161
+
162
+ return {
163
+ inputUrl: parsedUrl.toString(),
164
+ matched: true,
165
+ resolvedUrl,
166
+ matchedRule: {
167
+ pattern: entry.pattern,
168
+ target: entry.target,
169
+ kind,
170
+ },
171
+ notes: buildNotes(kind, entry.target, resolvedUrl, parsedUrl.toString()),
172
+ }
173
+ }
174
+
175
+ module.exports = {
176
+ previewRouteTargetLocal,
177
+ testRulePattern,
178
+ findMatchedRouteRule,
179
+ getTargetKind,
180
+ }
@@ -0,0 +1,54 @@
1
+ /**
2
+ * --session flag resolution & MEDDLE_HOME precedence.
3
+ *
4
+ * Rules (per proposal §5.3):
5
+ * - --session <id> only → resolve id via sessions.json, set MEDDLE_HOME
6
+ * to the session's meddleHome so proxy-detect /
7
+ * file-access see its data dir, and pin the
8
+ * proxy port.
9
+ * - MEDDLE_HOME env only → use that path directly (already handled by
10
+ * resolveMeddleHome() in meddle-home.js)
11
+ * - both set → error, exit
12
+ * - neither set → default (~/.meddle), backward compatible
13
+ *
14
+ * bin/index strips --session <id> from argv and stashes the id in
15
+ * MEDDLE_SESSION_ID. This module reads that env var so every CLI command
16
+ * picks up the session context without individual changes.
17
+ */
18
+
19
+ const { resolveMeddleHome } = require('./meddle-home')
20
+ const { getSession } = require('./sessions')
21
+
22
+ const GLOBAL_DEFAULT_PORT = 8989
23
+
24
+ function applySessionContext() {
25
+ const sessionId = (process.env.MEDDLE_SESSION_ID || '').trim()
26
+ const meddleHomeEnv = (process.env.MEDDLE_HOME || '').trim()
27
+
28
+ if (sessionId && meddleHomeEnv) {
29
+ console.error('error: --session and MEDDLE_HOME are mutually exclusive')
30
+ process.exit(2)
31
+ }
32
+
33
+ if (sessionId) {
34
+ const record = getSession(sessionId)
35
+ if (!record) {
36
+ console.error(`error: session not found: ${sessionId}`)
37
+ process.exit(1)
38
+ }
39
+ // Pin MEDDLE_HOME so resolveMeddleHome() everywhere returns the session dir
40
+ process.env.MEDDLE_HOME = record.meddleHome
41
+ // Stash the port so proxy-detect can return it instead of reading
42
+ // mcp-proxy-url.json (which may not exist for non-default sessions
43
+ // that weren't started via MCP).
44
+ process.env.MEDDLE_SESSION_PORT = String(record.port)
45
+ return { sessionId, port: record.port, meddleHome: record.meddleHome }
46
+ }
47
+
48
+ return { sessionId: null, port: null, meddleHome: resolveMeddleHome() }
49
+ }
50
+
51
+ module.exports = {
52
+ applySessionContext,
53
+ GLOBAL_DEFAULT_PORT,
54
+ }
@@ -0,0 +1,213 @@
1
+ /**
2
+ * Session registry — tracks all non-default proxy sessions.
3
+ *
4
+ * Storage: ~/.meddle/sessions.json
5
+ *
6
+ * Concurrency: atomic writes (tmp + rename) + optimistic-lock retry on
7
+ * port allocation. No file locking (cross-platform complexity not
8
+ * justified for the low-frequency create path).
9
+ *
10
+ * NOTE: the CA directory (~/.meddle/ca) is intentionally NOT registered —
11
+ * all sessions share it. Only config (route-rules, mocks, plugins, …)
12
+ * is isolated per session via MEDDLE_HOME.
13
+ */
14
+
15
+ const fs = require('fs')
16
+ const path = require('path')
17
+ const { resolveMeddleHome } = require('./meddle-home')
18
+
19
+ const MAX_SESSIONS = 32
20
+ const PORT_RANGE_START = 9000
21
+ const PORT_RANGE_END = 9999
22
+
23
+ function registryPath() {
24
+ return path.join(resolveMeddleHome(), 'sessions.json')
25
+ }
26
+
27
+ function sessionsDir() {
28
+ return path.join(resolveMeddleHome(), 'sessions')
29
+ }
30
+
31
+ function sessionDir(id) {
32
+ return path.join(sessionsDir(), id)
33
+ }
34
+
35
+ /**
36
+ * Read the registry. Returns {} if missing or corrupt.
37
+ */
38
+ function readRegistry() {
39
+ try {
40
+ const raw = fs.readFileSync(registryPath(), 'utf8')
41
+ const parsed = JSON.parse(raw)
42
+ return (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) ? parsed : {}
43
+ } catch (_) {
44
+ return {}
45
+ }
46
+ }
47
+
48
+ /**
49
+ * Atomically write the registry (tmp file + rename).
50
+ */
51
+ function writeRegistry(registry) {
52
+ const file = registryPath()
53
+ const dir = path.dirname(file)
54
+ if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true })
55
+ const tmp = file + '.tmp'
56
+ fs.writeFileSync(tmp, JSON.stringify(registry, null, 2), 'utf8')
57
+ fs.renameSync(tmp, file)
58
+ }
59
+
60
+ /**
61
+ * Check whether a TCP port is currently free on 127.0.0.1.
62
+ */
63
+ function isPortFree(port) {
64
+ try {
65
+ const net = require('net')
66
+ const server = net.createServer()
67
+ server.listen(port, '127.0.0.1')
68
+ // sync check: if listen throws synchronously we catch below
69
+ server.close()
70
+ return true
71
+ } catch (_) {
72
+ return false
73
+ }
74
+ }
75
+
76
+ /**
77
+ * Allocate a free port in [PORT_RANGE_START, PORT_RANGE_END], avoiding
78
+ * ports already recorded in the registry. Returns null if exhausted.
79
+ *
80
+ * Uses optimistic locking: caller should re-verify the port is still
81
+ * free in the registry before committing.
82
+ */
83
+ function allocatePort(registry) {
84
+ const usedPorts = new Set()
85
+ for (const id of Object.keys(registry)) {
86
+ if (registry[id] && typeof registry[id].port === 'number') {
87
+ usedPorts.add(registry[id].port)
88
+ }
89
+ }
90
+ for (let port = PORT_RANGE_START; port <= PORT_RANGE_END; port++) {
91
+ if (usedPorts.has(port)) continue
92
+ if (!isPortFree(port)) continue
93
+ return port
94
+ }
95
+ return null
96
+ }
97
+
98
+ /**
99
+ * Generate a session ID: `{label}-{timestamp}`.
100
+ */
101
+ function generateId(label) {
102
+ const safe = String(label || 'session').trim().replace(/[^a-zA-Z0-9_-]/g, '-').slice(0, 32) || 'session'
103
+ return `${safe}-${Date.now()}`
104
+ }
105
+
106
+ /**
107
+ * Check if a process is alive. pid 0 / negative → false.
108
+ */
109
+ function isPidAlive(pid) {
110
+ if (!pid || typeof pid !== 'number' || pid <= 0) return false
111
+ try {
112
+ process.kill(pid, 0)
113
+ return true
114
+ } catch (err) {
115
+ // ESRCH: no such process — definitely not alive
116
+ if (err.code === 'ESRCH') return false
117
+ // EPERM: exists but we don't have permission to signal — alive
118
+ if (err.code === 'EPERM') return true
119
+ // Unexpected error — assume alive to be safe (don't prune on fluke)
120
+ return true
121
+ }
122
+ }
123
+
124
+ /**
125
+ * Create a new session record. Returns the new record (with id, port,
126
+ * pid, meddleHome, createdAt, label) or throws on conflict / limit.
127
+ *
128
+ * `pid` should be the spawned child's pid; caller spawns first, then
129
+ * calls this to register.
130
+ */
131
+ function createSession({ id, label, port, pid, meddleHome }) {
132
+ const registry = readRegistry()
133
+ const ids = Object.keys(registry)
134
+ if (ids.length >= MAX_SESSIONS) {
135
+ throw new Error(`session limit reached (${MAX_SESSIONS}); run 'meddle session prune' to clean orphaned records`)
136
+ }
137
+ if (registry[id]) {
138
+ throw new Error(`session already exists: ${id}`)
139
+ }
140
+ const record = {
141
+ port,
142
+ pid,
143
+ meddleHome,
144
+ createdAt: new Date().toISOString(),
145
+ label: label || '',
146
+ }
147
+ registry[id] = record
148
+ writeRegistry(registry)
149
+ return { id, ...record }
150
+ }
151
+
152
+ function getSession(id) {
153
+ const registry = readRegistry()
154
+ return registry[id] ? { id, ...registry[id] } : null
155
+ }
156
+
157
+ function listSessions() {
158
+ const registry = readRegistry()
159
+ return Object.keys(registry).map((id) => ({
160
+ id,
161
+ ...registry[id],
162
+ alive: isPidAlive(registry[id].pid),
163
+ }))
164
+ }
165
+
166
+ /**
167
+ * Remove a session from the registry. Does NOT kill the process or
168
+ * delete the MEDDLE_HOME directory — caller handles those.
169
+ */
170
+ function deleteSession(id) {
171
+ const registry = readRegistry()
172
+ if (!registry[id]) return null
173
+ const record = { id, ...registry[id] }
174
+ delete registry[id]
175
+ writeRegistry(registry)
176
+ return record
177
+ }
178
+
179
+ /**
180
+ * Remove all sessions whose pid is no longer alive. Returns the
181
+ * removed records. Does NOT delete their MEDDLE_HOME directories.
182
+ */
183
+ function pruneOrphaned() {
184
+ const registry = readRegistry()
185
+ const removed = []
186
+ for (const id of Object.keys(registry)) {
187
+ if (!isPidAlive(registry[id].pid)) {
188
+ removed.push({ id, ...registry[id] })
189
+ delete registry[id]
190
+ }
191
+ }
192
+ if (removed.length > 0) writeRegistry(registry)
193
+ return removed
194
+ }
195
+
196
+ module.exports = {
197
+ MAX_SESSIONS,
198
+ PORT_RANGE_START,
199
+ PORT_RANGE_END,
200
+ registryPath,
201
+ sessionsDir,
202
+ sessionDir,
203
+ readRegistry,
204
+ writeRegistry,
205
+ allocatePort,
206
+ generateId,
207
+ isPidAlive,
208
+ createSession,
209
+ getSession,
210
+ listSessions,
211
+ deleteSession,
212
+ pruneOrphaned,
213
+ }
package/dist/cert.d.ts ADDED
@@ -0,0 +1,10 @@
1
+ declare const crtMgr: any;
2
+ interface CAStatus {
3
+ exist: boolean;
4
+ trusted?: boolean;
5
+ }
6
+ export declare function getCAStatus(): Promise<CAStatus>;
7
+ export declare function ensureRootCA(): Promise<void>;
8
+ export declare function getRootCAPath(): string;
9
+ export { crtMgr };
10
+ //# sourceMappingURL=cert.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cert.d.ts","sourceRoot":"","sources":["../cert.ts"],"names":[],"mappings":"AAsBA,QAAA,MAAM,MAAM,KAA8B,CAAC;AA+B3C,UAAU,QAAQ;IACd,KAAK,EAAE,OAAO,CAAC;IACf,OAAO,CAAC,EAAE,OAAO,CAAC;CACrB;AAGD,wBAAsB,WAAW,IAAI,OAAO,CAAC,QAAQ,CAAC,CAcrD;AAkED,wBAAsB,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC,CAgBlD;AAED,wBAAgB,aAAa,IAAI,MAAM,CAEtC;AAED,OAAO,EAAE,MAAM,EAAE,CAAC"}