@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.
- package/README.md +11 -35
- package/dist/config/index.js +2 -1
- package/dist/config/schema.d.ts +48 -0
- package/dist/config/schema.js +11 -1
- package/dist/server/chat-route.d.ts +3 -0
- package/dist/server/chat-route.js +401 -0
- package/dist/server/data-push.d.ts +1 -1
- package/dist/server/data-push.js +3 -3
- package/dist/server/index.js +2 -0
- package/dist/server/mcp-route.d.ts +2 -0
- package/dist/server/mcp-route.js +161 -0
- package/dist/server/proxy.d.ts +2 -0
- package/dist/server/proxy.js +55 -101
- package/dist/server/ui-route.js +3 -0
- package/dist/tools/mcp-bridge.d.ts +13 -0
- package/dist/tools/mcp-bridge.js +36 -0
- package/dist/tools/registry.js +10 -4
- package/dist/ui/assets/{1c-CgVqmGt6.js → 1c-BKfNxcqO.js} +1 -1
- package/dist/ui/assets/{abnf-JPM4b6fj.js → abnf-kurmJZQ_.js} +1 -1
- package/dist/ui/assets/{abnfDiagram-VRR7QNED-DJkd8PHl.js → abnfDiagram-VRR7QNED-ByeCIWIR.js} +1 -1
- package/dist/ui/assets/{accesslog-CLIMhXWi.js → accesslog-D64BZ_De.js} +1 -1
- package/dist/ui/assets/{actionscript-DqniQGld.js → actionscript-pDK74uly.js} +1 -1
- package/dist/ui/assets/{ada-2BFfY7fF.js → ada-DRb-_v9Q.js} +1 -1
- package/dist/ui/assets/{angelscript-C47qRqcs.js → angelscript-CZNb0D_x.js} +1 -1
- package/dist/ui/assets/{apache-DP-LC5-h.js → apache-DXxCmfqn.js} +1 -1
- package/dist/ui/assets/{applescript-BB0gk3HQ.js → applescript-SH5nkFFY.js} +1 -1
- package/dist/ui/assets/{arc-D8wRCC4D.js → arc-MeodV3jp.js} +1 -1
- package/dist/ui/assets/{arcade-1R6g1VPm.js → arcade-BBDVvGqJ.js} +1 -1
- package/dist/ui/assets/{architectureDiagram-ZJ3FMSHR-CbHhHV9v.js → architectureDiagram-ZJ3FMSHR-BemxtZtq.js} +1 -1
- package/dist/ui/assets/{arduino-B8YryK0R.js → arduino-BzSPoel-.js} +1 -1
- package/dist/ui/assets/{armasm-CYdj7mzR.js → armasm-bxTyTYQU.js} +1 -1
- package/dist/ui/assets/{asciidoc-bZ11zz6i.js → asciidoc-CTwbDxt_.js} +1 -1
- package/dist/ui/assets/{aspectj-D5WPU-RQ.js → aspectj-CG5ykwLW.js} +1 -1
- package/dist/ui/assets/{autohotkey-70tZvCLL.js → autohotkey-C5JGxVuA.js} +1 -1
- package/dist/ui/assets/{autoit-CX2GaaHP.js → autoit-y4Yl0UCW.js} +1 -1
- package/dist/ui/assets/{avrasm-C154El0d.js → avrasm-bGE35O5G.js} +1 -1
- package/dist/ui/assets/{awk-DdXKOeux.js → awk-EaW3U0nk.js} +1 -1
- package/dist/ui/assets/{axapta-CwLwkXST.js → axapta-DR4gLXP2.js} +1 -1
- package/dist/ui/assets/{bash-Uu61S1nB.js → bash-ce3pZrbv.js} +1 -1
- package/dist/ui/assets/{basic-CeiAWoiF.js → basic-BUjgcgEE.js} +1 -1
- package/dist/ui/assets/{blockDiagram-677ZJIJ3-DcvhphUd.js → blockDiagram-677ZJIJ3-_o8CsocQ.js} +1 -1
- package/dist/ui/assets/{bnf-B5KF61QW.js → bnf-CweJzP3u.js} +1 -1
- package/dist/ui/assets/{brainfuck-CP0Y7_VW.js → brainfuck-CdSx1voD.js} +1 -1
- package/dist/ui/assets/{coq-D-WTlq_d.js → c-CRHUjHXY.js} +1 -1
- package/dist/ui/assets/{c-like-DXr53gS6.js → c-like-CEkf_5bN.js} +1 -1
- package/dist/ui/assets/{c4Diagram-LMCZKHZV-Cn017lmJ.js → c4Diagram-LMCZKHZV-DOkmzOL2.js} +1 -1
- package/dist/ui/assets/{cal-7ld1j-Wh.js → cal-n5KEHShP.js} +1 -1
- package/dist/ui/assets/{capnproto-DrddNBCZ.js → capnproto-DBqs0rUq.js} +1 -1
- package/dist/ui/assets/{ceylon-XPuE6IIL.js → ceylon-Bqm782As.js} +1 -1
- package/dist/ui/assets/channel-ouobCd00.js +1 -0
- package/dist/ui/assets/{chunk-2Q5K7J3B-BoX3IESS.js → chunk-2Q5K7J3B-DW9ak6HE.js} +1 -1
- package/dist/ui/assets/{chunk-32BRIVSS-C300ACzq.js → chunk-32BRIVSS-BrSieCRZ.js} +1 -1
- package/dist/ui/assets/{chunk-5VM5RSS4-MtSkFsde.js → chunk-5VM5RSS4-DfQ4qP83.js} +1 -1
- package/dist/ui/assets/{chunk-EX3LRPZG-CEeHrGNV.js → chunk-EX3LRPZG-Ct5q5MD9.js} +1 -1
- package/dist/ui/assets/{chunk-JWPE2WC7-DTRgpK0R.js → chunk-JWPE2WC7-CmPr6d57.js} +1 -1
- package/dist/ui/assets/{chunk-MOJQB5TN-DiOl0HJx.js → chunk-MOJQB5TN-TVmHnDCp.js} +1 -1
- package/dist/ui/assets/{chunk-RYQCIY6F-CVC3opqY.js → chunk-RYQCIY6F-CJid4ifN.js} +1 -1
- package/dist/ui/assets/{chunk-V7JOEXUC-yQYlqQCC.js → chunk-V7JOEXUC-DpPBugpJ.js} +1 -1
- package/dist/ui/assets/{chunk-VR4S4FIN-iAA8ZgkK.js → chunk-VR4S4FIN-ChvE2cdM.js} +1 -1
- package/dist/ui/assets/{chunk-XXDRQBXY-B303eieF.js → chunk-XXDRQBXY-CQkAaDcz.js} +1 -1
- package/dist/ui/assets/classDiagram-OUVF2IWQ-BLjfj6C1.js +1 -0
- package/dist/ui/assets/classDiagram-v2-EOCWNBFH-BLjfj6C1.js +1 -0
- package/dist/ui/assets/{clean-MfHaW_uS.js → clean-C6pxrVpV.js} +1 -1
- package/dist/ui/assets/{clojure-9L8TfiWA.js → clojure-DBFV_cQs.js} +1 -1
- package/dist/ui/assets/{clojure-repl-CjsH9sxr.js → clojure-repl-gAHGPM6b.js} +1 -1
- package/dist/ui/assets/{cmake-D0D1Q30G.js → cmake-kWW8kCUc.js} +1 -1
- package/dist/ui/assets/{coffeescript-BI4jWZnB.js → coffeescript-6GnANHV0.js} +1 -1
- package/dist/ui/assets/{c-BgqCrSpv.js → coq-BZ36Oykn.js} +1 -1
- package/dist/ui/assets/{cos-DHax5LIJ.js → cos-7hQ1utRX.js} +1 -1
- package/dist/ui/assets/{cose-bilkent-JH36ORCC-BzrKmTAZ.js → cose-bilkent-JH36ORCC-C3eaOw98.js} +1 -1
- package/dist/ui/assets/{cpp-M4aMPUas.js → cpp-3tqV0Eg4.js} +1 -1
- package/dist/ui/assets/{crmsh-DAAczfR0.js → crmsh-BCWSxGj_.js} +1 -1
- package/dist/ui/assets/{crystal-7g2CpWm4.js → crystal-DWYK1_zJ.js} +1 -1
- package/dist/ui/assets/{csharp-DW5GdKKf.js → csharp-4MXdBrfn.js} +1 -1
- package/dist/ui/assets/{csp-Bq74fG7-.js → csp-B6w1ig4q.js} +1 -1
- package/dist/ui/assets/{css-DHyeLXff.js → css-DF73D19j.js} +1 -1
- package/dist/ui/assets/{cynefin-VYW2F7L2-DwV1t9iV.js → cynefin-VYW2F7L2-CBT889Q1.js} +1 -1
- package/dist/ui/assets/{cynefinDiagram-TSTJHNR4-kBCFRYPz.js → cynefinDiagram-TSTJHNR4-CTpbDnI7.js} +1 -1
- package/dist/ui/assets/{d-yey2lm3v.js → d-DzYDcQHZ.js} +1 -1
- package/dist/ui/assets/{dagre-VKFMJZFB-CErVJ1s0.js → dagre-VKFMJZFB-WWoYj0oQ.js} +1 -1
- package/dist/ui/assets/{dart-BadDxflP.js → dart-D3jB16SU.js} +1 -1
- package/dist/ui/assets/{delphi-CqzVqtDp.js → delphi-CZl4UAcT.js} +1 -1
- package/dist/ui/assets/{diagram-FQU43EPY-C7zAW2DU.js → diagram-FQU43EPY-3wQZQkQz.js} +1 -1
- package/dist/ui/assets/{diagram-G47NLZAW-CbUb6BZI.js → diagram-G47NLZAW-Ca-cA51I.js} +1 -1
- package/dist/ui/assets/{diagram-NH7WQ7WH-C5mgi3dn.js → diagram-NH7WQ7WH-YisQNOg5.js} +1 -1
- package/dist/ui/assets/{diagram-OA4YK3LP-Cok2YNfS.js → diagram-OA4YK3LP-0EJamcdw.js} +1 -1
- package/dist/ui/assets/{diagram-WEI45ONY-BODuP2EB.js → diagram-WEI45ONY-C49BDAKI.js} +1 -1
- package/dist/ui/assets/{diff-EVigJ-h2.js → diff-_OXjiwKq.js} +1 -1
- package/dist/ui/assets/{django-BH2EEal6.js → django-MC7gw7Ba.js} +1 -1
- package/dist/ui/assets/{dns-BSc8VTm8.js → dns-D3uYm_NR.js} +1 -1
- package/dist/ui/assets/{dockerfile-Br_pZjru.js → dockerfile-CbxCn4X2.js} +1 -1
- package/dist/ui/assets/{dos-Bx3ludet.js → dos-D7MpkWlZ.js} +1 -1
- package/dist/ui/assets/{dsconfig-DSI-ePne.js → dsconfig-DejdiVkX.js} +1 -1
- package/dist/ui/assets/{dts-ClCuE1Xq.js → dts-CMTiAYoj.js} +1 -1
- package/dist/ui/assets/{dust-CC9Z8iuW.js → dust-DrNExIio.js} +1 -1
- package/dist/ui/assets/{ebnf-DI0w_fbi.js → ebnf-CQl_HyGP.js} +1 -1
- package/dist/ui/assets/{ebnfDiagram-CCIWWBDH-CgsnO8Qm.js → ebnfDiagram-CCIWWBDH-Cpbm8Saa.js} +1 -1
- package/dist/ui/assets/{elixir-hdzZik8p.js → elixir-DjKAXtge.js} +1 -1
- package/dist/ui/assets/{elm-DJAgqt5I.js → elm-DbFMwRfr.js} +1 -1
- package/dist/ui/assets/{erDiagram-Q63AITRT-K4zJcEKd.js → erDiagram-Q63AITRT-CjiUln3_.js} +1 -1
- package/dist/ui/assets/{erb-Cq4OQqkl.js → erb-CmcM27bT.js} +1 -1
- package/dist/ui/assets/{erlang-CHoXLODu.js → erlang-Se5g1C-_.js} +1 -1
- package/dist/ui/assets/{erlang-repl-Brp70Zip.js → erlang-repl-BYXNE8Rp.js} +1 -1
- package/dist/ui/assets/{excel-DjS-QR9P.js → excel-C0rpMYUp.js} +1 -1
- package/dist/ui/assets/{fix-BsO9Oq6H.js → fix-MKKAkUZt.js} +1 -1
- package/dist/ui/assets/{flix-2A7CKozm.js → flix-P1JtxtSk.js} +1 -1
- package/dist/ui/assets/{flowDiagram-23GEKE2U-Ck4tfxWX.js → flowDiagram-23GEKE2U-BHmxHBjF.js} +1 -1
- package/dist/ui/assets/{fortran-BQu3wORI.js → fortran-yDT4QtkM.js} +1 -1
- package/dist/ui/assets/{fsharp-D439S6PZ.js → fsharp-P9pwJwTA.js} +1 -1
- package/dist/ui/assets/{gams-CPRxKfRH.js → gams-B5t8fTmX.js} +1 -1
- package/dist/ui/assets/{ganttDiagram-NO4QXBWP-QTPyXXxa.js → ganttDiagram-NO4QXBWP-CLZshSdd.js} +1 -1
- package/dist/ui/assets/{gauss-GJFW9Vod.js → gauss-BnurLk3c.js} +1 -1
- package/dist/ui/assets/{gcode-CF6woDAl.js → gcode-ChY-gRbf.js} +1 -1
- package/dist/ui/assets/{gherkin-Co-YjHfW.js → gherkin-Dvnrp8BP.js} +1 -1
- package/dist/ui/assets/{gitGraphDiagram-IHSO6WYX-Do9VfPHL.js → gitGraphDiagram-IHSO6WYX-BRB4at2D.js} +1 -1
- package/dist/ui/assets/{glsl-D3lldBTJ.js → glsl-DcovBIzp.js} +1 -1
- package/dist/ui/assets/{gml-DyoCibnw.js → gml-S6feXRA_.js} +1 -1
- package/dist/ui/assets/{go-BNeAS1jC.js → go-B81WXVYZ.js} +1 -1
- package/dist/ui/assets/{golo-BuXecWAH.js → golo-DKL2IdWk.js} +1 -1
- package/dist/ui/assets/{gradle-BP7ToLe9.js → gradle-T97Z3PII.js} +1 -1
- package/dist/ui/assets/{groovy-GqWVT09g.js → groovy-BXX6Iv9v.js} +1 -1
- package/dist/ui/assets/{haml-SLbvCHsC.js → haml-D8q-wDTz.js} +1 -1
- package/dist/ui/assets/{handlebars-BnaCJTc5.js → handlebars-DDdkLhQc.js} +1 -1
- package/dist/ui/assets/{haskell-CrX9ftWp.js → haskell-DfxSCvE8.js} +1 -1
- package/dist/ui/assets/{haxe-DNoaIxsE.js → haxe-CYmtAuGy.js} +1 -1
- package/dist/ui/assets/{hsp-CLjy3djj.js → hsp-B6vrbmnn.js} +1 -1
- package/dist/ui/assets/{htmlbars-w96Kz5NL.js → htmlbars-D2C_JXNB.js} +1 -1
- package/dist/ui/assets/{http-VIMXIxM8.js → http-CF4dzBBt.js} +1 -1
- package/dist/ui/assets/{hy-_qE83_aW.js → hy-Bo3ftzPr.js} +1 -1
- package/dist/ui/assets/index-BLxwrLko.js +2655 -0
- package/dist/ui/assets/{index-DpcPfZl3.js → index-CMOhE8Fu.js} +3 -3
- package/dist/ui/assets/index-bwex7GGt.css +10 -0
- package/dist/ui/assets/{infoDiagram-FWYZ7A6U-D9O7SZ2X.js → infoDiagram-FWYZ7A6U-CsP_vXYo.js} +1 -1
- package/dist/ui/assets/{inform7-CnyW73C1.js → inform7-DW_1PfgW.js} +1 -1
- package/dist/ui/assets/{ini-GFMFAjln.js → ini-DFoyjgSu.js} +1 -1
- package/dist/ui/assets/{irpf90-BPmSYATn.js → irpf90-C-6-eyAC.js} +1 -1
- package/dist/ui/assets/{isbl-BnStGiBQ.js → isbl-4gc8Swo4.js} +1 -1
- package/dist/ui/assets/{ishikawaDiagram-FXEZZL3T-DgcUDM9X.js → ishikawaDiagram-FXEZZL3T-D6bH6CQh.js} +1 -1
- package/dist/ui/assets/{java-CVORcFd8.js → java-bb2y4EiS.js} +1 -1
- package/dist/ui/assets/{javascript-B2pFzODm.js → javascript-BAtDHP3W.js} +1 -1
- package/dist/ui/assets/{jboss-cli-B9cQeKvZ.js → jboss-cli-qZg2Imzs.js} +1 -1
- package/dist/ui/assets/{journeyDiagram-5HDEW3XC-Bivjw4h7.js → journeyDiagram-5HDEW3XC-DxDCxUCo.js} +1 -1
- package/dist/ui/assets/{json-BJof8L10.js → json-CNupTqez.js} +1 -1
- package/dist/ui/assets/{julia-D_dGrCpZ.js → julia-DK5AbWFh.js} +1 -1
- package/dist/ui/assets/{julia-repl-Dsw0K1B1.js → julia-repl-CY2KMHbB.js} +1 -1
- package/dist/ui/assets/{kanban-definition-HUTT4EX6-Dg7NbKta.js → kanban-definition-HUTT4EX6-Dt5KtIgo.js} +1 -1
- package/dist/ui/assets/{kotlin-8oetHRtX.js → kotlin-D9FIaw0d.js} +1 -1
- package/dist/ui/assets/{lasso-e37r_NX1.js → lasso-DFGV2pQw.js} +1 -1
- package/dist/ui/assets/{latex-DAmwzl3n.js → latex-B4vw8fyc.js} +1 -1
- package/dist/ui/assets/{ldif-CD0mgmt4.js → ldif-Dm2FIlTD.js} +1 -1
- package/dist/ui/assets/{leaf-GfPKlp7a.js → leaf-BfPV5rQV.js} +1 -1
- package/dist/ui/assets/{less-PndaZJ6n.js → less-DlD-uNfa.js} +1 -1
- package/dist/ui/assets/{lisp-CNaspu3A.js → lisp-fwHwKhac.js} +1 -1
- package/dist/ui/assets/{livecodeserver-DEKsXiP3.js → livecodeserver-2Iqy9OJM.js} +1 -1
- package/dist/ui/assets/{livescript-DM7jasJn.js → livescript-CsVjBiYy.js} +1 -1
- package/dist/ui/assets/{llvm-D_29j9MV.js → llvm-Dr1LxL0C.js} +1 -1
- package/dist/ui/assets/{lsl-DY0WRYhg.js → lsl-C19lQilh.js} +1 -1
- package/dist/ui/assets/{lua-DZ_v4xaE.js → lua-Bt6lk_UK.js} +1 -1
- package/dist/ui/assets/{makefile-VOjcUGXf.js → makefile-BjpMOWNL.js} +1 -1
- package/dist/ui/assets/{markdown-yUEmZWvu.js → markdown-BCvk5Luj.js} +1 -1
- package/dist/ui/assets/{mathematica-BLXYGKkd.js → mathematica-CMAvLFmv.js} +1 -1
- package/dist/ui/assets/{matlab-B7SkIpvh.js → matlab-Dp9rgor5.js} +1 -1
- package/dist/ui/assets/{maxima-C7Fw8Vyt.js → maxima-UUgZl2h3.js} +1 -1
- package/dist/ui/assets/{mel-C_Znst2Y.js → mel-DU6cwelq.js} +1 -1
- package/dist/ui/assets/{mercury-DjUnQNsq.js → mercury-DXd4_3jU.js} +1 -1
- package/dist/ui/assets/{mindmap-definition-LN4V7U3C-Dp6mEy6L.js → mindmap-definition-LN4V7U3C-BThZR1du.js} +1 -1
- package/dist/ui/assets/{mipsasm-DaGHhR8c.js → mipsasm-CMNMWNFn.js} +1 -1
- package/dist/ui/assets/{mizar-CZnct-_Z.js → mizar-B6c3dauU.js} +1 -1
- package/dist/ui/assets/{mojolicious-BdWFK35j.js → mojolicious-Cprwk6o_.js} +1 -1
- package/dist/ui/assets/{monkey-ta_jgafo.js → monkey-BaAReGcY.js} +1 -1
- package/dist/ui/assets/{moonscript-B9qovjV6.js → moonscript-gS515C7R.js} +1 -1
- package/dist/ui/assets/{n1ql-BciXbxiw.js → n1ql-Z_4MPbYI.js} +1 -1
- package/dist/ui/assets/{nginx-DRCZYbxj.js → nginx-Dc_6EmJn.js} +1 -1
- package/dist/ui/assets/{nim-DTMCxPJt.js → nim-DtjvH3ft.js} +1 -1
- package/dist/ui/assets/{nix-D39yZxF9.js → nix-Bu2r_I9_.js} +1 -1
- package/dist/ui/assets/{node-repl-vAEXdnYM.js → node-repl-8HGWlvcp.js} +1 -1
- package/dist/ui/assets/{nsis-CCMP8mq3.js → nsis-9FG-YMvD.js} +1 -1
- package/dist/ui/assets/{objectivec-CZx4kSLP.js → objectivec-CX1QmJoj.js} +1 -1
- package/dist/ui/assets/{ocaml-DBnEo9uR.js → ocaml-4qT3O786.js} +1 -1
- package/dist/ui/assets/{openscad-BKc7u4Bl.js → openscad-CvJzggqO.js} +1 -1
- package/dist/ui/assets/{oxygene-M_Z4lQ6l.js → oxygene-BwtAuPgg.js} +1 -1
- package/dist/ui/assets/{parser3-DS9UKiKD.js → parser3-DKnhj506.js} +1 -1
- package/dist/ui/assets/{pegDiagram-2B236MQR-BBEXn76M.js → pegDiagram-2B236MQR-ZVgEXVAh.js} +1 -1
- package/dist/ui/assets/{perl-D6iEALGE.js → perl-BApvz3gE.js} +1 -1
- package/dist/ui/assets/{pf-JQL0ClGi.js → pf--Fg5j93h.js} +1 -1
- package/dist/ui/assets/{pgsql-DEmCURBr.js → pgsql-DOapqed0.js} +1 -1
- package/dist/ui/assets/{php-DVm-0PY5.js → php-DIm5UjQ3.js} +1 -1
- package/dist/ui/assets/{php-template-DfWbDpnE.js → php-template-DTFQ-Xzw.js} +1 -1
- package/dist/ui/assets/{pieDiagram-ENE6RG2P-D5PZFiDj.js → pieDiagram-ENE6RG2P-viaSeTd2.js} +1 -1
- package/dist/ui/assets/{plaintext-BahVkGlu.js → plaintext-NRztTbl1.js} +1 -1
- package/dist/ui/assets/{pony-wVig0caC.js → pony-BfL7O-OQ.js} +1 -1
- package/dist/ui/assets/{powershell-COjMBUit.js → powershell-CLt45Qf4.js} +1 -1
- package/dist/ui/assets/{processing-DnUzvFZx.js → processing-afiHf7ow.js} +1 -1
- package/dist/ui/assets/{profile-mDlbwJeL.js → profile-Ch1BVwxN.js} +1 -1
- package/dist/ui/assets/{prolog-x2hG6DnA.js → prolog-Tf3A0bWy.js} +1 -1
- package/dist/ui/assets/{properties-DzZyyivC.js → properties-8SdgBqK7.js} +1 -1
- package/dist/ui/assets/{protobuf-a5NwbYD5.js → protobuf-DPDrI7Qg.js} +1 -1
- package/dist/ui/assets/{puppet-CCWyPVuC.js → puppet-CXofbQOs.js} +1 -1
- package/dist/ui/assets/{purebasic-CXNdqtD4.js → purebasic-eUJ8DEfM.js} +1 -1
- package/dist/ui/assets/{python-iSR9YlDJ.js → python-C98zkBPD.js} +1 -1
- package/dist/ui/assets/{python-repl-CCmKzWru.js → python-repl-Xul3ztGs.js} +1 -1
- package/dist/ui/assets/{q-B30ZmDuD.js → q-BkAM-a7C.js} +1 -1
- package/dist/ui/assets/{qml-BGdPdB4X.js → qml-BsEaix_u.js} +1 -1
- package/dist/ui/assets/{quadrantDiagram-ABIIQ3AL-BBF1rAvI.js → quadrantDiagram-ABIIQ3AL-Bvz1yyu9.js} +1 -1
- package/dist/ui/assets/{r-B8ASdWL1.js → r-ItUdMzSw.js} +1 -1
- package/dist/ui/assets/{railroadDiagram-RFXS5EU6-DQFUXGVD.js → railroadDiagram-RFXS5EU6-DdFuoPrk.js} +1 -1
- package/dist/ui/assets/{reasonml-Dw4Bi5B5.js → reasonml-BDbdIYs9.js} +1 -1
- package/dist/ui/assets/{requirementDiagram-TGXJPOKE-DCgrs7-P.js → requirementDiagram-TGXJPOKE-B8hcvLSP.js} +1 -1
- package/dist/ui/assets/{rib-CgUGGGZ9.js → rib-zIraQ_mX.js} +1 -1
- package/dist/ui/assets/{roboconf-CCZNQvSP.js → roboconf-CzoIRml1.js} +1 -1
- package/dist/ui/assets/{routeros-DVT5M6iV.js → routeros-B3UgD0yV.js} +1 -1
- package/dist/ui/assets/{rsl-BY-LhdKq.js → rsl-wAwFfXwD.js} +1 -1
- package/dist/ui/assets/{ruby-CZW4dclw.js → ruby-D3Thdpv8.js} +1 -1
- package/dist/ui/assets/{ruleslanguage-CZdjv1of.js → ruleslanguage-CPWvLcMl.js} +1 -1
- package/dist/ui/assets/{rust-D5Xa_mSD.js → rust-DOnpus5t.js} +1 -1
- package/dist/ui/assets/{sankeyDiagram-HTMAVEWB-BXeEgUB7.js → sankeyDiagram-HTMAVEWB-CH-sCFAi.js} +1 -1
- package/dist/ui/assets/{sas-B_UJ-HCZ.js → sas-B2858_1j.js} +1 -1
- package/dist/ui/assets/{scala-B8wSdZik.js → scala-Cveq3ftT.js} +1 -1
- package/dist/ui/assets/{scheme-DD7U81eh.js → scheme-DcdF6kjo.js} +1 -1
- package/dist/ui/assets/{scilab-aJGpbkKs.js → scilab-Dycxtkgn.js} +1 -1
- package/dist/ui/assets/{scss-BBqyvWYh.js → scss-DFUrItbr.js} +1 -1
- package/dist/ui/assets/{sequenceDiagram-DBY2YBRQ-CnDTZN18.js → sequenceDiagram-DBY2YBRQ-B6WOhYgY.js} +1 -1
- package/dist/ui/assets/{shell-CR23jqfz.js → shell-CdK6mfw0.js} +1 -1
- package/dist/ui/assets/{sizeCapture-X5ZJPWSS-joZ477RB.js → sizeCapture-X5ZJPWSS-DEtOtMCB.js} +1 -1
- package/dist/ui/assets/{smali-ZmLyRCrQ.js → smali-BWrgi9Uw.js} +1 -1
- package/dist/ui/assets/{smalltalk-CnADYfPr.js → smalltalk-D7rVc6SF.js} +1 -1
- package/dist/ui/assets/{sml-zj1KD04_.js → sml-BwZXpnKa.js} +1 -1
- package/dist/ui/assets/{sqf-DCCaZ3e3.js → sqf-GLi5DNBX.js} +1 -1
- package/dist/ui/assets/{sql-CHGw2SCR.js → sql-B3C8FGL3.js} +1 -1
- package/dist/ui/assets/{sql_more-DsnvjMwh.js → sql_more-DnUCbJeD.js} +1 -1
- package/dist/ui/assets/{stan-ChxdV8f9.js → stan-Sm9c5Vis.js} +1 -1
- package/dist/ui/assets/{stata-CgFw45qg.js → stata-pulikDkU.js} +1 -1
- package/dist/ui/assets/{stateDiagram-2N3HPSRC-CzLIdKbt.js → stateDiagram-2N3HPSRC-ncOw7g4V.js} +1 -1
- package/dist/ui/assets/stateDiagram-v2-6OUMAXLB-D1kUHFw1.js +1 -0
- package/dist/ui/assets/{step21-DaraQMOk.js → step21-pX15wqtK.js} +1 -1
- package/dist/ui/assets/{stylus-BZpiJEzN.js → stylus-fOumlpdp.js} +1 -1
- package/dist/ui/assets/{subunit-B6Gp0n7h.js → subunit-uu3Ov4HX.js} +1 -1
- package/dist/ui/assets/{swift-DQzoz60p.js → swift-CmLDJWUd.js} +1 -1
- package/dist/ui/assets/{swimlanes-5IMT3BWC-DOMOhwX0.js → swimlanes-5IMT3BWC-DqgXf_9D.js} +2 -2
- package/dist/ui/assets/swimlanesDiagram-G3AALYLV-C-113Xl1.js +8 -0
- package/dist/ui/assets/{taggerscript-BMLkfiab.js → taggerscript-CazB9nt4.js} +1 -1
- package/dist/ui/assets/{tap-PUNWTFgu.js → tap-DojnLl9r.js} +1 -1
- package/dist/ui/assets/{tcl-BODH5qJa.js → tcl-CMSHuPY4.js} +1 -1
- package/dist/ui/assets/{thrift-BQ-W_YlC.js → thrift-D9T_iaQS.js} +1 -1
- package/dist/ui/assets/{timeline-definition-FHXFAJF6-DQBDeTzH.js → timeline-definition-FHXFAJF6--1I0coei.js} +1 -1
- package/dist/ui/assets/{tp-Dt3WwOGF.js → tp-tKwomxNq.js} +1 -1
- package/dist/ui/assets/{twig-44RQtw7Z.js → twig-CEsN-ViC.js} +1 -1
- package/dist/ui/assets/{typescript-BsouHXHR.js → typescript-BwkWaYfc.js} +1 -1
- package/dist/ui/assets/{vala-DqJj6fPT.js → vala-BFkwjsLY.js} +1 -1
- package/dist/ui/assets/{vbnet-CuqWYg5r.js → vbnet-BoJ1NvBH.js} +1 -1
- package/dist/ui/assets/{vbscript-w20MQMYP.js → vbscript-D8XSgQnu.js} +1 -1
- package/dist/ui/assets/{vbscript-html-BP0D0WEV.js → vbscript-html-hn6cBiCZ.js} +1 -1
- package/dist/ui/assets/{vennDiagram-L72KCM5P-DwNnj3Kc.js → vennDiagram-L72KCM5P--d_scOj_.js} +1 -1
- package/dist/ui/assets/{verilog-DIpBpJAe.js → verilog-CHsNT9Cy.js} +1 -1
- package/dist/ui/assets/{vhdl-D5nCxDbL.js → vhdl-BHAdjshQ.js} +1 -1
- package/dist/ui/assets/{vim-CPfbBM_x.js → vim-CXGYjr0E.js} +1 -1
- package/dist/ui/assets/{wardleyDiagram-EHGQE667-WxVQHmM7.js → wardleyDiagram-EHGQE667-C1OlFa5w.js} +1 -1
- package/dist/ui/assets/{x86asm-D_t4Z_eq.js → x86asm-BMtTtbdc.js} +1 -1
- package/dist/ui/assets/{xl-DQf5IG_W.js → xl-2RPeIz-_.js} +1 -1
- package/dist/ui/assets/{xml-D-Bn0NMR.js → xml-BdgFaqW_.js} +1 -1
- package/dist/ui/assets/{xquery-DqushYX1.js → xquery-C-Nme7tR.js} +1 -1
- package/dist/ui/assets/{xychartDiagram-FW5EYKEG-B6D8mgs8.js → xychartDiagram-FW5EYKEG-BzM0JoN5.js} +1 -1
- package/dist/ui/assets/{yaml-B2GFZenc.js → yaml-CVfovUzE.js} +1 -1
- package/dist/ui/assets/{zephir-SiNGockR.js → zephir-BLoFpefb.js} +1 -1
- package/dist/ui/index.html +2 -2
- package/dist/utils/__tests__/tool-injector.test.js +32 -35
- package/dist/utils/db.d.ts +1 -0
- package/dist/utils/db.js +22 -0
- package/dist/utils/inject-loop.d.ts +52 -1
- package/dist/utils/inject-loop.js +70 -2
- package/dist/utils/mcp-db.d.ts +35 -0
- package/dist/utils/mcp-db.js +79 -0
- package/dist/utils/mcp-manager.d.ts +36 -0
- package/dist/utils/mcp-manager.js +215 -0
- package/dist/utils/request-writer.d.ts +4 -0
- package/dist/utils/request-writer.js +66 -0
- package/dist/utils/sse-stream-processor.d.ts +27 -0
- package/dist/utils/sse-stream-processor.js +144 -0
- package/dist/utils/tool-injector.d.ts +6 -9
- package/dist/utils/tool-injector.js +13 -14
- package/dist/utils/version.d.ts +1 -0
- package/dist/utils/version.js +4 -1
- package/package.json +8 -9
- package/dist/ui/assets/channel-C5JlZ38H.js +0 -1
- package/dist/ui/assets/classDiagram-OUVF2IWQ-j5FVBKaD.js +0 -1
- package/dist/ui/assets/classDiagram-v2-EOCWNBFH-j5FVBKaD.js +0 -1
- package/dist/ui/assets/index-Baqd6LlK.js +0 -2625
- package/dist/ui/assets/index-fHtNI_e8.css +0 -1
- package/dist/ui/assets/stateDiagram-v2-6OUMAXLB-Bg4GAkB5.js +0 -1
- 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
|
|
4
|
-
|
|
5
|
-
一站式解决国内网络访问 Claude Code 的问题,同时提供请求日志、Token 统计、供应商切换、SSE 流式抓包等运维能力。
|
|
3
|
+
Claude Code 代理工具 + Token 消耗监控面板。一行命令启动代理,实时追踪每次请求的模型、Token 用量和响应状态。
|
|
6
4
|
|
|
7
5
|
[](https://www.npmjs.com/package/@cc-monitoring/proxy-core)
|
|
8
6
|
[](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:
|
|
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":
|
|
68
|
+
"server": { "port": 9527, "host": "localhost" },
|
|
71
69
|
"proxy": {
|
|
72
|
-
"target": "https://
|
|
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
|
-
"
|
|
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) | 监听端口,默认
|
|
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:
|
|
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
|
| 变量 | 说明 |
|
package/dist/config/index.js
CHANGED
package/dist/config/schema.d.ts
CHANGED
|
@@ -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;
|
package/dist/config/schema.js
CHANGED
|
@@ -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,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;
|
package/dist/server/data-push.js
CHANGED
|
@@ -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() {
|
package/dist/server/index.js
CHANGED
|
@@ -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() {
|