@cc-monitoring/proxy-core 0.1.4 → 0.1.5-alpha.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 (290) hide show
  1. package/README.md +11 -35
  2. package/dist/config/index.js +2 -1
  3. package/dist/config/schema.d.ts +48 -0
  4. package/dist/config/schema.js +11 -1
  5. package/dist/server/chat-route.d.ts +3 -0
  6. package/dist/server/chat-route.js +401 -0
  7. package/dist/server/data-push.d.ts +1 -1
  8. package/dist/server/data-push.js +3 -3
  9. package/dist/server/index.js +2 -0
  10. package/dist/server/mcp-route.d.ts +2 -0
  11. package/dist/server/mcp-route.js +161 -0
  12. package/dist/server/proxy.d.ts +2 -0
  13. package/dist/server/proxy.js +55 -101
  14. package/dist/server/ui-route.js +3 -0
  15. package/dist/tools/mcp-bridge.d.ts +13 -0
  16. package/dist/tools/mcp-bridge.js +36 -0
  17. package/dist/tools/registry.js +10 -4
  18. package/dist/ui/assets/{1c-CgVqmGt6.js → 1c-BKfNxcqO.js} +1 -1
  19. package/dist/ui/assets/{abnf-JPM4b6fj.js → abnf-kurmJZQ_.js} +1 -1
  20. package/dist/ui/assets/{abnfDiagram-VRR7QNED-DJkd8PHl.js → abnfDiagram-VRR7QNED-ByeCIWIR.js} +1 -1
  21. package/dist/ui/assets/{accesslog-CLIMhXWi.js → accesslog-D64BZ_De.js} +1 -1
  22. package/dist/ui/assets/{actionscript-DqniQGld.js → actionscript-pDK74uly.js} +1 -1
  23. package/dist/ui/assets/{ada-2BFfY7fF.js → ada-DRb-_v9Q.js} +1 -1
  24. package/dist/ui/assets/{angelscript-C47qRqcs.js → angelscript-CZNb0D_x.js} +1 -1
  25. package/dist/ui/assets/{apache-DP-LC5-h.js → apache-DXxCmfqn.js} +1 -1
  26. package/dist/ui/assets/{applescript-BB0gk3HQ.js → applescript-SH5nkFFY.js} +1 -1
  27. package/dist/ui/assets/{arc-D8wRCC4D.js → arc-MeodV3jp.js} +1 -1
  28. package/dist/ui/assets/{arcade-1R6g1VPm.js → arcade-BBDVvGqJ.js} +1 -1
  29. package/dist/ui/assets/{architectureDiagram-ZJ3FMSHR-CbHhHV9v.js → architectureDiagram-ZJ3FMSHR-BemxtZtq.js} +1 -1
  30. package/dist/ui/assets/{arduino-B8YryK0R.js → arduino-BzSPoel-.js} +1 -1
  31. package/dist/ui/assets/{armasm-CYdj7mzR.js → armasm-bxTyTYQU.js} +1 -1
  32. package/dist/ui/assets/{asciidoc-bZ11zz6i.js → asciidoc-CTwbDxt_.js} +1 -1
  33. package/dist/ui/assets/{aspectj-D5WPU-RQ.js → aspectj-CG5ykwLW.js} +1 -1
  34. package/dist/ui/assets/{autohotkey-70tZvCLL.js → autohotkey-C5JGxVuA.js} +1 -1
  35. package/dist/ui/assets/{autoit-CX2GaaHP.js → autoit-y4Yl0UCW.js} +1 -1
  36. package/dist/ui/assets/{avrasm-C154El0d.js → avrasm-bGE35O5G.js} +1 -1
  37. package/dist/ui/assets/{awk-DdXKOeux.js → awk-EaW3U0nk.js} +1 -1
  38. package/dist/ui/assets/{axapta-CwLwkXST.js → axapta-DR4gLXP2.js} +1 -1
  39. package/dist/ui/assets/{bash-Uu61S1nB.js → bash-ce3pZrbv.js} +1 -1
  40. package/dist/ui/assets/{basic-CeiAWoiF.js → basic-BUjgcgEE.js} +1 -1
  41. package/dist/ui/assets/{blockDiagram-677ZJIJ3-DcvhphUd.js → blockDiagram-677ZJIJ3-_o8CsocQ.js} +1 -1
  42. package/dist/ui/assets/{bnf-B5KF61QW.js → bnf-CweJzP3u.js} +1 -1
  43. package/dist/ui/assets/{brainfuck-CP0Y7_VW.js → brainfuck-CdSx1voD.js} +1 -1
  44. package/dist/ui/assets/{coq-D-WTlq_d.js → c-CRHUjHXY.js} +1 -1
  45. package/dist/ui/assets/{c-like-DXr53gS6.js → c-like-CEkf_5bN.js} +1 -1
  46. package/dist/ui/assets/{c4Diagram-LMCZKHZV-Cn017lmJ.js → c4Diagram-LMCZKHZV-DOkmzOL2.js} +1 -1
  47. package/dist/ui/assets/{cal-7ld1j-Wh.js → cal-n5KEHShP.js} +1 -1
  48. package/dist/ui/assets/{capnproto-DrddNBCZ.js → capnproto-DBqs0rUq.js} +1 -1
  49. package/dist/ui/assets/{ceylon-XPuE6IIL.js → ceylon-Bqm782As.js} +1 -1
  50. package/dist/ui/assets/channel-ouobCd00.js +1 -0
  51. package/dist/ui/assets/{chunk-2Q5K7J3B-BoX3IESS.js → chunk-2Q5K7J3B-DW9ak6HE.js} +1 -1
  52. package/dist/ui/assets/{chunk-32BRIVSS-C300ACzq.js → chunk-32BRIVSS-BrSieCRZ.js} +1 -1
  53. package/dist/ui/assets/{chunk-5VM5RSS4-MtSkFsde.js → chunk-5VM5RSS4-DfQ4qP83.js} +1 -1
  54. package/dist/ui/assets/{chunk-EX3LRPZG-CEeHrGNV.js → chunk-EX3LRPZG-Ct5q5MD9.js} +1 -1
  55. package/dist/ui/assets/{chunk-JWPE2WC7-DTRgpK0R.js → chunk-JWPE2WC7-CmPr6d57.js} +1 -1
  56. package/dist/ui/assets/{chunk-MOJQB5TN-DiOl0HJx.js → chunk-MOJQB5TN-TVmHnDCp.js} +1 -1
  57. package/dist/ui/assets/{chunk-RYQCIY6F-CVC3opqY.js → chunk-RYQCIY6F-CJid4ifN.js} +1 -1
  58. package/dist/ui/assets/{chunk-V7JOEXUC-yQYlqQCC.js → chunk-V7JOEXUC-DpPBugpJ.js} +1 -1
  59. package/dist/ui/assets/{chunk-VR4S4FIN-iAA8ZgkK.js → chunk-VR4S4FIN-ChvE2cdM.js} +1 -1
  60. package/dist/ui/assets/{chunk-XXDRQBXY-B303eieF.js → chunk-XXDRQBXY-CQkAaDcz.js} +1 -1
  61. package/dist/ui/assets/classDiagram-OUVF2IWQ-BLjfj6C1.js +1 -0
  62. package/dist/ui/assets/classDiagram-v2-EOCWNBFH-BLjfj6C1.js +1 -0
  63. package/dist/ui/assets/{clean-MfHaW_uS.js → clean-C6pxrVpV.js} +1 -1
  64. package/dist/ui/assets/{clojure-9L8TfiWA.js → clojure-DBFV_cQs.js} +1 -1
  65. package/dist/ui/assets/{clojure-repl-CjsH9sxr.js → clojure-repl-gAHGPM6b.js} +1 -1
  66. package/dist/ui/assets/{cmake-D0D1Q30G.js → cmake-kWW8kCUc.js} +1 -1
  67. package/dist/ui/assets/{coffeescript-BI4jWZnB.js → coffeescript-6GnANHV0.js} +1 -1
  68. package/dist/ui/assets/{c-BgqCrSpv.js → coq-BZ36Oykn.js} +1 -1
  69. package/dist/ui/assets/{cos-DHax5LIJ.js → cos-7hQ1utRX.js} +1 -1
  70. package/dist/ui/assets/{cose-bilkent-JH36ORCC-BzrKmTAZ.js → cose-bilkent-JH36ORCC-C3eaOw98.js} +1 -1
  71. package/dist/ui/assets/{cpp-M4aMPUas.js → cpp-3tqV0Eg4.js} +1 -1
  72. package/dist/ui/assets/{crmsh-DAAczfR0.js → crmsh-BCWSxGj_.js} +1 -1
  73. package/dist/ui/assets/{crystal-7g2CpWm4.js → crystal-DWYK1_zJ.js} +1 -1
  74. package/dist/ui/assets/{csharp-DW5GdKKf.js → csharp-4MXdBrfn.js} +1 -1
  75. package/dist/ui/assets/{csp-Bq74fG7-.js → csp-B6w1ig4q.js} +1 -1
  76. package/dist/ui/assets/{css-DHyeLXff.js → css-DF73D19j.js} +1 -1
  77. package/dist/ui/assets/{cynefin-VYW2F7L2-DwV1t9iV.js → cynefin-VYW2F7L2-CBT889Q1.js} +1 -1
  78. package/dist/ui/assets/{cynefinDiagram-TSTJHNR4-kBCFRYPz.js → cynefinDiagram-TSTJHNR4-CTpbDnI7.js} +1 -1
  79. package/dist/ui/assets/{d-yey2lm3v.js → d-DzYDcQHZ.js} +1 -1
  80. package/dist/ui/assets/{dagre-VKFMJZFB-CErVJ1s0.js → dagre-VKFMJZFB-WWoYj0oQ.js} +1 -1
  81. package/dist/ui/assets/{dart-BadDxflP.js → dart-D3jB16SU.js} +1 -1
  82. package/dist/ui/assets/{delphi-CqzVqtDp.js → delphi-CZl4UAcT.js} +1 -1
  83. package/dist/ui/assets/{diagram-FQU43EPY-C7zAW2DU.js → diagram-FQU43EPY-3wQZQkQz.js} +1 -1
  84. package/dist/ui/assets/{diagram-G47NLZAW-CbUb6BZI.js → diagram-G47NLZAW-Ca-cA51I.js} +1 -1
  85. package/dist/ui/assets/{diagram-NH7WQ7WH-C5mgi3dn.js → diagram-NH7WQ7WH-YisQNOg5.js} +1 -1
  86. package/dist/ui/assets/{diagram-OA4YK3LP-Cok2YNfS.js → diagram-OA4YK3LP-0EJamcdw.js} +1 -1
  87. package/dist/ui/assets/{diagram-WEI45ONY-BODuP2EB.js → diagram-WEI45ONY-C49BDAKI.js} +1 -1
  88. package/dist/ui/assets/{diff-EVigJ-h2.js → diff-_OXjiwKq.js} +1 -1
  89. package/dist/ui/assets/{django-BH2EEal6.js → django-MC7gw7Ba.js} +1 -1
  90. package/dist/ui/assets/{dns-BSc8VTm8.js → dns-D3uYm_NR.js} +1 -1
  91. package/dist/ui/assets/{dockerfile-Br_pZjru.js → dockerfile-CbxCn4X2.js} +1 -1
  92. package/dist/ui/assets/{dos-Bx3ludet.js → dos-D7MpkWlZ.js} +1 -1
  93. package/dist/ui/assets/{dsconfig-DSI-ePne.js → dsconfig-DejdiVkX.js} +1 -1
  94. package/dist/ui/assets/{dts-ClCuE1Xq.js → dts-CMTiAYoj.js} +1 -1
  95. package/dist/ui/assets/{dust-CC9Z8iuW.js → dust-DrNExIio.js} +1 -1
  96. package/dist/ui/assets/{ebnf-DI0w_fbi.js → ebnf-CQl_HyGP.js} +1 -1
  97. package/dist/ui/assets/{ebnfDiagram-CCIWWBDH-CgsnO8Qm.js → ebnfDiagram-CCIWWBDH-Cpbm8Saa.js} +1 -1
  98. package/dist/ui/assets/{elixir-hdzZik8p.js → elixir-DjKAXtge.js} +1 -1
  99. package/dist/ui/assets/{elm-DJAgqt5I.js → elm-DbFMwRfr.js} +1 -1
  100. package/dist/ui/assets/{erDiagram-Q63AITRT-K4zJcEKd.js → erDiagram-Q63AITRT-CjiUln3_.js} +1 -1
  101. package/dist/ui/assets/{erb-Cq4OQqkl.js → erb-CmcM27bT.js} +1 -1
  102. package/dist/ui/assets/{erlang-CHoXLODu.js → erlang-Se5g1C-_.js} +1 -1
  103. package/dist/ui/assets/{erlang-repl-Brp70Zip.js → erlang-repl-BYXNE8Rp.js} +1 -1
  104. package/dist/ui/assets/{excel-DjS-QR9P.js → excel-C0rpMYUp.js} +1 -1
  105. package/dist/ui/assets/{fix-BsO9Oq6H.js → fix-MKKAkUZt.js} +1 -1
  106. package/dist/ui/assets/{flix-2A7CKozm.js → flix-P1JtxtSk.js} +1 -1
  107. package/dist/ui/assets/{flowDiagram-23GEKE2U-Ck4tfxWX.js → flowDiagram-23GEKE2U-BHmxHBjF.js} +1 -1
  108. package/dist/ui/assets/{fortran-BQu3wORI.js → fortran-yDT4QtkM.js} +1 -1
  109. package/dist/ui/assets/{fsharp-D439S6PZ.js → fsharp-P9pwJwTA.js} +1 -1
  110. package/dist/ui/assets/{gams-CPRxKfRH.js → gams-B5t8fTmX.js} +1 -1
  111. package/dist/ui/assets/{ganttDiagram-NO4QXBWP-QTPyXXxa.js → ganttDiagram-NO4QXBWP-CLZshSdd.js} +1 -1
  112. package/dist/ui/assets/{gauss-GJFW9Vod.js → gauss-BnurLk3c.js} +1 -1
  113. package/dist/ui/assets/{gcode-CF6woDAl.js → gcode-ChY-gRbf.js} +1 -1
  114. package/dist/ui/assets/{gherkin-Co-YjHfW.js → gherkin-Dvnrp8BP.js} +1 -1
  115. package/dist/ui/assets/{gitGraphDiagram-IHSO6WYX-Do9VfPHL.js → gitGraphDiagram-IHSO6WYX-BRB4at2D.js} +1 -1
  116. package/dist/ui/assets/{glsl-D3lldBTJ.js → glsl-DcovBIzp.js} +1 -1
  117. package/dist/ui/assets/{gml-DyoCibnw.js → gml-S6feXRA_.js} +1 -1
  118. package/dist/ui/assets/{go-BNeAS1jC.js → go-B81WXVYZ.js} +1 -1
  119. package/dist/ui/assets/{golo-BuXecWAH.js → golo-DKL2IdWk.js} +1 -1
  120. package/dist/ui/assets/{gradle-BP7ToLe9.js → gradle-T97Z3PII.js} +1 -1
  121. package/dist/ui/assets/{groovy-GqWVT09g.js → groovy-BXX6Iv9v.js} +1 -1
  122. package/dist/ui/assets/{haml-SLbvCHsC.js → haml-D8q-wDTz.js} +1 -1
  123. package/dist/ui/assets/{handlebars-BnaCJTc5.js → handlebars-DDdkLhQc.js} +1 -1
  124. package/dist/ui/assets/{haskell-CrX9ftWp.js → haskell-DfxSCvE8.js} +1 -1
  125. package/dist/ui/assets/{haxe-DNoaIxsE.js → haxe-CYmtAuGy.js} +1 -1
  126. package/dist/ui/assets/{hsp-CLjy3djj.js → hsp-B6vrbmnn.js} +1 -1
  127. package/dist/ui/assets/{htmlbars-w96Kz5NL.js → htmlbars-D2C_JXNB.js} +1 -1
  128. package/dist/ui/assets/{http-VIMXIxM8.js → http-CF4dzBBt.js} +1 -1
  129. package/dist/ui/assets/{hy-_qE83_aW.js → hy-Bo3ftzPr.js} +1 -1
  130. package/dist/ui/assets/index-BLxwrLko.js +2655 -0
  131. package/dist/ui/assets/{index-DpcPfZl3.js → index-CMOhE8Fu.js} +3 -3
  132. package/dist/ui/assets/index-bwex7GGt.css +10 -0
  133. package/dist/ui/assets/{infoDiagram-FWYZ7A6U-D9O7SZ2X.js → infoDiagram-FWYZ7A6U-CsP_vXYo.js} +1 -1
  134. package/dist/ui/assets/{inform7-CnyW73C1.js → inform7-DW_1PfgW.js} +1 -1
  135. package/dist/ui/assets/{ini-GFMFAjln.js → ini-DFoyjgSu.js} +1 -1
  136. package/dist/ui/assets/{irpf90-BPmSYATn.js → irpf90-C-6-eyAC.js} +1 -1
  137. package/dist/ui/assets/{isbl-BnStGiBQ.js → isbl-4gc8Swo4.js} +1 -1
  138. package/dist/ui/assets/{ishikawaDiagram-FXEZZL3T-DgcUDM9X.js → ishikawaDiagram-FXEZZL3T-D6bH6CQh.js} +1 -1
  139. package/dist/ui/assets/{java-CVORcFd8.js → java-bb2y4EiS.js} +1 -1
  140. package/dist/ui/assets/{javascript-B2pFzODm.js → javascript-BAtDHP3W.js} +1 -1
  141. package/dist/ui/assets/{jboss-cli-B9cQeKvZ.js → jboss-cli-qZg2Imzs.js} +1 -1
  142. package/dist/ui/assets/{journeyDiagram-5HDEW3XC-Bivjw4h7.js → journeyDiagram-5HDEW3XC-DxDCxUCo.js} +1 -1
  143. package/dist/ui/assets/{json-BJof8L10.js → json-CNupTqez.js} +1 -1
  144. package/dist/ui/assets/{julia-D_dGrCpZ.js → julia-DK5AbWFh.js} +1 -1
  145. package/dist/ui/assets/{julia-repl-Dsw0K1B1.js → julia-repl-CY2KMHbB.js} +1 -1
  146. package/dist/ui/assets/{kanban-definition-HUTT4EX6-Dg7NbKta.js → kanban-definition-HUTT4EX6-Dt5KtIgo.js} +1 -1
  147. package/dist/ui/assets/{kotlin-8oetHRtX.js → kotlin-D9FIaw0d.js} +1 -1
  148. package/dist/ui/assets/{lasso-e37r_NX1.js → lasso-DFGV2pQw.js} +1 -1
  149. package/dist/ui/assets/{latex-DAmwzl3n.js → latex-B4vw8fyc.js} +1 -1
  150. package/dist/ui/assets/{ldif-CD0mgmt4.js → ldif-Dm2FIlTD.js} +1 -1
  151. package/dist/ui/assets/{leaf-GfPKlp7a.js → leaf-BfPV5rQV.js} +1 -1
  152. package/dist/ui/assets/{less-PndaZJ6n.js → less-DlD-uNfa.js} +1 -1
  153. package/dist/ui/assets/{lisp-CNaspu3A.js → lisp-fwHwKhac.js} +1 -1
  154. package/dist/ui/assets/{livecodeserver-DEKsXiP3.js → livecodeserver-2Iqy9OJM.js} +1 -1
  155. package/dist/ui/assets/{livescript-DM7jasJn.js → livescript-CsVjBiYy.js} +1 -1
  156. package/dist/ui/assets/{llvm-D_29j9MV.js → llvm-Dr1LxL0C.js} +1 -1
  157. package/dist/ui/assets/{lsl-DY0WRYhg.js → lsl-C19lQilh.js} +1 -1
  158. package/dist/ui/assets/{lua-DZ_v4xaE.js → lua-Bt6lk_UK.js} +1 -1
  159. package/dist/ui/assets/{makefile-VOjcUGXf.js → makefile-BjpMOWNL.js} +1 -1
  160. package/dist/ui/assets/{markdown-yUEmZWvu.js → markdown-BCvk5Luj.js} +1 -1
  161. package/dist/ui/assets/{mathematica-BLXYGKkd.js → mathematica-CMAvLFmv.js} +1 -1
  162. package/dist/ui/assets/{matlab-B7SkIpvh.js → matlab-Dp9rgor5.js} +1 -1
  163. package/dist/ui/assets/{maxima-C7Fw8Vyt.js → maxima-UUgZl2h3.js} +1 -1
  164. package/dist/ui/assets/{mel-C_Znst2Y.js → mel-DU6cwelq.js} +1 -1
  165. package/dist/ui/assets/{mercury-DjUnQNsq.js → mercury-DXd4_3jU.js} +1 -1
  166. package/dist/ui/assets/{mindmap-definition-LN4V7U3C-Dp6mEy6L.js → mindmap-definition-LN4V7U3C-BThZR1du.js} +1 -1
  167. package/dist/ui/assets/{mipsasm-DaGHhR8c.js → mipsasm-CMNMWNFn.js} +1 -1
  168. package/dist/ui/assets/{mizar-CZnct-_Z.js → mizar-B6c3dauU.js} +1 -1
  169. package/dist/ui/assets/{mojolicious-BdWFK35j.js → mojolicious-Cprwk6o_.js} +1 -1
  170. package/dist/ui/assets/{monkey-ta_jgafo.js → monkey-BaAReGcY.js} +1 -1
  171. package/dist/ui/assets/{moonscript-B9qovjV6.js → moonscript-gS515C7R.js} +1 -1
  172. package/dist/ui/assets/{n1ql-BciXbxiw.js → n1ql-Z_4MPbYI.js} +1 -1
  173. package/dist/ui/assets/{nginx-DRCZYbxj.js → nginx-Dc_6EmJn.js} +1 -1
  174. package/dist/ui/assets/{nim-DTMCxPJt.js → nim-DtjvH3ft.js} +1 -1
  175. package/dist/ui/assets/{nix-D39yZxF9.js → nix-Bu2r_I9_.js} +1 -1
  176. package/dist/ui/assets/{node-repl-vAEXdnYM.js → node-repl-8HGWlvcp.js} +1 -1
  177. package/dist/ui/assets/{nsis-CCMP8mq3.js → nsis-9FG-YMvD.js} +1 -1
  178. package/dist/ui/assets/{objectivec-CZx4kSLP.js → objectivec-CX1QmJoj.js} +1 -1
  179. package/dist/ui/assets/{ocaml-DBnEo9uR.js → ocaml-4qT3O786.js} +1 -1
  180. package/dist/ui/assets/{openscad-BKc7u4Bl.js → openscad-CvJzggqO.js} +1 -1
  181. package/dist/ui/assets/{oxygene-M_Z4lQ6l.js → oxygene-BwtAuPgg.js} +1 -1
  182. package/dist/ui/assets/{parser3-DS9UKiKD.js → parser3-DKnhj506.js} +1 -1
  183. package/dist/ui/assets/{pegDiagram-2B236MQR-BBEXn76M.js → pegDiagram-2B236MQR-ZVgEXVAh.js} +1 -1
  184. package/dist/ui/assets/{perl-D6iEALGE.js → perl-BApvz3gE.js} +1 -1
  185. package/dist/ui/assets/{pf-JQL0ClGi.js → pf--Fg5j93h.js} +1 -1
  186. package/dist/ui/assets/{pgsql-DEmCURBr.js → pgsql-DOapqed0.js} +1 -1
  187. package/dist/ui/assets/{php-DVm-0PY5.js → php-DIm5UjQ3.js} +1 -1
  188. package/dist/ui/assets/{php-template-DfWbDpnE.js → php-template-DTFQ-Xzw.js} +1 -1
  189. package/dist/ui/assets/{pieDiagram-ENE6RG2P-D5PZFiDj.js → pieDiagram-ENE6RG2P-viaSeTd2.js} +1 -1
  190. package/dist/ui/assets/{plaintext-BahVkGlu.js → plaintext-NRztTbl1.js} +1 -1
  191. package/dist/ui/assets/{pony-wVig0caC.js → pony-BfL7O-OQ.js} +1 -1
  192. package/dist/ui/assets/{powershell-COjMBUit.js → powershell-CLt45Qf4.js} +1 -1
  193. package/dist/ui/assets/{processing-DnUzvFZx.js → processing-afiHf7ow.js} +1 -1
  194. package/dist/ui/assets/{profile-mDlbwJeL.js → profile-Ch1BVwxN.js} +1 -1
  195. package/dist/ui/assets/{prolog-x2hG6DnA.js → prolog-Tf3A0bWy.js} +1 -1
  196. package/dist/ui/assets/{properties-DzZyyivC.js → properties-8SdgBqK7.js} +1 -1
  197. package/dist/ui/assets/{protobuf-a5NwbYD5.js → protobuf-DPDrI7Qg.js} +1 -1
  198. package/dist/ui/assets/{puppet-CCWyPVuC.js → puppet-CXofbQOs.js} +1 -1
  199. package/dist/ui/assets/{purebasic-CXNdqtD4.js → purebasic-eUJ8DEfM.js} +1 -1
  200. package/dist/ui/assets/{python-iSR9YlDJ.js → python-C98zkBPD.js} +1 -1
  201. package/dist/ui/assets/{python-repl-CCmKzWru.js → python-repl-Xul3ztGs.js} +1 -1
  202. package/dist/ui/assets/{q-B30ZmDuD.js → q-BkAM-a7C.js} +1 -1
  203. package/dist/ui/assets/{qml-BGdPdB4X.js → qml-BsEaix_u.js} +1 -1
  204. package/dist/ui/assets/{quadrantDiagram-ABIIQ3AL-BBF1rAvI.js → quadrantDiagram-ABIIQ3AL-Bvz1yyu9.js} +1 -1
  205. package/dist/ui/assets/{r-B8ASdWL1.js → r-ItUdMzSw.js} +1 -1
  206. package/dist/ui/assets/{railroadDiagram-RFXS5EU6-DQFUXGVD.js → railroadDiagram-RFXS5EU6-DdFuoPrk.js} +1 -1
  207. package/dist/ui/assets/{reasonml-Dw4Bi5B5.js → reasonml-BDbdIYs9.js} +1 -1
  208. package/dist/ui/assets/{requirementDiagram-TGXJPOKE-DCgrs7-P.js → requirementDiagram-TGXJPOKE-B8hcvLSP.js} +1 -1
  209. package/dist/ui/assets/{rib-CgUGGGZ9.js → rib-zIraQ_mX.js} +1 -1
  210. package/dist/ui/assets/{roboconf-CCZNQvSP.js → roboconf-CzoIRml1.js} +1 -1
  211. package/dist/ui/assets/{routeros-DVT5M6iV.js → routeros-B3UgD0yV.js} +1 -1
  212. package/dist/ui/assets/{rsl-BY-LhdKq.js → rsl-wAwFfXwD.js} +1 -1
  213. package/dist/ui/assets/{ruby-CZW4dclw.js → ruby-D3Thdpv8.js} +1 -1
  214. package/dist/ui/assets/{ruleslanguage-CZdjv1of.js → ruleslanguage-CPWvLcMl.js} +1 -1
  215. package/dist/ui/assets/{rust-D5Xa_mSD.js → rust-DOnpus5t.js} +1 -1
  216. package/dist/ui/assets/{sankeyDiagram-HTMAVEWB-BXeEgUB7.js → sankeyDiagram-HTMAVEWB-CH-sCFAi.js} +1 -1
  217. package/dist/ui/assets/{sas-B_UJ-HCZ.js → sas-B2858_1j.js} +1 -1
  218. package/dist/ui/assets/{scala-B8wSdZik.js → scala-Cveq3ftT.js} +1 -1
  219. package/dist/ui/assets/{scheme-DD7U81eh.js → scheme-DcdF6kjo.js} +1 -1
  220. package/dist/ui/assets/{scilab-aJGpbkKs.js → scilab-Dycxtkgn.js} +1 -1
  221. package/dist/ui/assets/{scss-BBqyvWYh.js → scss-DFUrItbr.js} +1 -1
  222. package/dist/ui/assets/{sequenceDiagram-DBY2YBRQ-CnDTZN18.js → sequenceDiagram-DBY2YBRQ-B6WOhYgY.js} +1 -1
  223. package/dist/ui/assets/{shell-CR23jqfz.js → shell-CdK6mfw0.js} +1 -1
  224. package/dist/ui/assets/{sizeCapture-X5ZJPWSS-joZ477RB.js → sizeCapture-X5ZJPWSS-DEtOtMCB.js} +1 -1
  225. package/dist/ui/assets/{smali-ZmLyRCrQ.js → smali-BWrgi9Uw.js} +1 -1
  226. package/dist/ui/assets/{smalltalk-CnADYfPr.js → smalltalk-D7rVc6SF.js} +1 -1
  227. package/dist/ui/assets/{sml-zj1KD04_.js → sml-BwZXpnKa.js} +1 -1
  228. package/dist/ui/assets/{sqf-DCCaZ3e3.js → sqf-GLi5DNBX.js} +1 -1
  229. package/dist/ui/assets/{sql-CHGw2SCR.js → sql-B3C8FGL3.js} +1 -1
  230. package/dist/ui/assets/{sql_more-DsnvjMwh.js → sql_more-DnUCbJeD.js} +1 -1
  231. package/dist/ui/assets/{stan-ChxdV8f9.js → stan-Sm9c5Vis.js} +1 -1
  232. package/dist/ui/assets/{stata-CgFw45qg.js → stata-pulikDkU.js} +1 -1
  233. package/dist/ui/assets/{stateDiagram-2N3HPSRC-CzLIdKbt.js → stateDiagram-2N3HPSRC-ncOw7g4V.js} +1 -1
  234. package/dist/ui/assets/stateDiagram-v2-6OUMAXLB-D1kUHFw1.js +1 -0
  235. package/dist/ui/assets/{step21-DaraQMOk.js → step21-pX15wqtK.js} +1 -1
  236. package/dist/ui/assets/{stylus-BZpiJEzN.js → stylus-fOumlpdp.js} +1 -1
  237. package/dist/ui/assets/{subunit-B6Gp0n7h.js → subunit-uu3Ov4HX.js} +1 -1
  238. package/dist/ui/assets/{swift-DQzoz60p.js → swift-CmLDJWUd.js} +1 -1
  239. package/dist/ui/assets/{swimlanes-5IMT3BWC-DOMOhwX0.js → swimlanes-5IMT3BWC-DqgXf_9D.js} +2 -2
  240. package/dist/ui/assets/swimlanesDiagram-G3AALYLV-C-113Xl1.js +8 -0
  241. package/dist/ui/assets/{taggerscript-BMLkfiab.js → taggerscript-CazB9nt4.js} +1 -1
  242. package/dist/ui/assets/{tap-PUNWTFgu.js → tap-DojnLl9r.js} +1 -1
  243. package/dist/ui/assets/{tcl-BODH5qJa.js → tcl-CMSHuPY4.js} +1 -1
  244. package/dist/ui/assets/{thrift-BQ-W_YlC.js → thrift-D9T_iaQS.js} +1 -1
  245. package/dist/ui/assets/{timeline-definition-FHXFAJF6-DQBDeTzH.js → timeline-definition-FHXFAJF6--1I0coei.js} +1 -1
  246. package/dist/ui/assets/{tp-Dt3WwOGF.js → tp-tKwomxNq.js} +1 -1
  247. package/dist/ui/assets/{twig-44RQtw7Z.js → twig-CEsN-ViC.js} +1 -1
  248. package/dist/ui/assets/{typescript-BsouHXHR.js → typescript-BwkWaYfc.js} +1 -1
  249. package/dist/ui/assets/{vala-DqJj6fPT.js → vala-BFkwjsLY.js} +1 -1
  250. package/dist/ui/assets/{vbnet-CuqWYg5r.js → vbnet-BoJ1NvBH.js} +1 -1
  251. package/dist/ui/assets/{vbscript-w20MQMYP.js → vbscript-D8XSgQnu.js} +1 -1
  252. package/dist/ui/assets/{vbscript-html-BP0D0WEV.js → vbscript-html-hn6cBiCZ.js} +1 -1
  253. package/dist/ui/assets/{vennDiagram-L72KCM5P-DwNnj3Kc.js → vennDiagram-L72KCM5P--d_scOj_.js} +1 -1
  254. package/dist/ui/assets/{verilog-DIpBpJAe.js → verilog-CHsNT9Cy.js} +1 -1
  255. package/dist/ui/assets/{vhdl-D5nCxDbL.js → vhdl-BHAdjshQ.js} +1 -1
  256. package/dist/ui/assets/{vim-CPfbBM_x.js → vim-CXGYjr0E.js} +1 -1
  257. package/dist/ui/assets/{wardleyDiagram-EHGQE667-WxVQHmM7.js → wardleyDiagram-EHGQE667-C1OlFa5w.js} +1 -1
  258. package/dist/ui/assets/{x86asm-D_t4Z_eq.js → x86asm-BMtTtbdc.js} +1 -1
  259. package/dist/ui/assets/{xl-DQf5IG_W.js → xl-2RPeIz-_.js} +1 -1
  260. package/dist/ui/assets/{xml-D-Bn0NMR.js → xml-BdgFaqW_.js} +1 -1
  261. package/dist/ui/assets/{xquery-DqushYX1.js → xquery-C-Nme7tR.js} +1 -1
  262. package/dist/ui/assets/{xychartDiagram-FW5EYKEG-B6D8mgs8.js → xychartDiagram-FW5EYKEG-BzM0JoN5.js} +1 -1
  263. package/dist/ui/assets/{yaml-B2GFZenc.js → yaml-CVfovUzE.js} +1 -1
  264. package/dist/ui/assets/{zephir-SiNGockR.js → zephir-BLoFpefb.js} +1 -1
  265. package/dist/ui/index.html +2 -2
  266. package/dist/utils/__tests__/tool-injector.test.js +32 -35
  267. package/dist/utils/db.d.ts +1 -0
  268. package/dist/utils/db.js +22 -0
  269. package/dist/utils/inject-loop.d.ts +52 -1
  270. package/dist/utils/inject-loop.js +70 -2
  271. package/dist/utils/mcp-db.d.ts +35 -0
  272. package/dist/utils/mcp-db.js +79 -0
  273. package/dist/utils/mcp-manager.d.ts +36 -0
  274. package/dist/utils/mcp-manager.js +215 -0
  275. package/dist/utils/request-writer.d.ts +4 -0
  276. package/dist/utils/request-writer.js +66 -0
  277. package/dist/utils/sse-stream-processor.d.ts +27 -0
  278. package/dist/utils/sse-stream-processor.js +144 -0
  279. package/dist/utils/tool-injector.d.ts +6 -9
  280. package/dist/utils/tool-injector.js +13 -14
  281. package/dist/utils/version.d.ts +1 -0
  282. package/dist/utils/version.js +4 -1
  283. package/package.json +8 -9
  284. package/dist/ui/assets/channel-C5JlZ38H.js +0 -1
  285. package/dist/ui/assets/classDiagram-OUVF2IWQ-j5FVBKaD.js +0 -1
  286. package/dist/ui/assets/classDiagram-v2-EOCWNBFH-j5FVBKaD.js +0 -1
  287. package/dist/ui/assets/index-Baqd6LlK.js +0 -2625
  288. package/dist/ui/assets/index-fHtNI_e8.css +0 -1
  289. package/dist/ui/assets/stateDiagram-v2-6OUMAXLB-Bg4GAkB5.js +0 -1
  290. package/dist/ui/assets/swimlanesDiagram-G3AALYLV-99wEK8yq.js +0 -8
package/README.md CHANGED
@@ -1,8 +1,6 @@
1
1
  # @cc-monitoring/proxy-core
2
2
 
3
- Claude Code 代理 + 监控 CLI。Fastify 应用层转发 + PM2 守护进程 + Web 管理面板 + 完整请求记录。
4
-
5
- 一站式解决国内网络访问 Claude Code 的问题,同时提供请求日志、Token 统计、供应商切换、SSE 流式抓包等运维能力。
3
+ Claude Code 代理工具 + Token 消耗监控面板。一行命令启动代理,实时追踪每次请求的模型、Token 用量和响应状态。
6
4
 
7
5
  [![npm version](https://img.shields.io/npm/v/@cc-monitoring/proxy-core.svg)](https://www.npmjs.com/package/@cc-monitoring/proxy-core)
8
6
  [![License: Apache-2.0](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
@@ -27,7 +25,7 @@ ccm start
27
25
  ccm ui
28
26
 
29
27
  # 3. 把 Claude Code 的 ANTHROPIC_BASE_URL 指向本地代理
30
- export ANTHROPIC_BASE_URL=http://localhost:3000
28
+ export ANTHROPIC_BASE_URL=http://localhost:9527
31
29
  ```
32
30
 
33
31
  首次运行会在 `~/.cc-monitoring/` 生成配置文件和数据库:
@@ -67,20 +65,21 @@ ccm config set proxy.target https://xxx # 修改上游地址
67
65
 
68
66
  ```json
69
67
  {
70
- "server": { "port": 3000, "host": "localhost" },
68
+ "server": { "port": 9527, "host": "localhost" },
71
69
  "proxy": {
72
- "target": "https://token-plan.cn-beijing.maas.aliyuncs.com/apps/anthropic",
73
- "changeOrigin": true,
74
- "rewritePrefix": ""
70
+ "target": "https://ark.cn-beijing.volces.com/api/coding",
71
+ "changeOrigin": true
75
72
  },
76
- "logging": { "level": "info", "file": "logs/proxy.log" },
77
- "auth": { "token": "" }
73
+ "logging": { "level": "info", "file": "logs/proxy.log", "maxSize": "10m", "interval": "1d", "compress": true },
74
+ "storage": { "type": "sqlite", "path": "logs/proxy.db", "maxDays": 7 }
78
75
  }
79
76
  ```
80
77
 
78
+ > `logs/` 路径相对于 config 所在目录解析,实际存 `~/.cc-monitoring/logs/` 下。
79
+
81
80
  | 字段 | 类型 | 说明 |
82
81
  |------|------|------|
83
- | `server.port` | number (1-65535) | 监听端口,默认 3000 |
82
+ | `server.port` | number (1-65535) | 监听端口,默认 9527 |
84
83
  | `server.host` | string | 监听主机 |
85
84
  | `proxy.target` | URL | 上游 AI 供应商 API |
86
85
  | `proxy.changeOrigin` | boolean | 是否重写 Origin 头 |
@@ -92,7 +91,7 @@ ccm config set proxy.target https://xxx # 修改上游地址
92
91
 
93
92
  ## Web 管理面板
94
93
 
95
- `ccm ui` 或访问 `http://localhost:3000/ui`:
94
+ `ccm ui` 或访问 `http://localhost:9527/ui`:
96
95
 
97
96
  - **状态监控**:CPU / 内存 / 运行时间 / 重启次数(5s 刷新)
98
97
  - **实时日志**:WebSocket 推流、级别过滤、关键字搜索
@@ -100,29 +99,6 @@ ccm config set proxy.target https://xxx # 修改上游地址
100
99
  - **配置编辑**:可视化改 `config.json`,Zod 实时校验
101
100
  - **供应商管理**:多供应商配置,一键切换 baseUrl / apiKey / model
102
101
 
103
- ## 架构要点
104
-
105
- **应用层转发**(Controller + Fetch + SSE Pipe),非透明代理:
106
-
107
- ```
108
- Claude Code
109
- ↓ POST /v1/messages
110
- Fastify(解析 body)
111
- ↓ saveRequest(记录完整 payload)
112
- fetch → 上游 API
113
- ↓ Web ReadableStream
114
- reply.hijack() + Readable.fromWeb().pipe(reply.raw)
115
- ↓ 原样 SSE 转发
116
- Claude Code
117
- ```
118
-
119
- 为什么不用透明代理:`@fastify/http-proxy` 内部消费 request stream,无法同时完成「记录 body + 转发 SSE + 未来鉴权/统计」。HTTP stream 只能消费一次。
120
-
121
- **关键处理**:
122
- - Web Stream → Node Stream:`Readable.fromWeb(response.body)`
123
- - 头处理:删 `host`(阿里云 404)、`content-length`(长度变化),保留 `anthropic-version` / `x-api-key` / `accept: text/event-stream`
124
- - SSE 记录:`nodeStream.on('end')` 落盘完整 events 数组
125
-
126
102
  ## 环境变量
127
103
 
128
104
  | 变量 | 说明 |
@@ -51,7 +51,8 @@ export async function resetConfig(configPath = getConfigPath()) {
51
51
  type: 'sqlite',
52
52
  path: 'logs/proxy.db',
53
53
  maxDays: 7
54
- }
54
+ },
55
+ mcpServers: []
55
56
  };
56
57
  await saveConfig(defaultConfig, configPath);
57
58
  }
@@ -65,6 +65,34 @@ export declare const AppConfigSchema: z.ZodObject<{
65
65
  }, {
66
66
  token: string;
67
67
  }>>;
68
+ mcpServers: z.ZodDefault<z.ZodOptional<z.ZodArray<z.ZodObject<{
69
+ name: z.ZodString;
70
+ transport_type: z.ZodEnum<["stdio", "sse", "streamable-http"]>;
71
+ command: z.ZodOptional<z.ZodString>;
72
+ args: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
73
+ env: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
74
+ url: z.ZodOptional<z.ZodString>;
75
+ headers: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
76
+ enabled: z.ZodDefault<z.ZodBoolean>;
77
+ }, "strip", z.ZodTypeAny, {
78
+ name: string;
79
+ transport_type: "stdio" | "sse" | "streamable-http";
80
+ enabled: boolean;
81
+ command?: string | undefined;
82
+ args?: string[] | undefined;
83
+ env?: Record<string, string> | undefined;
84
+ url?: string | undefined;
85
+ headers?: Record<string, string> | undefined;
86
+ }, {
87
+ name: string;
88
+ transport_type: "stdio" | "sse" | "streamable-http";
89
+ command?: string | undefined;
90
+ args?: string[] | undefined;
91
+ env?: Record<string, string> | undefined;
92
+ url?: string | undefined;
93
+ headers?: Record<string, string> | undefined;
94
+ enabled?: boolean | undefined;
95
+ }>, "many">>>;
68
96
  }, "strip", z.ZodTypeAny, {
69
97
  server: {
70
98
  port: number;
@@ -88,6 +116,16 @@ export declare const AppConfigSchema: z.ZodObject<{
88
116
  type: "sqlite";
89
117
  maxDays: number;
90
118
  };
119
+ mcpServers: {
120
+ name: string;
121
+ transport_type: "stdio" | "sse" | "streamable-http";
122
+ enabled: boolean;
123
+ command?: string | undefined;
124
+ args?: string[] | undefined;
125
+ env?: Record<string, string> | undefined;
126
+ url?: string | undefined;
127
+ headers?: Record<string, string> | undefined;
128
+ }[];
91
129
  auth?: {
92
130
  token: string;
93
131
  } | undefined;
@@ -117,6 +155,16 @@ export declare const AppConfigSchema: z.ZodObject<{
117
155
  auth?: {
118
156
  token: string;
119
157
  } | undefined;
158
+ mcpServers?: {
159
+ name: string;
160
+ transport_type: "stdio" | "sse" | "streamable-http";
161
+ command?: string | undefined;
162
+ args?: string[] | undefined;
163
+ env?: Record<string, string> | undefined;
164
+ url?: string | undefined;
165
+ headers?: Record<string, string> | undefined;
166
+ enabled?: boolean | undefined;
167
+ }[] | undefined;
120
168
  }>;
121
169
  export type AppConfig = z.infer<typeof AppConfigSchema>;
122
170
  export declare function validateConfig(config: unknown): ValidationResult;
@@ -24,7 +24,17 @@ export const AppConfigSchema = z.object({
24
24
  }).optional().default({ type: 'sqlite', path: 'logs/proxy.db', maxDays: 7 }),
25
25
  auth: z.object({
26
26
  token: z.string().min(1)
27
- }).optional()
27
+ }).optional(),
28
+ mcpServers: z.array(z.object({
29
+ name: z.string().min(1),
30
+ transport_type: z.enum(['stdio', 'sse', 'streamable-http']),
31
+ command: z.string().optional(),
32
+ args: z.array(z.string()).optional(),
33
+ env: z.record(z.string()).optional(),
34
+ url: z.string().optional(),
35
+ headers: z.record(z.string()).optional(),
36
+ enabled: z.boolean().default(true)
37
+ })).optional().default([])
28
38
  });
29
39
  export function validateConfig(config) {
30
40
  const result = AppConfigSchema.safeParse(config);
@@ -0,0 +1,3 @@
1
+ import { FastifyInstance } from 'fastify';
2
+ import { ProxyConfig } from '../types/config.js';
3
+ export declare function setupChatRoute(fastify: FastifyInstance, proxyConfig: ProxyConfig): Promise<void>;
@@ -0,0 +1,401 @@
1
+ import { Readable } from 'stream';
2
+ import { randomUUID } from 'node:crypto';
3
+ import { loadConfig } from '../config/index.js';
4
+ import { saveRequestDB, extractTokenUsage, loadSessionHistory } from '../utils/request-writer.js';
5
+ import { cleanOldRequestsDB } from '../utils/request-writer.js';
6
+ import { pushNewRequest } from './data-push.js';
7
+ import { initDatabase, getDatabase } from '../utils/db.js';
8
+ import { resolveProxyTarget, getProxyModel, filterForwardHeaders, extractSafeHeaders } from './proxy.js';
9
+ import { injectMcpTools } from '../utils/tool-injector.js';
10
+ import { findInjectedCall, runJsonInjectLoop, runStreamingInjectLoop } from '../utils/inject-loop.js';
11
+ import { findEnabledTool } from '../tools/index.js';
12
+ import { writeSSEEvent, writeTextAsSSE, shouldMock } from '../utils/sse-writer.js';
13
+ import { SSEStreamProcessor } from '../utils/sse-stream-processor.js';
14
+ import { getMachineIdSync, preloadMachineId } from '../utils/machine-id.js';
15
+ export async function setupChatRoute(fastify, proxyConfig) {
16
+ const fullConfig = await loadConfig();
17
+ const maxDays = fullConfig.storage?.maxDays ?? 7;
18
+ initDatabase();
19
+ await preloadMachineId();
20
+ fastify.post('/api/chat', async (request, reply) => {
21
+ const startTime = Date.now();
22
+ const resolved = resolveProxyTarget(proxyConfig);
23
+ // Generate or reuse session ID
24
+ const providedSessionId = request.headers['x-chat-session-id'];
25
+ const sessionId = providedSessionId || randomUUID();
26
+ // Validate request body
27
+ if (!request.body?.model || !Array.isArray(request.body?.messages)) {
28
+ return reply.code(400).send({
29
+ error: 'invalid_request',
30
+ message: 'Request body must contain "model" and "messages" fields'
31
+ });
32
+ }
33
+ // Session resume: if sessionId exists in DB, load history and prepend
34
+ if (providedSessionId) {
35
+ const history = loadSessionHistory(providedSessionId);
36
+ if (history) {
37
+ // Prepend history messages before the new user messages
38
+ request.body.messages = [...history.messages, ...request.body.messages];
39
+ // Carry over system prompt if provided and not in current request
40
+ if (history.system && !request.body.system && !request.body.system_prompt) {
41
+ request.body.system = history.system;
42
+ }
43
+ request.log.info(`[chat] session resumed: ${providedSessionId}, history: ${history.messages.length} messages`);
44
+ }
45
+ }
46
+ // Rewrite model based on tier
47
+ const originalModel = request.body.model;
48
+ const proxyModel = getProxyModel(originalModel, resolved);
49
+ if (proxyModel) {
50
+ request.body.model = proxyModel;
51
+ }
52
+ const forwardedModel = request.body.model;
53
+ // Inject MCP tools only (not probe/curl)
54
+ const injectedNames = injectMcpTools(request.body);
55
+ const injected = injectedNames.length > 0;
56
+ if (injected) {
57
+ request.log.info(`[chat] MCP tools injected: ${injectedNames.join(',')} (${request.id})`);
58
+ }
59
+ // Filter and forward headers
60
+ const forwardHeaders = filterForwardHeaders(extractSafeHeaders(request.headers), resolved.apiKey);
61
+ forwardHeaders['x-chat-session-id'] = sessionId;
62
+ // Extract API keys for recording
63
+ const authHeader = request.headers['authorization'];
64
+ const apiKey = authHeader?.startsWith('Bearer ')
65
+ ? authHeader.slice(7)
66
+ : request.headers['x-api-key'];
67
+ const forwardedAuthHeader = forwardHeaders['authorization'];
68
+ const proxyApiKey = forwardHeaders['x-api-key'] ||
69
+ (forwardedAuthHeader?.startsWith('Bearer ') ? forwardedAuthHeader.slice(7) : undefined);
70
+ // Build request data
71
+ const machineId = getMachineIdSync() ?? undefined;
72
+ const requestData = {
73
+ requestId: request.id,
74
+ sessionId,
75
+ timestamp: new Date().toISOString(),
76
+ apiKey,
77
+ proxyApiKey,
78
+ baseUrl: resolved.baseUrl,
79
+ model: forwardedModel,
80
+ machineId,
81
+ request: {
82
+ method: request.method,
83
+ path: request.url,
84
+ headers: forwardHeaders,
85
+ body: request.body
86
+ },
87
+ response: {
88
+ statusCode: 0,
89
+ events: []
90
+ }
91
+ };
92
+ await cleanOldRequestsDB(maxDays);
93
+ // Save initial record + push pending status to frontend
94
+ await saveRequestDB(sessionId, request.id, requestData);
95
+ pushNewRequest({
96
+ requestId: request.id,
97
+ sessionId,
98
+ compositeId: `${sessionId}:${request.id}`,
99
+ method: request.method,
100
+ path: request.url,
101
+ timestamp: requestData.timestamp,
102
+ statusCode: 0,
103
+ responseTime: 0,
104
+ model: forwardedModel,
105
+ machineId,
106
+ baseUrl: resolved.baseUrl
107
+ }, 'pending');
108
+ // Mock interception (PoC)
109
+ if (shouldMock(request.body)) {
110
+ reply.hijack();
111
+ reply.raw.writeHead(200, {
112
+ 'content-type': 'text/event-stream',
113
+ 'cache-control': 'no-cache',
114
+ 'connection': 'keep-alive'
115
+ });
116
+ writeTextAsSSE(reply.raw, '[PoC] 这是 /api/chat 构造的合成响应,未经过真实大模型。', `msg_poc_chat_${request.id}`);
117
+ reply.raw.end();
118
+ return;
119
+ }
120
+ // Build target URL — always target /v1/messages
121
+ const targetUrlStr = `${resolved.baseUrl}${resolved.targetPath}/v1/messages`;
122
+ request.log.info(`[chat] forwarding to: ${targetUrlStr}`);
123
+ // Forward to upstream
124
+ const response = await fetch(targetUrlStr, {
125
+ method: 'POST',
126
+ headers: forwardHeaders,
127
+ body: JSON.stringify(request.body)
128
+ });
129
+ request.log.info(`[chat] response status: ${response.status}`);
130
+ // Extract cloud request ID
131
+ const cloudRequestId = response.headers.get('x-request-id') || request.id;
132
+ requestData.requestId = cloudRequestId;
133
+ requestData.response.statusCode = response.status;
134
+ requestData.response.headers = Object.fromEntries(response.headers);
135
+ // Check response type
136
+ const contentType = response.headers.get('content-type') || '';
137
+ const isSSE = contentType.includes('text/event-stream');
138
+ const isJSON = contentType.includes('application/json');
139
+ // === JSON response (non-streaming) ===
140
+ if (isJSON && !isSSE && response.body) {
141
+ const responseBody = await response.text();
142
+ let jsonBody;
143
+ try {
144
+ jsonBody = JSON.parse(responseBody);
145
+ requestData.response.events.push(jsonBody);
146
+ }
147
+ catch {
148
+ requestData.response.events.push({ raw: responseBody });
149
+ }
150
+ // JSON inject loop: if MCP tools injected and response has tool_use
151
+ if (injected && jsonBody && jsonBody.stop_reason === 'tool_use') {
152
+ const toolCalls = (jsonBody.content || []).filter((b) => b.type === 'tool_use');
153
+ const hitCall = toolCalls.find((b) => findEnabledTool(b.name));
154
+ if (hitCall) {
155
+ request.log.info(`[chat] json tool hit: ${hitCall.name} (${cloudRequestId})`);
156
+ const loopResult = await runJsonInjectLoop({
157
+ initialBody: jsonBody,
158
+ requestBody: request.body,
159
+ callUpstream: async (b) => {
160
+ const r = await fetch(targetUrlStr, {
161
+ method: 'POST',
162
+ headers: forwardHeaders,
163
+ body: JSON.stringify(b)
164
+ });
165
+ const loopResponseBody = await r.text();
166
+ let loopJson;
167
+ try {
168
+ loopJson = JSON.parse(loopResponseBody);
169
+ }
170
+ catch { /* ignore */ }
171
+ // Record each loop iteration as a separate request
172
+ if (loopJson) {
173
+ const loopRequestId = r.headers.get('x-request-id') || `loop_${request.id}_${Date.now()}`;
174
+ const loopData = {
175
+ requestId: loopRequestId,
176
+ sessionId,
177
+ timestamp: new Date().toISOString(),
178
+ apiKey,
179
+ proxyApiKey,
180
+ baseUrl: resolved.baseUrl,
181
+ model: forwardedModel,
182
+ machineId,
183
+ request: { method: 'POST', path: '/api/chat', headers: forwardHeaders, body: b },
184
+ response: {
185
+ statusCode: r.status,
186
+ headers: Object.fromEntries(r.headers),
187
+ events: [loopJson],
188
+ completedAt: new Date().toISOString()
189
+ }
190
+ };
191
+ await saveRequestDB(sessionId, loopRequestId, loopData);
192
+ const loopUsage = extractTokenUsage(loopData.response.events);
193
+ pushNewRequest({
194
+ requestId: loopRequestId,
195
+ sessionId,
196
+ compositeId: `${sessionId}:${loopRequestId}`,
197
+ method: 'POST',
198
+ path: '/api/chat',
199
+ timestamp: loopData.timestamp,
200
+ statusCode: r.status,
201
+ responseTime: 0,
202
+ model: forwardedModel,
203
+ machineId,
204
+ baseUrl: resolved.baseUrl,
205
+ usage: loopUsage
206
+ }, 'completed');
207
+ }
208
+ return loopJson || JSON.parse(loopResponseBody);
209
+ }
210
+ });
211
+ request.log.info(`[chat] json loop done: ${loopResult.iterations} iter (${cloudRequestId})`);
212
+ requestData.response.completedAt = new Date().toISOString();
213
+ // Remove pending row if cloudRequestId differs from request.id
214
+ if (cloudRequestId !== request.id) {
215
+ const db = getDatabase();
216
+ db.prepare('DELETE FROM requests WHERE request_id = ? AND session_id = ?').run(request.id, sessionId);
217
+ }
218
+ await saveRequestDB(sessionId, cloudRequestId, requestData);
219
+ const usage = extractTokenUsage(requestData.response.events);
220
+ pushNewRequest({
221
+ requestId: cloudRequestId,
222
+ sessionId,
223
+ compositeId: `${sessionId}:${cloudRequestId}`,
224
+ method: request.method,
225
+ path: request.url,
226
+ timestamp: requestData.timestamp,
227
+ statusCode: response.status,
228
+ responseTime: Date.now() - startTime,
229
+ model: forwardedModel,
230
+ machineId,
231
+ baseUrl: resolved.baseUrl,
232
+ usage,
233
+ pendingId: cloudRequestId !== request.id ? `${sessionId}:${request.id}` : undefined
234
+ }, 'completed');
235
+ const finalBody = { ...loopResult.finalBody, _sessionId: sessionId };
236
+ reply.code(200).header('x-chat-session-id', sessionId).send(JSON.stringify(finalBody));
237
+ return;
238
+ }
239
+ }
240
+ // Normal JSON passthrough
241
+ requestData.response.completedAt = new Date().toISOString();
242
+ // Remove pending row if cloudRequestId differs from request.id
243
+ if (cloudRequestId !== request.id) {
244
+ const db = getDatabase();
245
+ db.prepare('DELETE FROM requests WHERE request_id = ? AND session_id = ?').run(request.id, sessionId);
246
+ }
247
+ await saveRequestDB(sessionId, cloudRequestId, requestData);
248
+ const usage = extractTokenUsage(requestData.response.events);
249
+ pushNewRequest({
250
+ requestId: cloudRequestId,
251
+ sessionId,
252
+ compositeId: `${sessionId}:${cloudRequestId}`,
253
+ method: request.method,
254
+ path: request.url,
255
+ timestamp: requestData.timestamp,
256
+ statusCode: response.status,
257
+ responseTime: Date.now() - startTime,
258
+ model: forwardedModel,
259
+ machineId,
260
+ baseUrl: resolved.baseUrl,
261
+ usage,
262
+ pendingId: cloudRequestId !== request.id ? `${sessionId}:${request.id}` : undefined
263
+ }, 'completed');
264
+ // Inject session ID into response for passthrough
265
+ try {
266
+ const passthroughBody = JSON.parse(responseBody);
267
+ passthroughBody._sessionId = sessionId;
268
+ reply.code(response.status);
269
+ reply.header('x-chat-session-id', sessionId);
270
+ reply.send(JSON.stringify(passthroughBody));
271
+ }
272
+ catch {
273
+ reply.code(response.status);
274
+ reply.headers(Object.fromEntries(response.headers));
275
+ reply.send(responseBody);
276
+ }
277
+ return;
278
+ }
279
+ // === SSE response (streaming — unified path) ===
280
+ if (isSSE && response.body) {
281
+ reply.hijack();
282
+ reply.raw.writeHead(response.status, { ...Object.fromEntries(response.headers), 'x-chat-session-id': sessionId });
283
+ const processor = new SSEStreamProcessor(reply.raw);
284
+ const nodeStream = Readable.fromWeb(response.body);
285
+ nodeStream.on('data', (chunk) => {
286
+ // SSEStreamProcessor.processChunk 同时转发到 reply.raw + 增量解析
287
+ processor.processChunk(chunk);
288
+ });
289
+ nodeStream.on('end', async () => {
290
+ processor.flushLeftover();
291
+ // 保存原始请求到 DB
292
+ requestData.response.events = processor.events;
293
+ requestData.response.completedAt = new Date().toISOString();
294
+ // Remove pending row if cloudRequestId differs from request.id
295
+ if (cloudRequestId !== request.id) {
296
+ const db = getDatabase();
297
+ db.prepare('DELETE FROM requests WHERE request_id = ? AND session_id = ?').run(request.id, sessionId);
298
+ }
299
+ await saveRequestDB(sessionId, cloudRequestId, requestData);
300
+ const usage = extractTokenUsage(requestData.response.events);
301
+ pushNewRequest({
302
+ requestId: cloudRequestId,
303
+ sessionId,
304
+ compositeId: `${sessionId}:${cloudRequestId}`,
305
+ method: request.method,
306
+ path: request.url,
307
+ timestamp: requestData.timestamp,
308
+ statusCode: response.status,
309
+ responseTime: Date.now() - startTime,
310
+ model: forwardedModel,
311
+ machineId,
312
+ baseUrl: resolved.baseUrl,
313
+ usage,
314
+ pendingId: cloudRequestId !== request.id ? `${sessionId}:${request.id}` : undefined
315
+ }, 'completed');
316
+ request.log.info(`[chat] stream completed: ${cloudRequestId} ${response.status} (${Date.now() - startTime}ms, ${processor.events.length} events)`);
317
+ // 检测注入的 MCP tool_use → 发 proxy_status 信号 + 跑 streaming inject loop
318
+ if (processor.hasInjectedToolUse()) {
319
+ const injectedCall = findInjectedCall(processor.getParsedUpstream());
320
+ // 通知客户端:proxy 正在代行 tool,同连接上还有续接数据
321
+ writeSSEEvent(reply.raw, { type: 'proxy_status', status: 'tool_executing', tool: injectedCall?.name });
322
+ request.log.info(`[chat] SSE tool hit, entering streaming inject loop: ${cloudRequestId}`);
323
+ await runStreamingInjectLoop({
324
+ initialParsed: processor.getParsedUpstream(),
325
+ body: request.body,
326
+ callUpstream: async (b) => {
327
+ const r = await fetch(targetUrlStr, {
328
+ method: 'POST',
329
+ headers: forwardHeaders,
330
+ body: JSON.stringify(b)
331
+ });
332
+ const loopRequestId = r.headers.get('x-request-id') || `loop_${request.id}_${Date.now()}`;
333
+ return { response: r, requestId: loopRequestId };
334
+ },
335
+ streamAndParse: async (loopResponse) => {
336
+ // 流式转发 loop 迭代的 SSE 到同一 reply.raw
337
+ const loopProcessor = new SSEStreamProcessor(reply.raw);
338
+ const loopStream = Readable.fromWeb(loopResponse.body);
339
+ loopStream.on('data', (chunk) => loopProcessor.processChunk(chunk));
340
+ return new Promise((resolve, reject) => {
341
+ loopStream.on('end', () => {
342
+ loopProcessor.flushLeftover();
343
+ resolve({ processor: loopProcessor, statusCode: loopResponse.status });
344
+ });
345
+ loopStream.on('error', (err) => {
346
+ request.log.error({ err }, `[chat] loop stream error`);
347
+ reject(err);
348
+ });
349
+ });
350
+ },
351
+ sessionId,
352
+ saveIterationDB: async (loopRequestId, loopProcessor, loopStatusCode, loopBody) => {
353
+ const loopData = {
354
+ requestId: loopRequestId,
355
+ sessionId,
356
+ timestamp: new Date().toISOString(),
357
+ apiKey,
358
+ proxyApiKey,
359
+ baseUrl: resolved.baseUrl,
360
+ model: forwardedModel,
361
+ machineId,
362
+ request: { method: 'POST', path: '/api/chat', headers: forwardHeaders, body: loopBody },
363
+ response: {
364
+ statusCode: loopStatusCode,
365
+ events: loopProcessor.events,
366
+ completedAt: new Date().toISOString()
367
+ }
368
+ };
369
+ await saveRequestDB(sessionId, loopRequestId, loopData);
370
+ const loopUsage = extractTokenUsage(loopProcessor.events);
371
+ pushNewRequest({
372
+ requestId: loopRequestId,
373
+ sessionId,
374
+ compositeId: `${sessionId}:${loopRequestId}`,
375
+ method: 'POST',
376
+ path: '/api/chat',
377
+ timestamp: loopData.timestamp,
378
+ statusCode: loopStatusCode,
379
+ responseTime: 0,
380
+ model: forwardedModel,
381
+ machineId,
382
+ baseUrl: resolved.baseUrl,
383
+ usage: loopUsage
384
+ }, 'completed');
385
+ },
386
+ raw: reply.raw
387
+ });
388
+ request.log.info(`[chat] SSE streaming inject loop done: ${cloudRequestId}`);
389
+ }
390
+ reply.raw.end();
391
+ });
392
+ nodeStream.on('error', (err) => {
393
+ request.log.error({ err }, `[chat] stream error: ${cloudRequestId}`);
394
+ reply.raw.end();
395
+ });
396
+ return;
397
+ }
398
+ // No body — error
399
+ reply.code(response.status).send('');
400
+ });
401
+ }
@@ -1,5 +1,5 @@
1
1
  import { WebSocket } from 'ws';
2
2
  export declare function addDataClient(ws: WebSocket): void;
3
3
  export declare function removeDataClient(ws: WebSocket): void;
4
- export declare function pushNewRequest(summary: any): void;
4
+ export declare function pushNewRequest(summary: any, status?: 'pending' | 'completed'): void;
5
5
  export declare function pushStatsNotify(): void;
@@ -8,11 +8,11 @@ export function removeDataClient(ws) {
8
8
  dataClients.delete(ws);
9
9
  }
10
10
  // Broadcast helpers
11
- export function pushNewRequest(summary) {
11
+ export function pushNewRequest(summary, status = 'completed') {
12
12
  broadcast({
13
13
  type: 'request',
14
- action: 'new',
15
- data: summary
14
+ action: status === 'pending' ? 'new' : 'update',
15
+ data: { ...summary, status }
16
16
  });
17
17
  }
18
18
  export function pushStatsNotify() {
@@ -5,6 +5,7 @@ import { configureDbPath } from '../utils/db.js';
5
5
  import { getCurrentModuleUrl } from '../utils/esm-dirname.js';
6
6
  import { setupProxy } from './proxy.js';
7
7
  import { setupUiRoutes } from './ui-route.js';
8
+ import { setupChatRoute } from './chat-route.js';
8
9
  import { requestIdMiddleware } from './middleware/request-id.js';
9
10
  export async function createServer() {
10
11
  const config = await loadConfig();
@@ -19,6 +20,7 @@ export async function createServer() {
19
20
  fastify.register(requestIdMiddleware);
20
21
  await setupUiRoutes(fastify); // UI routes registered BEFORE proxy to avoid being proxied
21
22
  await setupProxy(fastify, config.proxy);
23
+ await setupChatRoute(fastify, config.proxy); // MCP-enhanced chat endpoint
22
24
  return fastify;
23
25
  }
24
26
  export async function startServer() {
@@ -0,0 +1,2 @@
1
+ import { FastifyInstance } from 'fastify';
2
+ export declare function setupMcpRoutes(fastify: FastifyInstance, config: any): Promise<void>;