@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,1201 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createAgentTools = createAgentTools;
4
+ exports.toToolDefinitions = toToolDefinitions;
5
+ exports.describeAgentTools = describeAgentTools;
6
+ const route_preview_1 = require("../../core/route-preview");
7
+ const helpers_1 = require("../../helpers");
8
+ const rule_files_1 = require("../rule-files");
9
+ const config_1 = require("../config");
10
+ const mocks_1 = require("../mocks");
11
+ const plugins_1 = require("../plugins");
12
+ const pipeline_1 = require("../pipeline");
13
+ function asString(value, field) {
14
+ if (typeof value !== 'string' || !value.trim()) {
15
+ throw new Error(`缺少 ${field}`);
16
+ }
17
+ return value.trim();
18
+ }
19
+ function asStringArray(value) {
20
+ if (value === undefined)
21
+ return [];
22
+ if (!Array.isArray(value))
23
+ throw new Error('exclusions 必须是字符串数组');
24
+ return value.map((item) => asString(item, 'exclusion'));
25
+ }
26
+ function asOptionalNumber(value, field) {
27
+ if (value === undefined)
28
+ return undefined;
29
+ const parsed = typeof value === 'number' ? value : Number(value);
30
+ if (!Number.isFinite(parsed)) {
31
+ throw new Error(`${field} 必须是数字`);
32
+ }
33
+ return parsed;
34
+ }
35
+ function asOptionalBoolean(value) {
36
+ if (value === undefined)
37
+ return undefined;
38
+ if (typeof value === 'boolean')
39
+ return value;
40
+ if (value === 'true')
41
+ return true;
42
+ if (value === 'false')
43
+ return false;
44
+ throw new Error('enabled 必须是布尔值');
45
+ }
46
+ function asHeaders(value) {
47
+ if (value === undefined)
48
+ return undefined;
49
+ if (!value || typeof value !== 'object' || Array.isArray(value)) {
50
+ throw new Error('headers 必须是对象');
51
+ }
52
+ const headers = {};
53
+ for (const [key, headerValue] of Object.entries(value)) {
54
+ if (typeof headerValue !== 'string') {
55
+ throw new Error(`header ${key} 必须是字符串`);
56
+ }
57
+ headers[key] = headerValue;
58
+ }
59
+ return headers;
60
+ }
61
+ function normalizeRoutePattern(pattern) {
62
+ const marker = pattern.match(/\[([^\]]+)\]/);
63
+ if (!marker) {
64
+ return { internalPattern: pattern, markerSuffix: '' };
65
+ }
66
+ return {
67
+ internalPattern: pattern.replace(marker[0], marker[1]),
68
+ markerSuffix: marker[0],
69
+ };
70
+ }
71
+ function normalizeRouteRuleAddInput(input) {
72
+ return {
73
+ ruleFile: asString(input.ruleFile, 'ruleFile'),
74
+ pattern: asString(input.pattern, 'pattern'),
75
+ target: asString(input.target, 'target'),
76
+ exclusions: asStringArray(input.exclusions),
77
+ };
78
+ }
79
+ function normalizeRouteRuleUpdateInput(input) {
80
+ const targetValue = input.target ?? input.newTarget;
81
+ const target = targetValue === undefined ? undefined : asString(targetValue, 'target');
82
+ const exclusions = input.exclusions === undefined ? undefined : asStringArray(input.exclusions);
83
+ if (target === undefined && exclusions === undefined) {
84
+ throw new Error('更新规则时必须提供 target/newTarget 或 exclusions');
85
+ }
86
+ return {
87
+ ruleFile: asString(input.ruleFile, 'ruleFile'),
88
+ pattern: asString(input.pattern, 'pattern'),
89
+ target,
90
+ exclusions,
91
+ };
92
+ }
93
+ function normalizeRouteRuleDeleteInput(input) {
94
+ return {
95
+ ruleFile: asString(input.ruleFile, 'ruleFile'),
96
+ pattern: asString(input.pattern, 'pattern'),
97
+ };
98
+ }
99
+ function formatRuleLine(pattern, target, exclusions) {
100
+ const exclusionText = exclusions.length ? ` !${exclusions.join(' !')}` : '';
101
+ return `${pattern}${exclusionText} ${target}`;
102
+ }
103
+ function buildRouteRuleAddContent(input, ctx) {
104
+ const content = (0, rule_files_1.readRuleFileContent)(ctx.serverContext, input.ruleFile);
105
+ const { ruleMap, excludeMap } = (0, helpers_1.parseEprcWithExclusions)(content);
106
+ const { internalPattern, markerSuffix } = normalizeRoutePattern(input.pattern);
107
+ const previousTarget = ruleMap[internalPattern];
108
+ ruleMap[internalPattern] = `${input.target}${markerSuffix}`;
109
+ excludeMap[internalPattern] = input.exclusions || [];
110
+ return {
111
+ content,
112
+ newContent: (0, helpers_1.ruleMapToEprcText)(ruleMap, excludeMap),
113
+ internalPattern,
114
+ previousTarget,
115
+ previousExclusions: previousTarget ? excludeMap[internalPattern] || [] : [],
116
+ newTarget: ruleMap[internalPattern],
117
+ exclusions: excludeMap[internalPattern] || [],
118
+ };
119
+ }
120
+ function buildRouteRuleUpdateContent(input, ctx) {
121
+ const content = (0, rule_files_1.readRuleFileContent)(ctx.serverContext, input.ruleFile);
122
+ const { ruleMap, excludeMap } = (0, helpers_1.parseEprcWithExclusions)(content);
123
+ const { internalPattern, markerSuffix } = normalizeRoutePattern(input.pattern);
124
+ const previousTarget = ruleMap[internalPattern];
125
+ if (!previousTarget) {
126
+ throw new Error(`未找到路由规则: ${input.pattern}`);
127
+ }
128
+ const previousExclusions = excludeMap[internalPattern] || [];
129
+ const nextTarget = input.target ? `${input.target}${markerSuffix}` : previousTarget;
130
+ const nextExclusions = input.exclusions === undefined ? previousExclusions : input.exclusions;
131
+ ruleMap[internalPattern] = nextTarget;
132
+ excludeMap[internalPattern] = nextExclusions;
133
+ return {
134
+ content,
135
+ newContent: (0, helpers_1.ruleMapToEprcText)(ruleMap, excludeMap),
136
+ internalPattern,
137
+ previousTarget,
138
+ previousExclusions,
139
+ newTarget: nextTarget,
140
+ exclusions: nextExclusions,
141
+ };
142
+ }
143
+ function buildRouteRuleDeleteContent(input, ctx) {
144
+ const content = (0, rule_files_1.readRuleFileContent)(ctx.serverContext, input.ruleFile);
145
+ const { ruleMap, excludeMap } = (0, helpers_1.parseEprcWithExclusions)(content);
146
+ const { internalPattern } = normalizeRoutePattern(input.pattern);
147
+ const previousTarget = ruleMap[internalPattern];
148
+ if (!previousTarget) {
149
+ throw new Error(`未找到路由规则: ${input.pattern}`);
150
+ }
151
+ const previousExclusions = excludeMap[internalPattern] || [];
152
+ delete ruleMap[internalPattern];
153
+ delete excludeMap[internalPattern];
154
+ return {
155
+ content,
156
+ newContent: (0, helpers_1.ruleMapToEprcText)(ruleMap, excludeMap),
157
+ internalPattern,
158
+ previousTarget,
159
+ previousExclusions,
160
+ };
161
+ }
162
+ function buildRouteRuleDiff(input, next) {
163
+ const previousLine = next.previousTarget
164
+ ? `- ${formatRuleLine(next.internalPattern, next.previousTarget, next.previousExclusions)}`
165
+ : null;
166
+ const nextLine = `+ ${formatRuleLine(next.internalPattern, next.newTarget, next.exclusions)}`;
167
+ return [
168
+ `规则文件: ${input.ruleFile}`,
169
+ previousLine,
170
+ nextLine,
171
+ ].filter(Boolean).join('\n');
172
+ }
173
+ function buildRouteRuleUpdateDiff(input, next) {
174
+ return [
175
+ `规则文件: ${input.ruleFile}`,
176
+ `- ${formatRuleLine(next.internalPattern, next.previousTarget, next.previousExclusions)}`,
177
+ `+ ${formatRuleLine(next.internalPattern, next.newTarget, next.exclusions)}`,
178
+ ].join('\n');
179
+ }
180
+ function buildRouteRuleDeleteDiff(input, next) {
181
+ return [
182
+ `规则文件: ${input.ruleFile}`,
183
+ `- ${formatRuleLine(next.internalPattern, next.previousTarget, next.previousExclusions)}`,
184
+ ].join('\n');
185
+ }
186
+ function normalizeRouteRuleCreateFileInput(input) {
187
+ const rawName = input.ruleFile ?? input.name;
188
+ const enabled = input.enabled === undefined ? true : input.enabled === true;
189
+ return {
190
+ name: asString(rawName, 'ruleFile'),
191
+ content: typeof input.content === 'string' ? input.content : '',
192
+ enabled,
193
+ };
194
+ }
195
+ function normalizeRouteRuleActiveSetInput(input) {
196
+ if (Array.isArray(input.ruleFiles)) {
197
+ return { ruleFiles: input.ruleFiles.map((item) => asString(item, 'ruleFile')) };
198
+ }
199
+ return { ruleFiles: [asString(input.ruleFile, 'ruleFile')] };
200
+ }
201
+ function normalizeMockRuleId(input) {
202
+ const id = asOptionalNumber(input.id, 'id');
203
+ if (id === undefined) {
204
+ throw new Error('缺少 id');
205
+ }
206
+ return id;
207
+ }
208
+ function normalizeMockRuleInput(input, requirePattern) {
209
+ const bodyTypeValue = input.bodyType;
210
+ const bodyType = bodyTypeValue === undefined ? undefined : asString(bodyTypeValue, 'bodyType');
211
+ if (bodyType !== undefined && bodyType !== 'inline' && bodyType !== 'file') {
212
+ throw new Error('bodyType 仅支持 inline 或 file');
213
+ }
214
+ const data = {};
215
+ if (input.name !== undefined)
216
+ data.name = asString(input.name, 'name');
217
+ if (input.urlPattern !== undefined)
218
+ data.urlPattern = asString(input.urlPattern, 'urlPattern');
219
+ if (input.method !== undefined)
220
+ data.method = asString(input.method, 'method').toUpperCase();
221
+ if (input.statusCode !== undefined)
222
+ data.statusCode = asOptionalNumber(input.statusCode, 'statusCode');
223
+ if (input.delay !== undefined)
224
+ data.delay = asOptionalNumber(input.delay, 'delay');
225
+ if (bodyType !== undefined)
226
+ data.bodyType = bodyType;
227
+ if (input.headers !== undefined)
228
+ data.headers = asHeaders(input.headers);
229
+ if (input.body !== undefined)
230
+ data.body = typeof input.body === 'string' ? input.body : JSON.stringify(input.body);
231
+ if (input.enabled !== undefined)
232
+ data.enabled = asOptionalBoolean(input.enabled);
233
+ if (requirePattern && !data.urlPattern) {
234
+ throw new Error('缺少 urlPattern');
235
+ }
236
+ return data;
237
+ }
238
+ function getMockRule(ctx, id) {
239
+ const rule = ctx.serverContext.mockRules.find((item) => item.id === id);
240
+ if (!rule) {
241
+ throw new Error(`未找到 Mock 规则: ${id}`);
242
+ }
243
+ return rule;
244
+ }
245
+ function formatMockRule(rule) {
246
+ return [
247
+ `id=${rule.id}`,
248
+ `name=${rule.name || '(未命名)'}`,
249
+ `method=${rule.method || '*'}`,
250
+ `pattern=${rule.urlPattern}`,
251
+ `status=${rule.statusCode}`,
252
+ `enabled=${rule.enabled}`,
253
+ ].join(' ');
254
+ }
255
+ function buildMockRuleDiff(previous, next) {
256
+ return [
257
+ previous ? `- ${formatMockRule(previous)}` : null,
258
+ `+ ${[
259
+ next.id !== undefined ? `id=${next.id}` : null,
260
+ `name=${next.name || '(未命名)'}`,
261
+ `method=${next.method || '*'}`,
262
+ `pattern=${next.urlPattern || ''}`,
263
+ `status=${next.statusCode || 200}`,
264
+ `enabled=${next.enabled !== false}`,
265
+ ].filter(Boolean).join(' ')}`,
266
+ ].filter(Boolean).join('\n');
267
+ }
268
+ function normalizeLogListInput(input) {
269
+ const limit = asOptionalNumber(input.limit, 'limit') ?? 20;
270
+ const method = typeof input.method === 'string' && input.method.trim() ? input.method.trim().toUpperCase() : null;
271
+ const keyword = typeof input.keyword === 'string' && input.keyword.trim() ? input.keyword.trim() : null;
272
+ const statusCode = asOptionalNumber(input.statusCode, 'statusCode');
273
+ return {
274
+ limit: Math.min(100, Math.max(1, Math.floor(limit))),
275
+ method,
276
+ keyword,
277
+ statusCode,
278
+ };
279
+ }
280
+ function normalizePipelineModeInput(input) {
281
+ const mode = (0, pipeline_1.normalizePipelineMode)(input.mode);
282
+ if (!mode) {
283
+ throw new Error('mode 必须是 off、shadow 或 on');
284
+ }
285
+ return { mode };
286
+ }
287
+ function normalizePluginToggleInput(input) {
288
+ const pluginId = asString(input.pluginId ?? input.id, 'pluginId');
289
+ const enabled = asOptionalBoolean(input.enabled);
290
+ if (enabled === undefined) {
291
+ throw new Error('缺少 enabled');
292
+ }
293
+ return { pluginId, enabled };
294
+ }
295
+ function getPluginState(ctx, pluginId) {
296
+ const plugin = ctx.serverContext.pluginManager.getAll().find((item) => item.manifest.id === pluginId);
297
+ if (!plugin) {
298
+ throw new Error(`未找到插件: ${pluginId}`);
299
+ }
300
+ return ctx.serverContext.pluginManager.getState(pluginId);
301
+ }
302
+ function buildPluginList(ctx) {
303
+ const pluginStats = ctx.serverContext.hookDispatcher.getPluginStats ? ctx.serverContext.hookDispatcher.getPluginStats() : {};
304
+ const plugins = ctx.serverContext.pluginManager.getAll().map((plugin) => ({
305
+ id: plugin.manifest.id,
306
+ name: plugin.manifest.name,
307
+ version: plugin.manifest.version,
308
+ hooks: plugin.manifest.hooks,
309
+ permissions: plugin.manifest.permissions,
310
+ priority: plugin.manifest.priority,
311
+ state: ctx.serverContext.pluginManager.getState(plugin.manifest.id),
312
+ stats: pluginStats[plugin.manifest.id] || null,
313
+ }));
314
+ return {
315
+ mode: ctx.serverContext.requestPipeline.mode,
316
+ total: plugins.length,
317
+ plugins,
318
+ };
319
+ }
320
+ function buildPipelineStatus(ctx) {
321
+ return {
322
+ mode: ctx.serverContext.requestPipeline.mode,
323
+ shadowStats: ctx.serverContext.shadowCompareTracker.getStats(),
324
+ onModeGate: ctx.serverContext.onModeGate.getStats(),
325
+ };
326
+ }
327
+ function readCombinedActiveRules(ctx) {
328
+ const activeNames = (0, rule_files_1.getActiveRuleFileNames)(ctx.serverContext);
329
+ return activeNames
330
+ .map((name) => (0, rule_files_1.readRuleFileContent)(ctx.serverContext, name))
331
+ .filter((content) => content.trim())
332
+ .join('\n');
333
+ }
334
+ function createRouteRuleActiveGetTool() {
335
+ return {
336
+ name: 'route_rule_active_get',
337
+ description: '查看当前启用的路由规则文件。用于决定写入哪个规则文件。',
338
+ risk: 'read',
339
+ requiresConfirmation: false,
340
+ parameters: {
341
+ type: 'object',
342
+ properties: {},
343
+ additionalProperties: false,
344
+ },
345
+ execute(_input, ctx) {
346
+ const files = (0, rule_files_1.listRuleFiles)(ctx.serverContext);
347
+ const activeFiles = files.filter((file) => file.enabled);
348
+ return {
349
+ activeRuleFiles: activeFiles.map((file) => file.name),
350
+ activeCount: activeFiles.length,
351
+ currentRuleFile: activeFiles.length === 1 ? activeFiles[0].name : null,
352
+ files,
353
+ };
354
+ },
355
+ };
356
+ }
357
+ function createRouteRuleListTool() {
358
+ return {
359
+ name: 'route_rule_list',
360
+ description: '列出所有路由规则文件,或读取指定规则文件中的规则。',
361
+ risk: 'read',
362
+ requiresConfirmation: false,
363
+ parameters: {
364
+ type: 'object',
365
+ properties: {
366
+ ruleFile: {
367
+ type: 'string',
368
+ description: '可选的规则文件名,不含 .txt。',
369
+ },
370
+ },
371
+ additionalProperties: false,
372
+ },
373
+ execute(input, ctx) {
374
+ const ruleFile = typeof input.ruleFile === 'string' ? input.ruleFile.trim() : '';
375
+ if (!ruleFile) {
376
+ return { files: (0, rule_files_1.listRuleFiles)(ctx.serverContext) };
377
+ }
378
+ const content = (0, rule_files_1.readRuleFileContent)(ctx.serverContext, ruleFile);
379
+ const parsed = (0, helpers_1.parseEprcWithExclusions)(content);
380
+ return {
381
+ ruleFile,
382
+ rules: parsed.rules,
383
+ };
384
+ },
385
+ };
386
+ }
387
+ function createRoutePreviewTool() {
388
+ return {
389
+ name: 'route_preview',
390
+ description: '预览指定 URL 会被路由到哪里。支持指定 ruleFile 或传入 rulesText。',
391
+ risk: 'read',
392
+ requiresConfirmation: false,
393
+ parameters: {
394
+ type: 'object',
395
+ properties: {
396
+ url: {
397
+ type: 'string',
398
+ description: '要预览的完整 URL。',
399
+ },
400
+ ruleFile: {
401
+ type: 'string',
402
+ description: '可选规则文件名,不传则使用全部启用规则文件。',
403
+ },
404
+ rulesText: {
405
+ type: 'string',
406
+ description: '可选临时规则文本;提供后优先使用。',
407
+ },
408
+ },
409
+ required: ['url'],
410
+ additionalProperties: false,
411
+ },
412
+ execute(input, ctx) {
413
+ const url = asString(input.url, 'url');
414
+ const rulesText = typeof input.rulesText === 'string' && input.rulesText.trim()
415
+ ? input.rulesText
416
+ : typeof input.ruleFile === 'string' && input.ruleFile.trim()
417
+ ? (0, rule_files_1.readRuleFileContent)(ctx.serverContext, input.ruleFile)
418
+ : readCombinedActiveRules(ctx);
419
+ if (!rulesText.trim()) {
420
+ throw new Error('无可用规则:请先创建并激活路由规则文件,或提供 rulesText。');
421
+ }
422
+ return (0, route_preview_1.previewRouteTarget)(url, rulesText);
423
+ },
424
+ };
425
+ }
426
+ function createRouteRuleAddTool() {
427
+ return {
428
+ name: 'route_rule_add',
429
+ description: '在指定规则文件中添加或覆盖一条路由规则。该工具会修改本地规则配置,执行前必须确认。',
430
+ risk: 'write',
431
+ requiresConfirmation: true,
432
+ parameters: {
433
+ type: 'object',
434
+ properties: {
435
+ ruleFile: {
436
+ type: 'string',
437
+ description: '规则文件名,不含 .txt。',
438
+ },
439
+ pattern: {
440
+ type: 'string',
441
+ description: '匹配完整请求 URL 的 pattern,支持正则、通配符和 [marker]。',
442
+ },
443
+ target: {
444
+ type: 'string',
445
+ description: '转发目标。若仅 host:port 则继承原请求协议、路径和 query。',
446
+ },
447
+ exclusions: {
448
+ type: 'array',
449
+ items: { type: 'string' },
450
+ description: '可选排除规则列表。',
451
+ },
452
+ },
453
+ required: ['ruleFile', 'pattern', 'target'],
454
+ additionalProperties: false,
455
+ },
456
+ prepareConfirmation(input, ctx) {
457
+ const normalized = normalizeRouteRuleAddInput(input);
458
+ const next = buildRouteRuleAddContent(normalized, ctx);
459
+ const action = next.previousTarget ? '覆盖' : '添加';
460
+ return {
461
+ summary: `${action}路由规则:${normalized.pattern} -> ${normalized.target}`,
462
+ diff: buildRouteRuleDiff(normalized, next),
463
+ preview: {
464
+ ruleFile: normalized.ruleFile,
465
+ pattern: normalized.pattern,
466
+ target: normalized.target,
467
+ exclusions: normalized.exclusions || [],
468
+ overwritesExistingRule: Boolean(next.previousTarget),
469
+ },
470
+ input: normalized,
471
+ };
472
+ },
473
+ execute(input, ctx) {
474
+ const normalized = normalizeRouteRuleAddInput(input);
475
+ const next = buildRouteRuleAddContent(normalized, ctx);
476
+ (0, rule_files_1.writeRuleFileContent)(ctx.serverContext, normalized.ruleFile, next.newContent);
477
+ return {
478
+ status: 'success',
479
+ message: `已写入规则:${normalized.pattern} -> ${normalized.target}`,
480
+ ruleFile: normalized.ruleFile,
481
+ pattern: normalized.pattern,
482
+ target: normalized.target,
483
+ exclusions: normalized.exclusions || [],
484
+ };
485
+ },
486
+ };
487
+ }
488
+ function createRouteRuleUpdateTool() {
489
+ return {
490
+ name: 'route_rule_update',
491
+ description: '更新指定规则文件中的路由规则 target 和/或 exclusions。该工具会修改本地规则配置,执行前必须确认。',
492
+ risk: 'write',
493
+ requiresConfirmation: true,
494
+ parameters: {
495
+ type: 'object',
496
+ properties: {
497
+ ruleFile: {
498
+ type: 'string',
499
+ description: '规则文件名,不含 .txt。',
500
+ },
501
+ pattern: {
502
+ type: 'string',
503
+ description: '要更新的现有路由规则 pattern,支持带 [marker] 的写法。',
504
+ },
505
+ target: {
506
+ type: 'string',
507
+ description: '新的转发目标。也兼容 newTarget 字段。',
508
+ },
509
+ newTarget: {
510
+ type: 'string',
511
+ description: '新的转发目标,兼容 MCP 工具命名。',
512
+ },
513
+ exclusions: {
514
+ type: 'array',
515
+ items: { type: 'string' },
516
+ description: '新的排除规则列表;传空数组表示清空。',
517
+ },
518
+ },
519
+ required: ['ruleFile', 'pattern'],
520
+ additionalProperties: false,
521
+ },
522
+ prepareConfirmation(input, ctx) {
523
+ const normalized = normalizeRouteRuleUpdateInput(input);
524
+ const next = buildRouteRuleUpdateContent(normalized, ctx);
525
+ return {
526
+ summary: `更新路由规则:${normalized.pattern}`,
527
+ diff: buildRouteRuleUpdateDiff(normalized, next),
528
+ preview: {
529
+ ruleFile: normalized.ruleFile,
530
+ pattern: normalized.pattern,
531
+ target: next.newTarget,
532
+ exclusions: next.exclusions,
533
+ },
534
+ input: normalized,
535
+ };
536
+ },
537
+ execute(input, ctx) {
538
+ const normalized = normalizeRouteRuleUpdateInput(input);
539
+ const next = buildRouteRuleUpdateContent(normalized, ctx);
540
+ (0, rule_files_1.writeRuleFileContent)(ctx.serverContext, normalized.ruleFile, next.newContent);
541
+ return {
542
+ status: 'success',
543
+ message: `已更新规则:${normalized.pattern}`,
544
+ ruleFile: normalized.ruleFile,
545
+ pattern: normalized.pattern,
546
+ target: next.newTarget,
547
+ exclusions: next.exclusions,
548
+ };
549
+ },
550
+ };
551
+ }
552
+ function createRouteRuleDeleteTool() {
553
+ return {
554
+ name: 'route_rule_delete',
555
+ description: '删除指定规则文件中的一条路由规则。该工具会修改本地规则配置,执行前必须确认。',
556
+ risk: 'destructive',
557
+ requiresConfirmation: true,
558
+ parameters: {
559
+ type: 'object',
560
+ properties: {
561
+ ruleFile: {
562
+ type: 'string',
563
+ description: '规则文件名,不含 .txt。',
564
+ },
565
+ pattern: {
566
+ type: 'string',
567
+ description: '要删除的现有路由规则 pattern,支持带 [marker] 的写法。',
568
+ },
569
+ },
570
+ required: ['ruleFile', 'pattern'],
571
+ additionalProperties: false,
572
+ },
573
+ prepareConfirmation(input, ctx) {
574
+ const normalized = normalizeRouteRuleDeleteInput(input);
575
+ const next = buildRouteRuleDeleteContent(normalized, ctx);
576
+ return {
577
+ summary: `删除路由规则:${normalized.pattern}`,
578
+ diff: buildRouteRuleDeleteDiff(normalized, next),
579
+ preview: {
580
+ ruleFile: normalized.ruleFile,
581
+ pattern: normalized.pattern,
582
+ target: next.previousTarget,
583
+ exclusions: next.previousExclusions,
584
+ },
585
+ input: normalized,
586
+ };
587
+ },
588
+ execute(input, ctx) {
589
+ const normalized = normalizeRouteRuleDeleteInput(input);
590
+ const next = buildRouteRuleDeleteContent(normalized, ctx);
591
+ (0, rule_files_1.writeRuleFileContent)(ctx.serverContext, normalized.ruleFile, next.newContent);
592
+ return {
593
+ status: 'success',
594
+ message: `已删除规则:${normalized.pattern}`,
595
+ ruleFile: normalized.ruleFile,
596
+ pattern: normalized.pattern,
597
+ };
598
+ },
599
+ };
600
+ }
601
+ function createRouteRuleCreateFileTool() {
602
+ return {
603
+ name: 'route_rule_create_file',
604
+ description: '创建新的路由规则文件,并可选择是否设为启用。该工具会修改本地规则配置,执行前必须确认。',
605
+ risk: 'write',
606
+ requiresConfirmation: true,
607
+ parameters: {
608
+ type: 'object',
609
+ properties: {
610
+ ruleFile: {
611
+ type: 'string',
612
+ description: '要创建的规则文件名,不含 .txt。也兼容 name 字段。',
613
+ },
614
+ name: {
615
+ type: 'string',
616
+ description: '要创建的规则文件名,不含 .txt。',
617
+ },
618
+ content: {
619
+ type: 'string',
620
+ description: '可选初始规则文本。',
621
+ },
622
+ enabled: {
623
+ type: 'boolean',
624
+ description: '是否创建后启用,默认 true。',
625
+ },
626
+ },
627
+ additionalProperties: false,
628
+ },
629
+ prepareConfirmation(input) {
630
+ const normalized = normalizeRouteRuleCreateFileInput(input);
631
+ return {
632
+ summary: `创建规则文件:${normalized.name}${normalized.enabled ? ',并启用' : ''}`,
633
+ diff: [
634
+ `+ 规则文件: ${normalized.name}`,
635
+ normalized.content ? `+ 初始内容:\n${normalized.content}` : null,
636
+ ].filter(Boolean).join('\n'),
637
+ preview: normalized,
638
+ input: normalized,
639
+ };
640
+ },
641
+ execute(input, ctx) {
642
+ const normalized = normalizeRouteRuleCreateFileInput(input);
643
+ const ruleFile = (0, rule_files_1.createRuleFile)(ctx.serverContext, normalized.name, normalized.content, normalized.enabled);
644
+ return {
645
+ status: 'success',
646
+ message: `已创建规则文件:${ruleFile.name}`,
647
+ ruleFile,
648
+ };
649
+ },
650
+ };
651
+ }
652
+ function createRouteRuleActiveSetTool() {
653
+ return {
654
+ name: 'route_rule_active_set',
655
+ description: '设置当前启用的路由规则文件列表。传 ruleFile 可设置单个启用文件,传 ruleFiles 可按顺序启用多个文件。执行前必须确认。',
656
+ risk: 'write',
657
+ requiresConfirmation: true,
658
+ parameters: {
659
+ type: 'object',
660
+ properties: {
661
+ ruleFile: {
662
+ type: 'string',
663
+ description: '单个要启用的规则文件名,不含 .txt。',
664
+ },
665
+ ruleFiles: {
666
+ type: 'array',
667
+ items: { type: 'string' },
668
+ description: '按顺序启用的规则文件名列表,不含 .txt。',
669
+ },
670
+ },
671
+ additionalProperties: false,
672
+ },
673
+ prepareConfirmation(input, ctx) {
674
+ const normalized = normalizeRouteRuleActiveSetInput(input);
675
+ const current = (0, rule_files_1.getActiveRuleFileNames)(ctx.serverContext);
676
+ return {
677
+ summary: `切换启用规则文件:${normalized.ruleFiles.join(', ')}`,
678
+ diff: [
679
+ `- 当前启用: ${current.join(', ') || '(无)'}`,
680
+ `+ 新启用: ${normalized.ruleFiles.join(', ') || '(无)'}`,
681
+ ].join('\n'),
682
+ preview: normalized,
683
+ input: normalized,
684
+ };
685
+ },
686
+ execute(input, ctx) {
687
+ const normalized = normalizeRouteRuleActiveSetInput(input);
688
+ const activeRuleFiles = (0, rule_files_1.setActiveRuleFileNames)(ctx.serverContext, normalized.ruleFiles);
689
+ return {
690
+ status: 'success',
691
+ message: `已切换启用规则文件:${activeRuleFiles.join(', ')}`,
692
+ activeRuleFiles,
693
+ };
694
+ },
695
+ };
696
+ }
697
+ function createMockRuleListTool() {
698
+ return {
699
+ name: 'mock_rule_list',
700
+ description: '列出所有 Mock 规则,或按 id 查看单条 Mock 规则。',
701
+ risk: 'read',
702
+ requiresConfirmation: false,
703
+ parameters: {
704
+ type: 'object',
705
+ properties: {
706
+ id: {
707
+ type: 'number',
708
+ description: '可选 Mock 规则 ID。',
709
+ },
710
+ },
711
+ additionalProperties: false,
712
+ },
713
+ execute(input, ctx) {
714
+ const id = asOptionalNumber(input.id, 'id');
715
+ if (id !== undefined) {
716
+ return { rule: getMockRule(ctx, id) };
717
+ }
718
+ return { rules: ctx.serverContext.mockRules };
719
+ },
720
+ };
721
+ }
722
+ function createMockRuleAddTool() {
723
+ return {
724
+ name: 'mock_rule_add',
725
+ description: '新增 Mock 规则。该工具会修改本地 Mock 配置,执行前必须确认。',
726
+ risk: 'write',
727
+ requiresConfirmation: true,
728
+ parameters: {
729
+ type: 'object',
730
+ properties: {
731
+ name: { type: 'string', description: '规则名称。' },
732
+ urlPattern: { type: 'string', description: 'URL 匹配正则或字符串。' },
733
+ method: { type: 'string', description: 'HTTP 方法,如 GET、POST、*。默认 *。' },
734
+ statusCode: { type: 'number', description: '响应状态码,默认 200。' },
735
+ delay: { type: 'number', description: '延迟毫秒数,默认 0。' },
736
+ bodyType: { type: 'string', description: 'body 类型:inline 或 file。默认 inline。' },
737
+ headers: { type: 'object', additionalProperties: { type: 'string' }, description: '响应头。' },
738
+ body: { type: 'string', description: '响应体内容。' },
739
+ enabled: { type: 'boolean', description: '是否启用,默认 true。' },
740
+ },
741
+ required: ['urlPattern'],
742
+ additionalProperties: false,
743
+ },
744
+ prepareConfirmation(input) {
745
+ const normalized = normalizeMockRuleInput(input, true);
746
+ return {
747
+ summary: `新增 Mock 规则:${normalized.name || normalized.urlPattern}`,
748
+ diff: buildMockRuleDiff(null, normalized),
749
+ preview: normalized,
750
+ input: normalized,
751
+ };
752
+ },
753
+ execute(input, ctx) {
754
+ const normalized = normalizeMockRuleInput(input, true);
755
+ const rule = (0, mocks_1.createMockRule)(ctx.serverContext, normalized);
756
+ return {
757
+ status: 'success',
758
+ message: `已新增 Mock 规则:${rule.name || rule.urlPattern}`,
759
+ rule,
760
+ };
761
+ },
762
+ };
763
+ }
764
+ function createMockRuleUpdateTool() {
765
+ return {
766
+ name: 'mock_rule_update',
767
+ description: '更新指定 Mock 规则。该工具会修改本地 Mock 配置,执行前必须确认。',
768
+ risk: 'write',
769
+ requiresConfirmation: true,
770
+ parameters: {
771
+ type: 'object',
772
+ properties: {
773
+ id: { type: 'number', description: '要更新的 Mock 规则 ID。' },
774
+ name: { type: 'string', description: '规则名称。' },
775
+ urlPattern: { type: 'string', description: 'URL 匹配正则或字符串。' },
776
+ method: { type: 'string', description: 'HTTP 方法,如 GET、POST、*。' },
777
+ statusCode: { type: 'number', description: '响应状态码。' },
778
+ delay: { type: 'number', description: '延迟毫秒数。' },
779
+ bodyType: { type: 'string', description: 'body 类型:inline 或 file。' },
780
+ headers: { type: 'object', additionalProperties: { type: 'string' }, description: '响应头。' },
781
+ body: { type: 'string', description: '响应体内容。' },
782
+ enabled: { type: 'boolean', description: '是否启用。' },
783
+ },
784
+ required: ['id'],
785
+ additionalProperties: false,
786
+ },
787
+ prepareConfirmation(input, ctx) {
788
+ const id = normalizeMockRuleId(input);
789
+ const previous = getMockRule(ctx, id);
790
+ const patch = normalizeMockRuleInput(input, false);
791
+ const next = { ...previous, ...patch, id };
792
+ return {
793
+ summary: `更新 Mock 规则:${previous.name || previous.urlPattern}`,
794
+ diff: buildMockRuleDiff(previous, next),
795
+ preview: next,
796
+ input: { id, ...patch },
797
+ };
798
+ },
799
+ execute(input, ctx) {
800
+ const id = normalizeMockRuleId(input);
801
+ const patch = normalizeMockRuleInput(input, false);
802
+ const rule = (0, mocks_1.updateMockRule)(ctx.serverContext, id, patch);
803
+ return {
804
+ status: 'success',
805
+ message: `已更新 Mock 规则:${rule.name || rule.urlPattern}`,
806
+ rule,
807
+ };
808
+ },
809
+ };
810
+ }
811
+ function createMockRuleDeleteTool() {
812
+ return {
813
+ name: 'mock_rule_delete',
814
+ description: '删除指定 Mock 规则。该工具会修改本地 Mock 配置,执行前必须确认。',
815
+ risk: 'destructive',
816
+ requiresConfirmation: true,
817
+ parameters: {
818
+ type: 'object',
819
+ properties: {
820
+ id: { type: 'number', description: '要删除的 Mock 规则 ID。' },
821
+ },
822
+ required: ['id'],
823
+ additionalProperties: false,
824
+ },
825
+ prepareConfirmation(input, ctx) {
826
+ const id = normalizeMockRuleId(input);
827
+ const previous = getMockRule(ctx, id);
828
+ return {
829
+ summary: `删除 Mock 规则:${previous.name || previous.urlPattern}`,
830
+ diff: `- ${formatMockRule(previous)}`,
831
+ preview: previous,
832
+ input: { id },
833
+ };
834
+ },
835
+ execute(input, ctx) {
836
+ const id = normalizeMockRuleId(input);
837
+ const previous = getMockRule(ctx, id);
838
+ (0, mocks_1.deleteMockRule)(ctx.serverContext, id);
839
+ return {
840
+ status: 'success',
841
+ message: `已删除 Mock 规则:${previous.name || previous.urlPattern}`,
842
+ id,
843
+ };
844
+ },
845
+ };
846
+ }
847
+ function createLogListTool() {
848
+ return {
849
+ name: 'log_list',
850
+ description: '查看最近的代理请求日志,可按 method、statusCode 或关键词过滤。',
851
+ risk: 'read',
852
+ requiresConfirmation: false,
853
+ parameters: {
854
+ type: 'object',
855
+ properties: {
856
+ limit: { type: 'number', description: '返回数量,默认 20,最大 100。' },
857
+ method: { type: 'string', description: '可选 HTTP 方法过滤。' },
858
+ statusCode: { type: 'number', description: '可选状态码过滤。' },
859
+ keyword: { type: 'string', description: '可选关键词,匹配源地址或目标地址。' },
860
+ },
861
+ additionalProperties: false,
862
+ },
863
+ execute(input, ctx) {
864
+ const normalized = normalizeLogListInput(input);
865
+ const records = [...ctx.serverContext.proxyRecordArr].reverse()
866
+ .filter((record) => !normalized.method || record.method.toUpperCase() === normalized.method)
867
+ .filter((record) => normalized.statusCode === undefined || record.statusCode === normalized.statusCode)
868
+ .filter((record) => {
869
+ if (!normalized.keyword)
870
+ return true;
871
+ return record.source.includes(normalized.keyword) || record.target.includes(normalized.keyword);
872
+ })
873
+ .slice(0, normalized.limit);
874
+ return {
875
+ total: ctx.serverContext.proxyRecordArr.length,
876
+ returned: records.length,
877
+ records,
878
+ };
879
+ },
880
+ };
881
+ }
882
+ function createLogDetailTool() {
883
+ return {
884
+ name: 'log_detail_get',
885
+ description: '按日志 ID 查看请求详情,包括请求头、响应头、body 摘要和状态码。',
886
+ risk: 'read',
887
+ requiresConfirmation: false,
888
+ parameters: {
889
+ type: 'object',
890
+ properties: {
891
+ id: { type: 'number', description: '日志记录 ID。' },
892
+ },
893
+ required: ['id'],
894
+ additionalProperties: false,
895
+ },
896
+ execute(input, ctx) {
897
+ const id = normalizeMockRuleId(input);
898
+ const detail = ctx.serverContext.proxyRecordDetailMap.get(id);
899
+ const record = ctx.serverContext.proxyRecordArr.find((item) => item.id === id);
900
+ if (!detail && !record) {
901
+ throw new Error(`未找到日志记录: ${id}`);
902
+ }
903
+ return {
904
+ record,
905
+ detail: detail || null,
906
+ };
907
+ },
908
+ };
909
+ }
910
+ function createPluginListTool() {
911
+ return {
912
+ name: 'plugin_list',
913
+ description: '查看当前插件列表、状态、hooks、权限和执行统计。',
914
+ risk: 'read',
915
+ requiresConfirmation: false,
916
+ parameters: {
917
+ type: 'object',
918
+ properties: {},
919
+ additionalProperties: false,
920
+ },
921
+ execute(_input, ctx) {
922
+ return buildPluginList(ctx);
923
+ },
924
+ };
925
+ }
926
+ function createPluginHealthTool() {
927
+ return {
928
+ name: 'plugin_health_get',
929
+ description: '查看插件健康概览,包括插件状态和 hook 统计。',
930
+ risk: 'read',
931
+ requiresConfirmation: false,
932
+ parameters: {
933
+ type: 'object',
934
+ properties: {},
935
+ additionalProperties: false,
936
+ },
937
+ execute(_input, ctx) {
938
+ const pluginStats = ctx.serverContext.hookDispatcher.getPluginStats ? ctx.serverContext.hookDispatcher.getPluginStats() : {};
939
+ const pluginStates = {};
940
+ const plugins = ctx.serverContext.pluginManager.getAll().map((plugin) => {
941
+ pluginStates[plugin.manifest.id] = ctx.serverContext.pluginManager.getState(plugin.manifest.id);
942
+ return {
943
+ id: plugin.manifest.id,
944
+ name: plugin.manifest.name,
945
+ version: plugin.manifest.version,
946
+ hooks: plugin.manifest.hooks,
947
+ permissions: plugin.manifest.permissions,
948
+ priority: plugin.manifest.priority,
949
+ };
950
+ });
951
+ return {
952
+ mode: ctx.serverContext.requestPipeline.mode,
953
+ total: plugins.length,
954
+ plugins,
955
+ pluginStates,
956
+ pluginStats,
957
+ };
958
+ },
959
+ };
960
+ }
961
+ function createPluginToggleTool() {
962
+ return {
963
+ name: 'plugin_toggle',
964
+ description: '启用或禁用指定插件。该工具会修改运行态和 settings.json,执行前必须确认。',
965
+ risk: 'write',
966
+ requiresConfirmation: true,
967
+ parameters: {
968
+ type: 'object',
969
+ properties: {
970
+ pluginId: { type: 'string', description: '插件 ID。也兼容 id 字段。' },
971
+ id: { type: 'string', description: '插件 ID,兼容简写。' },
972
+ enabled: { type: 'boolean', description: 'true 表示启用,false 表示禁用。' },
973
+ },
974
+ required: ['enabled'],
975
+ additionalProperties: false,
976
+ },
977
+ prepareConfirmation(input, ctx) {
978
+ const normalized = normalizePluginToggleInput(input);
979
+ const currentState = getPluginState(ctx, normalized.pluginId);
980
+ const nextState = normalized.enabled ? 'running' : 'disabled';
981
+ return {
982
+ summary: `${normalized.enabled ? '启用' : '禁用'}插件:${normalized.pluginId}`,
983
+ diff: [
984
+ `- ${normalized.pluginId}: state=${currentState}`,
985
+ `+ ${normalized.pluginId}: state=${nextState}`,
986
+ ].join('\n'),
987
+ preview: {
988
+ pluginId: normalized.pluginId,
989
+ currentState,
990
+ nextState,
991
+ },
992
+ input: normalized,
993
+ };
994
+ },
995
+ execute(input, ctx) {
996
+ const normalized = normalizePluginToggleInput(input);
997
+ return (0, plugins_1.setPluginEnabled)(ctx.serverContext, normalized.pluginId, normalized.enabled);
998
+ },
999
+ };
1000
+ }
1001
+ function createPluginReloadTool() {
1002
+ return {
1003
+ name: 'plugin_reload',
1004
+ description: '热加载自定义插件。该工具会重新扫描并注册本地插件,执行前必须确认。',
1005
+ risk: 'write',
1006
+ requiresConfirmation: true,
1007
+ parameters: {
1008
+ type: 'object',
1009
+ properties: {},
1010
+ additionalProperties: false,
1011
+ },
1012
+ prepareConfirmation() {
1013
+ return {
1014
+ summary: '热加载自定义插件',
1015
+ diff: [
1016
+ '- 当前自定义插件注册状态',
1017
+ '+ 重新扫描并加载自定义插件',
1018
+ ].join('\n'),
1019
+ preview: {},
1020
+ input: {},
1021
+ };
1022
+ },
1023
+ execute(_input, ctx) {
1024
+ return (0, plugins_1.reloadPlugins)(ctx.serverContext);
1025
+ },
1026
+ };
1027
+ }
1028
+ function createPipelineStatusTool() {
1029
+ return {
1030
+ name: 'pipeline_status_get',
1031
+ description: '查看 request pipeline 当前模式、shadow 统计和 on-mode gate 统计。',
1032
+ risk: 'read',
1033
+ requiresConfirmation: false,
1034
+ parameters: {
1035
+ type: 'object',
1036
+ properties: {},
1037
+ additionalProperties: false,
1038
+ },
1039
+ execute(_input, ctx) {
1040
+ return buildPipelineStatus(ctx);
1041
+ },
1042
+ };
1043
+ }
1044
+ function createPipelineShadowStatsResetTool() {
1045
+ return {
1046
+ name: 'pipeline_shadow_stats_reset',
1047
+ description: '重置 request pipeline 的 shadow 比对统计和 on-mode gate 统计。执行前必须确认。',
1048
+ risk: 'destructive',
1049
+ requiresConfirmation: true,
1050
+ parameters: {
1051
+ type: 'object',
1052
+ properties: {},
1053
+ additionalProperties: false,
1054
+ },
1055
+ prepareConfirmation(_input, ctx) {
1056
+ return {
1057
+ summary: '重置 shadow 统计',
1058
+ diff: [
1059
+ `- shadowStats=${JSON.stringify(ctx.serverContext.shadowCompareTracker.getStats())}`,
1060
+ `- onModeGate=${JSON.stringify(ctx.serverContext.onModeGate.getStats())}`,
1061
+ '+ shadowStats=reset',
1062
+ '+ onModeGate=reset',
1063
+ ].join('\n'),
1064
+ preview: buildPipelineStatus(ctx),
1065
+ input: {},
1066
+ };
1067
+ },
1068
+ execute(_input, ctx) {
1069
+ return (0, pipeline_1.resetShadowStats)(ctx.serverContext);
1070
+ },
1071
+ };
1072
+ }
1073
+ function createPipelineModeSetTool() {
1074
+ return {
1075
+ name: 'pipeline_mode_set',
1076
+ description: '切换插件 request pipeline 模式,可选 off、shadow、on。该工具会修改运行态和 settings.json,执行前必须确认。',
1077
+ risk: 'write',
1078
+ requiresConfirmation: true,
1079
+ parameters: {
1080
+ type: 'object',
1081
+ properties: {
1082
+ mode: { type: 'string', description: '目标模式:off、shadow 或 on。' },
1083
+ },
1084
+ required: ['mode'],
1085
+ additionalProperties: false,
1086
+ },
1087
+ prepareConfirmation(input, ctx) {
1088
+ const normalized = normalizePipelineModeInput(input);
1089
+ const current = ctx.serverContext.requestPipeline.mode;
1090
+ return {
1091
+ summary: `切换插件模式:${current} -> ${normalized.mode}`,
1092
+ diff: [
1093
+ `- pluginMode=${current}`,
1094
+ `+ pluginMode=${normalized.mode}`,
1095
+ ].join('\n'),
1096
+ preview: {
1097
+ currentMode: current,
1098
+ nextMode: normalized.mode,
1099
+ },
1100
+ input: normalized,
1101
+ };
1102
+ },
1103
+ execute(input, ctx) {
1104
+ const normalized = normalizePipelineModeInput(input);
1105
+ return (0, pipeline_1.setPipelineMode)(ctx.serverContext, normalized.mode);
1106
+ },
1107
+ };
1108
+ }
1109
+ function createConfigRefreshTool() {
1110
+ return {
1111
+ name: 'config_refresh',
1112
+ description: '刷新本地配置,重新加载路由规则和 Mock 规则。执行前必须确认。',
1113
+ risk: 'write',
1114
+ requiresConfirmation: true,
1115
+ parameters: {
1116
+ type: 'object',
1117
+ properties: {},
1118
+ additionalProperties: false,
1119
+ },
1120
+ prepareConfirmation(_input, ctx) {
1121
+ return {
1122
+ summary: '刷新配置',
1123
+ diff: [
1124
+ '- 当前内存中的规则和 Mock 配置',
1125
+ '+ 从本地配置文件重新加载规则和 Mock 配置',
1126
+ ].join('\n'),
1127
+ preview: {
1128
+ mocksPath: ctx.serverContext.getMockFilePath(),
1129
+ },
1130
+ input: {},
1131
+ };
1132
+ },
1133
+ execute(_input, ctx) {
1134
+ return (0, config_1.refreshConfig)(ctx.serverContext);
1135
+ },
1136
+ };
1137
+ }
1138
+ function createConfigDoctorTool() {
1139
+ return {
1140
+ name: 'config_doctor',
1141
+ description: '运行配置文件健康检查,查看规则、Mock、插件等配置状态。',
1142
+ risk: 'read',
1143
+ requiresConfirmation: false,
1144
+ parameters: {
1145
+ type: 'object',
1146
+ properties: {},
1147
+ additionalProperties: false,
1148
+ },
1149
+ execute(_input, ctx) {
1150
+ return ctx.serverContext.performConfigDiagnostics();
1151
+ },
1152
+ };
1153
+ }
1154
+ function createAgentTools() {
1155
+ const tools = [
1156
+ createRouteRuleActiveGetTool(),
1157
+ createRouteRuleListTool(),
1158
+ createRoutePreviewTool(),
1159
+ createRouteRuleCreateFileTool(),
1160
+ createRouteRuleActiveSetTool(),
1161
+ createRouteRuleAddTool(),
1162
+ createRouteRuleUpdateTool(),
1163
+ createRouteRuleDeleteTool(),
1164
+ createMockRuleListTool(),
1165
+ createMockRuleAddTool(),
1166
+ createMockRuleUpdateTool(),
1167
+ createMockRuleDeleteTool(),
1168
+ createLogListTool(),
1169
+ createLogDetailTool(),
1170
+ createPluginListTool(),
1171
+ createPluginHealthTool(),
1172
+ createPluginToggleTool(),
1173
+ createPluginReloadTool(),
1174
+ createPipelineStatusTool(),
1175
+ createPipelineShadowStatsResetTool(),
1176
+ createPipelineModeSetTool(),
1177
+ createConfigRefreshTool(),
1178
+ createConfigDoctorTool(),
1179
+ ];
1180
+ return new Map(tools.map((tool) => [tool.name, tool]));
1181
+ }
1182
+ function toToolDefinitions(tools) {
1183
+ return Array.from(tools.values()).map((tool) => ({
1184
+ type: 'function',
1185
+ function: {
1186
+ name: tool.name,
1187
+ description: tool.description,
1188
+ parameters: tool.parameters,
1189
+ },
1190
+ }));
1191
+ }
1192
+ function describeAgentTools(tools) {
1193
+ return Array.from(tools.values()).map((tool) => ({
1194
+ name: tool.name,
1195
+ description: tool.description,
1196
+ risk: tool.risk,
1197
+ requiresConfirmation: tool.requiresConfirmation,
1198
+ parameters: tool.parameters,
1199
+ }));
1200
+ }
1201
+ //# sourceMappingURL=tools.js.map