@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,337 @@
1
+ /**
2
+ * Direct file operations for when proxy is not running
3
+ */
4
+
5
+ const fs = require('fs')
6
+ const path = require('path')
7
+ const { meddleDir } = require('./proxy-detect')
8
+
9
+ const routeRulesDir = path.join(meddleDir, 'route-rules')
10
+ const settingsPath = path.join(meddleDir, 'settings.json')
11
+ const defaultMocksPath = path.join(meddleDir, 'mocks.json')
12
+
13
+ // ========== Settings ==========
14
+
15
+ /**
16
+ * Load settings.json
17
+ */
18
+ function loadSettings() {
19
+ try {
20
+ if (fs.existsSync(settingsPath)) {
21
+ return JSON.parse(fs.readFileSync(settingsPath, 'utf8'))
22
+ }
23
+ } catch (_) {}
24
+ return {}
25
+ }
26
+
27
+ /**
28
+ * Save settings.json
29
+ */
30
+ function saveSettings(settings) {
31
+ const dir = path.dirname(settingsPath)
32
+ if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true })
33
+ fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2), 'utf8')
34
+ }
35
+
36
+ /**
37
+ * Get active rule file names
38
+ */
39
+ function getActiveRuleFileNames() {
40
+ const settings = loadSettings()
41
+ const arr = settings.activeRuleFiles
42
+ return Array.isArray(arr) ? arr : []
43
+ }
44
+
45
+ /**
46
+ * Set active rule file names
47
+ */
48
+ function setActiveRuleFileNames(names) {
49
+ const settings = loadSettings()
50
+ settings.activeRuleFiles = names
51
+ saveSettings(settings)
52
+ }
53
+
54
+ // ========== Mocks ==========
55
+
56
+ /**
57
+ * Get mocks file path (supports custom path in settings)
58
+ */
59
+ function getMocksPath() {
60
+ const settings = loadSettings()
61
+ return settings.mocksFilePath || defaultMocksPath
62
+ }
63
+
64
+ /**
65
+ * Load mock rules from file
66
+ */
67
+ function loadMockRules() {
68
+ const mocksPath = getMocksPath()
69
+ try {
70
+ if (fs.existsSync(mocksPath)) {
71
+ const data = JSON.parse(fs.readFileSync(mocksPath, 'utf8'))
72
+ return data.rules || []
73
+ }
74
+ } catch (_) {}
75
+ return []
76
+ }
77
+
78
+ /**
79
+ * Save mock rules to file
80
+ */
81
+ function saveMockRules(rules) {
82
+ const mocksPath = getMocksPath()
83
+ const dir = path.dirname(mocksPath)
84
+ if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true })
85
+
86
+ // Find max id for sequence
87
+ let maxId = 0
88
+ rules.forEach(r => {
89
+ if (r.id > maxId) maxId = r.id
90
+ })
91
+
92
+ const data = {
93
+ rules,
94
+ lastId: maxId
95
+ }
96
+ fs.writeFileSync(mocksPath, JSON.stringify(data, null, 2), 'utf8')
97
+ }
98
+
99
+ /**
100
+ * Add mock rule
101
+ */
102
+ function addMockRule(rule) {
103
+ const rules = loadMockRules()
104
+ const mocksPath = getMocksPath()
105
+
106
+ // Get next id
107
+ let nextId = 1
108
+ try {
109
+ if (fs.existsSync(mocksPath)) {
110
+ const data = JSON.parse(fs.readFileSync(mocksPath, 'utf8'))
111
+ nextId = (data.lastId || 0) + 1
112
+ }
113
+ } catch (_) {}
114
+ if (rules.length > 0) {
115
+ const maxId = Math.max(...rules.map(r => r.id))
116
+ if (maxId >= nextId) nextId = maxId + 1
117
+ }
118
+
119
+ rule.id = nextId
120
+ rules.push(rule)
121
+ saveMockRules(rules)
122
+ return rule
123
+ }
124
+
125
+ /**
126
+ * Update mock rule by id
127
+ */
128
+ function updateMockRule(id, updates) {
129
+ const rules = loadMockRules()
130
+ const idx = rules.findIndex(r => r.id === id)
131
+ if (idx === -1) return null
132
+ rules[idx] = { ...rules[idx], ...updates, id }
133
+ saveMockRules(rules)
134
+ return rules[idx]
135
+ }
136
+
137
+ /**
138
+ * Delete mock rule by id
139
+ */
140
+ function deleteMockRule(id) {
141
+ const rules = loadMockRules()
142
+ const idx = rules.findIndex(r => r.id === id)
143
+ if (idx === -1) return false
144
+ rules.splice(idx, 1)
145
+ saveMockRules(rules)
146
+ return true
147
+ }
148
+
149
+ // ========== Route Rules ==========
150
+
151
+ /**
152
+ * Ensure route-rules directory exists
153
+ */
154
+ function ensureRouteRulesDir() {
155
+ if (!fs.existsSync(routeRulesDir)) {
156
+ fs.mkdirSync(routeRulesDir, { recursive: true })
157
+ }
158
+ }
159
+
160
+ /**
161
+ * Get rule file path
162
+ */
163
+ function getRuleFilePath(name) {
164
+ return path.join(routeRulesDir, `${name}.txt`)
165
+ }
166
+
167
+ /**
168
+ * List all rule files
169
+ */
170
+ function listRuleFiles() {
171
+ ensureRouteRulesDir()
172
+ const activeNames = getActiveRuleFileNames()
173
+
174
+ const files = fs.readdirSync(routeRulesDir)
175
+ .filter(f => f.endsWith('.txt'))
176
+ .map(f => f.replace(/\.txt$/, ''))
177
+
178
+ return files.map(name => {
179
+ const filePath = getRuleFilePath(name)
180
+ let ruleCount = 0
181
+ let excludeCount = 0
182
+ try {
183
+ const content = fs.readFileSync(filePath, 'utf8')
184
+ const { ruleMap, excludeMap } = parseEprcWithExclusions(content)
185
+ ruleCount = Object.keys(ruleMap).length
186
+ // Count total exclusions across all rules
187
+ for (const exclusions of Object.values(excludeMap)) {
188
+ excludeCount += exclusions.length
189
+ }
190
+ } catch (_) {}
191
+ return {
192
+ name,
193
+ enabled: activeNames.includes(name),
194
+ ruleCount,
195
+ excludeCount
196
+ }
197
+ })
198
+ }
199
+
200
+ /**
201
+ * Get rule file content
202
+ */
203
+ function getRuleFileContent(name) {
204
+ const filePath = getRuleFilePath(name)
205
+ try {
206
+ if (fs.existsSync(filePath)) {
207
+ return fs.readFileSync(filePath, 'utf8')
208
+ }
209
+ } catch (_) {}
210
+ return null
211
+ }
212
+
213
+ /**
214
+ * Save rule file content
215
+ */
216
+ function saveRuleFileContent(name, content) {
217
+ ensureRouteRulesDir()
218
+ const filePath = getRuleFilePath(name)
219
+ fs.writeFileSync(filePath, content, 'utf8')
220
+ }
221
+
222
+ /**
223
+ * Create rule file
224
+ */
225
+ function createRuleFile(name, content = '', enabled = true) {
226
+ ensureRouteRulesDir()
227
+ const safeName = name.trim().replace(/[/\\:*?"<>|]/g, '_')
228
+ const filePath = getRuleFilePath(safeName)
229
+
230
+ if (fs.existsSync(filePath)) {
231
+ throw new Error(`规则文件 "${safeName}" 已存在`)
232
+ }
233
+
234
+ fs.writeFileSync(filePath, content, 'utf8')
235
+
236
+ if (enabled) {
237
+ const activeNames = getActiveRuleFileNames()
238
+ if (!activeNames.includes(safeName)) {
239
+ activeNames.push(safeName)
240
+ setActiveRuleFileNames(activeNames)
241
+ }
242
+ }
243
+
244
+ const ruleCount = content.trim() ? Object.keys(parseEprc(content)).length : 0
245
+ return { name: safeName, enabled, ruleCount }
246
+ }
247
+
248
+ /**
249
+ * Delete rule file
250
+ */
251
+ function deleteRuleFile(name) {
252
+ const filePath = getRuleFilePath(name)
253
+ if (!fs.existsSync(filePath)) {
254
+ throw new Error('规则文件不存在')
255
+ }
256
+ fs.unlinkSync(filePath)
257
+
258
+ const activeNames = getActiveRuleFileNames()
259
+ const idx = activeNames.indexOf(name)
260
+ if (idx !== -1) {
261
+ activeNames.splice(idx, 1)
262
+ setActiveRuleFileNames(activeNames)
263
+ }
264
+ }
265
+
266
+ /**
267
+ * Enable/disable rule file
268
+ */
269
+ function setRuleFileEnabled(name, enabled) {
270
+ const filePath = getRuleFilePath(name)
271
+ if (!fs.existsSync(filePath)) {
272
+ throw new Error('规则文件不存在')
273
+ }
274
+
275
+ const activeNames = getActiveRuleFileNames()
276
+ const idx = activeNames.indexOf(name)
277
+
278
+ if (enabled && idx === -1) {
279
+ activeNames.push(name)
280
+ } else if (!enabled && idx !== -1) {
281
+ activeNames.splice(idx, 1)
282
+ }
283
+
284
+ setActiveRuleFileNames(activeNames)
285
+ }
286
+
287
+ /**
288
+ * Get content of all active rule files merged
289
+ */
290
+ function getActiveRuleFilesContent() {
291
+ const activeNames = getActiveRuleFileNames()
292
+ const contents = []
293
+ for (const name of activeNames) {
294
+ const content = getRuleFileContent(name)
295
+ if (content) {
296
+ contents.push(content)
297
+ }
298
+ }
299
+ return contents.join('\n')
300
+ }
301
+
302
+ // ========== Parser (imported) ==========
303
+
304
+ const { parseEprc, parseEprcWithExclusions, ruleMapToEprcText } = require('./parsers')
305
+
306
+ module.exports = {
307
+ // Settings
308
+ loadSettings,
309
+ saveSettings,
310
+ getActiveRuleFileNames,
311
+ setActiveRuleFileNames,
312
+
313
+ // Mocks
314
+ getMocksPath,
315
+ loadMockRules,
316
+ saveMockRules,
317
+ addMockRule,
318
+ updateMockRule,
319
+ deleteMockRule,
320
+
321
+ // Route Rules
322
+ routeRulesDir,
323
+ ensureRouteRulesDir,
324
+ getRuleFilePath,
325
+ listRuleFiles,
326
+ getRuleFileContent,
327
+ getActiveRuleFilesContent,
328
+ saveRuleFileContent,
329
+ createRuleFile,
330
+ deleteRuleFile,
331
+ setRuleFileEnabled,
332
+
333
+ // Parser (re-exported)
334
+ parseEprc,
335
+ parseEprcWithExclusions,
336
+ ruleMapToEprcText
337
+ }
@@ -0,0 +1,20 @@
1
+ /**
2
+ * MEDDLE_HOME resolver — single source of truth for meddle data directory.
3
+ *
4
+ * Resolution order:
5
+ * 1. MEDDLE_HOME env var (if set and non-empty)
6
+ * 2. ~/.meddle (default, backward compatible)
7
+ *
8
+ * Pure JS so the CLI can require it without a build step.
9
+ */
10
+
11
+ const os = require('os')
12
+ const path = require('path')
13
+
14
+ function resolveMeddleHome() {
15
+ const fromEnv = (process.env.MEDDLE_HOME || '').trim()
16
+ if (fromEnv) return path.resolve(fromEnv)
17
+ return path.resolve(os.homedir(), '.meddle')
18
+ }
19
+
20
+ module.exports = { resolveMeddleHome }
@@ -0,0 +1,146 @@
1
+ /**
2
+ * Output formatter for CLI commands
3
+ * Supports both human-readable and JSON output
4
+ */
5
+
6
+ const chalk = require('chalk')
7
+
8
+ let jsonMode = false
9
+
10
+ /**
11
+ * Set JSON output mode
12
+ */
13
+ function setJsonMode(mode) {
14
+ jsonMode = mode
15
+ }
16
+
17
+ /**
18
+ * Check if JSON mode is enabled
19
+ */
20
+ function isJsonMode() {
21
+ return jsonMode
22
+ }
23
+
24
+ /**
25
+ * Print header with title
26
+ */
27
+ function header(title) {
28
+ if (jsonMode) return
29
+ console.log('')
30
+ console.log(chalk.bold.cyan('════════════════════════════════════════'))
31
+ console.log(chalk.bold.cyan(` ${title}`))
32
+ console.log(chalk.bold.cyan('════════════════════════════════════════'))
33
+ console.log('')
34
+ }
35
+
36
+ /**
37
+ * Print section header
38
+ */
39
+ function section(title) {
40
+ if (jsonMode) return
41
+ console.log(chalk.bold.yellow(`\n▶ ${title}`))
42
+ console.log(chalk.gray('─'.repeat(40)))
43
+ }
44
+
45
+ /**
46
+ * Print success message
47
+ */
48
+ function success(message) {
49
+ if (jsonMode) return
50
+ console.log(chalk.green(' ✓'), message)
51
+ }
52
+
53
+ /**
54
+ * Print error message
55
+ */
56
+ function error(message) {
57
+ if (jsonMode) return
58
+ console.log(chalk.red(' ✗'), message)
59
+ }
60
+
61
+ /**
62
+ * Print warning message
63
+ */
64
+ function warning(message) {
65
+ if (jsonMode) return
66
+ console.log(chalk.yellow(' ⚠'), message)
67
+ }
68
+
69
+ /**
70
+ * Print info message
71
+ */
72
+ function info(message) {
73
+ if (jsonMode) return
74
+ console.log(chalk.gray(' →'), message)
75
+ }
76
+
77
+ /**
78
+ * Print JSON output (only in JSON mode)
79
+ */
80
+ function json(data) {
81
+ if (!jsonMode) return
82
+ console.log(JSON.stringify(data, null, 2))
83
+ }
84
+
85
+ /**
86
+ * Print raw JSON (without formatting, for --json output)
87
+ */
88
+ function jsonRaw(data) {
89
+ console.log(JSON.stringify(data))
90
+ }
91
+
92
+ /**
93
+ * Print plain text message
94
+ */
95
+ function plain(message) {
96
+ if (jsonMode) return
97
+ console.log(message)
98
+ }
99
+
100
+ /**
101
+ * Print key-value pair
102
+ */
103
+ function kv(key, value, indent = 2) {
104
+ if (jsonMode) return
105
+ const spaces = ' '.repeat(indent)
106
+ console.log(spaces + chalk.gray(key + ':'), value)
107
+ }
108
+
109
+ /**
110
+ * Print bullet item
111
+ */
112
+ function bullet(message, active = false, indent = 2) {
113
+ if (jsonMode) return
114
+ const spaces = ' '.repeat(indent)
115
+ const marker = active ? chalk.green('●') : chalk.gray('○')
116
+ console.log(spaces + marker, message)
117
+ }
118
+
119
+ /**
120
+ * Print table row
121
+ */
122
+ function tableRow(columns, widths) {
123
+ if (jsonMode) return
124
+ const row = columns.map((col, i) => {
125
+ const width = widths[i] || 10
126
+ return String(col).padEnd(width)
127
+ }).join(' ')
128
+ console.log(' ' + row)
129
+ }
130
+
131
+ module.exports = {
132
+ setJsonMode,
133
+ isJsonMode,
134
+ header,
135
+ section,
136
+ success,
137
+ error,
138
+ warning,
139
+ info,
140
+ json,
141
+ jsonRaw,
142
+ plain,
143
+ kv,
144
+ bullet,
145
+ tableRow
146
+ }
@@ -0,0 +1,127 @@
1
+ /**
2
+ * EPRC file parsers
3
+ * Ported from helpers.ts
4
+ */
5
+
6
+ const path = require('path')
7
+
8
+ const FILE_PATTERN = /^file:\/\//
9
+ const LOCAL_FILE_PATTERN = /^[A-Za-z]:\\|^\/|^\\/
10
+
11
+ function routeRulesToLegacyMaps(rules) {
12
+ const ruleMap = Object.create(null)
13
+ const excludeMap = Object.create(null)
14
+ for (const entry of rules) {
15
+ ruleMap[entry.pattern] = entry.target
16
+ excludeMap[entry.pattern] = entry.exclusions.slice()
17
+ }
18
+ return { ruleMap, excludeMap }
19
+ }
20
+
21
+ /**
22
+ * Parse EPRC content into ordered rules + legacy ruleMap/excludeMap
23
+ */
24
+ function parseEprcWithExclusions(content) {
25
+ const rules = []
26
+
27
+ content.split(/\r?\n/).forEach(line => {
28
+ const trimmed = line.trim()
29
+ if (!trimmed || trimmed.startsWith('#') || trimmed.startsWith('//')) return
30
+
31
+ const parts = trimmed.split(/\s+/).filter(Boolean)
32
+ if (parts.length < 2) return
33
+
34
+ const exclusions = []
35
+ const regularParts = parts.filter(p => {
36
+ if (p.startsWith('!')) {
37
+ exclusions.push(p.slice(1))
38
+ return false
39
+ }
40
+ return true
41
+ })
42
+
43
+ if (regularParts.length < 2) return
44
+
45
+ let target = regularParts[regularParts.length - 1]
46
+ const patterns = regularParts.slice(0, -1)
47
+
48
+ if (LOCAL_FILE_PATTERN.test(target) && !FILE_PATTERN.test(target)) {
49
+ target = 'file://' + target.replace(/\\/g, '/')
50
+ }
51
+
52
+ const lineExclusions = exclusions.slice()
53
+
54
+ patterns.forEach(rule => {
55
+ const bm = rule.match(/\[([^\]]+)\]/)
56
+ let patternKey
57
+ let storedTarget = target
58
+ if (bm) {
59
+ patternKey = rule.replace(bm[0], bm[1])
60
+ storedTarget = target + bm[0]
61
+ } else {
62
+ patternKey = rule
63
+ }
64
+
65
+ rules.push({
66
+ pattern: patternKey,
67
+ target: storedTarget,
68
+ exclusions: lineExclusions,
69
+ })
70
+ })
71
+ })
72
+
73
+ const { ruleMap, excludeMap } = routeRulesToLegacyMaps(rules)
74
+ return { rules, ruleMap, excludeMap }
75
+ }
76
+
77
+ /**
78
+ * Parse EPRC content into ruleMap (without exclusions)
79
+ */
80
+ function parseEprc(content) {
81
+ return parseEprcWithExclusions(content).ruleMap
82
+ }
83
+
84
+ /**
85
+ * Convert ruleMap back to EPRC text format
86
+ */
87
+ function ruleMapToEprcText(ruleMap, excludeMap) {
88
+ const entries = Object.entries(ruleMap)
89
+ if (entries.length === 0) return ''
90
+
91
+ const byTargetAndExclusions = {}
92
+
93
+ entries.forEach(([rule, target]) => {
94
+ const bm = target.match(/\[([^\]]+)\]/)
95
+ const groupKey = bm ? target.replace(bm[0], '') : target
96
+ const displayRule = bm ? rule.replace(bm[1], bm[0]) : rule
97
+ const exclusions = excludeMap?.[rule] || []
98
+ const exclusionsKey = exclusions.join(',')
99
+
100
+ const compoundKey = `${groupKey}|||${exclusionsKey}`
101
+
102
+ if (!byTargetAndExclusions[compoundKey]) {
103
+ byTargetAndExclusions[compoundKey] = { target: groupKey, rules: [], exclusions }
104
+ }
105
+ byTargetAndExclusions[compoundKey].rules.push(displayRule)
106
+ })
107
+
108
+ return Object.values(byTargetAndExclusions)
109
+ .map(({ target, rules, exclusions }) => {
110
+ let displayTarget = target
111
+ if (FILE_PATTERN.test(target)) {
112
+ displayTarget = target.replace(/^file:\/\//, '').replace(/\//g, path.sep)
113
+ }
114
+
115
+ const exclusionStr = exclusions.map(e => `!${e}`).join(' ')
116
+ const rulesStr = rules.join(' ')
117
+ return exclusionStr ? `${rulesStr} ${exclusionStr} ${displayTarget}` : `${rulesStr} ${displayTarget}`
118
+ })
119
+ .join('\n')
120
+ }
121
+
122
+ module.exports = {
123
+ parseEprcWithExclusions,
124
+ parseEprc,
125
+ ruleMapToEprcText,
126
+ routeRulesToLegacyMaps,
127
+ }